From 9077de63b9f5d596b8ea3df5baeac3f87835e7a2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 17 Jun 2008 17:44:30 +0000 Subject: fixed some bugs; disabled devirtualize; desiabl... fixed some bugs; disabled devirtualize; desiabled bells in JLineReader; fixed Gilles problems with GADTs --- src/compiler/scala/tools/nsc/Global.scala | 9 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 20 +- .../scala/tools/nsc/interpreter/JLineReader.scala | 1 + src/compiler/scala/tools/nsc/symtab/Symbols.scala | 16 +- src/compiler/scala/tools/nsc/symtab/Types.scala | 24 +- .../scala/tools/nsc/transform/Erasure.scala | 2 +- .../scala/tools/nsc/typechecker/DeVirtualize.scala | 249 ++++++++++++++++----- .../scala/tools/nsc/typechecker/Infer.scala | 48 ++-- .../scala/tools/nsc/typechecker/Namers.scala | 38 +++- .../scala/tools/nsc/typechecker/RefChecks.scala | 34 ++- .../tools/nsc/typechecker/SyntheticMethods.scala | 34 ++- .../scala/tools/nsc/typechecker/Typers.scala | 8 +- src/library/scala/List.scala | 11 +- 13 files changed, 367 insertions(+), 127 deletions(-) (limited to 'src') 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 * x. */ - 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 Iterables. -- cgit v1.2.3