Skip to content

Fix erasure of this types and refactor value class erasure #697

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/dotty/tools/dotc/config/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,16 @@ object Config {
*/
final val checkConstraintsPropagated = false

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

/** Check that no type appearing as the info of a SymDenotation contains
* skolem types.
Expand Down
27 changes: 14 additions & 13 deletions src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,20 @@ object TypeErasure {
private def erasureCtx(implicit ctx: Context) =
if (ctx.erasedTypes) ctx.withPhase(ctx.erasurePhase).addMode(Mode.FutureDefsOK) else ctx

/** The standard erasure of a Scala type.
/** The standard erasure of a Scala type. Value classes are erased as normal classes.
*
* @param tp The type to erase.
*/
def erasure(tp: Type)(implicit ctx: Context): Type =
erasureFn(isJava = false, semiEraseVCs = false, isConstructor = false, wildcardOK = false)(tp)(erasureCtx)

/** The value class erasure of a Scala type, where value classes are semi-erased to
* ErasedValueType (they will be fully erased in [[ElimErasedValueType]]).
*
* @param tp The type to erase.
* @param semiEraseVCs If true, value classes are semi-erased to ErasedValueType
* (they will be fully erased in [[ElimErasedValueType]]).
* If false, they are erased like normal classes.
*/
def erasure(tp: Type, semiEraseVCs: Boolean = false)(implicit ctx: Context): Type =
erasureFn(isJava = false, semiEraseVCs, isConstructor = false, wildcardOK = false)(tp)(erasureCtx)
def valueErasure(tp: Type)(implicit ctx: Context): Type =
erasureFn(isJava = false, semiEraseVCs = true, isConstructor = false, wildcardOK = false)(tp)(erasureCtx)

def sigName(tp: Type, isJava: Boolean)(implicit ctx: Context): TypeName = {
val seqClass = if (isJava) defn.ArrayClass else defn.SeqClass
Expand All @@ -141,7 +146,7 @@ object TypeErasure {
case tp: ThisType =>
tp
case tp =>
erasure(tp, semiEraseVCs = true)
valueErasure(tp)
}

/** The symbol's erased info. This is the type's erasure, except for the following symbols:
Expand Down Expand Up @@ -315,12 +320,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
val parent = tp.parent
if (parent isRef defn.ArrayClass) eraseArray(tp)
else this(parent)
case tp: TermRef =>
case _: TermRef | _: ThisType =>
this(tp.widen)
case tp: ThisType =>
def thisTypeErasure(tpToErase: Type) =
erasureFn(isJava, semiEraseVCs = false, isConstructor, wildcardOK)(tpToErase)
thisTypeErasure(tp.cls.typeRef)
case SuperType(thistpe, supertpe) =>
SuperType(this(thistpe), this(supertpe))
case ExprType(rt) =>
Expand Down Expand Up @@ -396,7 +397,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
private def eraseDerivedValueClassRef(tref: TypeRef)(implicit ctx: Context): Type = {
val cls = tref.symbol.asClass
val underlying = underlyingOfValueClass(cls)
ErasedValueType(cls, erasure(underlying, semiEraseVCs = true))
ErasedValueType(cls, valueErasure(underlying))
}


Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/TyperState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ extends TyperState(r) {

override def constraint = myConstraint
override def constraint_=(c: Constraint)(implicit ctx: Context) = {
if (Config.checkConstraintsClosed && isGlobalCommittable) c.checkClosed()
if (Config.debugCheckConstraintsClosed && isGlobalCommittable) c.checkClosed()
myConstraint = c
}

Expand Down
2 changes: 2 additions & 0 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2460,6 +2460,8 @@ object Types {

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

instantiateWith(inst)
}
Expand Down
28 changes: 11 additions & 17 deletions src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -268,35 +268,29 @@ object Erasure extends TypeTestsCasts{
class Typer extends typer.ReTyper with NoChecking {
import Boxing._

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

def promote(tree: untpd.Tree, semiEraseVCs: Boolean)(implicit ctx: Context): tree.ThisTree[Type] = {
override def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = {
assert(tree.hasType)
val erased = erasedType(tree, semiEraseVCs)
val erased = erasedType(tree)
ctx.log(s"promoting ${tree.show}: ${erased.showWithUnderlying()}")
tree.withType(erased)
}

override def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = {
promote(tree, true)
}

/** When erasing most TypeTrees we should not semi-erase value types.
* This is not the case for [[DefDef#tpt]], [[ValDef#tpt]] and [[Typed#tpt]], they
* are handled separately by [[typedDefDef]], [[typedValDef]] and [[typedTyped]].
*/
override def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = {
promote(tree, semiEraseVCs = false)
}
override def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree =
tree.withType(erasure(tree.tpe))

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

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

override def typedThis(tree: untpd.This)(implicit ctx: Context): Tree =
if (tree.symbol == ctx.owner.enclosingClass || tree.symbol.isStaticOwner) promote(tree)
Expand Down Expand Up @@ -460,7 +454,7 @@ object Erasure extends TypeTestsCasts{
if (pt.isValueType) pt else {
if (tree.typeOpt.derivesFrom(ctx.definitions.UnitClass))
tree.typeOpt
else erasure(tree.typeOpt, semiEraseVCs = true)
else valueErasure(tree.typeOpt)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/transform/ExtensionMethods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import core._
import Phases.Phase
import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._
import TypeErasure.{ erasure, ErasedValueType }
import TypeErasure.{ erasure, valueErasure, ErasedValueType }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

erasure does not need to be imported anymore.

import TypeUtils._
import util.Positions._
import Decorators._
Expand Down Expand Up @@ -65,7 +65,7 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
}
}

val underlying = erasure(underlyingOfValueClass(valueClass), semiEraseVCs = true)
val underlying = valueErasure(underlyingOfValueClass(valueClass))
val evt = ErasedValueType(valueClass, underlying)
val u2evtSym = ctx.newSymbol(moduleSym, nme.U2EVT, Synthetic | Method,
MethodType(List(nme.x_0), List(underlying), evt))
Expand Down
1 change: 0 additions & 1 deletion tests/pending/run/unittest_collection.check

This file was deleted.