Skip to content

Commit

Permalink
Fix scala#13197: Deskolemize lifted named arguments (scala#13590)
Browse files Browse the repository at this point in the history
  • Loading branch information
noti0na1 authored and olsdavis committed Apr 4, 2022
1 parent 4c8037c commit d11a156
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 11 deletions.
11 changes: 11 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1389,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
*/
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 1 addition & 10 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1704,16 +1704,7 @@ 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 = 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)
Expand Down
7 changes: 7 additions & 0 deletions tests/explicit-nulls/pos/i13197.scala
Original file line number Diff line number Diff line change
@@ -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)
12 changes: 12 additions & 0 deletions tests/pos/i13197.scala
Original file line number Diff line number Diff line change
@@ -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: String)

object Foo:
def foo(bar: Bar) = Foo(b = bar.b.forceString)

0 comments on commit d11a156

Please sign in to comment.