summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2008-05-30 18:00:25 +0000
committerMartin Odersky <odersky@gmail.com>2008-05-30 18:00:25 +0000
commit562647a37a6675fbf328f72e081a7f88913dd004 (patch)
tree36a8f00923e6991bf483af901f34ec31763111e0
parentb6281cd5a72fa31356020fab3929c6e0f4ad578f (diff)
downloadscala-562647a37a6675fbf328f72e081a7f88913dd004.tar.gz
scala-562647a37a6675fbf328f72e081a7f88913dd004.tar.bz2
scala-562647a37a6675fbf328f72e081a7f88913dd004.zip
fixed #807. More stuff for virtual classes.
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Phase.scala7
-rw-r--r--src/compiler/scala/tools/nsc/SubComponent.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala19
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala1
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala7
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala5
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Flags.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala15
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala396
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala19
-rw-r--r--test/pending/run/t0807.scala5
17 files changed, 284 insertions, 233 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 75a57a3ff4..254b34a2ee 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -248,6 +248,8 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
override def erasedTypes: Boolean = isErased
private val isFlat = prev.name == "flatten" || prev.flatClasses
override def flatClasses: Boolean = isFlat
+ private val isDevirtualized = prev.name == "devirtualize" || prev.devirtualized
+ override def devirtualized: Boolean = isDevirtualized // (part of DEVIRTUALIZE)
/** Is current phase cancelled on this unit? */
def cancelled(unit: CompilationUnit) =
diff --git a/src/compiler/scala/tools/nsc/Phase.scala b/src/compiler/scala/tools/nsc/Phase.scala
index 7ecce6b3f3..57780ed5ee 100644
--- a/src/compiler/scala/tools/nsc/Phase.scala
+++ b/src/compiler/scala/tools/nsc/Phase.scala
@@ -14,9 +14,14 @@ abstract class Phase(val prev: Phase) {
val id: Id = if (prev eq null) 0 else prev.id + 1
+ /** New flags visible after this phase has completed */
+ def nextFlags: Long = 0l
+
+ /** New flags visible once this phase has started */
def newFlags: Long = 0l
+
private var fmask: Long =
- if (prev eq null) Flags.InitialFlags else prev.flagMask | newFlags
+ if (prev eq null) Flags.InitialFlags else prev.flagMask | prev.nextFlags | newFlags
def flagMask: Long = fmask
private var nx: Phase = this
diff --git a/src/compiler/scala/tools/nsc/SubComponent.scala b/src/compiler/scala/tools/nsc/SubComponent.scala
index 5f879a550c..adb54dd2ec 100644
--- a/src/compiler/scala/tools/nsc/SubComponent.scala
+++ b/src/compiler/scala/tools/nsc/SubComponent.scala
@@ -21,6 +21,9 @@ abstract class SubComponent {
/** New flags defined by the phase which are not valid before */
def phaseNewFlags: Long = 0
+ /** New flags defined by the phase which are not valid until immediately after it */
+ def phaseNextFlags: Long = 0
+
/** The phase factory */
def newPhase(prev: Phase): Phase
@@ -43,5 +46,6 @@ abstract class SubComponent {
abstract class StdPhase(prev: Phase) extends global.GlobalPhase(prev) {
def name = phaseName
override def newFlags = phaseNewFlags
+ override def nextFlags = phaseNextFlags
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 7a335a6c93..734921eac6 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -282,6 +282,25 @@ abstract class TreeGen {
def mkSynchronized(monitor: Tree, body: Tree): Tree =
Apply(Select(monitor, definitions.Object_synchronized), List(body))
+ def wildcardStar(tree: Tree) =
+ atPos(tree.pos) { Typed(tree, Ident(nme.WILDCARD_STAR.toTypeName)) }
+
+ def paramToArg(vparam: Symbol) = {
+ val arg = Ident(vparam)
+ if (vparam.tpe.typeSymbol == RepeatedParamClass) wildcardStar(arg)
+ else arg
+ }
+
+ def paramToArg(vparam: ValDef) = {
+ val arg = Ident(vparam.name)
+ if (treeInfo.isRepeatedParamType(vparam.tpt)) wildcardStar(arg)
+ else arg
+ }
+
+ /** Make forwarder to method `target', passing all parameters in `params' */
+ def mkForwarder(target: Tree, vparamss: List[List[Symbol]]) =
+ (target /: vparamss)((fn, vparams) => Apply(fn, vparams map paramToArg))
+
def evalOnce(expr: Tree, owner: Symbol, unit: CompilationUnit)(within: (() => Tree) => Tree): Tree =
if (treeInfo.isPureExpr(expr)) {
within(() => expr);
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index c034aa67f9..48fdfe0f7f 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -159,6 +159,7 @@ abstract class TreeInfo {
/** Is type a of the form T* ? */
def isRepeatedParamType(tpt: Tree) = tpt match {
case AppliedTypeTree(Select(_, rp), _) => rp == nme.REPEATED_PARAM_CLASS_NAME.toTypeName
+ case TypeTree() => tpt.tpe.typeSymbol == definitions.RepeatedParamClass
case _ => false
}
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
index fd1c3e786b..006f27f88c 100644
--- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
@@ -139,9 +139,9 @@ abstract class TreePrinters {
case ClassDef(mods, name, tparams, impl) =>
printAnnotations(tree)
printModifiers(tree, mods)
- print((if (mods hasFlag TRAIT) "trait " else "class ") + symName(tree, name))
+ print((if (mods.isTrait) "trait " else "class ") + symName(tree, name))
printTypeParams(tparams)
- print(" extends "); print(impl)
+ print(if (mods hasFlag DEFERRED) " <: " else " extends "); print(impl) // (part of DEVIRTUALIZE)
case PackageDef(packaged, stats) =>
printAnnotations(tree)
@@ -379,6 +379,9 @@ abstract class TreePrinters {
printRaw(
if (tree.isDef && tree.symbol != NoSymbol && tree.symbol.isInitialized) {
tree match {
+ case ClassDef(_, _, _, impl @ Template(ps, trees.emptyValDef, body))
+ if (tree.symbol.thisSym != tree.symbol) =>
+ ClassDef(tree.symbol, Template(ps, ValDef(tree.symbol.thisSym), body))
case ClassDef(_, _, _, impl) => ClassDef(tree.symbol, impl)
case ModuleDef(_, _, impl) => ModuleDef(tree.symbol, impl)
case ValDef(_, _, _, rhs) => ValDef(tree.symbol, rhs)
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 2f699146cd..ceab218a8d 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -58,7 +58,7 @@ trait Trees {
def isCase = hasFlag(CASE )
def isSealed = hasFlag(SEALED )
def isFinal = hasFlag(FINAL )
- def isTrait = hasFlag(TRAIT )
+ def isTrait = hasFlag(TRAIT | notDEFERRED) // (part of DEVIRTUALIZE)
def isImplicit = hasFlag(IMPLICIT )
def isPublic = !isPrivate && !isProtected
def hasFlag(flag: Long) = (flag & flags) != 0
@@ -326,6 +326,7 @@ trait Trees {
*/
def ClassDef(sym: Symbol, impl: Template): ClassDef =
posAssigner.atPos(sym.pos) {
+ var flags = sym.flags
ClassDef(Modifiers(sym.flags),
sym.name,
sym.typeParams map TypeDef,
@@ -549,7 +550,7 @@ trait Trees {
}
}
val constrs =
- if (constrMods hasFlag TRAIT) {
+ if (constrMods.isTrait) {
if (body forall treeInfo.isInterfaceMember) List()
else List(
DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, List(), List(List()), TypeTree(), Block(lvdefs, Literal(()))))
diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala
index fae47dd0f3..f8ea35df70 100644
--- a/src/compiler/scala/tools/nsc/symtab/Flags.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala
@@ -87,6 +87,7 @@ object Flags extends Enumeration {
// late flags (set by a transformer phase)
final val latePRIVATE = (PRIVATE: Long) << LateShift
+ final val lateABSTRACT = (ABSTRACT: Long) << LateShift
final val lateDEFERRED = (DEFERRED: Long) << LateShift
final val lateINTERFACE = (INTERFACE: Long) << LateShift
final val lateMODULE = (MODULE: Long) << LateShift
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index b72f9c9908..d72a484a35 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -214,7 +214,7 @@ trait Symbols {
//final def isMonomorphicType = isType && hasFlag(MONOMORPHIC)
final def isError = hasFlag(IS_ERROR)
final def isErroneous = isError || isInitialized && tpe.isErroneous
- final def isTrait = isClass & hasFlag(TRAIT)
+ final def isTrait = isClass & hasFlag(TRAIT | notDEFERRED) // A virtual class becomes a trait (part of DEVIRTUALIZE)
final def isTypeParameterOrSkolem = isType && hasFlag(PARAM)
final def isTypeSkolem = isSkolem && hasFlag(PARAM)
final def isTypeParameter = isTypeParameterOrSkolem && !isSkolem
@@ -1506,7 +1506,9 @@ trait Symbols {
else rawowner
override def name: Name =
- if (phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass) {
+ if ((rawflags & notDEFERRED) != 0 && phase.devirtualized && !phase.erasedTypes) {
+ newTypeName(rawname+"$trait") // (part of DEVIRTUALIZE)
+ } else if (phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass) {
if (flatname == nme.EMPTY) {
assert(rawowner.isClass)
flatname = newTypeName(compactify(rawowner.name.toString() + "$" + rawname))
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index a2340da4b4..6a75d98b63 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -172,12 +172,14 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
}
else erasure(tp)
} else {
+/*
val erased =
if (sym.isGetter && sym.tpe.isInstanceOf[MethodType])
erasure mapOver sym.tpe // for getters, unlike for normal methods, always convert Unit to BoxedUnit.
else
erasure(tp)
- transformMixinInfo(erased)
+*/
+ transformMixinInfo(erasure(tp))
}
val deconstMap = new TypeMap {
@@ -893,7 +895,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
tree1 setType erasure(tree1.tpe)
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
val result = super.transform(tree1) setType null
- tpt.tpe = transformInfo(tree.symbol, tree.symbol.tpe).resultType
+ tpt.tpe = erasure(tree.symbol.tpe).resultType
result
case _ =>
case class MyError(count : Int, ex : AssertionError) extends Error(ex.getMessage)
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index f421529346..ad41f64e72 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -248,8 +248,8 @@ abstract class Mixin extends InfoTransform {
// member is a constant; only getter is needed
;
case MethodType(List(), TypeRef(_, tpeSym, _))
- if member.hasFlag(LAZY) && tpeSym == definitions.UnitClass =>
- // member is a lazy value of type unit. No field needed
+ if tpeSym == definitions.UnitClass =>
+ // member is a value of type unit. No field needed
;
case _ =>
// otherwise mixin a field as well
@@ -642,10 +642,17 @@ abstract class Mixin extends InfoTransform {
}
offset += 1
rhs1
- } else
+ } else if (sym.getter(sym.owner).tpe.resultType.typeSymbol == definitions.UnitClass) {
+ Literal(())
+ } else {
Select(This(clazz), sym.accessed)
+ }
}
- if (sym.isSetter) Assign(accessedRef, Ident(vparams.head))
+ if (sym.isSetter)
+ accessedRef match {
+ case Literal(_) => accessedRef
+ case _ => Assign(accessedRef, Ident(vparams.head))
+ }
else gen.mkCheckInit(accessedRef)
})
} else if (sym.isModule && !(sym hasFlag LIFTED | BRIDGE)) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
index e88ba6f194..75994cf72b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
@@ -22,18 +22,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
val phaseName: String = "devirtualize"
/** The phase might set the following new flags: */
- override def phaseNewFlags: Long = notOVERRIDE | notFINAL
- //
- // todo: this does not work yet: for some unknown reason the backend
- // generates unverifiable code when notOVERRIDE is set for any phase whatsoever
- // (I tried to set it later at phase Mixin, with same effect.
- // One gets error messages like the following:
- //
- // /home/odersky/scala/sabbus.xml:37: The following error occurred while executing this line:
- // /home/odersky/scala/sabbus.xml:456: Could not create type quick-bin due to java.lang.VerifyError: (class: scala/Option, method: productPrefix signature: ()Ljava/lang/String;) Illegal local variable number
- //
- // we need to fix this before notOVERRIDE can be turned on here.
-
+ override def phaseNextFlags: Long = notDEFERRED | notOVERRIDE | notFINAL | lateABSTRACT
def newTransformer(unit: CompilationUnit): DeVirtualizeTransformer =
new DeVirtualizeTransformer(unit)
@@ -41,7 +30,14 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
/** The class does not change base-classes of existing classes */
override def changesBaseClasses = false
- def transformInfo(sym: Symbol, tp: Type): Type = devirtualizeMap(tp)
+ def transformInfo(sym: Symbol, tp: Type): Type =
+ if (sym.isThisSym && sym.owner.isVirtualClass) {
+ val clazz = sym.owner
+ intersectionType(
+ List(
+ appliedType(abstractType(clazz).typeConstructor, clazz.typeParams map (_.tpe)),
+ clazz.tpe))
+ } else devirtualizeMap(tp)
/* todo:
handle constructor arguments
@@ -51,15 +47,31 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
/** Do the following transformations everywhere in a type:
*
- * 1. If a class defines virtual classes VC, add abstract types VA,
- * worker traits VT and factories VF instead (@see devirtualize).
- * 2. For all virtual member classes VC which
- * are not abstract and which are or inherit from a virtual class defined in current class
- * add a factory (@see addFactory)
- * 3. Convert VC.this where VC is a virtual class to WT.this where WT is the worker trait for VC
- * (@see workerTrait)
- * 4. Convert TypeRef's to VC where VC is a virtual class to TypeRef's to AT, where AT
- * is the abstract type corresponding to VC.
+ * 1. Replace a virtual class
+ *
+ * attrs mods class VC[Ts] <: Ps { decls }
+ *
+ * by the following symbols
+ *
+ * attrs mods1 type VC[Ts] <: dvm(Ps) with VC$trait[Ts]
+ * attrs mods2 trait VC$trait[Ts] extends AnyRef with ScalaObject {
+ * this: VC[Ts] with VC$trait[Ts] => decls1
+ * }
+ *
+ * The class symbol VC becomes the symbol of the workertrait.
+ *
+ * dvm is the devirtalization mapping which converts refs to
+ * virtual classes to refs to their abstract types (@see devirtualize)
+ * mods1 are the modifiers inherited to abstract types
+ * mods2 are the modifiers inherited to worker traits
+ * decls1 is decls but members that have an override modifier
+ * lose it and any final modifier as well.
+ *
+ * 2. For all virtual member classes VC which
+ * are not abstract and which are or inherit from a virtual class defined in current class
+ * add a factory (@see mkFactory)
+ * 3. Convert TypeRef's to VC where VC is a virtual class to TypeRef's to AT, where AT
+ * is the abstract type corresponding to VC.
*
* Note: If a class inherits vc's from two different paths, a vc in the
* inheriting class has to be created beforehand. This is done in phase ??? (NOT YET DONE!)
@@ -68,27 +80,40 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
* isVirtualClass returns true for them also.
*/
object devirtualizeMap extends TypeMap {
- def apply(tp: Type): Type = {
-// println("devirtualizeMap on " + tp)
- mapOver(tp) match {
- case tp1 @ ClassInfoType(parents, decls, clazz) if containsVirtuals(clazz) =>
-// println(clazz + " contains virtuals")
- transformOwnerInfo(clazz) // we might need to do this in two phases: enter/resolve
- val ds = decls.toList
- val decls1 = newScope(ds)
- for (m <- ds)
- if (m.isVirtualClass) devirtualize(m, decls1)
- for (m <- classesInNeedOfFactories(clazz))
- addFactory(m, clazz, decls1)
-// println("Built ourselves a " + ClassInfoType(parents, decls1, clazz))
- ClassInfoType(parents, decls1, clazz)
- case tp1 @ ThisType(clazz) if clazz.isVirtualClass =>
- ThisType(workerTrait(clazz))
+ def apply(tp: Type): Type = mapOver(tp) match {
+ case tp1 @ ClassInfoType(parents, decls0, clazz) =>
+ var decls = decls0
+ def enter(sym: Symbol) = // at next phase because names of worker traits change
+ atPhase(ownPhase.next) { decls.enter(sym) }
+ if (containsVirtuals(clazz)) {
+ decls = newScope
+ for (m <- decls0.toList) {
+ if (m.isVirtualClass) {
+ m.setFlag(notDEFERRED | notFINAL | lateABSTRACT)
+ enter(mkAbstractType(m))
+ }
+ enter(m)
+ }
+ for (m <- classesInNeedOfFactories(clazz))
+ enter(mkFactory(m, clazz))
+ }
+ if (clazz.isVirtualClass) {
+ println("virtual class: "+clazz+clazz.locationString)
+ transformOwnerInfo(clazz)
+ // remove OVERRIDE from all workertrait members,
+ for (val m <- decls.toList) {
+ if (m hasFlag OVERRIDE) m setFlag (notOVERRIDE | notFINAL)
+ }
+ if (clazz.thisSym == clazz) clazz.typeOfThis = clazz.thisType
+ // ... to give a hook on which we can hang selftype transformers
+ ClassInfoType(List(ObjectClass.tpe, ScalaObjectClass.tpe), decls, clazz)
+ } else {
+ ClassInfoType(parents map this, decls, clazz)
+ }
case tp1 @ TypeRef(pre, clazz, args) if clazz.isVirtualClass =>
TypeRef(pre, abstractType(clazz), args)
case tp1 =>
tp1
- }
}
}
@@ -96,9 +121,10 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
protected def transformOwnerInfo(clazz: Symbol) { atPhase(ownPhase.next) { clazz.owner.info } }
/** Names of derived classes and factories */
- protected def workerTraitName(clazzName: Name) = newTypeName(clazzName+"$trait")
- protected def concreteClassName(clazzName: Name) = newTypeName(clazzName+"$fix")
- protected def factoryName(clazzName: Name) = newTermName("new$"+clazzName)
+ protected def concreteClassName(clazz: Symbol) =
+ atPhase(ownPhase) { newTypeName(clazz.name+"$fix") }
+ protected def factoryName(clazz: Symbol) =
+ atPhase(ownPhase) { newTermName("new$"+clazz.name) }
/** Does `clazz' contaion virtual classes? */
protected def containsVirtuals(clazz: Symbol) = clazz.info.decls.toList exists (_.isVirtualClass)
@@ -116,41 +142,28 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
* }
*/
protected def classesInNeedOfFactories(clazz: Symbol) = atPhase(ownPhase) {
- def isDefinedVirtual(c: Symbol) = c.isVirtualClass && c.owner == clazz
- val buf = new ListBuffer[Symbol]
- for (m <- clazz.info.members)
- if (m.isVirtualClass && !(m hasFlag ABSTRACT) && (m.info.baseClasses exists isDefinedVirtual))
- buf += m
- buf.toList
+ def isOverriddenVirtual(c: Symbol) =
+ c.isVirtualClass && clazz.info.decl(c.name).isVirtualClass
+ val xs = clazz.info.members.toList filter (x => x.isVirtualClass && !x.hasFlag(ABSTRACT))
+ for (m <- clazz.info.members.toList;
+ if (m.isVirtualClass && !(m hasFlag ABSTRACT) &&
+ (m.info.baseClasses exists isOverriddenVirtual))) yield m
}
/** The abstract type corresponding to a virtual class. */
- protected def abstractType(clazz: Symbol): Symbol = atPhase(ownPhase.next) {
-// println("Looking up the abstract type for " + clazz)
- val tsym = clazz.owner.info.member(clazz.name)
- assert(tsym.isAbstractType, clazz)
-// println("Found " + tsym)
- tsym
- }
-
- /** The worker trait corresponding to a virtual class. */
- protected def workerTrait(clazz: Symbol) = atPhase(ownPhase.next) {
- val tsym = clazz.owner.info.member(workerTraitName(clazz.name))
- assert(tsym.isTrait, clazz)
- tsym
+ protected def abstractType(clazz: Symbol): Symbol = atPhase(ownPhase.next) {
+ val abstpe = clazz.owner.info.decl(atPhase(ownPhase) { clazz.name })
+ assert(abstpe.isAbstractType)
+ abstpe
}
/** The factory corresponding to a virtual class. */
- protected def factory(clazz: Symbol) = atPhase(ownPhase.next) {
- assert(!(clazz hasFlag ABSTRACT), clazz)
- val fsym = clazz.owner.info.member(factoryName(clazz.name))
+ protected def factory(clazz: Symbol, owner: Symbol) = atPhase(ownPhase.next) {
+ val fsym = owner.info.member(factoryName(clazz))
assert(fsym.isMethod, clazz)
fsym
}
- /** The flags that a worker trait can inherit from its virtual class */
- protected val traitFlagMask = AccessFlags
-
/** The flags that an abstract type can inherit from its virtual class */
protected val absTypeFlagMask = AccessFlags | DEFERRED
@@ -162,69 +175,54 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
protected def mkPolyType(tparams: List[Symbol], tp: Type) =
if (tparams.isEmpty) tp else PolyType(tparams, tp)
- /** Set info of `dst' to `tp', potentially wrapped by copies of any type
- * parameters of symbol `from' */
- def setPolyInfo(dst: Symbol, from: Symbol, tp: Type) = {
- val tparams = cloneSymbols(from.typeParams, dst)
- dst setInfo mkPolyType(tparams, tp substSym (from.typeParams, tparams))
+ /** A lazy type to complete `sym', which is is generated for virtual class
+ * `clazz'.
+ * The info of the symbol is computed by method `getInfo'.
+ * It is wrapped in copies of the type parameters of `clazz'.
+ */
+ abstract class PolyTypeCompleter(sym: Symbol, clazz: Symbol) extends LazyType {
+ def getInfo: Type
+ override val typeParams = cloneSymbols(clazz.typeParams, sym)
+ override def complete(sym: Symbol) {
+ sym.setInfo(
+ mkPolyType(typeParams, getInfo.substSym(clazz.typeParams, typeParams)))
+ }
}
- /** Replace a virtual class
- *
- * attrs mods class VC[Ts] <: Ps { decls }
- *
- * by the following symbols
- *
- * attrs mods1 type VC[Ts] <: dvm(Ps) with VC$trait[Ts]
- * attrs mods2 trait VC$trait[Ts] extends AnyRef with ScalaObject {
- * this: VC[Ts] with VC$trait[Ts] => decls1
- * }
- *
- * where
- *
- * dvm is the devirtalization mapping which converts refs to
- * virtual classes to refs to their abstract types (@see devirtualize)
- * mods1 are the modifiers inherited to abstract types
- * mods2 are the modifiers inherited to worker traits
- * decls1 is decls but members that have an override modifier
- * lose it and any final modifier as well.
- */
- protected def devirtualize(clazz: Symbol, scope: Scope) {
- scope.unlink(clazz)
+ protected def wasVirtualClass(sym: Symbol) = {
+ sym.isVirtualClass || {
+ sym.info
+ sym hasFlag notDEFERRED
+ }
+ }
+
+ protected def addOverriddenVirtuals(clazz: Symbol) = {
+ (clazz.allOverriddenSymbols filter wasVirtualClass) ::: List(clazz)
+ }
+ protected def addOverriddenVirtuals(tpe: Type) = tpe match {
+ case TypeRef(pre, sym, args) =>
+ { for (vc <- sym.allOverriddenSymbols if wasVirtualClass(vc))
+ yield typeRef(pre, vc, args) }.reverse ::: List(tpe)
+ }
+
+ protected def mkAbstractType(clazz: Symbol): Symbol = {
val cabstype = clazz.owner.newAbstractType(clazz.pos, clazz.name)
- .setFlag(clazz.flags & absTypeFlagMask)
+ .setFlag(clazz.flags & absTypeFlagMask | SYNTHETIC)
.setAttributes(clazz.attributes)
- scope.enter(cabstype)
-
- cabstype setInfo new LazyType {
- override val typeParams = cloneSymbols(clazz.typeParams, cabstype)
- override def complete(sym: Symbol) {
- def parentTypeRef(tp: Type) =
- devirtualizeMap(tp.substSym(clazz.typeParams, typeParams))
- val parents = (clazz.info.parents map parentTypeRef) :::
- List(appliedType(workerTrait(clazz).typeConstructor, typeParams map (_.tpe)))
- sym.setInfo(
- mkPolyType(typeParams, mkTypeBounds(AllClass.tpe, intersectionType(parents))))
+ atPhase(ownPhase.next) {
+ cabstype setInfo new PolyTypeCompleter(cabstype, clazz) {
+ def getInfo = {
+ val parents1 = clazz.info.parents map {
+ p => devirtualizeMap(p.substSym(clazz.typeParams, typeParams))
+ }
+ val parents2 = addOverriddenVirtuals(clazz) map {
+ c => typeRef(clazz.owner.thisType, c, typeParams map (_.tpe))
+ }
+ mkTypeBounds(AllClass.tpe, intersectionType(parents1 ::: parents2))
+ }
}
}
-
- val wtrait = clazz.owner.newClass(clazz.pos, workerTraitName(clazz.name))
- .setFlag(clazz.flags & traitFlagMask | TRAIT)
- .setAttributes(clazz.attributes)
- scope.enter(wtrait)
-
- // remove OVERRIDE from all workertrait members
- val decls1 = clazz.info.decls.toList
- for (val m <- decls1)
- if (m hasFlag OVERRIDE) m setFlag (notOVERRIDE | notFINAL)
-
- setPolyInfo(
- wtrait, clazz,
- ClassInfoType(List(ObjectClass.tpe, ScalaObjectClass.tpe), newScope(decls1), wtrait))
- wtrait.typeOfThis = intersectionType(List(
- appliedType(cabstype.typeConstructor, wtrait.typeParams map (_.tpe)),
- wtrait.tpe))
}
/* Add a factory symbol for a virtual class
@@ -242,47 +240,59 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
* where
*
* mods3 are the modifiers inherited to factories
- * v2w is maps every virtual class to its workertrait and leaves other types alone.
+ * v2w maps every virtual class to its workertrait and leaves other types alone.
*
* @param clazz The virtual class for which factory is added
* @param owner The owner for which factory is added as a member
* @param scope The scope into which factory is entered
*/
- def addFactory(clazz: Symbol, owner: Symbol, scope: Scope) {
-// println("Adding a factory to " + clazz.owner + "." + clazz)
+ def mkFactory(clazz: Symbol, owner: Symbol): Symbol = {
val pos = if (clazz.owner == owner) clazz.pos else owner.pos
- val factory = owner.newMethod(pos, factoryName(clazz.name))
- .setFlag(clazz.flags & factoryFlagMask)
+ val factory = owner.newMethod(pos, factoryName(clazz))
+ .setFlag(clazz.flags & factoryFlagMask | SYNTHETIC)
.setAttributes(clazz.attributes)
- scope.enter(factory)
- // val cabstype = abstractType(clazz)
-// setPolyInfo(factory, cabstype, MethodType(List(/*todo: handle constructor parameters*/),
-// cabstype.tpe))
+ factory setInfo new PolyTypeCompleter(factory, clazz) {
+ def getInfo = {
+ MethodType(List(/*todo: handle constructor parameters*/),
+ owner.thisType.memberType(abstractType(clazz)))
+ }
+ }
factory
}
- /** The concrete class symbol VC$fix in the factory symbol (@see addFactory)
+ def removeDuplicates(ts: List[Type]): List[Type] = ts match {
+ case List() => List()
+ case t :: ts1 => t :: removeDuplicates(ts1 filter (_.typeSymbol != t.typeSymbol))
+ }
+
+ /** The concrete class symbol VC$fix in the factory symbol (@see mkFactory)
* @param clazz the virtual class
* @param factory the factory which returns an instance of this class
*/
- protected def concreteClassSym(clazz: Symbol, factory: Symbol) = {
- val cclazz = factory.newClass(clazz.pos, concreteClassName(clazz.name))
- .setFlag(FINAL)
+ protected def mkConcreteClass(clazz: Symbol, factory: Symbol) = {
+ val cclazz = factory.newClass(clazz.pos, concreteClassName(clazz))
+ .setFlag(FINAL | SYNTHETIC)
.setAttributes(clazz.attributes)
cclazz setInfo new LazyType {
override def complete(sym: Symbol) {
- def v2w(bc: Symbol): Type = {
- val btp = clazz.info baseType bc
- if (bc.isVirtualClass)
- (btp: @unchecked) match {
- case TypeRef(pre, _, args) =>
- TypeRef(pre, workerTrait(bc), args)
- }
- else btp
- }.substSym(clazz.typeParams, factory.typeParams)
- val parents = clazz.info.baseClasses.reverse map v2w
- sym setInfo ClassInfoType(parents, newScope, cclazz)
+ val parents1 = atPhase(ownPhase) {
+ var superclazz = clazz
+ do {
+ superclazz = superclazz.info.parents.head.typeSymbol
+ } while (wasVirtualClass(superclazz))
+ val bcs = superclazz :: (clazz.info.baseClasses takeWhile (superclazz != )).reverse
+ println("MKConcrete1 "+cclazz+factory.locationString+" "+bcs+" from "+clazz+clazz.locationString)
+ println("MKConcrete2 "+cclazz+factory.locationString+" "+(bcs map factory.owner.thisType.memberType))
+ bcs map factory.owner.thisType.memberType
+ }
+ atPhase(ownPhase.next) {
+ println("MKConcrete3 "+cclazz+" "+parents1)
+ val parents2 =
+ removeDuplicates(parents1.flatMap(addOverriddenVirtuals))
+ .map(_.substSym(clazz.typeParams, factory.typeParams))
+ sym setInfo ClassInfoType(parents2, newScope, cclazz)
+ }
}
}
@@ -293,7 +303,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
*
* 1. Add trees for abstract types (@see devirtualize),
* worker traits (@see devirtualize)
- * and factories (@see addFactory)
+ * and factories (@see mkFactory)
*
* 2. Replace a new VC().init(...) where VC is a virtual class with new$VC(...)
*
@@ -306,22 +316,20 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
class DeVirtualizeTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
// all code is executed at phase ownPhase.next
- /** Add trees for abstract types, worker traits, and factories (@see addFactory)
+ /** Add trees for abstract types, worker traits, and factories (@see mkFactory)
* to template body `stats'
*/
override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
-// println("QUX!")
val stats1 = stats flatMap transformStat map transform
- val newDefs = new ListBuffer[Tree]
- if (currentOwner.isClass && containsVirtuals(currentOwner)) {
- for (m <- classesInNeedOfFactories(currentOwner))
- newDefs += factoryDef(m)
+ val fclasses = atPhase(ownPhase) {
+ if (currentOwner.isClass && containsVirtuals(currentOwner)) classesInNeedOfFactories(currentOwner)
+ else List()
}
- if (newDefs.isEmpty) stats1
- else stats1 ::: newDefs.toList
+ val newDefs = fclasses map factoryDef
+ if (newDefs.isEmpty) stats1 else stats1 ::: newDefs
}
- /** The factory definition for virtual class `clazz' (@see addFactory)
+ /** The factory definition for virtual class `clazz' (@see mkFactory)
* For a virtual class
*
* attrs mods class VC[Ts] <: Ps { decls }
@@ -333,7 +341,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
* class VC$fix extends _VC$trait's[Ts] with VC$trait[Ts] {
* override-bridges
* }
- * new VC$fix
+ * new VC$fix.asInstanceOf[VC[Ts]]
* }
*
* where
@@ -344,16 +352,29 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
* //todo: not sure what happens with abstract override?
*/
def factoryDef(clazz: Symbol): Tree = {
- val factorySym = factory(clazz)
- val cclazzSym = concreteClassSym(clazz, factorySym)
+ val factorySym = factory(clazz, currentOwner)
+ val cclazzSym = mkConcreteClass(clazz, factorySym)
val overrideBridges =
- for (m <- workerTrait(clazz).info.decls.toList if m hasFlag notOVERRIDE)
+ for (m <- clazz.info.decls.toList if m hasFlag notOVERRIDE)
yield overrideBridge(m, cclazzSym)
val cclazzDef = ClassDef(cclazzSym, Modifiers(0), List(List()), List(List()), overrideBridges)
+ val abstpeSym = abstractType(clazz)
val factoryExpr = atPos(factorySym.pos) {
- Block(List(cclazzDef), New(TypeTree(cclazzSym.tpe), List(List())))
+ Block(
+ List(cclazzDef),
+ TypeApply(
+ Select(
+ New(TypeTree(cclazzSym.tpe), List(List())),
+ Any_asInstanceOf),
+ List(
+ TypeTree(
+ currentOwner.thisType.memberType(abstpeSym)
+ .substSym(abstpeSym.typeParams, factorySym.typeParams)))))
+ }
+ println("factory def "+DefDef(factorySym, vparamss => factoryExpr)+" "+phase)
+ localTyper.typed {
+ DefDef(factorySym, vparamss => factoryExpr)
}
- DefDef(factorySym, vparamss => factoryExpr)
}
/** Create an override bridge for method `meth' in concrete class `cclazz'.
@@ -365,55 +386,37 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
val bridge = meth.cloneSymbol(cclazz)
.resetFlag(notOVERRIDE | notFINAL)
val superRef: Tree = Select(Super(cclazz, nme.EMPTY.toTypeName), meth)
- DefDef(bridge, vparamss => (superRef /: vparamss)((fn, vparams) =>
- Apply(fn, vparams map (param => Ident(param) setPos param.pos))))
+ DefDef(bridge, vparamss => gen.mkForwarder(superRef, vparamss))
}
/** Replace definitions of virtual classes by definitions of corresponding
* abstract type and worker traits.
+ * Eliminate constructors of former virtual classes because these are now traits.
*/
- protected def transformStat(tree: Tree): List[Tree] = {
-// println("QUZZ!")
- tree match {
- case ClassDef(mods, name, tparams, templ @ Template(parents, self, body)) if (tree.symbol.isVirtualClass) =>
-// println("QUXX!")
+ protected def transformStat(tree: Tree): List[Tree] = tree match {
+ case ClassDef(mods, name, tparams, templ @ Template(parents, self, body))
+ if (wasVirtualClass(tree.symbol)) =>
val clazz = tree.symbol
-// println("QUXY!")
val absTypeSym = abstractType(clazz)
-// println("QUXY2!")
- val workerTraitSym = workerTrait(clazz)
-// println("QUXY3!")
val abstypeDef = TypeDef(abstractType(clazz))
-// println("QUXY4!")
- val workerTraitDef = ClassDef(
- workerTraitSym,
- Modifiers(0),
- List(List()),
- List(List()),
- body)
-// println("QUXY5!")
- new ChangeOwnerTraverser(clazz, workerTraitSym)(
- new ChangeOwnerTraverser(templ.symbol, workerTraitDef.impl.symbol)(workerTraitDef.impl))
-// println("QUXY6!")
- List(abstypeDef, workerTraitDef) map localTyper.typed
+// println("abstypeDef = "+abstypeDef)
+ List(localTyper.typed(abstypeDef), tree)
+ case DefDef(_, nme.CONSTRUCTOR, _, _, _, _)
+ if (wasVirtualClass(tree.symbol.owner)) =>
+ List()
case _ =>
List(tree)
- }
}
override def transform(tree: Tree): Tree = {
-// println("FOOB!")
tree match {
- // Replace references to VC.this and VC.super where VC is a virtual class
- // with VC$trait.this and VC$trait.super
- case This(_) | Super(_, _) if tree.symbol.isVirtualClass =>
-// println("BARB!")
- tree setSymbol workerTrait(tree.symbol)
-
// Replace a new VC().init() where VC is a virtual class with new$VC
- case Select(New(tpt), name) if (tree.symbol.isConstructor && tree.symbol.owner.isVirtualClass) =>
+ case Select(New(tpt), name) if (tree.symbol.isConstructor && wasVirtualClass(tree.symbol.owner)) =>
val clazz = tpt.tpe.typeSymbol
- val fn = gen.mkAttributedRef(factory(clazz))
+ val fn =
+ Select(
+ gen.mkAttributedQualifier(tpt.tpe.prefix),
+ factory(clazz, clazz.owner).name)
val targs = tpt.tpe.typeArgs
atPos(tree.pos) {
localTyper.typed {
@@ -424,7 +427,6 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
}
case _ =>
-// println("BAZ!")
super.transform(tree)
}
} setType devirtualizeMap(tree.tpe)
diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
index 1c6412419d..adf08cb3bb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
@@ -111,13 +111,8 @@ trait EtaExpansion { self: Analyzer =>
cnt0 - 1
}
val params = formals map (formal =>
- ValDef(Modifiers(SYNTHETIC | PARAM), freshName(tree.pos, cnt), TypeTree()
- .setType(formal), EmptyTree))
- val args = params map (param => Ident(param.name))
- val applyArgs =
- if (isVarArgs(formals)) args.init ::: Typed(args.last, Ident(nme.WILDCARD_STAR.toTypeName)) :: Nil
- else args
- atPos(tree.pos)(Function(params, expand(Apply(tree, applyArgs), restpe)))
+ ValDef(Modifiers(SYNTHETIC | PARAM), freshName(tree.pos, cnt), TypeTree(formal), EmptyTree))
+ atPos(tree.pos)(Function(params, expand(Apply(tree, params map gen.paramToArg), restpe)))
//atPos(tree.pos)(Function(params, expand(Apply(tree, args), restpe)))
case _ =>
tree
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 46b84f4ac1..c8dad51275 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -93,6 +93,9 @@ abstract class RefChecks extends InfoTransform {
val self = clazz.thisType
+ def isAbstractTypeForVirtual(sym: Symbol) = // (part of DEVIRTUALIZE)
+ sym.isAbstractType && sym.hasFlag(SYNTHETIC)
+
def infoString(sym: Symbol) = {
val sym1 = analyzer.underlying(sym)
sym1.toString() +
@@ -173,7 +176,7 @@ abstract class RefChecks extends InfoTransform {
overrideAccessError()
} else if (other hasFlag FINAL) { // (1.2)
overrideError("cannot override final member");
- } else if (!other.isDeferred && !(member hasFlag (OVERRIDE | ABSOVERRIDE))) { // (1.3)
+ } else if (!other.isDeferred && !(member hasFlag (OVERRIDE | ABSOVERRIDE | SYNTHETIC))) { // (1.3), SYNTHETIC because of DEVIRTUALIZE
overrideError("needs `override' modifier");
} else if ((other hasFlag ABSOVERRIDE) && other.isIncompleteIn(clazz) && !(member hasFlag ABSOVERRIDE)) {
overrideError("needs `abstract override' modifiers")
@@ -262,6 +265,7 @@ abstract class RefChecks extends InfoTransform {
})
for (val member <- clazz.tpe.nonPrivateMembers)
if (member.isDeferred && !(clazz hasFlag ABSTRACT) &&
+ !isAbstractTypeForVirtual(member) &&
!((member hasFlag JAVA) && javaErasedOverridingSym(member) != NoSymbol)) {
abstractClassError(
false, infoString(member) + " is not defined" + analyzer.varNotice(member))
@@ -283,7 +287,7 @@ abstract class RefChecks extends InfoTransform {
// (3) is violated but not (2).
def checkNoAbstractDecls(bc: Symbol) {
for (val decl <- bc.info.decls.elements) {
- if (decl.isDeferred) {
+ if (decl.isDeferred && !isAbstractTypeForVirtual(decl)) {
val impl = decl.matchingSymbol(clazz.thisType)
if (impl == NoSymbol || (decl.owner isSubClass impl.owner)) {
abstractClassError(false, "there is a deferred declaration of "+infoString(decl)+
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index ce461952e1..be25970027 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -991,7 +991,10 @@ trait Typers { self: Analyzer =>
else
psym addChild context.owner
}
- if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes) { //@M .typeOfThis seems necessary
+ if (!(selfType <:< parent.tpe.typeOfThis) &&
+ !phase.erasedTypes &&
+ !(context.owner hasFlag SYNTHETIC)) // don't do this check for synthetic concrete classes for virtuals (part of DEVIRTUALIZE)
+ {
//Console.println(context.owner);//DEBUG
//Console.println(context.owner.unsafeTypeParams);//DEBUG
//Console.println(List.fromArray(context.owner.info.closure));//DEBUG
@@ -1628,7 +1631,7 @@ trait Typers { self: Analyzer =>
"I assume that the elements of this array should be passed as individual arguments to the vararg.\n"+
"Therefore I wrap the array in a `: _*', to mark it as a vararg argument.\n"+
"If that's not what you want, compile this file with option -Xno-varargs-conversion.")
- args0 = args.init ::: List(atPos(lastarg.pos) { Typed(lastarg, Ident(nme.WILDCARD_STAR.toTypeName)) })
+ args0 = args.init ::: List(gen.wildcardStar(args.last))
}
}
val suffix =
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index e077329d4c..f68884cddd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -106,7 +106,7 @@ trait Unapplies { self: Analyzer =>
if (tparams.isEmpty) tycon else AppliedTypeTree(tycon, tparams map (x => Ident(x.name)))
}
- private def constrParams(cdef: ClassDef): List[List[ValDef]] = {
+ private def constrParamss(cdef: ClassDef): List[List[ValDef]] = {
val constr = treeInfo.firstConstructor(cdef.impl.body)
(constr: @unchecked) match {
case DefDef(_, _, _, vparamss, _, _) => vparamss map (_ map copyUntyped[ValDef])
@@ -135,8 +135,8 @@ trait Unapplies { self: Analyzer =>
*/
def caseModuleDef(cdef: ClassDef): ModuleDef = atPos(cdef.pos) {
var parents = List(gen.scalaScalaObjectConstr)
- if (!(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParams(cdef).length == 1)
- parents = gen.scalaFunctionConstr(constrParams(cdef).head map (_.tpt),
+ if (!(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParamss(cdef).length == 1)
+ parents = gen.scalaFunctionConstr(constrParamss(cdef).head map (_.tpt),
Ident(cdef.name)) :: parents
ModuleDef(
Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin),
@@ -148,20 +148,15 @@ trait Unapplies { self: Analyzer =>
*/
def caseModuleApplyMeth(cdef: ClassDef): DefDef = {
val tparams = cdef.tparams map copyUntyped[TypeDef]
- def paramToArg(param: ValDef) = {
- val id = Ident(param.name)
- if (treeInfo.isRepeatedParamType(param.tpt)) Typed(id, Ident(nme.WILDCARD_STAR.toTypeName))
- else id
- }
- val cparams = constrParams(cdef)
+ val cparamss = constrParamss(cdef)
atPos(cdef.pos) {
DefDef(
Modifiers(SYNTHETIC | CASE),
nme.apply,
tparams,
- cparams,
+ cparamss,
classType(cdef, tparams),
- New(classType(cdef, tparams), cparams map (_ map paramToArg)))
+ New(classType(cdef, tparams), cparamss map (_ map gen.paramToArg)))
}
}
@@ -170,7 +165,7 @@ trait Unapplies { self: Analyzer =>
def caseModuleUnapplyMeth(cdef: ClassDef): DefDef = {
val tparams = cdef.tparams map copyUntyped[TypeDef]
val unapplyParamName = newTermName("x$0")
- val hasVarArg = constrParams(cdef) match {
+ val hasVarArg = constrParamss(cdef) match {
case (cps @ (_ :: _)) :: _ => treeInfo.isRepeatedParamType(cps.last.tpt)
case _ => false
}
diff --git a/test/pending/run/t0807.scala b/test/pending/run/t0807.scala
new file mode 100644
index 0000000000..e69aa1c71c
--- /dev/null
+++ b/test/pending/run/t0807.scala
@@ -0,0 +1,5 @@
+trait A
+trait B extends A { val x = println("early") }
+object Test extends Application {
+ new B {}
+}