diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 7c54d1392720..64d916d12b5e 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -786,9 +786,6 @@ object Contexts { def withNotNullInfos(infos: List[NotNullInfo]): Context = if !c.explicitNulls || (c.notNullInfos eq infos) then c else c.fresh.setNotNullInfos(infos) - def relaxedOverrideContext: Context = - c.withModeBits(c.mode &~ Mode.SafeNulls | Mode.RelaxedOverriding) - // TODO: Fix issue when converting ModeChanges and FreshModeChanges to extension givens extension (c: Context) { final def withModeBits(mode: Mode): Context = diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 85ff51bc19de..c5047cb5d806 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -478,12 +478,11 @@ object Denotations { else if sym1.is(Method) && !sym2.is(Method) then 1 else 0 - val relaxedOverriding = ctx.explicitNulls && (sym1.is(JavaDefined) || sym2.is(JavaDefined)) val matchLoosely = sym1.matchNullaryLoosely || sym2.matchNullaryLoosely - if symScore <= 0 && info2.overrides(info1, relaxedOverriding, matchLoosely, checkClassInfo = false) then + if symScore <= 0 && info2.overrides(info1, matchLoosely, checkClassInfo = false) then denot2 - else if symScore >= 0 && info1.overrides(info2, relaxedOverriding, matchLoosely, checkClassInfo = false) then + else if symScore >= 0 && info1.overrides(info2, matchLoosely, checkClassInfo = false) then denot1 else val jointInfo = infoMeet(info1, info2, safeIntersection) diff --git a/compiler/src/dotty/tools/dotc/core/JavaNullInterop.scala b/compiler/src/dotty/tools/dotc/core/JavaNullInterop.scala index 46ce0d2d7852..f3e62bc36e06 100644 --- a/compiler/src/dotty/tools/dotc/core/JavaNullInterop.scala +++ b/compiler/src/dotty/tools/dotc/core/JavaNullInterop.scala @@ -6,6 +6,8 @@ import Flags.JavaDefined import StdNames.nme import Symbols.* import Types.* +import dotty.tools.dotc.reporting.* +import dotty.tools.dotc.core.Decorators.i /** This module defines methods to interpret types of Java symbols, which are implicitly nullable in Java, * as Scala types, which are explicitly nullable. @@ -51,7 +53,7 @@ object JavaNullInterop { * * But the selection can throw an NPE if the returned value is `null`. */ - def nullifyMember(sym: Symbol, tp: Type, isEnumValueDef: Boolean)(using Context): Type = { + def nullifyMember(sym: Symbol, tp: Type, isEnumValueDef: Boolean)(using Context): Type = trace(i"nullifyMember ${sym}, ${tp}"){ assert(ctx.explicitNulls) assert(sym.is(JavaDefined), "can only nullify java-defined members") diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala index 14d7827974c0..55e88eae4f6e 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -105,7 +105,7 @@ object Mode { /** Use previous Scheme for implicit resolution. Currently significant * in 3.0-migration where we use Scala-2's scheme instead and in 3.5 and 3.6-migration - * where we use the previous scheme up to 3.4 for comparison with the new scheme. + * where we use the previous scheme up to 3.4 for comparison with the new scheme. */ val OldImplicitResolution: Mode = newMode(15, "OldImplicitResolution") @@ -163,11 +163,6 @@ object Mode { */ val ForceInline: Mode = newMode(29, "ForceInline") - /** This mode is enabled when we check Java overriding in explicit nulls. - * Type `Null` becomes a subtype of non-primitive value types in TypeComparer. - */ - val RelaxedOverriding: Mode = newMode(30, "RelaxedOverriding") - /** Skip inlining of methods. */ val NoInline: Mode = newMode(31, "NoInline") } diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index bbe157d4a29b..a65d1c633a7e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -967,17 +967,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling || compareGADT || tryLiftedToThis1 case _ => - // `Mode.RelaxedOverriding` is only enabled when checking Java overriding - // in explicit nulls, and `Null` becomes a bottom type, which allows - // `T | Null` being a subtype of `T`. - // A type variable `T` from Java is translated to `T >: Nothing <: Any`. - // However, `null` can always be a value of `T` for Java side. - // So the best solution here is to let `Null` be a subtype of non-primitive - // value types temporarily. def isNullable(tp: Type): Boolean = tp.dealias match case tp: TypeRef => val tpSym = tp.symbol - ctx.mode.is(Mode.RelaxedOverriding) && !tpSym.isPrimitiveValueClass || tpSym.isNullableClass case tp: TermRef => // https://scala-lang.org/files/archive/spec/2.13/03-types.html#singleton-types diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c5937074f4bc..884a71e23339 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1160,17 +1160,14 @@ object Types extends TypeUtils { * * @param isSubType a function used for checking subtype relationships. */ - final def overrides(that: Type, relaxedCheck: Boolean, matchLoosely: => Boolean, checkClassInfo: Boolean = true, + final def overrides(that: Type, matchLoosely: => Boolean, checkClassInfo: Boolean = true, isSubType: (Type, Type) => Context ?=> Boolean = (tp1, tp2) => tp1 frozen_<:< tp2)(using Context): Boolean = { - val overrideCtx = if relaxedCheck then ctx.relaxedOverrideContext else ctx - inContext(overrideCtx) { - !checkClassInfo && this.isInstanceOf[ClassInfo] - || isSubType(this.widenExpr, that.widenExpr) - || matchLoosely && { - val this1 = this.widenNullaryMethod - val that1 = that.widenNullaryMethod - ((this1 `ne` this) || (that1 `ne` that)) && this1.overrides(that1, relaxedCheck, false, checkClassInfo) - } + !checkClassInfo && this.isInstanceOf[ClassInfo] + || isSubType(this.widenExpr, that.widenExpr) + || matchLoosely && { + val this1 = this.widenNullaryMethod + val that1 = that.widenNullaryMethod + ((this1 `ne` this) || (that1 `ne` that)) && this1.overrides(that1, false, checkClassInfo) } } @@ -1196,8 +1193,8 @@ object Types extends TypeUtils { */ def matches(that: Type)(using Context): Boolean = { record("matches") - val overrideCtx = if ctx.explicitNulls then ctx.relaxedOverrideContext else ctx - TypeComparer.matchesType(this, that, relaxed = !ctx.phase.erasedTypes)(using overrideCtx) + withoutMode(Mode.SafeNulls)( + TypeComparer.matchesType(this, that, relaxed = !ctx.phase.erasedTypes)) } /** This is the same as `matches` except that it also matches => T with T and diff --git a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala index 6529eed77fa0..a9a17f6db464 100644 --- a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala +++ b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala @@ -225,11 +225,7 @@ object OverridingPairs: } ) else - // releaxed override check for explicit nulls if one of the symbols is Java defined, - // force `Null` to be a subtype of non-primitive value types during override checking. - val relaxedOverriding = ctx.explicitNulls && (member.is(JavaDefined) || other.is(JavaDefined)) member.name.is(DefaultGetterName) // default getters are not checked for compatibility - || memberTp.overrides(otherTp, relaxedOverriding, - member.matchNullaryLoosely || other.matchNullaryLoosely || fallBack, isSubType = isSubType) + || memberTp.overrides(otherTp, member.matchNullaryLoosely || other.matchNullaryLoosely || fallBack, isSubType = isSubType) end OverridingPairs diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index 6bc5db79fee5..67fd233e117a 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -111,11 +111,8 @@ object ResolveSuper { // of the superaccessor's type, see i5433.scala for an example where this matters val otherTp = other.asSeenFrom(base.thisType).info val accTp = acc.asSeenFrom(base.thisType).info - // Since the super class can be Java defined, - // we use relaxed overriding check for explicit nulls if one of the symbols is Java defined. - // This forces `Null` to be a subtype of non-primitive value types during override checking. - val relaxedOverriding = ctx.explicitNulls && (sym.is(JavaDefined) || acc.is(JavaDefined)) - if !otherTp.overrides(accTp, relaxedOverriding, matchLoosely = true) then + + if !otherTp.overrides(accTp, matchLoosely = true) then report.error(IllegalSuperAccessor(base, memberName, targetName, acc, accTp, other.symbol, otherTp), base.srcPos) bcs = bcs.tail } diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index dcdabaf3a72d..b444ba595a12 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -906,7 +906,7 @@ object RefChecks { for (mbrd <- self.member(name).alternatives) { val mbr = mbrd.symbol val mbrType = mbr.info.asSeenFrom(self, mbr.owner) - if (!mbrType.overrides(mbrd.info, relaxedCheck = false, matchLoosely = true)) + if (!mbrType.overrides(mbrd.info, matchLoosely = true)) report.errorOrMigrationWarning( em"""${mbr.showLocated} is not a legal implementation of `$name` in $clazz | its type $mbrType diff --git a/project/Build.scala b/project/Build.scala index b67974f4405d..c7369a5d522a 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1059,7 +1059,6 @@ object Build { // compiler is updated. // Then, the next step is to enable flexible types by default and reduce the use of // `unsafeNulls`. - scalacOptions ++= Seq("-Yno-flexible-types"), packageAll := { (`scala3-compiler` / packageAll).value ++ Seq( "scala3-compiler" -> (Compile / packageBin).value.getAbsolutePath, @@ -1451,10 +1450,6 @@ object Build { .dependsOn(`scala3-compiler-bootstrapped`, `scala3-library-bootstrapped`, `scala3-presentation-compiler-testcases` % "test->test") .settings(presentationCompilerSettings) .settings(scala3PresentationCompilerBuildInfo) - .settings( - // Add `-Yno-flexible-types` flag for bootstrap, see comments for `bootstrappedDottyCompilerSettings` - Compile / scalacOptions += "-Yno-flexible-types" - ) def scala3PresentationCompilerBuildInfo = Seq(