Skip to content

Commit 3f2365d

Browse files
authored
Remove special overriding logic for explicit nulls (#22243)
Fixes #22071
2 parents 3ea209b + 9ac0663 commit 3f2365d

File tree

10 files changed

+19
-49
lines changed

10 files changed

+19
-49
lines changed

Diff for: compiler/src/dotty/tools/dotc/core/Contexts.scala

-3
Original file line numberDiff line numberDiff line change
@@ -786,9 +786,6 @@ object Contexts {
786786
def withNotNullInfos(infos: List[NotNullInfo]): Context =
787787
if !c.explicitNulls || (c.notNullInfos eq infos) then c else c.fresh.setNotNullInfos(infos)
788788

789-
def relaxedOverrideContext: Context =
790-
c.withModeBits(c.mode &~ Mode.SafeNulls | Mode.RelaxedOverriding)
791-
792789
// TODO: Fix issue when converting ModeChanges and FreshModeChanges to extension givens
793790
extension (c: Context) {
794791
final def withModeBits(mode: Mode): Context =

Diff for: compiler/src/dotty/tools/dotc/core/Denotations.scala

+2-3
Original file line numberDiff line numberDiff line change
@@ -478,12 +478,11 @@ object Denotations {
478478
else if sym1.is(Method) && !sym2.is(Method) then 1
479479
else 0
480480

481-
val relaxedOverriding = ctx.explicitNulls && (sym1.is(JavaDefined) || sym2.is(JavaDefined))
482481
val matchLoosely = sym1.matchNullaryLoosely || sym2.matchNullaryLoosely
483482

484-
if symScore <= 0 && info2.overrides(info1, relaxedOverriding, matchLoosely, checkClassInfo = false) then
483+
if symScore <= 0 && info2.overrides(info1, matchLoosely, checkClassInfo = false) then
485484
denot2
486-
else if symScore >= 0 && info1.overrides(info2, relaxedOverriding, matchLoosely, checkClassInfo = false) then
485+
else if symScore >= 0 && info1.overrides(info2, matchLoosely, checkClassInfo = false) then
487486
denot1
488487
else
489488
val jointInfo = infoMeet(info1, info2, safeIntersection)

Diff for: compiler/src/dotty/tools/dotc/core/JavaNullInterop.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import Flags.JavaDefined
66
import StdNames.nme
77
import Symbols.*
88
import Types.*
9+
import dotty.tools.dotc.reporting.*
10+
import dotty.tools.dotc.core.Decorators.i
911

1012
/** This module defines methods to interpret types of Java symbols, which are implicitly nullable in Java,
1113
* as Scala types, which are explicitly nullable.
@@ -51,7 +53,7 @@ object JavaNullInterop {
5153
*
5254
* But the selection can throw an NPE if the returned value is `null`.
5355
*/
54-
def nullifyMember(sym: Symbol, tp: Type, isEnumValueDef: Boolean)(using Context): Type = {
56+
def nullifyMember(sym: Symbol, tp: Type, isEnumValueDef: Boolean)(using Context): Type = trace(i"nullifyMember ${sym}, ${tp}"){
5557
assert(ctx.explicitNulls)
5658
assert(sym.is(JavaDefined), "can only nullify java-defined members")
5759

Diff for: compiler/src/dotty/tools/dotc/core/Mode.scala

+1-6
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ object Mode {
105105

106106
/** Use previous Scheme for implicit resolution. Currently significant
107107
* in 3.0-migration where we use Scala-2's scheme instead and in 3.5 and 3.6-migration
108-
* where we use the previous scheme up to 3.4 for comparison with the new scheme.
108+
* where we use the previous scheme up to 3.4 for comparison with the new scheme.
109109
*/
110110
val OldImplicitResolution: Mode = newMode(15, "OldImplicitResolution")
111111

@@ -163,11 +163,6 @@ object Mode {
163163
*/
164164
val ForceInline: Mode = newMode(29, "ForceInline")
165165

166-
/** This mode is enabled when we check Java overriding in explicit nulls.
167-
* Type `Null` becomes a subtype of non-primitive value types in TypeComparer.
168-
*/
169-
val RelaxedOverriding: Mode = newMode(30, "RelaxedOverriding")
170-
171166
/** Skip inlining of methods. */
172167
val NoInline: Mode = newMode(31, "NoInline")
173168
}

Diff for: compiler/src/dotty/tools/dotc/core/TypeComparer.scala

-8
Original file line numberDiff line numberDiff line change
@@ -967,17 +967,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
967967
|| compareGADT
968968
|| tryLiftedToThis1
969969
case _ =>
970-
// `Mode.RelaxedOverriding` is only enabled when checking Java overriding
971-
// in explicit nulls, and `Null` becomes a bottom type, which allows
972-
// `T | Null` being a subtype of `T`.
973-
// A type variable `T` from Java is translated to `T >: Nothing <: Any`.
974-
// However, `null` can always be a value of `T` for Java side.
975-
// So the best solution here is to let `Null` be a subtype of non-primitive
976-
// value types temporarily.
977970
def isNullable(tp: Type): Boolean = tp.dealias match
978971
case tp: TypeRef =>
979972
val tpSym = tp.symbol
980-
ctx.mode.is(Mode.RelaxedOverriding) && !tpSym.isPrimitiveValueClass ||
981973
tpSym.isNullableClass
982974
case tp: TermRef =>
983975
// https://scala-lang.org/files/archive/spec/2.13/03-types.html#singleton-types

Diff for: compiler/src/dotty/tools/dotc/core/Types.scala

+9-12
Original file line numberDiff line numberDiff line change
@@ -1160,17 +1160,14 @@ object Types extends TypeUtils {
11601160
*
11611161
* @param isSubType a function used for checking subtype relationships.
11621162
*/
1163-
final def overrides(that: Type, relaxedCheck: Boolean, matchLoosely: => Boolean, checkClassInfo: Boolean = true,
1163+
final def overrides(that: Type, matchLoosely: => Boolean, checkClassInfo: Boolean = true,
11641164
isSubType: (Type, Type) => Context ?=> Boolean = (tp1, tp2) => tp1 frozen_<:< tp2)(using Context): Boolean = {
1165-
val overrideCtx = if relaxedCheck then ctx.relaxedOverrideContext else ctx
1166-
inContext(overrideCtx) {
1167-
!checkClassInfo && this.isInstanceOf[ClassInfo]
1168-
|| isSubType(this.widenExpr, that.widenExpr)
1169-
|| matchLoosely && {
1170-
val this1 = this.widenNullaryMethod
1171-
val that1 = that.widenNullaryMethod
1172-
((this1 `ne` this) || (that1 `ne` that)) && this1.overrides(that1, relaxedCheck, false, checkClassInfo)
1173-
}
1165+
!checkClassInfo && this.isInstanceOf[ClassInfo]
1166+
|| isSubType(this.widenExpr, that.widenExpr)
1167+
|| matchLoosely && {
1168+
val this1 = this.widenNullaryMethod
1169+
val that1 = that.widenNullaryMethod
1170+
((this1 `ne` this) || (that1 `ne` that)) && this1.overrides(that1, false, checkClassInfo)
11741171
}
11751172
}
11761173

@@ -1196,8 +1193,8 @@ object Types extends TypeUtils {
11961193
*/
11971194
def matches(that: Type)(using Context): Boolean = {
11981195
record("matches")
1199-
val overrideCtx = if ctx.explicitNulls then ctx.relaxedOverrideContext else ctx
1200-
TypeComparer.matchesType(this, that, relaxed = !ctx.phase.erasedTypes)(using overrideCtx)
1196+
withoutMode(Mode.SafeNulls)(
1197+
TypeComparer.matchesType(this, that, relaxed = !ctx.phase.erasedTypes))
12011198
}
12021199

12031200
/** This is the same as `matches` except that it also matches => T with T and

Diff for: compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala

+1-5
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,7 @@ object OverridingPairs:
225225
}
226226
)
227227
else
228-
// releaxed override check for explicit nulls if one of the symbols is Java defined,
229-
// force `Null` to be a subtype of non-primitive value types during override checking.
230-
val relaxedOverriding = ctx.explicitNulls && (member.is(JavaDefined) || other.is(JavaDefined))
231228
member.name.is(DefaultGetterName) // default getters are not checked for compatibility
232-
|| memberTp.overrides(otherTp, relaxedOverriding,
233-
member.matchNullaryLoosely || other.matchNullaryLoosely || fallBack, isSubType = isSubType)
229+
|| memberTp.overrides(otherTp, member.matchNullaryLoosely || other.matchNullaryLoosely || fallBack, isSubType = isSubType)
234230

235231
end OverridingPairs

Diff for: compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala

+2-5
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,8 @@ object ResolveSuper {
111111
// of the superaccessor's type, see i5433.scala for an example where this matters
112112
val otherTp = other.asSeenFrom(base.thisType).info
113113
val accTp = acc.asSeenFrom(base.thisType).info
114-
// Since the super class can be Java defined,
115-
// we use relaxed overriding check for explicit nulls if one of the symbols is Java defined.
116-
// This forces `Null` to be a subtype of non-primitive value types during override checking.
117-
val relaxedOverriding = ctx.explicitNulls && (sym.is(JavaDefined) || acc.is(JavaDefined))
118-
if !otherTp.overrides(accTp, relaxedOverriding, matchLoosely = true) then
114+
115+
if !otherTp.overrides(accTp, matchLoosely = true) then
119116
report.error(IllegalSuperAccessor(base, memberName, targetName, acc, accTp, other.symbol, otherTp), base.srcPos)
120117
bcs = bcs.tail
121118
}

Diff for: compiler/src/dotty/tools/dotc/typer/RefChecks.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ object RefChecks {
906906
for (mbrd <- self.member(name).alternatives) {
907907
val mbr = mbrd.symbol
908908
val mbrType = mbr.info.asSeenFrom(self, mbr.owner)
909-
if (!mbrType.overrides(mbrd.info, relaxedCheck = false, matchLoosely = true))
909+
if (!mbrType.overrides(mbrd.info, matchLoosely = true))
910910
report.errorOrMigrationWarning(
911911
em"""${mbr.showLocated} is not a legal implementation of `$name` in $clazz
912912
| its type $mbrType

Diff for: project/Build.scala

-5
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,6 @@ object Build {
10661066
// compiler is updated.
10671067
// Then, the next step is to enable flexible types by default and reduce the use of
10681068
// `unsafeNulls`.
1069-
scalacOptions ++= Seq("-Yno-flexible-types"),
10701069
packageAll := {
10711070
(`scala3-compiler` / packageAll).value ++ Seq(
10721071
"scala3-compiler" -> (Compile / packageBin).value.getAbsolutePath,
@@ -1460,10 +1459,6 @@ object Build {
14601459
.dependsOn(`scala3-compiler-bootstrapped`, `scala3-library-bootstrapped`, `scala3-presentation-compiler-testcases` % "test->test")
14611460
.settings(presentationCompilerSettings)
14621461
.settings(scala3PresentationCompilerBuildInfo)
1463-
.settings(
1464-
// Add `-Yno-flexible-types` flag for bootstrap, see comments for `bootstrappedDottyCompilerSettings`
1465-
Compile / scalacOptions += "-Yno-flexible-types"
1466-
)
14671462

14681463
def scala3PresentationCompilerBuildInfo =
14691464
Seq(

0 commit comments

Comments
 (0)