Skip to content

Commit 0e44254

Browse files
committed
Deskolemize types inferred for vals and defs
We want to establish the invariant (optionally checked by assertNoSkolems) that symbols do not contain skolemized types as their info. This avoids unsoundness situations where a skolem gets exported as part if the result type of a method, so different instantiations look like their are the same instance.
1 parent 42010e5 commit 0e44254

File tree

5 files changed

+52
-4
lines changed

5 files changed

+52
-4
lines changed

src/dotty/tools/dotc/config/Config.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ object Config {
3232
*/
3333
final val checkConstraintsPropagated = false
3434

35+
/** Check that no type appearing as the info of a SymDenotation contains
36+
* skolem types.
37+
*/
38+
final val checkNoSkolemsInInfo = false
39+
3540
/** Type comparer will fail with an assert if the upper bound
3641
* of a constrained parameter becomes Nothing. This should be turned
3742
* on only for specific debugging as normally instantiation to Nothing

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ object SymDenotations {
7979
super.validFor_=(p)
8080
}
8181
*/
82+
if (Config.checkNoSkolemsInInfo) assertNoSkolems(initInfo)
8283

8384
// ------ Getting and setting fields -----------------------------
8485

@@ -168,8 +169,8 @@ object SymDenotations {
168169
}
169170

170171
protected[dotc] final def info_=(tp: Type) = {
171-
/*
172-
def illegal: String = s"illegal type for $this: $tp"
172+
/* // DEBUG
173+
def illegal: String = s"illegal type for $this: $tp"
173174
if (this is Module) // make sure module invariants that allow moduleClass and sourceModule to work are kept.
174175
tp match {
175176
case tp: ClassInfo => assert(tp.selfInfo.isInstanceOf[TermRefBySym], illegal)
@@ -178,6 +179,7 @@ object SymDenotations {
178179
case _ =>
179180
}
180181
*/
182+
if (Config.checkNoSkolemsInInfo) assertNoSkolems(initInfo)
181183
myInfo = tp
182184
}
183185

@@ -1038,8 +1040,28 @@ object SymDenotations {
10381040
s"$kindString $name"
10391041
}
10401042

1043+
// ----- Sanity checks and debugging */
1044+
10411045
def debugString = toString + "#" + symbol.id // !!! DEBUG
10421046

1047+
def hasSkolems(tp: Type): Boolean = tp match {
1048+
case tp: SkolemType => true
1049+
case tp: NamedType => hasSkolems(tp.prefix)
1050+
case tp: RefinedType => hasSkolems(tp.parent) || hasSkolems(tp.refinedInfo)
1051+
case tp: PolyType => tp.paramBounds.exists(hasSkolems) || hasSkolems(tp.resType)
1052+
case tp: MethodType => tp.paramTypes.exists(hasSkolems) || hasSkolems(tp.resType)
1053+
case tp: ExprType => hasSkolems(tp.resType)
1054+
case tp: AndOrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2)
1055+
case tp: TypeBounds => hasSkolems(tp.lo) || hasSkolems(tp.hi)
1056+
case tp: AnnotatedType => hasSkolems(tp.tpe)
1057+
case tp: TypeVar => hasSkolems(tp.inst)
1058+
case _ => false
1059+
}
1060+
1061+
def assertNoSkolems(tp: Type) =
1062+
if (!this.isSkolem)
1063+
assert(!hasSkolems(tp), s"assigning type $tp containing skolems to $this")
1064+
10431065
// ----- copies and transforms ----------------------------------------
10441066

10451067
protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = new UniqueRefDenotation(s, i, validFor)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2011,7 +2011,7 @@ object Types {
20112011
def isJava = false
20122012
def isImplicit = false
20132013

2014-
private val resType = resultTypeExp(this)
2014+
private[core] val resType = resultTypeExp(this)
20152015
assert(resType.exists)
20162016

20172017
override def resultType(implicit ctx: Context): Type =

src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,8 @@ class Namer { typer: Typer =>
677677
// println(s"final inherited for $sym: ${inherited.toString}") !!!
678678
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
679679
val rhsCtx = ctx.fresh addMode Mode.InferringReturnType
680-
def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion
680+
def rhsType = ctx.deskolemize(
681+
typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion)
681682
def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos)
682683
if (inherited.exists) inherited
683684
else {

tests/pos/i583a.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
object Test1 {
2+
3+
class Box[B](x: B)
4+
5+
class C {
6+
type T
7+
val box: Box[T] = ???
8+
def f(x: T): T = ???
9+
def x: T = ???
10+
}
11+
12+
def c: C = new C
13+
14+
val b = c.box
15+
16+
val f = c.f _
17+
18+
}
19+
20+

0 commit comments

Comments
 (0)