From 224b13bcd1f3d4b753b8d99c3c09ced2e70841eb Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Wed, 22 Sep 2021 18:04:02 +0000 Subject: [PATCH 1/4] Fix widen in AndType --- compiler/src/dotty/tools/dotc/core/Types.scala | 1 + tests/explicit-nulls/pos/i13197.scala | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 tests/explicit-nulls/pos/i13197.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c8162fcca948..5df2d0005d42 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1208,6 +1208,7 @@ object Types { if tp.isOverloaded then tp else tp.underlying.widen case tp: SingletonType => tp.underlying.widen case tp: ExprType => tp.resultType.widen + case tp: AndType => tp.derivedAndType(tp.tp1.widen, tp.tp2.widen) case tp => val tp1 = tp.stripped if tp1 eq tp then tp diff --git a/tests/explicit-nulls/pos/i13197.scala b/tests/explicit-nulls/pos/i13197.scala new file mode 100644 index 000000000000..85835f9850c5 --- /dev/null +++ b/tests/explicit-nulls/pos/i13197.scala @@ -0,0 +1,7 @@ +trait Bar: + def b: String | Null + +class Foo(a: String = "", b: String) + +object Foo: + def foo(bar: Bar) = Foo(b = bar.b.nn) \ No newline at end of file From a781883cdfe772ee225355b6e195783c3a4834e9 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Wed, 22 Sep 2021 19:59:37 +0000 Subject: [PATCH 2/4] Add test without explicit-nulls --- tests/pos/i13197.scala | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/pos/i13197.scala diff --git a/tests/pos/i13197.scala b/tests/pos/i13197.scala new file mode 100644 index 000000000000..f8f9e53de7f3 --- /dev/null +++ b/tests/pos/i13197.scala @@ -0,0 +1,12 @@ +// this test is similar to explicit-nulls/pos/i13197.scala, but without explicit nulls + +extension [T](x: T | String) inline def forceString: x.type & String = + x.asInstanceOf + +trait Bar: + def b: String | Int + +class Foo(a: String = "", b: Any) + +object Foo: + def foo(bar: Bar) = Foo(b = bar.b.forceString) \ No newline at end of file From d4cbbe5f045293460ea42b020adfdbbde15444c5 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Thu, 23 Sep 2021 21:32:22 +0000 Subject: [PATCH 3/4] deskolemize the type of ValDef --- compiler/src/dotty/tools/dotc/core/Types.scala | 12 +++++++++++- .../src/dotty/tools/dotc/typer/EtaExpansion.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- tests/pos/i13197.scala | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 5df2d0005d42..d3c0eeab73d9 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1208,7 +1208,6 @@ object Types { if tp.isOverloaded then tp else tp.underlying.widen case tp: SingletonType => tp.underlying.widen case tp: ExprType => tp.resultType.widen - case tp: AndType => tp.derivedAndType(tp.tp1.widen, tp.tp2.widen) case tp => val tp1 = tp.stripped if tp1 eq tp then tp @@ -1390,6 +1389,17 @@ object Types { /** Like `dealiasKeepAnnots`, but keeps only refining annotations */ final def dealiasKeepRefiningAnnots(using Context): Type = dealias1(keepIfRefining) + /** Approximate this type with a type that does not contain skolem types. */ + final def deskolemized(using Context): Type = + val deskolemizer = new ApproximatingTypeMap { + def apply(tp: Type) = /*trace(i"deskolemize($tp) at $variance", show = true)*/ + tp match { + case tp: SkolemType => range(defn.NothingType, atVariance(1)(apply(tp.info))) + case _ => mapOver(tp) + } + } + deskolemizer(this) + /** The result of normalization using `tryNormalize`, or the type itself if * tryNormlize yields NoType */ diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index 74891fccd985..c04b5f1d2d85 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -48,7 +48,7 @@ abstract class Lifter { else { val name = UniqueName.fresh(prefix) // don't instantiate here, as the type params could be further constrained, see tests/pos/pickleinf.scala - var liftedType = expr.tpe.widen + var liftedType = expr.tpe.widen.deskolemized if (liftedFlags.is(Method)) liftedType = ExprType(liftedType) val lifted = newSymbol(ctx.owner, name, liftedFlags | Synthetic, liftedType, coord = spanCoord(expr.span)) defs += liftedDef(lifted, expr) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 1eb6c47bce4a..c0ed720bb369 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1713,7 +1713,7 @@ class Namer { typer: Typer => } } - def cookedRhsType = deskolemize(dealiasIfUnit(rhsType)) + def cookedRhsType = dealiasIfUnit(rhsType).deskolemized def lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.span) //if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType") if (inherited.exists) diff --git a/tests/pos/i13197.scala b/tests/pos/i13197.scala index f8f9e53de7f3..cf8b2bb3ef0d 100644 --- a/tests/pos/i13197.scala +++ b/tests/pos/i13197.scala @@ -6,7 +6,7 @@ extension [T](x: T | String) inline def forceString: x.type & String = trait Bar: def b: String | Int -class Foo(a: String = "", b: Any) +class Foo(a: String = "", b: String) object Foo: def foo(bar: Bar) = Foo(b = bar.b.forceString) \ No newline at end of file From 837a9a9041c0e367008cf472bd899c3917df401e Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Thu, 23 Sep 2021 21:35:44 +0000 Subject: [PATCH 4/4] remove necessary deskolemize function --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index c0ed720bb369..8fba8b59ba8f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1704,15 +1704,6 @@ class Namer { typer: Typer => // it would be erased to BoxedUnit. def dealiasIfUnit(tp: Type) = if (tp.isRef(defn.UnitClass)) defn.UnitType else tp - // Approximate a type `tp` with a type that does not contain skolem types. - val deskolemize = new ApproximatingTypeMap { - def apply(tp: Type) = /*trace(i"deskolemize($tp) at $variance", show = true)*/ - tp match { - case tp: SkolemType => range(defn.NothingType, atVariance(1)(apply(tp.info))) - case _ => mapOver(tp) - } - } - def cookedRhsType = dealiasIfUnit(rhsType).deskolemized def lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.span) //if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType")