diff options
author | Martin Odersky <odersky@gmail.com> | 2008-01-17 16:37:27 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2008-01-17 16:37:27 +0000 |
commit | 76c06b4661b70e934530a0debad34a5766ee43e9 (patch) | |
tree | 4abb85699a2d663681a9ca31fb7ccff45b80746f /src | |
parent | e5ca1a3906ae29c1d6db5de333932bbfc189cedc (diff) | |
download | scala-76c06b4661b70e934530a0debad34a5766ee43e9.tar.gz scala-76c06b4661b70e934530a0debad34a5766ee43e9.tar.bz2 scala-76c06b4661b70e934530a0debad34a5766ee43e9.zip |
build target is now 1.5
case classes now generate objects not factory methods. some small
cleanups for type inference
Diffstat (limited to 'src')
21 files changed, 403 insertions, 191 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 1aaa2f41bf..f37a34ae74 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -18,6 +18,21 @@ abstract class TreeGen { import definitions._ import posAssigner.atPos + def scalaDot(name: Name): Tree = + Select(Ident(nme.scala_) setSymbol ScalaPackage, name) + def scalaAnyRefConstr: Tree = + scalaDot(nme.AnyRef.toTypeName) + def scalaUnitConstr: Tree = + scalaDot(nme.Unit.toTypeName) + def scalaScalaObjectConstr: Tree = + scalaDot(nme.ScalaObject.toTypeName) + def productConstr: Tree = + scalaDot(nme.Product.toTypeName) + + def scalaFunctionConstr(argtpes: List[Tree], restpe: Tree): Tree = + AppliedTypeTree( + scalaDot(newTypeName("Function"+argtpes.length)), + argtpes ::: List(restpe)) /** Builds a reference to value whose type is given stable prefix. * The type must be suitable for this. For example, it @@ -135,7 +150,6 @@ abstract class TreeGen { This(sym.name) setSymbol sym setType sym.thisType def mkAttributedIdent(sym: Symbol): Tree = { - assert(sym.isTerm, sym) Ident(sym.name) setSymbol sym setType sym.tpe } @@ -145,7 +159,6 @@ abstract class TreeGen { qual.symbol.name.toTermName == nme.EMPTY_PACKAGE_NAME)) { mkAttributedIdent(sym) } else { - assert(sym.isTerm) val result = Select(qual, sym.name) setSymbol sym if (qual.tpe ne null) result setType qual.tpe.memberType(sym) result @@ -207,7 +220,9 @@ abstract class TreeGen { /** Builds a tuple */ def mkTuple(elems: List[Tree]): Tree = if (elems.isEmpty) Literal(()) - else Apply(mkAttributedRef(definitions.TupleClass(elems.length).caseFactory), elems) + else Apply( + Select(mkAttributedRef(definitions.TupleClass(elems.length).caseModule), nme.apply), + elems) def mkAnd(tree1: Tree, tree2: Tree) = Apply(Select(tree1, Boolean_and), List(tree2)) diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index d814c5cd6c..b6dd026a84 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -244,22 +244,6 @@ abstract class TreeInfo { case _ => false } - /** is this pattern of the form S(...) where S is a subclass of Seq - * and S is not a case class? The pattern might be wrapped in binds or alternatives. - */ - def isSequencePattern(tree: Tree): Boolean = tree match { - case Apply(fn, _) => - (fn.symbol ne null) && - !fn.symbol.hasFlag(CASE) && - fn.symbol.isNonBottomSubClass(definitions.SeqClass) - case Bind(name, body) => - isSequencePattern(body) - case Alternative(ts) => - ts forall isSequencePattern - case _ => - false - } - /** The method part of an application node */ def methPart(tree: Tree): Tree = tree match { diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 4412aa0896..81f10c7a31 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -755,6 +755,8 @@ trait Trees { case class TypeTree() extends TypTree { var original: Tree = _ + override def symbol = tpe.typeSymbol + def setOriginal(tree: Tree): this.type = { original = tree setPos(tree.pos) diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index 4fb9f310b1..b7355c86ff 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -244,7 +244,7 @@ abstract class DeadCodeElimination extends SubComponent { def find(bb: BasicBlock): Option[(BasicBlock, Int)] = { var xs = bb.toList xs.zipWithIndex find { hd => hd._1 eq i } match { - case Some(_, idx) => Some(bb, idx) + case Some((_, idx)) => Some(bb, idx) case None => None } } diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index d019b4cc89..6814ef7465 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -673,9 +673,9 @@ trait ParallelMatching { pat match { case Bind(_,p) => subpatterns(p) - case app @ Apply(fn, pats) if isCaseClass(app.tpe) && (fn.symbol eq null)=> + case app @ Apply(fn, pats) if isCaseClass(app.tpe) && fn.isType => if (isCaseHead) pats else dummies - case Apply(fn,xs) => assert((xs.isEmpty) && (fn.symbol ne null), "strange Apply"); dummies // named constant + case Apply(fn,xs) => assert((xs.isEmpty) && (!fn.isType), "strange Apply"); dummies // named constant case _: UnApply => dummies case pat => @@ -1230,7 +1230,7 @@ trait ParallelMatching { */ final def applyRule(implicit theOwner: Symbol, rep: RepFactory): RuleApplication = row match { case Nil => - ErrorRule + ErrorRule() case Row(pats, subst, g, bx)::xs => var px = 0; var rpats = pats; var bnd = subst; var temps = temp; while((bnd ne null) && (rpats ne Nil)) { val (vs,p) = strip(rpats.head); diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala index 92b59ff20f..030e46175f 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala @@ -78,14 +78,14 @@ trait PatternNodes { self: transform.ExplicitOuter => } object Apply_Value { - def unapply(x:Apply) = if ((x.symbol ne null) && (x.args eq Nil)) Some(x.tpe.prefix, x.symbol) else None + def unapply(x:Apply) = if (!x.fun.isType && x.args.isEmpty) Some(x.tpe.prefix, x.symbol) else None } object Apply_CaseClass_NoArgs { - def unapply(x:Apply) = if ((x.symbol eq null) && (x.args eq Nil)) Some(x.tpe) else None + def unapply(x:Apply) = if (x.fun.isType && x.args.isEmpty) Some(x.tpe) else None } object Apply_CaseClass_WithArgs { - def unapply(x:Apply) = if (x.symbol eq null) true else false + def unapply(x:Apply) = x.fun.isType } object __UnApply { diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala index eefc6457e4..7befdc9719 100644 --- a/src/compiler/scala/tools/nsc/symtab/Flags.scala +++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala @@ -126,7 +126,7 @@ object Flags extends Enumeration { final val PickledFlags: Long = 0xFFFFFFFFL /** Module flags inherited by their module-class */ - final val ModuleToClassFlags: Long = AccessFlags | PACKAGE | CASE + final val ModuleToClassFlags: Long = AccessFlags | MODULE | PACKAGE | CASE | SYNTHETIC private def listToString(ss: List[String]): String = ss.filter("" !=).mkString("", " ", "") diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 68e5e35f60..f6a2904a45 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -215,6 +215,7 @@ trait StdNames { val Finally = newTermName("Finally") val Float = newTermName("Float") val Function = newTermName("Function") + val Function1 = newTermName("Function1") val Int = newTermName("Int") val Labelled = newTermName("Labelled") val Long = newTermName("Long") diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 5bec708d45..e085c13e9c 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -261,9 +261,9 @@ trait Symbols { final def isPrimaryConstructor = isConstructor && owner.primaryConstructor == this - /** Is this symbol a case class factory method? */ - final def isCaseFactory = - isMethod && hasFlag(CASE) + /** Is this symbol a synthetic apply or unapply method in a companion object of a case class? */ + final def isCaseApplyOrUnapply = + isMethod && hasFlag(CASE) && hasFlag(SYNTHETIC) /** Is this symbol an implementation class for a mixin? */ final def isImplClass: Boolean = isClass && hasFlag(IMPLCLASS) @@ -930,14 +930,14 @@ trait Symbols { final def setter(base: Symbol): Symbol = base.info.decl(nme.getterToSetter(nme.getterName(name))) filter (_.hasFlag(ACCESSOR)) - /** The case factory corresponding to this case class + /** The case module corresponding to this case class * @pre case class is a member of some other class or package */ - final def caseFactory: Symbol = { - var facname = name.toTermName + final def caseModule: Symbol = { + var modname = name.toTermName if (privateWithin.isClass && !privateWithin.isModuleClass && !hasFlag(EXPANDEDNAME)) - facname = privateWithin.expandedName(facname) - initialize.owner.info.decl(facname).suchThat(_.isCaseFactory) + modname = privateWithin.expandedName(modname) + initialize.owner.info.decl(modname).suchThat(_.isModule) } /** If this symbol is a type parameter skolem (not an existential skolem!) diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index f690766561..1f24ff1bf6 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -139,6 +139,7 @@ trait Types { override def termSymbol = underlying.termSymbol override def termSymbolDirect = underlying.termSymbolDirect override def typeParams = underlying.typeParams + override def boundSyms = underlying.boundSyms override def typeSymbol = underlying.typeSymbol override def typeSymbolDirect = underlying.typeSymbolDirect override def widen = underlying.widen @@ -172,7 +173,6 @@ trait Types { override def paramSectionCount = 0 override def paramTypes: List[Type] = List() override def typeArgs = underlying.typeArgs - override def typeParams = underlying.typeParams override def notNull = maybeRewrap(underlying.notNull) override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = underlying.instantiateTypeParams(formals, actuals) override def skolemizeExistential(owner: Symbol, origin: AnyRef) = underlying.skolemizeExistential(owner, origin) @@ -296,10 +296,14 @@ trait Types { * the empty list for all other types */ def paramTypes: List[Type] = List() - /** For a poly type, its type parameters, + /** For a (potentially wrapped) poly type, its type parameters, * the empty list for all other types */ def typeParams: List[Symbol] = List() + /** For a (potentially wrapped) poly or existential type, its bound symbols, + * the empty list for all other types */ + def boundSyms: List[Symbol] = List() + /** Mixin a NotNull trait unless type already has one */ def notNull: Type = if (isNotNull || phase.erasedTypes) this else NotNullType(this) @@ -709,8 +713,8 @@ trait Types { var skolems: List[Symbol] = List() for (t <- this) { t match { - case ExistentialType(tparams, qtpe) => - boundSyms = boundSyms ::: tparams + case ExistentialType(quantified, qtpe) => + boundSyms = boundSyms ::: quantified case TypeRef(_, sym, _) => if ((sym hasFlag EXISTENTIAL) && !(boundSyms contains sym) && !(skolems contains sym)) skolems = sym :: skolems @@ -1610,6 +1614,7 @@ A type's typeSymbol should never be inspected directly. override def decls: Scope = resultType.decls override def termSymbol: Symbol = resultType.termSymbol override def typeSymbol: Symbol = resultType.typeSymbol + override def boundSyms: List[Symbol] = typeParams override def prefix: Type = resultType.prefix override def closure: Array[Type] = resultType.closure override def closureDepth: Int = resultType.closureDepth @@ -1654,6 +1659,7 @@ A type's typeSymbol should never be inspected directly. override def isStable: Boolean = false override def bounds = TypeBounds(maybeRewrap(underlying.bounds.lo), maybeRewrap(underlying.bounds.hi)) override def parents = underlying.parents map maybeRewrap + override def boundSyms: List[Symbol] = quantified override def prefix = maybeRewrap(underlying.prefix) override def typeArgs = underlying.typeArgs map maybeRewrap override def paramTypes = underlying.paramTypes map maybeRewrap @@ -2648,8 +2654,22 @@ A type's typeSymbol should never be inspected directly. else if (matches(from.head, sym)) toType(tp, to.head) else subst(tp, sym, from.tail, to.tail) + private def renameBoundSyms(tp: Type) = tp match { + case PolyType(bs, restp) => + val bs1 = cloneSymbols(bs) + PolyType(bs1, restp.substSym(bs, bs1)) + case ExistentialType(bs, restp) => + val bs1 = cloneSymbols(bs) + ExistentialType(bs1, restp.substSym(bs, bs1)) + case _ => + tp + } + def apply(tp0: Type): Type = if (from.isEmpty) tp0 else { - val tp = mapOver(tp0) + val boundSyms = tp0.boundSyms + val tp1 = if (boundSyms.isEmpty || !(boundSyms exists (from contains))) tp0 + else renameBoundSyms(tp0) + val tp = mapOver(tp1) tp match { // @M @@ -2673,13 +2693,6 @@ A type's typeSymbol should never be inspected directly. } case SingleType(NoPrefix, sym) => subst(tp, sym, from, to) - case PolyType(tparams, restp) => - assert(!(tparams exists (from contains))) - tp - case ExistentialType(tparams, restp) => - if (tparams exists (from contains)) - assert(false, "["+from.mkString(",")+":="+to.mkString(",")+"]"+tp) - tp case _ => tp } diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index b03c05ce3b..d7150d981f 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -154,12 +154,18 @@ abstract class Constructors extends Transform { if (stat.symbol.tpe.isInstanceOf[ConstantType]) assert(stat.symbol.getter(stat.symbol.owner) != NoSymbol, stat) else { + try { if (rhs != EmptyTree && !stat.symbol.hasFlag(LAZY)) { val rhs1 = intoConstructor(stat.symbol, rhs); (if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign( stat.symbol, rhs1) } defBuf += copy.ValDef(stat, mods, name, tpt, EmptyTree) + } catch { + case ex: Throwable => + println("error when transforming "+stat+" in "+stats) + throw ex + } } case ClassDef(_, _, _, _) => defBuf += (new ConstructorTransformer).transform(stat) @@ -205,14 +211,13 @@ abstract class Constructors extends Transform { defBuf.toList filter (stat => isAccessed(stat.symbol))) } - override def transform(tree: Tree): Tree = { + override def transform(tree: Tree): Tree = tree match { case ClassDef(mods, name, tparams, impl) if !tree.symbol.hasFlag(INTERFACE) => copy.ClassDef(tree, mods, name, tparams, transformClassTemplate(impl)) case _ => super.transform(tree) } - } } // ConstructorTransformer diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 80a1fc1f0c..a83c68f797 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -763,7 +763,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { */ private val preTransformer = new Transformer { override def transform(tree: Tree): Tree = { - if (tree.symbol == ArrayClass) return tree + if (tree.symbol == ArrayClass && !tree.isType) return tree val tree1 = tree match { case ClassDef(mods, name, tparams, impl) => if (settings.debug.value) diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 8bf0994af6..144081efcb 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -59,7 +59,7 @@ abstract class Mixin extends InfoTransform { * inherits the trait. */ private def isForwarded(sym: Symbol) = - isImplementedStatically(sym) && !sym.isImplOnly && !sym.isCaseFactory + isImplementedStatically(sym) && !sym.isImplOnly /** Maps the type of an implementation class to its interface; * maps all other types to themselves. diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index defcc6ce2e..4ede3dec3b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -35,7 +35,7 @@ trait Analyzer extends AnyRef val global: Analyzer.this.global.type = Analyzer.this.global val phaseName = "typer" def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) { - resetTyper + resetTyper() def apply(unit: CompilationUnit) { unit.body = newTyper(rootContext(unit)).typed(unit.body) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index f0311dd885..782c003b25 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -76,7 +76,7 @@ trait Contexts { self: Analyzer => c } - def resetContexts { + def resetContexts() { var sc = startContext while (sc != NoContext) { sc.tree match { diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 8571148479..ea2a4c59c8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -512,12 +512,33 @@ trait Infer { if (targ.typeSymbol == AllClass && (varianceInType(restpe)(tparam) & COVARIANT) == 0) { uninstantiated += tparam tparam.tpe //@M TODO: might be affected by change to tpe in Symbol - } else targ.widen + } else if (targ.typeSymbol == RepeatedParamClass) { + targ.baseType(SeqClass) + } else { + targ.widen + } } // println("meth type args "+", tparams = "+tparams+", formals = "+formals+", restpe = "+restpe+", argtpes = "+argtpes+", underlying = "+(argtpes map (_.widen))+", pt = "+pt+", uninstantiated = "+uninstantiated.toList+", result = "+res) //DEBUG // res } + def followApply(tp: Type): Type = tp match { + case PolyType(List(), restp) => + val restp1 = followApply(restp) + if (restp1 eq restp) tp else restp1 + case _ => + val appmeth = tp.nonPrivateMember(nme.apply) filter (_.isPublic) + if (appmeth == NoSymbol) tp + else OverloadedType(tp, appmeth.alternatives) + } + + def hasExactlyNumParams(tp: Type, n: Int): Boolean = tp match { + case OverloadedType(pre, alts) => + alts exists (alt => hasExactlyNumParams(pre.memberType(alt), n)) + case _ => + formalTypes(tp.paramTypes, n).length == n + } + /** Is there an instantiation of free type variables <code>undetparams</code> * such that function type <code>ftpe</code> is applicable to * <code>argtpes</code> and its result conform to <code>pt</code>? @@ -531,6 +552,8 @@ trait Infer { def isApplicable(undetparams: List[Symbol], ftpe: Type, argtpes0: List[Type], pt: Type): Boolean = ftpe match { + case OverloadedType(pre, alts) => + alts exists (alt => isApplicable(undetparams, pre.memberType(alt), argtpes0, pt)) case ExistentialType(tparams, qtpe) => isApplicable(undetparams, qtpe, argtpes0, pt) case MethodType(formals0, _) => @@ -573,29 +596,70 @@ trait Infer { } } - /** Does type <code>ftpe1</code> specialize type <code>ftpe2</code> + /** Is type <code>ftpe1</code> strictly more specific than type <code>ftpe2</code> * when both are alternatives in an overloaded function? + * @see SLS (sec:overloading-resolution) * * @param ftpe1 ... * @param ftpe2 ... * @return ... */ - def specializes(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match { + def isMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match { + case OverloadedType(pre, alts) => + alts exists (alt => isMoreSpecific(pre.memberType(alt), ftpe2)) case et: ExistentialType => - et.withTypeVars(specializes(_, ftpe2)) - case MethodType(formals, _) => + et.withTypeVars(isStrictlyMoreSpecific(_, ftpe2)) + case MethodType(formals @ (x :: xs), _) => isApplicable(List(), ftpe2, formals, WildcardType) - case PolyType(tparams, MethodType(formals, _)) => + case PolyType(_, MethodType(formals @ (x :: xs), _)) => isApplicable(List(), ftpe2, formals, WildcardType) case ErrorType => true case _ => - false + ftpe2 match { + case OverloadedType(pre, alts) => + alts forall (alt => isMoreSpecific(ftpe1, pre.memberType(alt))) + case et: ExistentialType => + et.withTypeVars(isStrictlyMoreSpecific(ftpe1, _)) + case MethodType(_, _) | PolyType(_, MethodType(_, _)) => + true + case _ => + isMoreSpecificValueType(ftpe1, ftpe2, List(), List()) + } } + def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean = + ftpe1.isError || isMoreSpecific(ftpe1, ftpe2) && + (!isMoreSpecific(ftpe2, ftpe1) || + !ftpe1.isInstanceOf[OverloadedType] && ftpe2.isInstanceOf[OverloadedType]) + + def isMoreSpecificValueType(tpe1: Type, tpe2: Type, undef1: List[Symbol], undef2: List[Symbol]): Boolean = (tpe1, tpe2) match { + case (PolyType(tparams1, rtpe1), _) => + isMoreSpecificValueType(rtpe1, tpe2, undef1 ::: tparams1, undef2) + case (_, PolyType(tparams2, rtpe2)) => + isMoreSpecificValueType(tpe1, rtpe2, undef1, undef2 ::: tparams2) + case _ => + existentialAbstraction(undef1, tpe1) <:< existentialAbstraction(undef2, tpe2) + } + +/* /** Is type `tpe1' a strictly better expression alternative than type `tpe2'? */ def isStrictlyBetterExpr(tpe1: Type, tpe2: Type) = { + isMethod(tpe2) && !isMethod(tpe1) || + isNullary(tpe1) && !isNullary(tpe2) || + isStrictlyBetter(tpe1, tpe2) + } + + /** Is type `tpe1' a strictly better alternative than type `tpe2'? + * non-methods are always strictly better than methods + * nullary methods are always strictly better than non-nullary + * if both are non-nullary methods, then tpe1 is strictly better than tpe2 if + * - tpe1 specializes tpe2 and tpe2 does not specialize tpe1 + * - tpe1 and tpe2 specialize each other and tpe1 has a strictly better resulttype than + * tpe2 + */ + def isStrictlyBetter(tpe1: Type, tpe2: Type) = { def isNullary(tpe: Type): Boolean = tpe match { case tp: RewrappingTypeProxy => isNullary(tp.underlying) case _ => tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty @@ -605,16 +669,21 @@ trait Infer { case MethodType(_, _) | PolyType(_, _) => true case _ => false } - isMethod(tpe2) && !isMethod(tpe1) || + def hasStrictlyBetterResult = + resultIsBetter(tpe1, tpe2, List(), List()) && !resultIsBetter(tpe2, tpe1, List(), List()) + if (!isMethod(tpe1)) + isMethod(tpe2) || hasStrictlyBetterResult + isNullary(tpe1) && !isNullary(tpe2) || - isStrictlyBetter(tpe1, tpe2) - } + is - /** Is type `tpe1' a strictly better alternative than type `tpe2'? - */ - def isStrictlyBetter(tpe1: Type, tpe2: Type) = - specializes(tpe1, tpe2) && !specializes(tpe2, tpe1) + else if (isNullary(tpe1)) + isMethod(tpe2) && (!isNullary(tpe2) || hasStrictlyBetterResult) + else + specializes(tpe1, tpe2) && (!specializes(tpe2, tpe1) || hasStrictlyBetterResult) + } +*/ /** error if arguments not within bounds. */ def checkBounds(pos: Position, pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type], prefix: String) = { @@ -715,7 +784,7 @@ trait Infer { else if (s.isContravariant) "contravariant" else "invariant"; - def qualify(a0: Symbol, b0: Symbol): String = if(a0.toString != b0.toString) "" else { + def qualify(a0: Symbol, b0: Symbol): String = if (a0.toString != b0.toString) "" else { assert((a0 ne b0) && (a0.owner ne b0.owner)); var a = a0; var b = b0 while (a.owner.name == b.owner.name) { a = a.owner; b = b.owner} @@ -1123,7 +1192,7 @@ trait Infer { */ def inferExprAlternative(tree: Tree, pt: Type): Unit = tree.tpe match { case OverloadedType(pre, alts) => tryTwice { - var alts1 = alts filter (alt => isCompatible(pre.memberType(alt), pt)) + var alts1 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt)) var secondTry = false if (alts1.isEmpty) { alts1 = alts @@ -1134,8 +1203,8 @@ trait Infer { { val tp1 = pre.memberType(sym1) val tp2 = pre.memberType(sym2) (tp2 == ErrorType || - !global.typer.infer.isCompatible(tp2, pt) && global.typer.infer.isCompatible(tp1, pt) || - isStrictlyBetterExpr(tp1, tp2)) } + !global.typer.infer.isWeaklyCompatible(tp2, pt) && global.typer.infer.isWeaklyCompatible(tp1, pt) || + isStrictlyMoreSpecific(tp1, tp2)) } val best = ((NoSymbol: Symbol) /: alts1) ((best, alt) => if (improves(alt, best)) alt else best) val competing = alts1 dropWhile (alt => best == alt || improves(best, alt)) @@ -1161,7 +1230,7 @@ trait Infer { } } else { val applicable = alts1 filter (alt => - global.typer.infer.isCompatible(pre.memberType(alt), pt)) + global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt)) checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) } @@ -1180,10 +1249,10 @@ trait Infer { case OverloadedType(pre, alts) => tryTwice { if (settings.debug.value) log("infer method alt " + tree.symbol + " with alternatives " + (alts map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt) - val applicable = alts filter (alt => isApplicable(undetparams, pre.memberType(alt), argtpes, pt)) + val applicable = alts filter (alt => isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt)) def improves(sym1: Symbol, sym2: Symbol) = sym2 == NoSymbol || sym2.isError || - isStrictlyBetter(pre.memberType(sym1), pre.memberType(sym2)) + isStrictlyMoreSpecific(followApply(pre.memberType(sym1)), followApply(pre.memberType(sym2))) val best = ((NoSymbol: Symbol) /: applicable) ((best, alt) => if (improves(alt, best)) alt else best) val competing = applicable dropWhile (alt => best == alt || improves(best, alt)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index e236f0f7e7..4f6d1682ad 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -6,6 +6,7 @@ package scala.tools.nsc.typechecker +import scala.collection.mutable.HashMap import scala.tools.nsc.util.Position import symtab.Flags import symtab.Flags._ @@ -18,6 +19,7 @@ import symtab.Flags._ trait Namers { self: Analyzer => import global._ import definitions._ + import posAssigner.atPos /** Convert to corresponding type parameters all skolems which satisfy one * of the following two conditions: @@ -41,6 +43,12 @@ trait Namers { self: Analyzer => private class NormalNamer(context : Context) extends Namer(context) def newNamer(context : Context) : Namer = new NormalNamer(context) + private val caseClassOfModuleClass = new HashMap[Symbol, ClassDef] + + def resetNamer() { + caseClassOfModuleClass.clear + } + abstract class Namer(val context: Context) { val typer = newTyper(context) @@ -51,6 +59,14 @@ trait Namers { self: Analyzer => sym } + + def inConstructorFlag: Long = + if (context.owner.isConstructor && !context.inConstructorSuffix || context.owner.isEarly) INCONSTRUCTOR + else 0l + + def moduleClassFlags(moduleFlags: Long) = + (moduleFlags & ModuleToClassFlags) | FINAL | inConstructorFlag + def updatePosFlags(sym: Symbol, pos: Position, flags: Long): Symbol = { if (settings.debug.value) log("overwriting " + sym) val lockedFlag = sym.flags & LOCKED @@ -58,7 +74,7 @@ trait Namers { self: Analyzer => sym setPos pos sym.flags = flags | lockedFlag if (sym.isModule && sym.moduleClass != NoSymbol) - updatePosFlags(sym.moduleClass, pos, (flags & ModuleToClassFlags) | MODULE | FINAL) + updatePosFlags(sym.moduleClass, pos, moduleClassFlags(flags)) if (sym.owner.isPackageClass && (sym.linkedSym.rawInfo.isInstanceOf[loaders.SymbolLoader] || sym.linkedSym.rawInfo.isComplete && runId(sym.validTo) != currentRunId)) @@ -112,13 +128,20 @@ trait Namers { self: Analyzer => !((newS.owner.isTypeParameter || newS.owner.isAbstractType) && newS.name.length==1 && newS.name(0)=='_') //@M: allow repeated use of `_' for higher-order type params } + + // IDE hook protected def setInfo[Sym <: Symbol](sym : Sym)(tpe : LazyType) : Sym = sym.setInfo(tpe) + private def doubleDefError(pos: Position, sym: Symbol) { context.error(pos, sym.name.toString() + " is already defined as " + (if (sym.hasFlag(CASE)) "case class " + sym.name else sym.toString())) } + private def inCurrentScope(m: Symbol) = + if (context.owner.isClass) context.owner == m.owner + else context.scope == m.owner.info.decls + def enterInScope(sym: Symbol): Symbol = { // allow for overloaded methods if (!(sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass)) { @@ -149,10 +172,6 @@ trait Namers { self: Analyzer => } } - def inConstructorFlag: Long = - if (context.owner.isConstructor && !context.inConstructorSuffix || context.owner.isEarly) INCONSTRUCTOR - else 0l - def enterClassSymbol(tree : ClassDef): Symbol = { var c: Symbol = context.scope.lookup(tree.name); if (!inIDE && c.isType && context.scope == c.owner.info.decls && !currentRun.compiles(c)) { @@ -179,21 +198,25 @@ trait Namers { self: Analyzer => assert(c.name.toString.indexOf('(') == -1) c } + + /** Enter a module symbol. The tree parameter can be either a module definition + * or a class definition */ def enterModuleSymbol(tree : ModuleDef): Symbol = { // .pos, mods.flags | MODULE | FINAL, name - assert(tree.name.isTermName) var m: Symbol = context.scope.lookup(tree.name) - if (!inIDE && m.isModule && !m.isPackage && (context.scope == m.owner.info.decls) && - !currentRun.compiles(m)) { - updatePosFlags(m, tree.pos, tree.mods.flags|MODULE|FINAL) + val moduleFlags = tree.mods.flags | MODULE | FINAL + if (!inIDE && m.isModule && !m.isPackage && inCurrentScope(m) && + (!currentRun.compiles(m) || (m hasFlag SYNTHETIC))) { + updatePosFlags(m, tree.pos, moduleFlags) setPrivateWithin(tree, m, tree.mods) + synthetics -= m } else { m = context.owner.newModule(tree.pos, tree.name) - m.setFlag(tree.mods.flags) + m.setFlag(moduleFlags) m = setPrivateWithin(tree, m, tree.mods) m = enterInScope(m) - m.moduleClass.setFlag(tree.mods.flags|MODULE|FINAL| inConstructorFlag) + m.moduleClass.setFlag(moduleClassFlags(moduleFlags)) setPrivateWithin(tree, m.moduleClass, tree.mods) } if (m.owner.isPackageClass) { @@ -203,26 +226,6 @@ trait Namers { self: Analyzer => m } - def enterCaseFactorySymbol(tree : ClassDef): Symbol = { - val pos = tree.pos - val flags = tree.mods.flags & AccessFlags | METHOD | CASE - val name = tree.name.toTermName - var m: Symbol = context.scope.lookup(name) - if (!inIDE && m.isTerm && !m.isPackage && !currentRun.compiles(m) && context.scope == m.owner.info.decls) { - updatePosFlags(m, pos, flags) - setPrivateWithin(tree, m, tree.mods) - } else { - // recycle the old fashion way. - m = enterInScope{ - var sym = context.owner.newMethod(pos, name).setFlag(flags) - sym = setPrivateWithin(tree, sym, tree.mods) - sym - } - } - if (m.owner.isPackageClass) - currentRun.symSource(m) = context.unit.source.file - m - } def enterSyms(trees: List[Tree]): Namer = { var namer : Namer = this for (tree <- trees) { @@ -231,6 +234,7 @@ trait Namers { self: Analyzer => } namer } + def newTypeSkolems(tparams: List[Symbol]): List[Symbol] = { val tskolems = tparams map (_.newTypeSkolem) val ltp = new LazyType { @@ -280,7 +284,6 @@ trait Namers { self: Analyzer => } def finish = finishWith(List()) - if (tree.symbol == NoSymbol) { val owner = context.owner tree match { @@ -292,9 +295,12 @@ trait Namers { self: Analyzer => case tree @ ClassDef(mods, name, tparams, impl) => tree.symbol = enterClassSymbol(tree) finishWith(tparams) - if ((mods.flags & CASE) != 0) { // enter case factory method. - val sym = enterCaseFactorySymbol(tree) - setInfo(sym)(namerOf(sym).caseFactoryCompleter(reuse(tree))) + if ((mods.flags & CASE) != 0) { + var m: Symbol = context.scope.lookup(tree.name.toTermName).filter(! _.isSourceMethod) + if (!(m.isModule && inCurrentScope(m) && currentRun.compiles(m))) { + m = enterSyntheticSym(caseModuleDef(tree)) + } + caseClassOfModuleClass(m.moduleClass) = tree } case tree @ ModuleDef(mods, name, _) => tree.symbol = enterModuleSymbol(tree) @@ -370,6 +376,12 @@ trait Namers { self: Analyzer => this.context } + def enterSyntheticSym(tree: Tree): Symbol = { + enterSym(tree) + synthetics(tree.symbol) = tree + tree.symbol + } + // --- Lazy Type Assignment -------------------------------------------------- def typeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym => @@ -421,14 +433,6 @@ trait Namers { self: Analyzer => sym.setInfo(selftpe) } - def caseFactoryCompleter(tree: Tree) = mkTypeCompleter(tree) { sym => - val clazz = tree.symbol - var tpe = clazz.primaryConstructor.tpe - val tparams = clazz.typeParams - if (!tparams.isEmpty) tpe = PolyType(tparams, tpe).cloneInfo(sym); - sym.setInfo(tpe) - } - private def widenIfNotFinal(sym: Symbol, tpe: Type, pt: Type): Type = { val getter = if (sym.isValue && sym.owner.isClass && (sym hasFlag PRIVATE)) @@ -508,7 +512,14 @@ trait Namers { self: Analyzer => val parents = typer.parentTypes(templ) map checkParent enterSelf(templ.self) val decls = newClassScope(clazz) - newNamer(context.make(templ, clazz, decls)).enterSyms(templ.body) + val templateNamer = newNamer(context.make(templ, clazz, decls)) + .enterSyms(templ.body) + caseClassOfModuleClass get clazz match { + case Some(cdef) => + addApplyUnapply(cdef, templateNamer) + caseClassOfModuleClass -= clazz + case None => + } ClassInfoType(parents, decls, clazz) } @@ -733,6 +744,28 @@ trait Namers { self: Analyzer => else polyType(tparamSyms, tp) } + /** Given a case class + * + * case class C[Ts] (ps: Us) + * + * Add the following methods to toScope: + * + * 1. if case class is not abstract, add + * + * <synthetic> <case> def apply[Ts](ps: Us): C[Ts] = new C[Ts](ps) + * + * 2. add a method + * + * <synthetic> <case> def unapply[Ts](x: C[Ts]) = <ret-val> + * + * where <ret-val> is the caseClassUnapplyReturnValue of class C (see UnApplies.scala) + */ + def addApplyUnapply(cdef: ClassDef, namer: Namer) { + if (!(cdef.symbol hasFlag ABSTRACT)) + namer.enterSyntheticSym(caseModuleApplyMeth(cdef)) + namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef)) + } + def typeSig(tree: Tree): Type = { val sym: Symbol = tree.symbol tree match { @@ -758,7 +791,7 @@ trait Namers { self: Analyzer => val clazz = sym.moduleClass clazz.setInfo(newNamer(context.makeNewScope(tree, clazz)).templateSig(impl)) //clazz.typeOfThis = singleType(sym.owner.thisType, sym); - clazz.tpe; + clazz.tpe case DefDef(_, _, tparams, vparamss, tpt, rhs) => val result = @@ -884,7 +917,7 @@ trait Namers { self: Analyzer => checkNoConflict(PRIVATE, PROTECTED) checkNoConflict(PRIVATE, OVERRIDE) checkNoConflict(DEFERRED, FINAL) - checkNoConflict(ABSTRACT, CASE) +// checkNoConflict(ABSTRACT, CASE) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 5c7841651b..e098224e59 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -373,7 +373,7 @@ abstract class RefChecks extends InfoTransform { var state = CoVariance while (sym != clazz && state != AnyVariance) { //Console.println("flip: " + sym + " " + sym.isParameter());//DEBUG - if ((sym hasFlag PARAM) && !sym.owner.isConstructor && !sym.owner.isCaseFactory && + if ((sym hasFlag PARAM) && !sym.owner.isConstructor && !sym.owner.isCaseApplyOrUnapply && !(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem && tvar.owner == sym.owner)) state = -state; else if (!sym.owner.isClass || @@ -574,9 +574,6 @@ abstract class RefChecks extends InfoTransform { } } - def isConcreteLocalCaseFactory(clazz: Symbol) = - (clazz hasFlag CASE) && !(clazz hasFlag ABSTRACT) && !(clazz.owner hasFlag PACKAGE) - override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { pushLevel() enterSyms(stats) @@ -635,32 +632,6 @@ abstract class RefChecks extends InfoTransform { else transformTrees(List(cdef, vdef, ddef)) } - case ClassDef(_, _, _, _) if isConcreteLocalCaseFactory(tree.symbol) => - val clazz = tree.symbol - val factory = clazz.caseFactory - if (factory == NoSymbol) { - assert(clazz.owner.isTerm, clazz) - List(transform(tree)) - } else { - def mkArgument(vparam: Symbol) = { - val id = Ident(vparam) - if (vparam.tpe.typeSymbol == RepeatedParamClass) Typed(id, Ident(nme.WILDCARD_STAR.toTypeName)) - else id - } - val caseFactoryDef = - localTyper.typed { - atPos(tree.pos) { - DefDef( - factory, - vparamss => - (toConstructor(tree.pos, factory.tpe) /: vparamss) { - (fn, vparams) => Apply(fn, vparams map mkArgument) - }) - } - } - List(transform(tree), caseFactoryDef) - } - case ValDef(_, _, _, _) => val tree1 = transform(tree); // important to do before forward reference check val ValDef(_, _, _, rhs) = tree1 diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 7429c9ccf7..ff31a95c8a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -38,13 +38,16 @@ trait Typers { self: Analyzer => private val superDefs = new HashMap[Symbol, ListBuffer[Tree]] - def resetTyper { + val synthetics = new HashMap[Symbol, Tree] + + def resetTyper() { resetContexts + resetNamer() transformed.clear superDefs.clear + synthetics.clear } - object UnTyper extends Traverser { override def traverse(tree: Tree) = { if (tree != EmptyTree) tree.tpe = null @@ -708,27 +711,32 @@ trait Typers { self: Analyzer => case _ => TypeTree(tree.tpe) setOriginal(tree) } } else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) { // (5) - val constr = tree.symbol.filter(_.isCaseFactory) - val clazz = constr.tpe.finalResultType.typeSymbol - if ((constr != NoSymbol) && (clazz hasFlag CASE)) { - val prefix = tree.tpe.finalResultType.prefix - val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner)) setOriginal tree - try { - inferConstructorInstance(tree1, clazz.typeParams, pt) - } catch { - case tpe : TypeError => throw tpe - case t : Exception => - logError("CONTEXT: " + (tree.pos).dbgString, t) - throw t - } - tree1 - } else { - val extractor = tree.symbol.filter(sym => unapplyMember(sym.tpe).exists) - if (extractor != NoSymbol) { - tree setSymbol extractor + val extractor = tree.symbol.filter(sym => unapplyMember(sym.tpe).exists) + if (extractor != NoSymbol) { + tree setSymbol extractor + val unapply = unapplyMember(extractor.tpe) + val clazz = if (unapply.tpe.paramTypes.length == 1) unapply.tpe.paramTypes.head.typeSymbol + else NoSymbol + if ((unapply hasFlag CASE) && (clazz hasFlag CASE)) { + if (!phase.erasedTypes) checkStable(tree) //todo: do we need to demand this? + // convert synthetic unapply of case class to case class constructor + val prefix = tree.tpe.prefix + val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner)) + .setOriginal(tree) + try { + inferConstructorInstance(tree1, clazz.typeParams, pt) + } catch { + case tpe : TypeError => throw tpe + case t : Exception => + logError("CONTEXT: " + (tree.pos).dbgString, t) + throw t + } + tree1 } else { - errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method") + tree } + } else { + errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method") } } else if ((mode & (EXPRmode | FUNmode)) == (EXPRmode | FUNmode) && !tree.tpe.isInstanceOf[MethodType] && @@ -1440,7 +1448,14 @@ trait Typers { self: Analyzer => if (vparam.tpt.isEmpty) vparam.tpt.tpe = if (isFullyDefined(argpt)) argpt - else { error(vparam.pos, "missing parameter type"); ErrorType } + else { + error( + vparam.pos, + "missing parameter type"+ + (if (vparam.mods.hasFlag(SYNTHETIC)) " for expanded function "+fun + else "")) + ErrorType + } enterSym(context, vparam) if (context.retyping) context.scope enter vparam.symbol vparam.symbol @@ -1479,7 +1494,9 @@ trait Typers { self: Analyzer => def typedImport(imp : Import) : Import = imp; def typedStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { + val inBlock = exprOwner == context.owner + def typedStat(stat: Tree): Tree = { if (context.owner.isRefinementClass && !treeInfo.isDeclaration(stat)) errorTree(stat, "only declarations allowed here") @@ -1510,14 +1527,19 @@ trait Typers { self: Analyzer => result } } + def accesses(accessor: Symbol, accessed: Symbol) = (accessed hasFlag LOCAL) && (accessed hasFlag PARAMACCESSOR) || (accessor hasFlag ACCESSOR) && !(accessed hasFlag ACCESSOR) && accessed.isPrivateLocal - def checkNoDoubleDefs(stats: List[Tree]) { + + def checkNoDoubleDefsAndAddSynthetics(stats: List[Tree]): List[Tree] = { val scope = if (inBlock) context.scope else context.owner.info.decls; + val newStats = new ListBuffer[Tree] var e = scope.elems; while ((e ne null) && e.owner == scope) { + + // check no double def var e1 = scope.lookupNextEntry(e); while ((e1 ne null) && e1.owner == scope) { if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) && @@ -1527,12 +1549,23 @@ trait Typers { self: Analyzer => {if(!settings.debug.value) "" else " in "+unit.toString}) e1 = scope.lookupNextEntry(e1); } + + // add synthetics + synthetics get e.sym match { + case Some(tree) => + newStats += tree + synthetics -= e.sym + case None => + } + e = e.next } + if (newStats.isEmpty) stats + else stats ::: (newStats.toList map typedStat) } val result = List.mapConserve(stats)(typedStat) - if (!phase.erasedTypes) checkNoDoubleDefs(result) - result + if (phase.erasedTypes) result + else checkNoDoubleDefsAndAddSynthetics(result) } def typedArg(arg: Tree, mode: Int, newmode: Int, pt: Type): Tree = @@ -1571,13 +1604,11 @@ trait Typers { self: Analyzer => val argtypes = args map (arg => AllClass.tpe) val pre = fun.symbol.tpe.prefix var sym = fun.symbol filter { alt => - isApplicableSafe(context.undetparams, pre.memberType(alt), argtypes, pt) + isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt) } if (sym hasFlag OVERLOADED) { // eliminate functions that would result from tupling transforms - val sym1 = sym filter { alt => - formalTypes(alt.tpe.paramTypes, argtypes.length).length == argtypes.length - } + val sym1 = sym filter (alt => hasExactlyNumParams(followApply(alt.tpe), argtypes.length)) if (sym1 != NoSymbol) sym = sym1 } if (sym != NoSymbol) @@ -1922,6 +1953,7 @@ trait Typers { self: Analyzer => trackSetInfo(quantified setFlag EXISTENTIAL)(bound.cloneInfo(quantified)) } val typeParamTypes = typeParams map (_.tpe) // don't trackSetInfo here, since type already set! + //println("ex trans "+rawSyms+" . "+tp+" "+typeParamTypes+" "+(typeParams map (_.info)))//DEBUG for (tparam <- typeParams) tparam.setInfo(tparam.info.subst(rawSyms, typeParamTypes)) (typeParams, tp.subst(rawSyms, typeParamTypes)) } @@ -2237,7 +2269,9 @@ trait Typers { self: Analyzer => } else { if (!lhs1.tpe.isError) { //println(lhs1+" = "+rhs)//DEBUG - error(tree.pos, "assignment to non-variable ") + error(tree.pos, "assignment to "+ + (if ((varsym ne null) && varsym.isValue) "immutable value" + else "non variable")) } setError(tree) } @@ -2629,7 +2663,6 @@ trait Typers { self: Analyzer => case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name) } val result = stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt) - if (sym.isCaseFactory && !phase.erasedTypes) checkStable(qual) if (!global.phase.erasedTypes && settings.Xchecknull.value && !sym.isConstructor && !(qual.tpe <:< NotNullClass.tpe) && !qual.tpe.isNotNull) @@ -2676,14 +2709,13 @@ trait Typers { self: Analyzer => var defSym: Symbol = tree.symbol // the directly found symbol var pre: Type = NoPrefix // the prefix type of defSym, if a class member var qual: Tree = EmptyTree // the qualififier tree if transformed tree is a select - // if we are in a constructor of a pattern, ignore all methods - // which are not case factories (note if we don't do that + + // if we are in a constructor of a pattern, ignore all definitions + // which are methods (note: if we don't do that // case x :: xs in class List would return the :: method). def qualifies(sym: Symbol): Boolean = sym.exists && - ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || - !sym.isSourceMethod || sym.isCaseFactory) - + ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod) if (defSym == NoSymbol) { var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope @@ -2795,8 +2827,7 @@ trait Typers { self: Analyzer => if (inIDE) { Ident(defSym.name) setType tree1.tpe setSymbol defSym setPos tree.pos } else tree1 - } - else { + } else { var tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(qual, name)) // atPos necessary because qualifier might come from startContext @@ -3380,7 +3411,7 @@ trait Typers { self: Analyzer => def improves(info1: ImplicitInfo, info2: ImplicitInfo) = (info2 == NoImplicitInfo) || (info1 != NoImplicitInfo) && - isStrictlyBetterExpr(info1.tpe, info2.tpe) + isStrictlyMoreSpecific(info1.tpe, info2.tpe) val shadowed = new HashSet[Name](8) def isApplicable(info: ImplicitInfo): Boolean = !containsError(info.tpe) && diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 98c6935953..c0be7a9454 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -6,6 +6,8 @@ package scala.tools.nsc.typechecker +import symtab.Flags._ + /* * @author Martin Odersky * @version 1.0 @@ -14,6 +16,7 @@ trait Unapplies { self: Analyzer => import global._ import definitions._ + import posAssigner.atPos /** returns type list for return type of the extraction */ def unapplyTypeList(ufn: Symbol, ufntpe: Type) = { @@ -79,7 +82,6 @@ trait Unapplies { self: Analyzer => else productType({val es = elems; if(useWildCards) elems map { x => WildcardType} else elems}) */ - def unapplyReturnTypeExpected(argsLength: Int) = argsLength match { case 0 => BooleanClass.tpe case 1 => optionType(WildcardType) @@ -92,4 +94,88 @@ trait Unapplies { self: Analyzer => if (unapp == NoSymbol) unapp = tp.member(nme.unapplySeq) unapp } + + private def copyUntyped[T <: Tree](tree: T): T = { + val tree1 = tree.duplicate + UnTyper.traverse(tree1) + tree1 + } + + private def classType(cdef: ClassDef, tparams: List[TypeDef]): Tree = { + val tycon = gen.mkAttributedRef(cdef.symbol) + if (tparams.isEmpty) tycon else AppliedTypeTree(tycon, tparams map (x => Ident(x.name))) + } + + private def constrParams(cdef: ClassDef): List[List[ValDef]] = { + val constr = treeInfo.firstConstructor(cdef.impl.body) + (constr: @unchecked) match { + case DefDef(_, _, _, vparamss, _, _) => vparamss map (_ map copyUntyped[ValDef]) + } + } + + /** The return value of an unapply method of a case class C[Ts] + * @param param The name of the parameter of the unapply method, assumed to be of type C[Ts] + * @param caseclazz The case class C[Ts] + */ + private def caseClassUnapplyReturnValue(param: Name, caseclazz: Symbol) = { + def caseFieldAccessorValue(selector: Symbol) = Select(Ident(param), selector) + val accessors = caseclazz.caseFieldAccessors + if (accessors.isEmpty) Literal(true) + else if (accessors.tail.isEmpty) caseFieldAccessorValue(accessors.head) + else Apply(gen.scalaDot(newTermName( "Tuple" + accessors.length)), accessors map caseFieldAccessorValue) + } + + /** The module corresponding to a case class; without any member definitions + */ + def caseModuleDef(cdef: ClassDef): ModuleDef = atPos(cdef.pos) { + var parents = List(gen.scalaScalaObjectConstr) + if (cdef.tparams.isEmpty && constrParams(cdef).length == 1) + parents = gen.scalaFunctionConstr(constrParams(cdef).head map (_.tpt), + Ident(cdef.name)) :: parents + ModuleDef( + Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin), + cdef.name.toTermName, + Template(parents, emptyValDef, Modifiers(0), List(), List(List()), List())) + } + + /** The apply method corresponding to a case class + */ + def caseModuleApplyMeth(cdef: ClassDef): DefDef = { + val tparams = cdef.tparams map copyUntyped[TypeDef] + def paramToArg(param: ValDef) = { + val id = Ident(param.name) + val RP = nme.REPEATED_PARAM_CLASS_NAME.toTypeName + param.tpt match { + case AppliedTypeTree(Select(_, RP), _) => Typed(id, Ident(nme.WILDCARD_STAR.toTypeName)) + case _ =>id + } + } + val cparams = constrParams(cdef) + atPos(cdef.pos) { + DefDef( + Modifiers(SYNTHETIC | CASE), + nme.apply, + tparams, + cparams, + classType(cdef, tparams), + New(classType(cdef, tparams), cparams map (_ map paramToArg))) + } + } + + /** The unapply method corresponding to a case class + */ + def caseModuleUnapplyMeth(cdef: ClassDef): DefDef = { + val tparams = cdef.tparams map copyUntyped[TypeDef] + val unapplyParamName = newTermName("x$0") + atPos(cdef.pos) { + DefDef( + Modifiers(SYNTHETIC | CASE), + nme.unapply, + tparams, + List(List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName, + classType(cdef, tparams), EmptyTree))), + TypeTree(), + caseClassUnapplyReturnValue(unapplyParamName, cdef.symbol)) + } + } } diff --git a/src/library/scala/collection/jcl/SortedSet.scala b/src/library/scala/collection/jcl/SortedSet.scala index d1317096ad..0e59eb5c43 100644 --- a/src/library/scala/collection/jcl/SortedSet.scala +++ b/src/library/scala/collection/jcl/SortedSet.scala @@ -9,6 +9,7 @@ // $Id$ package scala.collection.jcl; +import Predef._ object SortedSet { trait Projection[A] extends Set.Projection[A] with SortedSet[A] { @@ -49,7 +50,8 @@ trait SortedSet[A] extends scala.collection.SortedSet[A] with jcl.Set[A] with So override def has(a : A) : Boolean = SortedSet.this.has(a) } - protected class Filter(p : A => Boolean) extends super.Filter(p) with SortedSet.Projection[A] { + protected class Filter(pp : A => Boolean) extends super.Filter(pp) with SortedSet.Projection[A] { + override def p(a : A) = pp(a) def compare(a0 : A, a1 : A) : Int = SortedSet.this.compare(a0, a1); override def filter(p0 : A => Boolean) = SortedSet.this.projection.filter(k => p(k) && p0(k)); } |