Skip to content

Commit 33ac95d

Browse files
committed
Testing new approach
1 parent 8f19949 commit 33ac95d

File tree

6 files changed

+45
-67
lines changed

6 files changed

+45
-67
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,6 @@ object Mode {
124124
* This mode forces expansion of inline calls in those positions even during typing.
125125
*/
126126
val ForceInline: Mode = newMode(29, "ForceInline")
127+
128+
val RelaxedOverriding: Mode = newMode(30, "ForceInline")
127129
}

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

Lines changed: 25 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,6 @@ import Types._
99
/** Defines operations on nullable types and tree. */
1010
object NullOpsDecorator:
1111

12-
private class StripNullsMap(isDeep: Boolean)(using Context) extends TypeMap:
13-
def strip(tp: Type): Type = tp match
14-
case tp @ OrType(lhs, rhs) =>
15-
val llhs = this(lhs)
16-
val rrhs = this(rhs)
17-
if rrhs.isNullType then llhs
18-
else if llhs.isNullType then rrhs
19-
else derivedOrType(tp, llhs, rrhs)
20-
case tp @ AndType(tp1, tp2) =>
21-
// We cannot `tp.derivedAndType(strip(tp1), strip(tp2))` directly,
22-
// since `stripNull((A | Null) & B)` would produce the wrong
23-
// result `(A & B) | Null`.
24-
val tp1s = this(tp1)
25-
val tp2s = this(tp2)
26-
if isDeep || (tp1s ne tp1) && (tp2s ne tp2) then
27-
derivedAndType(tp, tp1s, tp2s)
28-
else tp
29-
case tp: TypeBounds =>
30-
mapOver(tp)
31-
case _ => tp
32-
33-
def stripOver(tp: Type): Type = tp match
34-
case appTp @ AppliedType(tycon, targs) =>
35-
derivedAppliedType(appTp, tycon, targs.map(this))
36-
case ptp: PolyType =>
37-
derivedLambdaType(ptp)(ptp.paramInfos, this(ptp.resType))
38-
case mtp: MethodType =>
39-
mapOver(mtp)
40-
case _ => strip(tp)
41-
42-
override def apply(tp: Type): Type =
43-
val tpw = tp.widenDealias
44-
val tpws = if isDeep then stripOver(tpw) else strip(tpw)
45-
if tpws ne tpw then tpws else tp
46-
47-
end StripNullsMap
48-
4912
extension (self: Type)
5013
/** Syntactically strips the nullability from this type.
5114
* If the type is `T1 | ... | Tn`, and `Ti` references to `Null`,
@@ -54,22 +17,38 @@ object NullOpsDecorator:
5417
* The type will not be changed if explicit-nulls is not enabled.
5518
*/
5619
def stripNull(using Context): Type = {
57-
if ctx.explicitNulls then new StripNullsMap(false)(self) else self
20+
def strip(tp: Type): Type =
21+
val tpWiden = tp.widenDealias
22+
val tpStripped = tpWiden match {
23+
case tp @ OrType(lhs, rhs) =>
24+
val llhs = strip(lhs)
25+
val rrhs = strip(rhs)
26+
if rrhs.isNullType then llhs
27+
else if llhs.isNullType then rrhs
28+
else tp.derivedOrType(llhs, rrhs)
29+
case tp @ AndType(tp1, tp2) =>
30+
// We cannot `tp.derivedAndType(strip(tp1), strip(tp2))` directly,
31+
// since `stripNull((A | Null) & B)` would produce the wrong
32+
// result `(A & B) | Null`.
33+
val tp1s = strip(tp1)
34+
val tp2s = strip(tp2)
35+
if (tp1s ne tp1) && (tp2s ne tp2) then
36+
tp.derivedAndType(tp1s, tp2s)
37+
else tp
38+
case tp @ TypeBounds(lo, hi) =>
39+
tp.derivedTypeBounds(strip(lo), strip(hi))
40+
case tp => tp
41+
}
42+
if tpStripped ne tpWiden then tpStripped else tp
43+
44+
if ctx.explicitNulls then strip(self) else self
5845
}
5946

6047
/** Is self (after widening and dealiasing) a type of the form `T | Null`? */
6148
def isNullableUnion(using Context): Boolean = {
6249
val stripped = self.stripNull
6350
stripped ne self
6451
}
65-
66-
/** Strips nulls from this type deeply.
67-
* Compaired to `stripNull`, `stripNullsDeep` will apply `stripNull` to
68-
* each member of function types as well.
69-
*/
70-
def stripNullsDeep(using Context): Type =
71-
if ctx.explicitNulls then new StripNullsMap(true)(self) else self
72-
7352
end extension
7453

7554
import ast.tpd._

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -766,13 +766,15 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
766766

767767
isSubType(hi1, tp2, approx.addLow) || compareGADT || tryLiftedToThis1
768768
case _ =>
769-
def isNullable(tp: Type): Boolean = tp.widenDealias match {
770-
case tp: TypeRef => tp.symbol.isNullableClass
771-
case tp: RefinedOrRecType => isNullable(tp.parent)
772-
case tp: AppliedType => isNullable(tp.tycon)
773-
case AndType(tp1, tp2) => isNullable(tp1) && isNullable(tp2)
774-
case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2)
775-
case _ => false
769+
def isNullable(tp: Type): Boolean = ctx.mode.is(Mode.RelaxedOverriding) || {
770+
tp.widenDealias match {
771+
case tp: TypeRef => tp.symbol.isNullableClass
772+
case tp: RefinedOrRecType => isNullable(tp.parent)
773+
case tp: AppliedType => isNullable(tp.tycon)
774+
case AndType(tp1, tp2) => isNullable(tp1) && isNullable(tp2)
775+
case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2)
776+
case _ => false
777+
}
776778
}
777779
val sym1 = tp1.symbol
778780
(sym1 eq NothingClass) && tp2.isValueTypeOrLambda ||

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,10 +1112,10 @@ object Types {
11121112
*/
11131113
def matches(that: Type)(using Context): Boolean = {
11141114
record("matches")
1115-
val thisTp1 = this.stripNullsDeep
1116-
val thatTp1 = that.stripNullsDeep
1117-
withoutMode(Mode.SafeNulls)(
1118-
TypeComparer.matchesType(thisTp1, thatTp1, relaxed = !ctx.phase.erasedTypes))
1115+
val overrideCtx = if ctx.explicitNulls
1116+
then ctx.retractMode(Mode.SafeNulls).addMode(Mode.RelaxedOverriding)
1117+
else ctx
1118+
TypeComparer.matchesType(this, that, relaxed = !ctx.phase.erasedTypes)(using overrideCtx)
11191119
}
11201120

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

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,9 @@ object OverridingPairs:
221221
member.name.is(DefaultGetterName) || {
222222
if ctx.explicitNulls && (member.is(JavaDefined) || other.is(JavaDefined)) then
223223
// releaxed override check for explicit nulls if one of the symbols is Java defined,
224-
// force `Null` being a subtype of reference types during override checking.
225-
// `stripNullsDeep` is used here because we may encounter type parameters
226-
// (`T | Null` is not a subtype of `T` even if we retract Mode.SafeNulls).
227-
val memberTp1 = memberTp.stripNullsDeep
228-
val otherTp1 = otherTp.stripNullsDeep
229-
withoutMode(Mode.SafeNulls)(
230-
memberTp1.overrides(otherTp1, matchNullaryLoosely))
224+
// force `Null` being a bottom types during override checking.
225+
val overrideCtx = ctx.retractMode(Mode.SafeNulls).addMode(Mode.RelaxedOverriding)
226+
memberTp.overrides(otherTp, matchNullaryLoosely)(using overrideCtx)
231227
else
232228
memberTp.overrides(otherTp, matchNullaryLoosely)
233229
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,8 @@ object ResolveSuper {
115115
// we use releaxed overriding check for explicit nulls if one of the symbols is Java defined.
116116
// This forces `Null` being a subtype of reference types during override checking.
117117
val overridesSuper = if ctx.explicitNulls && (sym.is(JavaDefined) || acc.is(JavaDefined)) then
118-
val otherTp1 = otherTp.stripNullsDeep
119-
val accTp1 = accTp.stripNullsDeep
120-
withoutMode(Mode.SafeNulls)(otherTp1.overrides(accTp1, matchLoosely = true))
118+
val overrideCtx = ctx.retractMode(Mode.SafeNulls).addMode(Mode.RelaxedOverriding)
119+
otherTp.overrides(accTp, matchLoosely = true)(using overrideCtx)
121120
else
122121
otherTp.overrides(accTp, matchLoosely = true)
123122
if !overridesSuper then

0 commit comments

Comments
 (0)