Skip to content

Commit 939ec21

Browse files
committed
Add restriction
1 parent 4472e61 commit 939ec21

File tree

4 files changed

+16
-13
lines changed

4 files changed

+16
-13
lines changed

compiler/src/dotty/tools/dotc/core/Mode.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ object Mode {
126126
val ForceInline: Mode = newMode(29, "ForceInline")
127127

128128
/** This mode is enabled when we check Java overriding in explicit nulls.
129-
* Type `Null` becomes a bottom type in TypeComparer.
129+
* Type `Null` becomes a subtype of non-primitive value types in TypeComparer.
130130
*/
131131
val RelaxedOverriding: Mode = newMode(30, "RelaxedOverriding")
132132
}

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -771,16 +771,19 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
771771
// `T | Null` being a subtype of `T`.
772772
// A type variable `T` from Java is translated to `T >: Nothing <: Any`.
773773
// However, `null` can always be a value of `T` for Java side.
774-
// So the best solution here is to let `Null` be bottom type temporarily.
775-
def isNullable(tp: Type): Boolean = ctx.mode.is(Mode.RelaxedOverriding) || {
776-
tp.widenDealias match
777-
case tp: TypeRef => tp.symbol.isNullableClass
778-
case tp: RefinedOrRecType => isNullable(tp.parent)
779-
case tp: AppliedType => isNullable(tp.tycon)
780-
case AndType(tp1, tp2) => isNullable(tp1) && isNullable(tp2)
781-
case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2)
782-
case _ => false
783-
}
774+
// So the best solution here is to let `Null` be a subtype of non-primitive
775+
// value types temporarily.
776+
def isNullable(tp: Type): Boolean = tp.widenDealias match
777+
case tp: TypeRef =>
778+
val tpSym = tp.symbol
779+
ctx.mode.is(Mode.RelaxedOverriding) && !tpSym.isPrimitiveValueClass ||
780+
tpSym.isNullableClass
781+
case tp: RefinedOrRecType => isNullable(tp.parent)
782+
case tp: AppliedType => isNullable(tp.tycon)
783+
case AndType(tp1, tp2) => isNullable(tp1) && isNullable(tp2)
784+
case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2)
785+
case _ => false
786+
784787
val sym1 = tp1.symbol
785788
(sym1 eq NothingClass) && tp2.isValueTypeOrLambda ||
786789
(sym1 eq NullClass) && isNullable(tp2)

compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ object OverridingPairs:
217217
)
218218
else
219219
// releaxed override check for explicit nulls if one of the symbols is Java defined,
220-
// force `Null` to be a bottom type during override checking.
220+
// force `Null` to be a subtype of non-primitive value types during override checking.
221221
val overrideCtx = if ctx.explicitNulls && (member.is(JavaDefined) || other.is(JavaDefined))
222222
then ctx.retractMode(Mode.SafeNulls).addMode(Mode.RelaxedOverriding) else ctx
223223
member.name.is(DefaultGetterName) // default getters are not checked for compatibility

compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ object ResolveSuper {
113113
val accTp = acc.asSeenFrom(base.typeRef).info
114114
// Since the super class can be Java defined,
115115
// we use relaxed overriding check for explicit nulls if one of the symbols is Java defined.
116-
// This forces `Null` to be a bottom type during override checking.
116+
// This forces `Null` to be a subtype of non-primitive value types during override checking.
117117
val overrideCtx = if ctx.explicitNulls && (sym.is(JavaDefined) || acc.is(JavaDefined))
118118
then ctx.retractMode(Mode.SafeNulls).addMode(Mode.RelaxedOverriding) else ctx
119119
if !otherTp.overrides(accTp, matchLoosely = true)(using overrideCtx) then

0 commit comments

Comments
 (0)