Skip to content

Fix trait constructors #699

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 10 commits into from
Jul 1, 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
3 changes: 1 addition & 2 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ class Compiler {
List(/*new PrivateToStatic,*/
new ExpandPrivate,
new CollectEntryPoints,
new LabelDefs,
new TraitConstructors),
new LabelDefs),
List(new GenBCode)
)

Expand Down
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
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ object Flags {
/** Symbol is a self name */
final val SelfName = termFlag(54, "<selfname>")

/** Symbol is an implementation class */
/** Symbol is an implementation class of a Scala2 trait */
final val ImplClass = typeFlag(54, "<implclass>")

final val SelfNameOrImplClass = SelfName.toCommonFlags
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object NameOps {
def likeTyped(n: Name): N =
(if (name.isTermName) n.toTermName else n.toTypeName).asInstanceOf[N]

def isConstructorName = name == CONSTRUCTOR || name == IMPLCLASS_CONSTRUCTOR
def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR
def isExceptionResultName = name startsWith EXCEPTION_RESULT_PREFIX
def isImplClassName = name endsWith IMPL_CLASS_SUFFIX
def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,6 @@ object StdNames {
val EVT2U: N = "evt2u$"
val EQEQ_LOCAL_VAR: N = "eqEqTemp$"
val FAKE_LOCAL_THIS: N = "this$"
val IMPLCLASS_CONSTRUCTOR: N = "$init$"
val LAZY_LOCAL: N = "$lzy"
val LAZY_LOCAL_INIT: N = "$lzyINIT"
val LAZY_FIELD_OFFSET: N = "OFFSET$"
Expand Down Expand Up @@ -261,6 +260,7 @@ object StdNames {
val SKOLEM: N = "<skolem>"
val SPECIALIZED_INSTANCE: N = "specInstance$"
val THIS: N = "_$this"
val TRAIT_CONSTRUCTOR: N = "$init$"
val U2EVT: N = "u2evt$"

final val Nil: N = "Nil"
Expand Down
9 changes: 6 additions & 3 deletions src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ object SymDenotations {
final def isClassConstructor = name == nme.CONSTRUCTOR

/** Is this the constructor of a trait? */
final def isImplClassConstructor = name == nme.IMPLCLASS_CONSTRUCTOR
final def isImplClassConstructor = name == nme.TRAIT_CONSTRUCTOR

/** Is this the constructor of a trait or a class */
final def isConstructor = name.isConstructorName
Expand Down Expand Up @@ -1630,8 +1630,11 @@ object SymDenotations {
override def fullName(implicit ctx: Context): Name = super.fullName

override def primaryConstructor(implicit ctx: Context): Symbol = {
val cname = if (this is ImplClass) nme.IMPLCLASS_CONSTRUCTOR else nme.CONSTRUCTOR
info.decls.denotsNamed(cname).last.symbol // denotsNamed returns Symbols in reverse order of occurrence
def constrNamed(cname: TermName) = info.decls.denotsNamed(cname).last.symbol
// denotsNamed returns Symbols in reverse order of occurrence
if (this.is(ImplClass)) constrNamed(nme.TRAIT_CONSTRUCTOR) // ignore normal constructor
else
constrNamed(nme.CONSTRUCTOR).orElse(constrNamed(nme.TRAIT_CONSTRUCTOR))
}

/** The parameter accessors of this class. Term and type accessors,
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
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
}

val name1 = name0.adjustIfModuleClass(flags)
val name = if (name1 == nme.IMPLCLASS_CONSTRUCTOR) nme.CONSTRUCTOR else name1
val name = if (name1 == nme.TRAIT_CONSTRUCTOR) nme.CONSTRUCTOR else name1

def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass)
def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module)
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/AugmentScala2Traits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransform
val mold =
if (meth.isConstructor)
meth.copySymDenotation(
name = nme.IMPLCLASS_CONSTRUCTOR,
name = nme.TRAIT_CONSTRUCTOR,
info = MethodType(Nil, defn.UnitType))
else meth.ensureNotPrivate
meth.copy(
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.{ valueErasure, ErasedValueType }
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
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class LinkScala2ImplClasses extends MiniPhaseTransform with IdentityDenotTransfo

private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol =
meth.owner.implClass.info
.decl(if (meth.isConstructor) nme.IMPLCLASS_CONSTRUCTOR else meth.name)
.decl(if (meth.isConstructor) nme.TRAIT_CONSTRUCTOR else meth.name)
.suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
.symbol

Expand Down
9 changes: 5 additions & 4 deletions src/dotty/tools/dotc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation =
if (sym.is(Accessor, butNot = Deferred) && sym.owner.is(Trait))
sym.copySymDenotation(initFlags = sym.flags &~ ParamAccessor | Deferred).ensureNotPrivate
else if (sym.isConstructor && sym.owner.is(Trait) && sym.info.firstParamTypes.nonEmpty)
sym.copySymDenotation(info = MethodType(Nil, sym.info.resultType))
else if (sym.isConstructor && sym.owner.is(Trait))
sym.copySymDenotation(
name = nme.TRAIT_CONSTRUCTOR,
info = MethodType(Nil, sym.info.resultType))
else
sym

Expand Down Expand Up @@ -231,8 +233,7 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>

cpy.Template(impl)(
constr =
if (cls.is(Trait) && impl.constr.vparamss.flatten.nonEmpty)
cpy.DefDef(impl.constr)(vparamss = Nil :: Nil)
if (cls.is(Trait)) cpy.DefDef(impl.constr)(vparamss = Nil :: Nil)
else impl.constr,
parents = impl.parents.map(p => TypeTree(p.tpe).withPos(p.pos)),
body =
Expand Down
36 changes: 0 additions & 36 deletions src/dotty/tools/dotc/transform/TraitConstructors.scala

This file was deleted.

1 change: 0 additions & 1 deletion tests/pending/run/unittest_collection.check

This file was deleted.