diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index e9b0a9676df0..dcb5ba37354b 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -76,8 +76,7 @@ class Compiler { List(/*new PrivateToStatic,*/ new ExpandPrivate, new CollectEntryPoints, - new LabelDefs, - new TraitConstructors), + new LabelDefs), List(new GenBCode) ) diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index 9e9974bdce85..97893647c7fb 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -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. diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index 759dff0d44d8..f39f2bac6ec6 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -388,7 +388,7 @@ object Flags { /** Symbol is a self name */ final val SelfName = termFlag(54, "") - /** Symbol is an implementation class */ + /** Symbol is an implementation class of a Scala2 trait */ final val ImplClass = typeFlag(54, "") final val SelfNameOrImplClass = SelfName.toCommonFlags diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index dc94f6db12da..4d6cca61dc08 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -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 diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index eaf4ce1e2080..eb1a73625381 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -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$" @@ -261,6 +260,7 @@ object StdNames { val SKOLEM: N = "" val SPECIALIZED_INSTANCE: N = "specInstance$" val THIS: N = "_$this" + val TRAIT_CONSTRUCTOR: N = "$init$" val U2EVT: N = "u2evt$" final val Nil: N = "Nil" diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index d8dddb0828cb..164b0b8f3d16 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -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 @@ -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, diff --git a/src/dotty/tools/dotc/core/TypeErasure.scala b/src/dotty/tools/dotc/core/TypeErasure.scala index abe5418d4424..9b41eb982a5e 100644 --- a/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/src/dotty/tools/dotc/core/TypeErasure.scala @@ -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 @@ -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: @@ -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) => @@ -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)) } diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala index ba7a6a8063fd..5617f568a2a7 100644 --- a/src/dotty/tools/dotc/core/TyperState.scala +++ b/src/dotty/tools/dotc/core/TyperState.scala @@ -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 } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 1270466e9cb1..d6bb9c3c574e 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -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) } diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 9498cf43c7f7..53e8478fa66f 100644 --- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -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) diff --git a/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala index 9f9d2dd67682..116fee899fd9 100644 --- a/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala +++ b/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala @@ -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( diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index ad261c16be71..8b4c6a87db19 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -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) } @@ -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) @@ -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) } } diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala index 503016d8bab2..087e15c71685 100644 --- a/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -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._ @@ -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)) diff --git a/src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala b/src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala index 8c247130a50f..60e8edc26a1c 100644 --- a/src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala +++ b/src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala @@ -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 diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala index de6cde8f2cc6..bebaf44f46cd 100644 --- a/src/dotty/tools/dotc/transform/Mixin.scala +++ b/src/dotty/tools/dotc/transform/Mixin.scala @@ -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 @@ -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 = diff --git a/src/dotty/tools/dotc/transform/TraitConstructors.scala b/src/dotty/tools/dotc/transform/TraitConstructors.scala deleted file mode 100644 index 9fea468dac82..000000000000 --- a/src/dotty/tools/dotc/transform/TraitConstructors.scala +++ /dev/null @@ -1,36 +0,0 @@ -package dotty.tools.dotc.transform - -import dotty.tools.dotc.ast.tpd -import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, DenotTransformer} -import dotty.tools.dotc.core.Denotations.SingleDenotation -import dotty.tools.dotc.core.Phases.Phase -import dotty.tools.dotc.core.StdNames._ -import dotty.tools.dotc.core.SymDenotations.SymDenotation -import dotty.tools.dotc.core._ -import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo} - -/*** - * Renames constructors in traits so that backend will call them with invokeInterface - * Also makes sure that renamed constructor bodies conforms to type of method - */ -class TraitConstructors extends MiniPhaseTransform with SymTransformer { - import dotty.tools.dotc.ast.tpd._ - def phaseName: String = "traitConstructors" - - override def treeTransformPhase: Phase = this.phase - - def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = { - if (sym.isPrimaryConstructor && (sym.owner is Flags.Trait)) - sym.copySymDenotation(name = nme.IMPLCLASS_CONSTRUCTOR) - else sym - } - - override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { - val sym = tree.symbol - if (sym.isPrimaryConstructor && (sym.owner is Flags.Trait)) - cpy.DefDef(tree)(rhs = Block(List(tree.rhs), This(tree.symbol.enclosingClass.asClass))) - else tree - } - -} diff --git a/tests/pending/run/unittest_collection.check b/tests/pending/run/unittest_collection.check deleted file mode 100644 index df1629dd7eb1..000000000000 --- a/tests/pending/run/unittest_collection.check +++ /dev/null @@ -1 +0,0 @@ -warning: there was one deprecation warning; re-run with -deprecation for details diff --git a/tests/pending/run/unittest_collection.scala b/tests/run/unittest_collection.scala similarity index 100% rename from tests/pending/run/unittest_collection.scala rename to tests/run/unittest_collection.scala