summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2008-06-17 17:44:30 +0000
committerMartin Odersky <odersky@gmail.com>2008-06-17 17:44:30 +0000
commit9077de63b9f5d596b8ea3df5baeac3f87835e7a2 (patch)
tree1fda0912e5bb534366478dc0cba91ea1475ba767
parentd34d51d220bd24e54f38e069250db8b692dc0178 (diff)
downloadscala-9077de63b9f5d596b8ea3df5baeac3f87835e7a2.tar.gz
scala-9077de63b9f5d596b8ea3df5baeac3f87835e7a2.tar.bz2
scala-9077de63b9f5d596b8ea3df5baeac3f87835e7a2.zip
fixed some bugs; disabled devirtualize; desiabl...
fixed some bugs; disabled devirtualize; desiabled bells in JLineReader; fixed Gilles problems with GADTs
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala9
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala20
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/JLineReader.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala16
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala24
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala249
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala48
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala38
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala34
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala34
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala8
-rw-r--r--src/library/scala/List.scala11
13 files changed, 367 insertions, 127 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 7c85d198f3..dd0ca0da10 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -292,11 +292,11 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
object refchecks extends RefChecks {
val global: Global.this.type = Global.this
}
-
+/*
object devirtualize extends DeVirtualize {
val global: Global.this.type = Global.this
}
-
+*/
object liftcode extends LiftCode {
val global: Global.this.type = Global.this
}
@@ -403,9 +403,10 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
analyzer.typerFactory: SubComponent, // consistency check after refchecks would fail.
superAccessors, // add super accessors
pickler // serialize symbol tables
- ) ::: (
+
// Desugar virtual classes
- if (settings.Xexperimental.value) List(devirtualize) else List()
+ // if (false && settings.Xexperimental.value) List(devirtualize) else List()
+
) ::: List(
refchecks // perform reference and override checking, translate nested objects
) ::: (
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index c2e1bd1e7e..96a550179f 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -394,10 +394,15 @@ trait Parsers extends NewScanners with MarkupParsers {
*/
def convertToParam(tree: Tree): ValDef =
atPos(tree.pos) {
+ def removeAsPlaceholder(name: Name) {
+ placeholderParams = placeholderParams filter (_.name != name)
+ }
tree match {
case Ident(name) =>
+ removeAsPlaceholder(name)
ValDef(Modifiers(Flags.PARAM), name, TypeTree(), EmptyTree)
case Typed(tree @ Ident(name), tpe) if (tpe.isType) => // get the ident!
+ removeAsPlaceholder(name)
ValDef(Modifiers(Flags.PARAM), name, tpe, EmptyTree).setPos(tree.pos)
case _ =>
syntaxError(tree.pos, "not a legal formal parameter", false)
@@ -919,7 +924,7 @@ trait Parsers extends NewScanners with MarkupParsers {
}
- /** Expr ::= (Bindings | Id) `=>' Expr
+ /** Expr ::= (Bindings | Id | `_') `=>' Expr
* | Expr1
* ResultExpr ::= (Bindings | Id `:' CompoundType) `=>' Block
* | Expr1
@@ -935,7 +940,7 @@ trait Parsers extends NewScanners with MarkupParsers {
* | PostfixExpr Ascription
* | PostfixExpr match `{' CaseClauses `}'
* Bindings ::= `(' [Binding {`,' Binding}] `)'
- * Binding ::= Id [`:' Type]
+ * Binding ::= (Id | `_') [`:' Type]
* Ascription ::= `:' CompoundType
* | `:' Annotation {Annotation}
* | `:' `_' `*'
@@ -957,7 +962,6 @@ trait Parsers extends NewScanners with MarkupParsers {
var res = inToken match {
case IF =>
val pos = inSkipToken
-
val cond = surround(LPAREN,RPAREN)(expr(),Literal(true))
newLinesOpt()
val thenp = expr()
@@ -2162,10 +2166,7 @@ trait Parsers extends NewScanners with MarkupParsers {
if (mods.hasFlag(Flags.TRAIT)) (Modifiers(Flags.TRAIT), List())
else (accessModifierOpt(), paramClauses(name, implicitClassViews, mods.hasFlag(Flags.CASE)))
val thistpe = requiresTypeOpt()
- var mods1 = mods
- if (settings.Xexperimental.value) {
- if (inToken == SUBTYPE) mods1 = mods | Flags.DEFERRED
- }
+ var mods1 = if (inToken == SUBTYPE) mods | Flags.DEFERRED else mods
var template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss)
if (!thistpe.isEmpty) {
if (template.self.isEmpty) {
@@ -2188,8 +2189,7 @@ trait Parsers extends NewScanners with MarkupParsers {
val name = ident().toTermName
if (name != nme.ERROR) pos = namePos
atPos(pos) {
- var mods1 = mods
- if (inToken == SUBTYPE) mods1 = mods | Flags.DEFERRED
+ val mods1 = if (inToken == SUBTYPE) mods | Flags.DEFERRED else mods
val template = templateOpt(mods1, name, NoMods, List())
ModuleDef(mods1, name, template)
}
@@ -2254,7 +2254,7 @@ trait Parsers extends NewScanners with MarkupParsers {
def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]]): Template = {
val pos = inCurrentPos;
val (parents0, argss, self, body) =
- if (inToken == EXTENDS || inToken == SUBTYPE) {
+ if (inToken == EXTENDS || settings.Xexperimental.value && (mods hasFlag TRAIT) && inToken == SUBTYPE) {
inNextToken
template(mods hasFlag Flags.TRAIT)
} else {
diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
index 8d687d48af..b3647178e3 100644
--- a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
@@ -19,6 +19,7 @@ class JLineReader extends InteractiveReader {
}
val r = new jline.ConsoleReader()
r.setHistory(history)
+ r.setBellEnabled(false)
r
}
def readLine(prompt: String) = consoleReader.readLine(prompt)
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index d72a484a35..c673dc30bb 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -275,8 +275,8 @@ trait Symbols {
def isVirtualClass =
hasFlag(DEFERRED) && isClass
- def isVirtualSubClass =
- info.baseClasses exists (_.isVirtualClass)
+ def isVirtualTrait =
+ hasFlag(DEFERRED) && isTrait
/** Is this symbol a public */
final def isPublic: Boolean =
@@ -999,14 +999,16 @@ trait Symbols {
if s != NoSymbol } yield s
else List()
- /** The virtual classes overridden by this virtual class (including `clazz' itself)
+ /** The virtual classes overridden by this virtual class (excluding `clazz' itself)
* Classes appear in linearization order (with superclasses before subclasses)
*/
final def overriddenVirtuals: List[Symbol] =
- this.owner.info.baseClasses
- .map(_.info.decl(name))
- .filter(_.isVirtualClass)
- .reverse
+ if (isVirtualTrait && hasFlag(OVERRIDE))
+ this.owner.info.baseClasses.tail
+ .map(_.info.decl(name))
+ .filter(_.isVirtualTrait)
+ .reverse
+ else List()
/** The symbol accessed by a super in the definition of this symbol when
* seen from class `base'. This symbol is always concrete.
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 69bee83f09..b1acd9f1d0 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1911,6 +1911,7 @@ A type's typeSymbol should never be inspected directly.
}
def refinementOfClass(clazz: Symbol, parents: List[Type], decls: Scope) = {
+ assert(!parents.isEmpty)
class RefinementOfClass extends RefinedType(parents, decls) {
override def typeSymbol: Symbol = clazz
}
@@ -3934,6 +3935,12 @@ A type's typeSymbol should never be inspected directly.
/** Eliminate from list of types all elements which are a subtype
* of some other element of the list. */
private def elimSub(ts: List[Type]): List[Type] = {
+ def elimAnonymousClass(t: Type) = t match {
+ case TypeRef(pre, clazz, List()) if clazz.isAnonymousClass =>
+ clazz.classBound.asSeenFrom(pre, clazz.owner)
+ case _ =>
+ t
+ }
def elimSub0(ts: List[Type]): List[Type] = ts match {
case List() => List()
case t :: ts1 =>
@@ -3943,21 +3950,26 @@ A type's typeSymbol should never be inspected directly.
val ts0 = elimSub0(ts)
if (ts0.length <= 1) ts0
else {
- val ts1 = List.mapConserve(ts0)(_.underlying)
+ val ts1 = List.mapConserve(ts0)(t => elimAnonymousClass(t.underlying))
if (ts1 eq ts0) ts0
else elimSub(ts1)
}
}
- private def stripExistentials(ts: List[Type]): (List[Type], List[Symbol]) = {
+ private def stripExistentialsAndTypeVars(ts: List[Type]): (List[Type], List[Symbol]) = {
val quantified = ts flatMap {
case ExistentialType(qs, _) => qs
case t => List()
}
- val strippedTypes = List.mapConserve(ts) {
- case ExistentialType(_, res) => res
+ def stripType(tp: Type) = tp match {
+ case ExistentialType(_, res) =>
+ res
+ case TypeVar(_, constr) =>
+ if ((constr.inst ne null) && (constr.inst ne NoType)) constr.inst
+ else throw new Error("trying to do lub/glb of typevar "+tp)
case t => t
}
+ val strippedTypes = List.mapConserve(ts)(stripType)
(strippedTypes, quantified)
}
@@ -3979,7 +3991,7 @@ A type's typeSymbol should never be inspected directly.
assert(false)
mkTypeBounds(glb(ts map (_.bounds.lo), depth), lub(ts map (_.bounds.hi), depth))
case ts0 =>
- val (ts, tparams) = stripExistentials(ts0)
+ val (ts, tparams) = stripExistentialsAndTypeVars(ts0)
val closures: List[Array[Type]] = ts map (_.closure)
val lubBaseTypes: Array[Type] = lubArray(closures, depth)
val lubParents = spanningTypes(List.fromArray(lubBaseTypes))
@@ -4069,7 +4081,7 @@ A type's typeSymbol should never be inspected directly.
mkTypeBounds(lub(ts map (_.bounds.lo), depth), glb(ts map (_.bounds.hi), depth))
case ts0 =>
try {
- val (ts, tparams) = stripExistentials(ts0)
+ val (ts, tparams) = stripExistentialsAndTypeVars(ts0)
val glbOwner = commonOwner(ts)
def refinedToParents(t: Type): List[Type] = t match {
case RefinedType(ps, _) => ps flatMap refinedToParents
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 6a75d98b63..30f0b71545 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -82,7 +82,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
if (sym == ArrayClass)
if (isGeneric(tp)) erasedTypeRef(BoxedArrayClass)
else typeRef(apply(pre), sym, args map this)
- else if (sym == AnyClass || sym == AnyValClass) erasedTypeRef(ObjectClass)
+ else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass) erasedTypeRef(ObjectClass)
else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass)
else if (sym.isClass)
typeRef(apply(if (sym.owner.isClass) sym.owner.tpe else pre), sym, List())
diff --git a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
index 75994cf72b..0233ba66ca 100644
--- a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala
@@ -100,9 +100,20 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
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)
+ decls = newScope
+
+ // add virtual fields for all primary constructor parameters
+ for (row <- paramTypesAndIndices(clazz.primaryConstructor.tpe, 0))
+ for ((pt, i) <- row)
+ enter(mkParamField(clazz, i, devirtualizeMap(pt)))
+
+ // remove OVERRIDE from all workertrait members, except if they override a member in Object
+ for (m <- decls0.toList) {
+ if (!m.isConstructor) {
+ if ((m hasFlag OVERRIDE) && m.overriddenSymbol(ObjectClass) == NoSymbol)
+ m setFlag (notOVERRIDE | notFINAL)
+ enter(m)
+ }
}
if (clazz.thisSym == clazz) clazz.typeOfThis = clazz.thisType
// ... to give a hook on which we can hang selftype transformers
@@ -164,6 +175,19 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
fsym
}
+ /** The name of the field representing a constructor parameter of a virtual class */
+ protected def paramFieldName(clazz: Symbol, index: Int) = atPhase(ownPhase) {
+ clazz.expandedName(newTermName("param$"+index))
+ }
+
+ /** The name of the field representing a constructor parameter of a virtual class */
+ protected def fixParamName(index: Int) = newTermName("fix$"+index)
+
+ /** The field representing a constructor parameter of a virtual class */
+ protected def paramField(clazz: Symbol, index: Int) = atPhase(ownPhase.next) {
+ clazz.info.decl(paramFieldName(clazz, index))
+ }
+
/** The flags that an abstract type can inherit from its virtual class */
protected val absTypeFlagMask = AccessFlags | DEFERRED
@@ -206,6 +230,15 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
yield typeRef(pre, vc, args) }.reverse ::: List(tpe)
}
+ protected def mkParamField(clazz: Symbol, index: Int, tpe: Type): Symbol = {
+ val param = clazz.newMethod(clazz.pos, paramFieldName(clazz, index))
+ .setFlag(PROTECTED | LOCAL | DEFERRED | EXPANDEDNAME | SYNTHETIC | STABLE)
+ atPhase(ownPhase.next) {
+ param.setInfo(PolyType(List(), tpe))
+ }
+ param
+ }
+
protected def mkAbstractType(clazz: Symbol): Symbol = {
val cabstype = clazz.owner.newAbstractType(clazz.pos, clazz.name)
.setFlag(clazz.flags & absTypeFlagMask | SYNTHETIC)
@@ -225,6 +258,15 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
}
}
+ protected def paramTypesAndIndices(tpe: Type, start: Int): List[List[(Type, Int)]] = tpe match {
+ case PolyType(_, restpe) => paramTypesAndIndices(restpe, start)
+ case MethodType(formals, restpe) =>
+ val end = start + formals.length
+ (formals zip List.range(start, end)) :: paramTypesAndIndices(restpe, end)
+ case _ =>
+ List()
+ }
+
/* Add a factory symbol for a virtual class
*
* attrs mods class VC[Ts] <: Ps { decls }
@@ -252,10 +294,13 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
.setFlag(clazz.flags & factoryFlagMask | SYNTHETIC)
.setAttributes(clazz.attributes)
factory setInfo new PolyTypeCompleter(factory, clazz) {
- def getInfo = {
- MethodType(List(/*todo: handle constructor parameters*/),
- owner.thisType.memberType(abstractType(clazz)))
+ private def copyType(tpe: Type): Type = tpe match {
+ case MethodType(formals, restpe) => MethodType(formals, copyType(restpe))
+ case PolyType(List(), restpe) => PolyType(List(), copyType(restpe))
+ case PolyType(_, _) => throw new Error("bad case: "+tpe)
+ case _ => owner.thisType.memberType(abstractType(clazz))
}
+ def getInfo = copyType(clazz.primaryConstructor.tpe)
}
factory
}
@@ -287,7 +332,6 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
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))
@@ -320,7 +364,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
* to template body `stats'
*/
override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
- val stats1 = stats flatMap transformStat map transform
+ val stats1 = stats flatMap transformStat
val fclasses = atPhase(ownPhase) {
if (currentOwner.isClass && containsVirtuals(currentOwner)) classesInNeedOfFactories(currentOwner)
else List()
@@ -329,6 +373,41 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
if (newDefs.isEmpty) stats1 else stats1 ::: newDefs
}
+ def fixClassDef(clazz: Symbol, factory: Symbol): Tree = {
+ val cclazz = mkConcreteClass(clazz, factory)
+ val overrideBridges =
+ for (m <- clazz.info.decls.toList if m hasFlag notOVERRIDE)
+ yield overrideBridge(m, cclazz)
+
+ val vparamss: List[List[ValDef]] = atPhase(ownPhase) {
+ paramTypesAndIndices(clazz.primaryConstructor.tpe, 0) map {
+ _ map {
+ case (pt, i) =>
+ atPos(factory.pos) {
+ ValDef(Modifiers(PARAMACCESSOR | PRIVATE | LOCAL), fixParamName(i),
+ TypeTree(devirtualizeMap(pt)), EmptyTree)
+ }
+ }
+ }
+ }
+ val pfields: List[DefDef] = atPhase(ownPhase) {
+ paramTypesAndIndices(clazz.primaryConstructor.tpe, 0) flatMap {
+ _ map {
+ case (pt, i) =>
+ val pfield = cclazz.newMethod(cclazz.pos, paramFieldName(clazz, i))
+ .setFlag(PROTECTED | LOCAL | EXPANDEDNAME | SYNTHETIC | STABLE)
+ .setInfo(PolyType(List(), pt))
+ cclazz.info.decls enter pfield
+ atPos(factory.pos) {
+ DefDef(pfield, vparamss => Ident(fixParamName(i)))
+ }
+ }
+ }
+ }
+ ClassDef(cclazz, Modifiers(0), vparamss, List(List()), pfields ::: overrideBridges)
+ }
+
+
/** The factory definition for virtual class `clazz' (@see mkFactory)
* For a virtual class
*
@@ -353,27 +432,25 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
*/
def factoryDef(clazz: Symbol): Tree = {
val factorySym = factory(clazz, currentOwner)
- val cclazzSym = mkConcreteClass(clazz, factorySym)
- val overrideBridges =
- 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 cclazzDef = fixClassDef(clazz, factorySym)
+ println("Concrete: "+cclazzDef)
val abstpeSym = abstractType(clazz)
- val factoryExpr = atPos(factorySym.pos) {
- Block(
- List(cclazzDef),
- TypeApply(
- Select(
- New(TypeTree(cclazzSym.tpe), List(List())),
- Any_asInstanceOf),
+ localTyper.typed {
+ atPos(factorySym.pos) {
+ DefDef(factorySym, vparamss =>
+ Block(
+ List(cclazzDef),
+ TypeApply(
+ Select(
+ gen.mkForwarder(
+ Select(New(TypeTree(cclazzDef.symbol.tpe)), nme.CONSTRUCTOR),
+ vparamss),
+ 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)
+ .substSym(abstpeSym.typeParams, factorySym.typeParams))))))
+ }
}
}
@@ -385,6 +462,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
def overrideBridge(meth: Symbol, cclazz: Symbol) = atPos(meth.pos) {
val bridge = meth.cloneSymbol(cclazz)
.resetFlag(notOVERRIDE | notFINAL)
+ cclazz.info.decls.enter(bridge)
val superRef: Tree = Select(Super(cclazz, nme.EMPTY.toTypeName), meth)
DefDef(bridge, vparamss => gen.mkForwarder(superRef, vparamss))
}
@@ -393,44 +471,85 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
* abstract type and worker traits.
* Eliminate constructors of former virtual classes because these are now traits.
*/
- 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
- val absTypeSym = abstractType(clazz)
- val abstypeDef = TypeDef(abstractType(clazz))
-// println("abstypeDef = "+abstypeDef)
- List(localTyper.typed(abstypeDef), tree)
- case DefDef(_, nme.CONSTRUCTOR, _, _, _, _)
- if (wasVirtualClass(tree.symbol.owner)) =>
- List()
- case _ =>
- List(tree)
+ protected def transformStat(tree: Tree): List[Tree] = {
+ val sym = tree.symbol
+ tree match {
+ case ClassDef(mods, name, tparams, templ)
+ if (wasVirtualClass(sym)) =>
+ val clazz = sym
+ val absTypeSym = abstractType(clazz)
+ val abstypeDef = TypeDef(absTypeSym)
+ List(localTyper.typed(abstypeDef), transform(tree))
+ case DefDef(_, nme.CONSTRUCTOR, _, _, _, _)
+ if (wasVirtualClass(sym.owner)) =>
+ if (atPhase(ownPhase)(sym != sym.owner.primaryConstructor))
+ unit.error(tree.pos, "virtual classes cannot have auxiliary constructors")
+ List()
+ case _ =>
+ List(transform(tree))
+ }
}
- override def transform(tree: Tree): Tree = {
+ override def transform(tree0: Tree): Tree = {
+ val tree = super.transform(tree0)
+ val sym = tree.symbol
tree match {
// Replace a new VC().init() where VC is a virtual class with new$VC
- case Select(New(tpt), name) if (tree.symbol.isConstructor && wasVirtualClass(tree.symbol.owner)) =>
- val clazz = tpt.tpe.typeSymbol
+ case Apply(Select(New(tpt), name), args) if (sym.isConstructor && wasVirtualClass(sym.owner)) =>
+ val clazz = sym.owner
val fn =
Select(
gen.mkAttributedQualifier(tpt.tpe.prefix),
factory(clazz, clazz.owner).name)
+ println("fac "+factory(clazz, clazz.owner).tpe)
val targs = tpt.tpe.typeArgs
atPos(tree.pos) {
localTyper.typed {
- Apply(
- if (targs.isEmpty) fn else TypeApply(fn, targs map TypeTree),
- List())
+ val res =
+ Apply(if (targs.isEmpty) fn else TypeApply(fn, targs map TypeTree), args)
+ println("typing "+res+" from "+args)
+ res
+ }
}
- }
+ case Template(parents, self, body) if (wasVirtualClass(sym.owner)) =>
+ // add param field accessors
+ val paramFieldAccessors = new ListBuffer[Tree]
+ val paramFields = new ListBuffer[Tree]
+ val presupers = new ListBuffer[Tree]
+ val others = new ListBuffer[Tree]
+ var paramFieldCount = 0
+ for (stat <- body) {
+ if (stat.symbol != null && (stat.symbol hasFlag PARAMACCESSOR))
+ stat match {
+ case pacc @ ValDef(mods, name, tpt, rhs) =>
+ pacc.symbol resetFlag PARAMACCESSOR setFlag PRESUPER
+ val pfield = paramField(sym.owner, paramFieldCount)
+ paramFieldCount += 1
+ pfield setPos pacc.pos
+ paramFields += localTyper.typed(DefDef(pfield, vparamss => EmptyTree))
+ val pfieldRef = localTyper.typed {
+ atPos(pacc.pos) {
+ Select(This(sym.owner), pfield)
+ }
+ }
+ paramFieldAccessors += copy.ValDef(pacc, mods, name, tpt, pfieldRef)
+ case _ =>
+ stat.symbol resetFlag PARAMACCESSOR // ??? can we do this
+ others += stat
+ }
+ else
+ (if (stat.symbol != null && (stat.symbol hasFlag PRESUPER)) presupers else others) += stat
+ }
+ copy.Template(tree, parents, self,
+ paramFieldAccessors.toList :::
+ presupers.toList :::
+ paramFields.toList :::
+ others.toList)
case _ =>
- super.transform(tree)
+ tree setType atPhase(ownPhase)(devirtualizeMap(tree.tpe))
}
- } setType devirtualizeMap(tree.tpe)
-
+ }
override def transformUnit(unit: CompilationUnit) = atPhase(ownPhase.next) {
super.transformUnit(unit)
}
@@ -441,19 +560,43 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers {
/*
class A {
- class C[X, Y](x: X) <: { var y = x ; def f(z: Y): X }
- class D[Y](z) extends C[Int, Y](f(z)) { override def f(z:Int) = 3 }
+ trait C[X, Y] <: {
+ var x: X
+ def f(y: Y): X = { println("A.T"); x }
+ }
+ class D[X](xp: X) extends C[X, Int] {
+ var x: X = xp
+ override def f(y: Int) = { println(y); super.f(y) }
+ }
}
class B extends A {
- class C[X, Y](x: X) <: { def g = 2 }
+ override trait C[X, Y] <: {
+ override def f(y: Y): X = { println("B.T"); super.f(y) }
+ def g: X = x
+ }
+ }
+ object Test extends B {
+ val c = new D[String]("OK")
+ println(c.g)
+ println(c.f(42))
}
maps to:
class A {
- type C[X, Y] <: CT[X, Y]
+ type C[X, Y] <: C$trait[X, Y]
+
+ trait C$trait[X, Y] { this: C with C$trait =>
+ var x: X
+ def f(y: Y): X = { println("A.T"); x }
+ }
+
+ class D[X](xp: X) extends C[X, Int] {
+ var x: X = xp
+ override def f(y: Int) = { println(y); super.f(y) }
+ }
- trait CT[X, Y] { self: C => protected[this] val x: Int; val y = x; def f(z:Int) = z + 1 }
+ protected[this] val x: Int; val y = x; def f(z:Int) = z + 1 }
type D <: C with DT
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 5887938753..1cec94d0d0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -757,6 +757,9 @@ trait Infer {
kindErrors.toList.mkString("\n", ", ", ""))
else if (!isWithinBounds(pre, owner, tparams, targs)) {
if (!(targs exists (_.isErroneous)) && !(tparams exists (_.isErroneous))) {
+ //val bounds = instantiatedBounds(pre, owner, tparams, targs)//DEBUG
+ //println("bounds = "+bounds+", targs = "+targs+", targclasses = "+(targs map (_.getClass))+", parents = "+(targs map (_.parents)))
+ //println(List.map2(bounds, targs)((bound, targ) => bound containsType targ))
error(pos,
prefix + "type arguments " + targs.mkString("[", ",", "]") +
" do not conform to " + tparams.head.owner + "'s type parameter bounds " +
@@ -1041,7 +1044,23 @@ trait Infer {
} else { if (settings.debug.value) Console.println("not fuly defined: " + pt); instError }
}
- def instantiateTypeVar(tvar: TypeVar) = {
+ def instBounds(tvar: TypeVar): (Type, Type) = {
+ val tparam = tvar.origin.typeSymbol
+ val instType = toOrigin(tvar.constr.inst)
+ val (loBounds, hiBounds) =
+ if (instType != NoType && isFullyDefined(instType)) (List(instType), List(instType))
+ else (tvar.constr.lobounds, tvar.constr.hibounds)
+ val lo = lub(tparam.info.bounds.lo :: loBounds map toOrigin)
+ val hi = glb(tparam.info.bounds.hi :: hiBounds map toOrigin)
+ (lo, hi)
+ }
+
+ def isInstantiatable(tvar: TypeVar) = {
+ val (lo, hi) = instBounds(tvar)
+ lo <:< hi
+ }
+
+ def instantiateTypeVar(tvar: TypeVar) {
val tparam = tvar.origin.typeSymbol
if (false &&
tvar.constr.inst != NoType &&
@@ -1052,20 +1071,17 @@ trait Infer {
tparam resetFlag DEFERRED
if (settings.debug.value) log("new alias of " + tparam + " = " + tparam.info)
} else {
- val instType = toOrigin(tvar.constr.inst)
- val (loBounds, hiBounds) =
- if (instType != NoType && isFullyDefined(instType)) (List(instType), List(instType))
- else (tvar.constr.lobounds, tvar.constr.hibounds)
- val lo = lub(tparam.info.bounds.lo :: loBounds map toOrigin)
- val hi = glb(tparam.info.bounds.hi :: hiBounds map toOrigin)
- if (!(lo <:< hi)) {
- if (settings.debug.value) log("inconsistent: "+tparam+" "+lo+" "+hi)
- } else if (!((lo <:< tparam.info.bounds.lo) && (tparam.info.bounds.hi <:< hi))) {
- context.nextEnclosing(_.tree.isInstanceOf[CaseDef]).pushTypeBounds(tparam)
- tparam setInfo mkTypeBounds(lo, hi)
- if (settings.debug.value) log("new bounds of " + tparam + " = " + tparam.info)
+ val (lo, hi) = instBounds(tvar)
+ if (lo <:< hi) {
+ if (!((lo <:< tparam.info.bounds.lo) && (tparam.info.bounds.hi <:< hi))) {
+ context.nextEnclosing(_.tree.isInstanceOf[CaseDef]).pushTypeBounds(tparam)
+ tparam setInfo mkTypeBounds(lo, hi)
+ if (settings.debug.value) log("new bounds of " + tparam + " = " + tparam.info)
+ } else {
+ if (settings.debug.value) log("redundant: "+tparam+" "+tparam.info+"/"+lo+" "+hi)
+ }
} else {
- if (settings.debug.value) log("redundant: "+tparam+" "+tparam.info+"/"+lo+" "+hi)
+ if (settings.debug.value) log("inconsistent: "+tparam+" "+lo+" "+hi)
}
}
}
@@ -1144,14 +1160,14 @@ trait Infer {
if (settings.debug.value) log("free type params (1) = " + tpparams)
var tvars = tpparams map freshVar
var tp = pattp.instantiateTypeParams(tpparams, tvars)
- if (!(tp <:< pt)) {
+ if (!((tp <:< pt) && (tvars forall isInstantiatable))) {
tvars = tpparams map freshVar
tp = pattp.instantiateTypeParams(tpparams, tvars)
val ptparams = freeTypeParamsOfTerms.collect(pt)
if (settings.debug.value) log("free type params (2) = " + ptparams)
val ptvars = ptparams map freshVar
val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
- if (!isPopulated(tp, pt1)) {
+ if (!(isPopulated(tp, pt1) && (tvars forall isInstantiatable) && (ptvars forall isInstantiatable))) {
error(pos, "pattern type is incompatible with expected type"+foundReqMsg(pattp, pt))
return pattp
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 05521a0865..fd5477397b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -347,7 +347,7 @@ trait Namers { self: Analyzer =>
setInfo(setter)(namerOf(setter).setterTypeCompleter(tree))
}
tree.symbol =
- if ((mods.flags & DEFERRED) == 0) { // not deferred
+ if ((mods.flags & DEFERRED) == 0) {
var vsym =
if (!context.owner.isClass) {
assert((mods.flags & LAZY) != 0) // if not a field, it has to be a lazy val
@@ -534,14 +534,36 @@ trait Namers { self: Analyzer =>
val decls = newClassScope(clazz)
val templateNamer = newNamer(context.make(templ, clazz, decls))
.enterSyms(templ.body)
- // make subclasses of virtual classes virtual as well
- if (parents exists (_.typeSymbol.isVirtualClass))
- clazz setFlag DEFERRED
- // add overridden virtuals to parents
- if (clazz.isVirtualClass) {
- parents = parents ::: ((clazz.overriddenVirtuals.filter(_ != clazz)) map (
- sym => TypeRef(sym.owner.thisType, sym, clazz.typeParams map (_.tpe))))
+
+ /* add overridden virtuals to parents
+ val overridden = clazz.overriddenVirtuals
+ if (!overridden.isEmpty)
+ parents = parents ::: ( overridden map (
+ sym => TypeRef(clazz.owner.thisType, sym, clazz.typeParams map (_.tpe))))
+ println("Parents of "+clazz+":"+parents)
+
+ // check that virtual classses are only defined as members of templates
+ if (clazz.isVirtualClass && !clazz.owner.isClass)
+ context.error(
+ clazz.pos,
+ "virtual traits and their subclasses must be defined as members of some other class")
+
+ // make subclasses of virtual classes virtual as well; check that
+ // they are defined in same scope.
+ val virtualParents = parents map (_.typeSymbol) filter (_.isVirtualClass)
+ virtualParents find {
+ vp => !(clazz.owner.isClass && (clazz.owner isSubClass vp.owner))
+ } match {
+ case Some(vp) =>
+ context.error(
+ clazz.pos,
+ "subclass of virtual "+vp+
+ " needs to be defined at same level,\nas member of "+vp.owner)
+ case None =>
+ if (!virtualParents.isEmpty) clazz setFlag DEFERRED // make it virtual
}
+ */
+
// add apply and unapply methods to companion objects of case classes,
// unless they exist already
Namers.this.caseClassOfModuleClass get clazz match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 5485c4ccc4..0e2227e3ed 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -62,6 +62,7 @@ abstract class RefChecks extends InfoTransform {
var localTyper: analyzer.Typer = typer;
var currentApplication: Tree = EmptyTree
+ var inPattern: Boolean = false
// Override checking ------------------------------------------------------------
@@ -768,17 +769,18 @@ abstract class RefChecks extends InfoTransform {
checkAllOverrides(currentOwner)
case TypeTree() =>
- new TypeTraverser {
- def traverse(tp: Type): TypeTraverser = tp match {
- case TypeRef(pre, sym, args) =>
- checkDeprecated(sym, tree.pos)
- if (!tp.isHigherKinded) checkBounds(pre, sym.owner, sym.typeParams, args)
- this
- case _ =>
- this
- }
- } traverse tree.tpe
-
+ if (!inPattern) {
+ new TypeTraverser {
+ def traverse(tp: Type): TypeTraverser = tp match {
+ case TypeRef(pre, sym, args) =>
+ checkDeprecated(sym, tree.pos)
+ if (!tp.isHigherKinded) checkBounds(pre, sym.owner, sym.typeParams, args)
+ this
+ case _ =>
+ this
+ }
+ } traverse tree.tpe
+ }
case TypeApply(fn, args) =>
checkBounds(NoPrefix, NoSymbol, fn.tpe.typeParams, args map (_.tpe))
if (sym.isSourceMethod && sym.hasFlag(CASE)) result = toConstructor(tree.pos, tree.tpe)
@@ -842,7 +844,15 @@ abstract class RefChecks extends InfoTransform {
}
case _ =>
}
- result = super.transform(result)
+ result = result match {
+ case CaseDef(pat, guard, body) =>
+ inPattern = true
+ val pat1 = transform(pat)
+ inPattern = false
+ copy.CaseDef(tree, pat1, transform(guard), transform(body))
+ case _ =>
+ super.transform(result)
+ }
result match {
case ClassDef(_, _, _, _)
| TypeDef(_, _, _, _) =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 51fa7f9b00..fc9585cfa1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -120,7 +120,28 @@ trait SyntheticMethods { self: Analyzer =>
Apply(gen.mkAttributedRef(target), This(clazz) :: (vparamss.head map Ident))))
}
- /** The equality method for case classes and modules:
+ def equalsSym =
+ syntheticMethod(nme.equals_, 0, MethodType(List(AnyClass.tpe), BooleanClass.tpe))
+
+ /** The equality method for case modules:
+ * def equals(that: Any) = this eq that
+ */
+ def equalsModuleMethod: Tree = {
+ val method = equalsSym
+ val methodDef =
+ DefDef(method, vparamss =>
+ Apply(
+ Select(This(clazz), Object_eq),
+ List(
+ TypeApply(
+ Select(
+ Ident(vparamss.head.head),
+ Any_asInstanceOf),
+ List(TypeTree(AnyRefClass.tpe))))))
+ localTyper.typed(methodDef)
+ }
+
+ /** The equality method for case classes:
* def equals(that: Any) =
* that.isInstanceOf[AnyRef] &&
* ((this eq that.asInstanceOf[AnyRef]) ||
@@ -129,9 +150,8 @@ trait SyntheticMethods { self: Analyzer =>
* case _ => false
* }))
*/
- def equalsMethod: Tree = {
- val method = syntheticMethod(
- nme.equals_, 0, MethodType(List(AnyClass.tpe), BooleanClass.tpe))
+ def equalsClassMethod: Tree = {
+ val method = equalsSym
val methodDef =
DefDef(
method,
@@ -278,10 +298,14 @@ trait SyntheticMethods { self: Analyzer =>
}
if (clazz.isModuleClass) {
if (!hasOverridingImplementation(Object_toString)) ts += moduleToStringMethod
+ // if there's a synthetic method in a parent case class, override its equality
+ // with eq (see #883)
+ val otherEquals = clazz.info.nonPrivateMember(Object_equals.name)
+ if (otherEquals.owner != clazz && (otherEquals hasFlag SYNTHETICMETH)) ts += equalsModuleMethod
} else {
if (!hasOverridingImplementation(Object_hashCode)) ts += forwardingMethod(nme.hashCode_)
if (!hasOverridingImplementation(Object_toString)) ts += forwardingMethod(nme.toString_)
- if (!hasOverridingImplementation(Object_equals)) ts += equalsMethod
+ if (!hasOverridingImplementation(Object_equals)) ts += equalsClassMethod
}
if (!hasOverridingImplementation(Product_productPrefix)) ts += productPrefixMethod
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 28025a6d22..40db3dd4a8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -148,11 +148,10 @@ trait Typers { self: Analyzer =>
import context0.unit
val infer = new Inferencer(context0) {
- override def isCoercible(tp: Type, pt: Type): Boolean = (
+ override def isCoercible(tp: Type, pt: Type): Boolean =
tp.isError || pt.isError ||
context0.implicitsEnabled && // this condition prevents chains of views
inferView(NoPosition, tp, pt, false) != EmptyTree
- )
}
/**
@@ -1470,7 +1469,10 @@ trait Typers { self: Analyzer =>
fun match {
case etaExpansion(vparams, fn, args) if !codeExpected =>
silent(_.typed(fn, funMode(mode), pt)) match {
- case fn1: Tree =>
+ case fn1: Tree if context.undetparams.isEmpty =>
+ // if context,undetparams is not empty, the function was polymorphic,
+ // so we need the missing arguments to infer its type. See #871
+ //println("typing eta "+fun+":"+fn1.tpe+"/"+context.undetparams)
val ftpe = normalize(fn1.tpe) baseType FunctionClass(fun.vparams.length)
if (isFunctionType(ftpe) && isFullyDefined(ftpe))
return typedFunction(fun, mode, ftpe)
diff --git a/src/library/scala/List.scala b/src/library/scala/List.scala
index f6f10161d6..23667f68d7 100644
--- a/src/library/scala/List.scala
+++ b/src/library/scala/List.scala
@@ -1276,8 +1276,15 @@ sealed abstract class List[+A] extends Seq[A] {
* @return this list without the elements of the given object
* <code>x</code>.
*/
- def - [B >: A](x: B): List[B] =
- this -- List(x)
+ def - [B >: A](x: B): List[B] = {
+ val b = new ListBuffer[B]
+ var these = this
+ while (!these.isEmpty) {
+ if (these.head != x) b += these.head
+ these = these.tail
+ }
+ b.toList
+ }
/** Concatenate the elements of this list. The elements of this list
* should be a <code>Iterables</code>.