Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 18f22ab

Browse files
Only nullify tasty if Ynullify-tasty is set; Refine FlexibleType nullification rules (#23938)
Given the nightly results, we think the nullification rules still need some polish and is not ready for all compiled Scala code. Hence, we only nullify tasty if `Ynullify-tasty` is set now. Based on #23911 Fixes #23908 Could fix #23933, #23935, #23936, and #23937 (I tested locally due the explicit nulls tests disabled temprarily)
2 parents 8c2b7ad + 1663038 commit 18f22ab

File tree

13 files changed

+282
-123
lines changed

13 files changed

+282
-123
lines changed

‎compiler/src/dotty/tools/dotc/config/ScalaSettings.scala‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ private sealed trait YSettings:
449449
val YnoKindPolymorphism: Setting[Boolean] = BooleanSetting(ForkSetting, "Yno-kind-polymorphism", "Disable kind polymorphism. (This flag has no effect)", deprecation = Deprecation.removed())
450450
val YexplicitNulls: Setting[Boolean] = BooleanSetting(ForkSetting, "Yexplicit-nulls", "Make reference types non-nullable. Nullable types can be expressed with unions: e.g. String|Null.")
451451
val YnoFlexibleTypes: Setting[Boolean] = BooleanSetting(ForkSetting, "Yno-flexible-types", "Disable turning nullable Java return types and parameter types into flexible types, which behave like abstract types with a nullable lower bound and non-nullable upper bound.")
452+
val YflexifyTasty: Setting[Boolean] = BooleanSetting(ForkSetting, "Yflexify-tasty", "Apply flexification to Scala code compiled without -Yexplicit-nulls, when reading from tasty.")
452453
val YsafeInitGlobal: Setting[Boolean] = BooleanSetting(ForkSetting, "Ysafe-init-global", "Check safe initialization of global objects.")
453454
val YrequireTargetName: Setting[Boolean] = BooleanSetting(ForkSetting, "Yrequire-targetName", "Warn if an operator is defined without a @targetName annotation.")
454455
val YrecheckTest: Setting[Boolean] = BooleanSetting(ForkSetting, "Yrecheck-test", "Run basic rechecking (internal test only).")

‎compiler/src/dotty/tools/dotc/core/Contexts.scala‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,9 @@ object Contexts {
480480
/** Is the flexible types option set? */
481481
def flexibleTypes: Boolean = base.settings.YexplicitNulls.value && !base.settings.YnoFlexibleTypes.value
482482

483+
/** Is the flexify tasty option set? */
484+
def flexifyTasty: Boolean = base.settings.YexplicitNulls.value && base.settings.YflexifyTasty.value
485+
483486
/** Is the best-effort option set? */
484487
def isBestEffort: Boolean = base.settings.YbestEffort.value
485488

‎compiler/src/dotty/tools/dotc/core/Definitions.scala‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,13 +1991,11 @@ class Definitions {
19911991
* - the upper bound of a TypeParamRef in the current constraint
19921992
*/
19931993
def asContextFunctionType(tp: Type)(using Context): Type =
1994-
tp.stripTypeVar.dealias match
1994+
tp.stripNull().stripTypeVar.dealias match
19951995
case tp1: TypeParamRef if ctx.typerState.constraint.contains(tp1) =>
19961996
asContextFunctionType(TypeComparer.bounds(tp1).hiBound)
19971997
case tp1 @ PolyFunctionOf(mt: MethodType) if mt.isContextualMethod =>
19981998
tp1
1999-
case tp1: FlexibleType =>
2000-
asContextFunctionType(tp1.underlying)
20011999
case tp1 =>
20022000
if tp1.typeSymbol.name.isContextFunction && isFunctionNType(tp1) then tp1
20032001
else NoType

‎compiler/src/dotty/tools/dotc/core/ImplicitNullInterop.scala‎

Lines changed: 163 additions & 112 deletions
Large diffs are not rendered by default.

‎compiler/src/dotty/tools/dotc/core/Types.scala‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6253,6 +6253,8 @@ object Types extends TypeUtils {
62536253
tp.derivedAndType(tp1, tp2)
62546254
protected def derivedOrType(tp: OrType, tp1: Type, tp2: Type): Type =
62556255
tp.derivedOrType(tp1, tp2)
6256+
protected def derivedAndOrType(tp: AndOrType, tp1: Type, tp2: Type): Type =
6257+
tp.derivedAndOrType(tp1, tp2)
62566258
protected def derivedMatchType(tp: MatchType, bound: Type, scrutinee: Type, cases: List[Type]): Type =
62576259
tp.derivedMatchType(bound, scrutinee, cases)
62586260
protected def derivedAnnotatedType(tp: AnnotatedType, underlying: Type, annot: Annotation): Type =

‎compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -921,10 +921,10 @@ class TreeUnpickler(reader: TastyReader,
921921

922922
def ta = ctx.typeAssigner
923923

924-
// If explicit nulls is enabled, and the source file did not have explicit
924+
// If explicit nulls and `Yflexify-tasty` is enabled, and the source file did not have explicit
925925
// nulls enabled, nullify the member to allow for compatibility.
926926
def nullify(sym: Symbol) =
927-
if (ctx.explicitNulls && ctx.flexibleTypes && !explicitNulls) then
927+
if (ctx.flexifyTasty && !explicitNulls) then
928928
sym.info = ImplicitNullInterop.nullifyMember(sym, sym.info, sym.is(Enum))
929929

930930
val name = readName()

‎compiler/test/dotty/tools/dotc/CompilationTests.scala‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,18 @@ class CompilationTests {
212212
compileFilesInDir("tests/explicit-nulls/neg", explicitNullsOptions, FileFilter.exclude(TestSources.negExplicitNullsScala2LibraryTastyExcludelisted)),
213213
compileFilesInDir("tests/explicit-nulls/flexible-types-common", explicitNullsOptions and "-Yno-flexible-types"),
214214
compileFilesInDir("tests/explicit-nulls/unsafe-common", explicitNullsOptions and "-Yno-flexible-types", FileFilter.exclude(TestSources.negExplicitNullsScala2LibraryTastyExcludelisted)),
215-
)
216-
}.checkExpectedErrors()
215+
).checkExpectedErrors()
216+
217+
locally {
218+
val unsafeFile = compileFile("tests/explicit-nulls/flexible-unpickle/neg/Unsafe_1.scala", explicitNullsOptions without "-Yexplicit-nulls")
219+
val flexibleFile = compileFile("tests/explicit-nulls/flexible-unpickle/neg/Flexible_2.scala",
220+
explicitNullsOptions.and("-Yflexify-tasty").withClasspath(defaultOutputDir + testGroup + "/Unsafe_1/neg/Unsafe_1"))
221+
222+
flexibleFile.keepOutput.checkExpectedErrors()
223+
224+
List(unsafeFile, flexibleFile).foreach(_.delete())
225+
}
226+
}
217227

218228
@Ignore
219229
@Test def explicitNullsPos: Unit = {
@@ -226,9 +236,9 @@ class CompilationTests {
226236

227237
locally {
228238
val tests = List(
229-
compileFile("tests/explicit-nulls/flexible-unpickle/Unsafe_1.scala", explicitNullsOptions without "-Yexplicit-nulls"),
230-
compileFile("tests/explicit-nulls/flexible-unpickle/Flexible_2.scala", explicitNullsOptions.withClasspath(
231-
defaultOutputDir + testGroup + "/Unsafe_1/flexible-unpickle/Unsafe_1")),
239+
compileFile("tests/explicit-nulls/flexible-unpickle/pos/Unsafe_1.scala", explicitNullsOptions without "-Yexplicit-nulls"),
240+
compileFile("tests/explicit-nulls/flexible-unpickle/pos/Flexible_2.scala",
241+
explicitNullsOptions.and("-Yflexify-tasty").withClasspath(defaultOutputDir + testGroup + "/Unsafe_1/pos/Unsafe_1")),
232242
).map(_.keepOutput.checkCompile())
233243

234244
tests.foreach(_.delete())
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import unsafe.*
2+
3+
@A[String] class C
4+
5+
def test =
6+
7+
val ii = Bar.f[Int](null) // error
8+
val jj = Bar.g[String](null) // error
9+
val jj2 = Bar.g[String | Null](null) // ok
10+
val kk = Bar.g2[String](null) // error
11+
val kk2 = Bar.g2[String | Null](null) // ok
12+
13+
val bar_x: Int = Bar.x
14+
val bar_y: String | Null = Bar.y.replaceAll(" ","")
15+
16+
def testUsingFoo(using Foo[Option]) = Bar.h(null)
17+
18+
val ii2 = Bar2[String]().f(null) // error
19+
val ii3 = Bar2[String | Null]().f(null) // ok
20+
21+
val a = Bar.ff(
22+
(x: AnyRef) => x.toString,
23+
42
24+
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package unsafe
2+
3+
import scala.annotation.*
4+
5+
type XtoY = [X] =>> [Y] =>> X => Y
6+
7+
class Foo[T[_]]
8+
9+
class A[T] extends Annotation
10+
11+
object Bar:
12+
def ff(f: AnyRef => String, g: AnyRef ?=> Int): (AnyRef => String) = ???
13+
var x: Int = 0
14+
var y: String = ""
15+
def f[T <: Int](x: T): T = x
16+
def g[T <: AnyRef](x: T): T = x
17+
def g2[T >: Null <: AnyRef](x: T): T = x
18+
def h(x: String)(using Foo[Option]): String = x
19+
def h2(a: Foo[XtoY[String]]) = ???
20+
21+
class Bar2[T]:
22+
def f(x: T): T = x

‎tests/explicit-nulls/flexible-unpickle/Flexible_2.scala‎ renamed to ‎tests/explicit-nulls/flexible-unpickle/pos/Flexible_2.scala‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import unsafeNulls.Foo.*
22
import unsafeNulls.Unsafe_1
3-
import unsafeNulls.{A, B, C, F, G, H, I, J, L, M, S, T, U, expects}
3+
import unsafeNulls.{A, B, C, F, G, H, I, J, L, M, N, S, T, U, expects}
44
import scala.reflect.Selectable.reflectiveSelectable
55
import scala.quoted.*
66

@@ -100,6 +100,11 @@ def Flexible_2() =
100100

101101
val m: String = M.test(null)
102102

103+
// i23911
104+
val n1: List[Map[String, Int]] = ???
105+
val n2 = new N[List]()
106+
val n3 = n2.accept[Any](n1)
107+
103108
// i23845
104109
transparent inline def typeName[A]: String = ${typeNameMacro[A]}
105110

@@ -109,3 +114,9 @@ def Flexible_2() =
109114
implicit val givenS: S[A] = ???
110115
expects(alphaTypeNameMacro[A])
111116
}
117+
118+
// i23935
119+
opaque type ZArrow[-I, -R, +E, +O] = I => ZIO[R, E, O]
120+
object ZArrow:
121+
def fromZIOAttempt[I, R, E, O](f: I => ZIO[R, E, O]): ZArrow[I, R, Throwable | E, O] =
122+
(in: I) => ZIO.attempt(f(in)).flatten

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /