diff options
author | Martin Odersky <odersky@gmail.com> | 2015-06-05 17:18:11 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2015-06-06 11:05:27 +0200 |
commit | 91dd827a726a12395d7b84c03d45ca6822bf8f12 (patch) | |
tree | d8acfd662bdea9800664e60e91bf7cc61ae25e4e | |
parent | 0ee8e506dac87bae6ec432b2cd277109df872145 (diff) | |
download | dotty-91dd827a726a12395d7b84c03d45ca6822bf8f12.tar.gz dotty-91dd827a726a12395d7b84c03d45ca6822bf8f12.tar.bz2 dotty-91dd827a726a12395d7b84c03d45ca6822bf8f12.zip |
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.
-rw-r--r-- | src/dotty/tools/dotc/config/Config.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 26 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Namer.scala | 3 | ||||
-rw-r--r-- | tests/pos/i583a.scala | 20 |
5 files changed, 52 insertions, 4 deletions
diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index 27d5effa5..782a2f2d3 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -32,6 +32,11 @@ object Config { */ final val checkConstraintsPropagated = false + /** Check that no type appearing as the info of a SymDenotation contains + * skolem types. + */ + final val checkNoSkolemsInInfo = false + /** Type comparer will fail with an assert if the upper bound * of a constrained parameter becomes Nothing. This should be turned * on only for specific debugging as normally instantiation to Nothing diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index f24c41ee2..8162126a5 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -79,6 +79,7 @@ object SymDenotations { super.validFor_=(p) } */ + if (Config.checkNoSkolemsInInfo) assertNoSkolems(initInfo) // ------ Getting and setting fields ----------------------------- @@ -168,8 +169,8 @@ object SymDenotations { } protected[dotc] final def info_=(tp: Type) = { - /* - def illegal: String = s"illegal type for $this: $tp" + /* // DEBUG + def illegal: String = s"illegal type for $this: $tp" if (this is Module) // make sure module invariants that allow moduleClass and sourceModule to work are kept. tp match { case tp: ClassInfo => assert(tp.selfInfo.isInstanceOf[TermRefBySym], illegal) @@ -178,6 +179,7 @@ object SymDenotations { case _ => } */ + if (Config.checkNoSkolemsInInfo) assertNoSkolems(initInfo) myInfo = tp } @@ -1038,8 +1040,28 @@ object SymDenotations { s"$kindString $name" } + // ----- Sanity checks and debugging */ + def debugString = toString + "#" + symbol.id // !!! DEBUG + def hasSkolems(tp: Type): Boolean = tp match { + case tp: SkolemType => true + case tp: NamedType => hasSkolems(tp.prefix) + case tp: RefinedType => hasSkolems(tp.parent) || hasSkolems(tp.refinedInfo) + case tp: PolyType => tp.paramBounds.exists(hasSkolems) || hasSkolems(tp.resType) + case tp: MethodType => tp.paramTypes.exists(hasSkolems) || hasSkolems(tp.resType) + case tp: ExprType => hasSkolems(tp.resType) + case tp: AndOrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2) + case tp: TypeBounds => hasSkolems(tp.lo) || hasSkolems(tp.hi) + case tp: AnnotatedType => hasSkolems(tp.tpe) + case tp: TypeVar => hasSkolems(tp.inst) + case _ => false + } + + def assertNoSkolems(tp: Type) = + if (!this.isSkolem) + assert(!hasSkolems(tp), s"assigning type $tp containing skolems to $this") + // ----- copies and transforms ---------------------------------------- protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = new UniqueRefDenotation(s, i, validFor) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 4e1da7c34..ba39e7bef 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2011,7 +2011,7 @@ object Types { def isJava = false def isImplicit = false - private val resType = resultTypeExp(this) + private[core] val resType = resultTypeExp(this) assert(resType.exists) override def resultType(implicit ctx: Context): Type = diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 10667f884..2e76d3171 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -677,7 +677,8 @@ class Namer { typer: Typer => // println(s"final inherited for $sym: ${inherited.toString}") !!! // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}") val rhsCtx = ctx.fresh addMode Mode.InferringReturnType - def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion + def rhsType = ctx.deskolemize( + typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion) def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos) if (inherited.exists) inherited else { diff --git a/tests/pos/i583a.scala b/tests/pos/i583a.scala new file mode 100644 index 000000000..a97a3998b --- /dev/null +++ b/tests/pos/i583a.scala @@ -0,0 +1,20 @@ +object Test1 { + + class Box[B](x: B) + + class C { + type T + val box: Box[T] = ??? + def f(x: T): T = ??? + def x: T = ??? + } + + def c: C = new C + + val b = c.box + + val f = c.f _ + +} + + |