Skip to content

Commit 68b4e6c

Browse files
committed
Merge pull request #697 from dotty-staging/fix/erasure-thistypes-vcs
Fix erasure of this types and refactor value class erasure
2 parents 5e6a9a2 + ef01848 commit 68b4e6c

File tree

8 files changed

+40
-36
lines changed

8 files changed

+40
-36
lines changed

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,16 @@ object Config {
3232
*/
3333
final val checkConstraintsPropagated = false
3434

35-
/** Check that constraints of globally committable typer states are closed */
36-
final val checkConstraintsClosed = true
35+
/** Check that constraints of globally committable typer states are closed.
36+
* NOTE: When enabled, the check can cause CyclicReference errors because
37+
* it traverses all elements of a type. Such failures were observed when
38+
* compiling all of dotty together (source seems to be in GenBCode which
39+
* accesses javac's settings.)
40+
*
41+
* It is recommended to turn this option on only when chasing down
42+
* a PolyParam instantiation error. See comment in Types.TypeVar.instantiate.
43+
*/
44+
final val debugCheckConstraintsClosed = false
3745

3846
/** Check that no type appearing as the info of a SymDenotation contains
3947
* skolem types.

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

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,20 @@ object TypeErasure {
110110
private def erasureCtx(implicit ctx: Context) =
111111
if (ctx.erasedTypes) ctx.withPhase(ctx.erasurePhase).addMode(Mode.FutureDefsOK) else ctx
112112

113-
/** The standard erasure of a Scala type.
113+
/** The standard erasure of a Scala type. Value classes are erased as normal classes.
114+
*
115+
* @param tp The type to erase.
116+
*/
117+
def erasure(tp: Type)(implicit ctx: Context): Type =
118+
erasureFn(isJava = false, semiEraseVCs = false, isConstructor = false, wildcardOK = false)(tp)(erasureCtx)
119+
120+
/** The value class erasure of a Scala type, where value classes are semi-erased to
121+
* ErasedValueType (they will be fully erased in [[ElimErasedValueType]]).
114122
*
115123
* @param tp The type to erase.
116-
* @param semiEraseVCs If true, value classes are semi-erased to ErasedValueType
117-
* (they will be fully erased in [[ElimErasedValueType]]).
118-
* If false, they are erased like normal classes.
119124
*/
120-
def erasure(tp: Type, semiEraseVCs: Boolean = false)(implicit ctx: Context): Type =
121-
erasureFn(isJava = false, semiEraseVCs, isConstructor = false, wildcardOK = false)(tp)(erasureCtx)
125+
def valueErasure(tp: Type)(implicit ctx: Context): Type =
126+
erasureFn(isJava = false, semiEraseVCs = true, isConstructor = false, wildcardOK = false)(tp)(erasureCtx)
122127

123128
def sigName(tp: Type, isJava: Boolean)(implicit ctx: Context): TypeName = {
124129
val seqClass = if (isJava) defn.ArrayClass else defn.SeqClass
@@ -141,7 +146,7 @@ object TypeErasure {
141146
case tp: ThisType =>
142147
tp
143148
case tp =>
144-
erasure(tp, semiEraseVCs = true)
149+
valueErasure(tp)
145150
}
146151

147152
/** The symbol's erased info. This is the type's erasure, except for the following symbols:
@@ -315,12 +320,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
315320
val parent = tp.parent
316321
if (parent isRef defn.ArrayClass) eraseArray(tp)
317322
else this(parent)
318-
case tp: TermRef =>
323+
case _: TermRef | _: ThisType =>
319324
this(tp.widen)
320-
case tp: ThisType =>
321-
def thisTypeErasure(tpToErase: Type) =
322-
erasureFn(isJava, semiEraseVCs = false, isConstructor, wildcardOK)(tpToErase)
323-
thisTypeErasure(tp.cls.typeRef)
324325
case SuperType(thistpe, supertpe) =>
325326
SuperType(this(thistpe), this(supertpe))
326327
case ExprType(rt) =>
@@ -396,7 +397,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
396397
private def eraseDerivedValueClassRef(tref: TypeRef)(implicit ctx: Context): Type = {
397398
val cls = tref.symbol.asClass
398399
val underlying = underlyingOfValueClass(cls)
399-
ErasedValueType(cls, erasure(underlying, semiEraseVCs = true))
400+
ErasedValueType(cls, valueErasure(underlying))
400401
}
401402

402403

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ extends TyperState(r) {
8787

8888
override def constraint = myConstraint
8989
override def constraint_=(c: Constraint)(implicit ctx: Context) = {
90-
if (Config.checkConstraintsClosed && isGlobalCommittable) c.checkClosed()
90+
if (Config.debugCheckConstraintsClosed && isGlobalCommittable) c.checkClosed()
9191
myConstraint = c
9292
}
9393

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,6 +2460,8 @@ object Types {
24602460

24612461
if (ctx.typerState.isGlobalCommittable)
24622462
assert(!inst.isInstanceOf[PolyParam], i"bad inst $this := $inst, constr = ${ctx.typerState.constraint}")
2463+
// If this fails, you might want to turn on Config.debugCheckConstraintsClosed
2464+
// to help find the root of the problem.
24632465

24642466
instantiateWith(inst)
24652467
}

src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -268,35 +268,29 @@ object Erasure extends TypeTestsCasts{
268268
class Typer extends typer.ReTyper with NoChecking {
269269
import Boxing._
270270

271-
def erasedType(tree: untpd.Tree, semiEraseVCs: Boolean)(implicit ctx: Context): Type =
272-
tree.typeOpt match {
273-
case tp: TermRef if tree.isTerm => erasedRef(tp)
274-
case tp => erasure(tp, semiEraseVCs)
275-
}
271+
def erasedType(tree: untpd.Tree)(implicit ctx: Context): Type = {
272+
val tp = tree.typeOpt
273+
if (tree.isTerm) erasedRef(tp) else valueErasure(tp)
274+
}
276275

277-
def promote(tree: untpd.Tree, semiEraseVCs: Boolean)(implicit ctx: Context): tree.ThisTree[Type] = {
276+
override def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = {
278277
assert(tree.hasType)
279-
val erased = erasedType(tree, semiEraseVCs)
278+
val erased = erasedType(tree)
280279
ctx.log(s"promoting ${tree.show}: ${erased.showWithUnderlying()}")
281280
tree.withType(erased)
282281
}
283282

284-
override def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = {
285-
promote(tree, true)
286-
}
287-
288283
/** When erasing most TypeTrees we should not semi-erase value types.
289284
* This is not the case for [[DefDef#tpt]], [[ValDef#tpt]] and [[Typed#tpt]], they
290285
* are handled separately by [[typedDefDef]], [[typedValDef]] and [[typedTyped]].
291286
*/
292-
override def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = {
293-
promote(tree, semiEraseVCs = false)
294-
}
287+
override def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree =
288+
tree.withType(erasure(tree.tpe))
295289

296290
/** This override is only needed to semi-erase type ascriptions */
297291
override def typedTyped(tree: untpd.Typed, pt: Type)(implicit ctx: Context): Tree = {
298292
val Typed(expr, tpt) = tree
299-
val tpt1 = promote(tpt, semiEraseVCs = true)
293+
val tpt1 = promote(tpt)
300294
val expr1 = typed(expr, tpt1.tpe)
301295
assignType(untpd.cpy.Typed(tree)(expr1, tpt1), tpt1)
302296
}
@@ -384,7 +378,7 @@ object Erasure extends TypeTestsCasts{
384378
}
385379

386380
override def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context) =
387-
untpd.Ident(tree.name).withPos(tree.pos).withType(erasedType(tree, semiEraseVCs = false))
381+
untpd.Ident(tree.name).withPos(tree.pos).withType(erasedType(tree))
388382

389383
override def typedThis(tree: untpd.This)(implicit ctx: Context): Tree =
390384
if (tree.symbol == ctx.owner.enclosingClass || tree.symbol.isStaticOwner) promote(tree)
@@ -460,7 +454,7 @@ object Erasure extends TypeTestsCasts{
460454
if (pt.isValueType) pt else {
461455
if (tree.typeOpt.derivesFrom(ctx.definitions.UnitClass))
462456
tree.typeOpt
463-
else erasure(tree.typeOpt, semiEraseVCs = true)
457+
else valueErasure(tree.typeOpt)
464458
}
465459
}
466460

src/dotty/tools/dotc/transform/ExtensionMethods.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import core._
1414
import Phases.Phase
1515
import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._
1616
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._
17-
import TypeErasure.{ erasure, ErasedValueType }
17+
import TypeErasure.{ erasure, valueErasure, ErasedValueType }
1818
import TypeUtils._
1919
import util.Positions._
2020
import Decorators._
@@ -65,7 +65,7 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
6565
}
6666
}
6767

68-
val underlying = erasure(underlyingOfValueClass(valueClass), semiEraseVCs = true)
68+
val underlying = valueErasure(underlyingOfValueClass(valueClass))
6969
val evt = ErasedValueType(valueClass, underlying)
7070
val u2evtSym = ctx.newSymbol(moduleSym, nme.U2EVT, Synthetic | Method,
7171
MethodType(List(nme.x_0), List(underlying), evt))

tests/pending/run/unittest_collection.check

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)