From 33ab1a574af0d5f736ab73c5a18cc6a4cb36cbb0 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 27 Dec 2011 22:28:41 -0800 Subject: Tone down insensible-equality warning. Closes SI-5175. --- test/files/neg/checksensible.check | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'test/files/neg') diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check index d45d16165f..0881205bb4 100644 --- a/test/files/neg/checksensible.check +++ b/test/files/neg/checksensible.check @@ -28,12 +28,6 @@ checksensible.scala:27: error: comparing values of types Int and Unit using `==' checksensible.scala:29: error: comparing values of types Int and String using `==' will always yield false 1 == "abc" ^ -checksensible.scala:32: error: String and Int are unrelated: they will most likely never compare equal - "abc" == 1 // warns because the lub of String and Int is Any - ^ -checksensible.scala:33: error: Some[Int] and Int are unrelated: they will most likely never compare equal - Some(1) == 1 // as above - ^ checksensible.scala:38: error: comparing a fresh object using `==' will always yield false new AnyRef == 1 ^ @@ -100,4 +94,4 @@ checksensible.scala:84: error: comparing values of types EqEqRefTest.this.C3 and checksensible.scala:95: error: comparing values of types Unit and Int using `!=' will always yield true while ((c = in.read) != -1) ^ -34 errors found +32 errors found -- cgit v1.2.3 From 82c793a438c7bd802daf96c8b2012f54fbd737ba Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 23 Dec 2011 03:52:03 -0800 Subject: More performance work. Custom versions of collections which methods which operate on 2 or 3 collections. Eliminated most users of zip/zipped. Cleaned up the kinds checking code somewhat. Reduced the number of silent typechecks being performed at named argument sites. --- src/compiler/scala/reflect/internal/Kinds.scala | 223 ++++++++++++++++ .../scala/reflect/internal/SymbolTable.scala | 2 + src/compiler/scala/reflect/internal/TreeInfo.scala | 64 +++-- src/compiler/scala/reflect/internal/Types.scala | 297 ++++++--------------- .../scala/reflect/internal/util/Collections.scala | 138 ++++++++++ src/compiler/scala/tools/nsc/ast/Trees.scala | 13 +- .../scala/tools/nsc/symtab/SymbolTable.scala | 3 +- .../scala/tools/nsc/transform/LiftCode.scala | 2 +- .../tools/nsc/transform/SpecializeTypes.scala | 16 +- .../scala/tools/nsc/transform/UnCurry.scala | 8 +- .../scala/tools/nsc/typechecker/Infer.scala | 80 ++---- .../tools/nsc/typechecker/NamesDefaults.scala | 243 ++++++++--------- .../scala/tools/nsc/typechecker/RefChecks.scala | 10 +- .../tools/nsc/typechecker/SuperAccessors.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 25 +- src/compiler/scala/tools/util/EditDistance.scala | 38 ++- src/library/scala/collection/LinearSeqLike.scala | 6 + test/files/neg/names-defaults-neg.check | 15 +- 18 files changed, 705 insertions(+), 480 deletions(-) create mode 100644 src/compiler/scala/reflect/internal/Kinds.scala create mode 100644 src/compiler/scala/reflect/internal/util/Collections.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/reflect/internal/Kinds.scala b/src/compiler/scala/reflect/internal/Kinds.scala new file mode 100644 index 0000000000..15fcb5f94d --- /dev/null +++ b/src/compiler/scala/reflect/internal/Kinds.scala @@ -0,0 +1,223 @@ +/* NSC -- new scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect +package internal + +import scala.collection.{ mutable, immutable } +import scala.tools.util.StringOps.{ countAsString, countElementsAsString } + +trait Kinds { + self: SymbolTable => + + import definitions._ + + private type SymPair = ((Symbol, Symbol)) // ((Argument, Parameter)) + + case class KindErrors( + arity: List[SymPair] = Nil, + variance: List[SymPair] = Nil, + strictness: List[SymPair] = Nil + ) { + def isEmpty = arity.isEmpty && variance.isEmpty && strictness.isEmpty + + def arityError(syms: SymPair) = copy(arity = arity :+ syms) + def varianceError(syms: SymPair) = copy(variance = variance :+ syms) + def strictnessError(syms: SymPair) = copy(strictness = strictness :+ syms) + + def ++(errs: KindErrors) = KindErrors( + arity ++ errs.arity, + variance ++ errs.variance, + strictness ++ errs.strictness + ) + // @M TODO this method is duplicated all over the place (varianceString) + private def varStr(s: Symbol): String = + if (s.isCovariant) "covariant" + else if (s.isContravariant) "contravariant" + else "invariant"; + + private def qualify(a0: Symbol, b0: Symbol): String = if (a0.toString != b0.toString) "" else { + if((a0 eq b0) || (a0.owner eq b0.owner)) "" + else { + var a = a0; var b = b0 + while (a.owner.name == b.owner.name) { a = a.owner; b = b.owner} + if (a.locationString ne "") " (" + a.locationString.trim + ")" else "" + } + } + private def kindMessage(a: Symbol, p: Symbol)(f: (String, String) => String): String = + f(a+qualify(a,p), p+qualify(p,a)) + + private def strictnessMessage(a: Symbol, p: Symbol) = + kindMessage(a, p)("%s's bounds %s are stricter than %s's declared bounds %s".format( + _, a.info, _, p.info)) + + private def varianceMessage(a: Symbol, p: Symbol) = + kindMessage(a, p)("%s is %s, but %s is declared %s".format(_, varStr(a), _, varStr(p))) + + private def arityMessage(a: Symbol, p: Symbol) = + kindMessage(a, p)("%s has %s, but %s has %s".format( + _, countElementsAsString(a.typeParams.length, "type parameter"), + _, countAsString(p.typeParams.length)) + ) + + def errorMessage(targ: Type, tparam: Symbol): String = ( + (targ+"'s type parameters do not match "+tparam+"'s expected parameters: ") + + (arity map { case (a, p) => arityMessage(a, p) } mkString ", ") + + (variance map { case (a, p) => varianceMessage(a, p) } mkString ", ") + + (strictness map { case (a, p) => strictnessMessage(a, p) } mkString ", ") + ) + } + val NoKindErrors = KindErrors(Nil, Nil, Nil) + + // TODO: this desperately needs to be cleaned up + // plan: split into kind inference and subkinding + // every Type has a (cached) Kind + def kindsConform(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): Boolean = + checkKindBounds0(tparams, targs, pre, owner, false).isEmpty + + /** Check whether `sym1`'s variance conforms to `sym2`'s variance. + * + * If `sym2` is invariant, `sym1`'s variance is irrelevant. Otherwise they must be equal. + */ + private def variancesMatch(sym1: Symbol, sym2: Symbol) = ( + sym2.variance==0 + || sym1.variance==sym2.variance + ) + + /** Check well-kindedness of type application (assumes arities are already checked) -- @M + * + * This check is also performed when abstract type members become concrete (aka a "type alias") -- then tparams.length==1 + * (checked one type member at a time -- in that case, prefix is the name of the type alias) + * + * Type application is just like value application: it's "contravariant" in the sense that + * the type parameters of the supplied type arguments must conform to the type parameters of + * the required type parameters: + * - their bounds must be less strict + * - variances must match (here, variances are absolute, the variance of a type parameter does not influence the variance of its higher-order parameters) + * - @M TODO: are these conditions correct,sufficient&necessary? + * + * e.g. class Iterable[t, m[+x <: t]] --> the application Iterable[Int, List] is okay, since + * List's type parameter is also covariant and its bounds are weaker than <: Int + */ + def checkKindBounds0( + tparams: List[Symbol], + targs: List[Type], + pre: Type, + owner: Symbol, + explainErrors: Boolean + ): List[(Type, Symbol, KindErrors)] = { + + // instantiate type params that come from outside the abstract type we're currently checking + def transform(tp: Type, clazz: Symbol): Type = + tp.asSeenFrom(pre, clazz) + def transformedBounds(p: Symbol, o: Symbol) = + transform(p.info.instantiateTypeParams(tparams, targs).bounds, o) + + // check that the type parameters hkargs to a higher-kinded type conform to the + // expected params hkparams + def checkKindBoundsHK( + hkargs: List[Symbol], + arg: Symbol, + param: Symbol, + paramowner: Symbol, + underHKParams: List[Symbol], + withHKArgs: List[Symbol] + ): KindErrors = { + + var kindErrors: KindErrors = NoKindErrors + def bindHKParams(tp: Type) = tp.substSym(underHKParams, withHKArgs) + // @M sometimes hkargs != arg.typeParams, the symbol and the type may + // have very different type parameters + val hkparams = param.typeParams + def kindCheck(cond: Boolean, f: KindErrors => KindErrors) { + if (!cond) + kindErrors = f(kindErrors) + } + + if (settings.debug.value) { + log("checkKindBoundsHK expected: "+ param +" with params "+ hkparams +" by definition in "+ paramowner) + log("checkKindBoundsHK supplied: "+ arg +" with params "+ hkargs +" from "+ owner) + log("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs) + } + + if (!sameLength(hkargs, hkparams)) { + // Any and Nothing are kind-overloaded + if (arg == AnyClass || arg == NothingClass) NoKindErrors + // shortcut: always set error, whether explainTypesOrNot + else return kindErrors.arityError(arg -> param) + } + else foreach2(hkargs, hkparams) { (hkarg, hkparam) => + if (hkparam.typeParams.isEmpty && hkarg.typeParams.isEmpty) { // base-case: kind * + kindCheck(variancesMatch(hkarg, hkparam), _ varianceError (hkarg -> hkparam)) + // instantiateTypeParams(tparams, targs) + // higher-order bounds, may contain references to type arguments + // substSym(hkparams, hkargs) + // these types are going to be compared as types of kind * + // + // Their arguments use different symbols, but are + // conceptually the same. Could also replace the types by + // polytypes, but can't just strip the symbols, as ordering + // is lost then. + val declaredBounds = transformedBounds(hkparam, paramowner) + val declaredBoundsInst = bindHKParams(declaredBounds) + val argumentBounds = transform(hkarg.info.bounds, owner) + + kindCheck(declaredBoundsInst <:< argumentBounds, _ strictnessError (hkarg -> hkparam)) + + debuglog( + "checkKindBoundsHK base case: " + hkparam + + " declared bounds: " + declaredBounds + + " after instantiating earlier hkparams: " + declaredBoundsInst + "\n" + + "checkKindBoundsHK base case: "+ hkarg + + " has bounds: " + argumentBounds + ) + } + else { + debuglog("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg) + kindErrors ++= checkKindBoundsHK( + hkarg.typeParams, + hkarg, + hkparam, + paramowner, + underHKParams ++ hkparam.typeParams, + withHKArgs ++ hkarg.typeParams + ) + } + if (!explainErrors && !kindErrors.isEmpty) + return kindErrors + } + if (explainErrors) kindErrors + else NoKindErrors + } + + if (settings.debug.value && (tparams.nonEmpty || targs.nonEmpty)) log( + "checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", " + + owner + ", " + explainErrors + ")" + ) + + flatMap2(tparams, targs) { (tparam, targ) => + // Prevent WildcardType from causing kind errors, as typevars may be higher-order + if (targ == WildcardType) Nil else { + // force symbol load for #4205 + targ.typeSymbolDirect.info + // @M must use the typeParams of the *type* targ, not of the *symbol* of targ!! + val tparamsHO = targ.typeParams + if (targ.isHigherKinded || tparam.typeParams.nonEmpty) { + // NOTE: *not* targ.typeSymbol, which normalizes + val kindErrors = checkKindBoundsHK( + tparamsHO, targ.typeSymbolDirect, tparam, + tparam.owner, tparam.typeParams, tparamsHO + ) + if (kindErrors.isEmpty) Nil else { + if (explainErrors) List((targ, tparam, kindErrors)) + // Return as soon as an error is seen if there's nothing to explain. + else return List((NoType, NoSymbol, NoKindErrors)) + } + } + else Nil + } + } + } +} \ No newline at end of file diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 29ac5fe539..5be69e06ad 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -10,9 +10,11 @@ import scala.collection.{ mutable, immutable } import util._ abstract class SymbolTable extends api.Universe + with Collections with Names with Symbols with Types + with Kinds with Scopes with Definitions with Constants diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index 1dc93a7add..14bf36fb47 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -107,7 +107,15 @@ abstract class TreeInfo { @deprecated("Use isExprSafeToInline instead", "2.10.0") def isPureExpr(tree: Tree) = isExprSafeToInline(tree) - def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] = { + def zipMethodParamsAndArgs(params: List[Symbol], args: List[Tree]): List[(Symbol, Tree)] = + mapMethodParamsAndArgs(params, args)((param, arg) => ((param, arg))) + + def mapMethodParamsAndArgs[R](params: List[Symbol], args: List[Tree])(f: (Symbol, Tree) => R): List[R] = { + val b = List.newBuilder[R] + foreachMethodParamAndArg(params, args)((param, arg) => b += f(param, arg)) + b.result + } + def foreachMethodParamAndArg(params: List[Symbol], args: List[Tree])(f: (Symbol, Tree) => Unit): Boolean = { val plen = params.length val alen = args.length def fail() = { @@ -116,27 +124,29 @@ abstract class TreeInfo { " params = " + params + "\n" + " args = " + args + "\n" ) - params zip args + false } - if (plen == alen) params zip args - else if (params.isEmpty) fail + if (plen == alen) foreach2(params, args)(f) + else if (params.isEmpty) return fail else if (isVarArgsList(params)) { val plenInit = plen - 1 if (alen == plenInit) { if (alen == 0) Nil // avoid calling mismatched zip - else params.init zip args + else foreach2(params.init, args)(f) } - else if (alen < plenInit) fail + else if (alen < plenInit) return fail else { - val front = params.init zip (args take plenInit) - val back = args drop plenInit map (a => (params.last, a)) - front ++ back + foreach2(params.init, args take plenInit)(f) + val remainingArgs = args drop plenInit + foreach2(List.fill(remainingArgs.size)(params.last), remainingArgs)(f) } } - else fail - } + else return fail + true + } + /** * Selects the correct parameter list when there are nested applications. * Given Apply(fn, args), args might correspond to any of fn.symbol's parameter @@ -144,22 +154,28 @@ abstract class TreeInfo { * applies: for instance Apply(fn @ Apply(Apply(_, _), _), args) implies args * correspond to the third parameter list. * + * The argument fn is the function part of the apply node being considered. + * * Also accounts for varargs. */ + private def applyMethodParameters(fn: Tree): List[Symbol] = { + val depth = applyDepth(fn) + // There could be applies which go beyond the parameter list(s), + // being applied to the result of the method call. + // !!! Note that this still doesn't seem correct, although it should + // be closer than what it replaced. + if (depth < fn.symbol.paramss.size) fn.symbol.paramss(depth) + else if (fn.symbol.paramss.isEmpty) Nil + else fn.symbol.paramss.last + } + def zipMethodParamsAndArgs(t: Tree): List[(Symbol, Tree)] = t match { - case Apply(fn, args) => - val depth = applyDepth(fn) - // There could be applies which go beyond the parameter list(s), - // being applied to the result of the method call. - // !!! Note that this still doesn't seem correct, although it should - // be closer than what it replaced. - val params = ( - if (depth < fn.symbol.paramss.size) fn.symbol.paramss(depth) - else if (fn.symbol.paramss.isEmpty) Nil - else fn.symbol.paramss.last - ) - zipMethodParamsAndArgs(params, args) - case _ => Nil + case Apply(fn, args) => zipMethodParamsAndArgs(applyMethodParameters(fn), args) + case _ => Nil + } + def foreachMethodParamAndArg(t: Tree)(f: (Symbol, Tree) => Unit): Unit = t match { + case Apply(fn, args) => foreachMethodParamAndArg(applyMethodParameters(fn), args)(f) + case _ => } /** Is symbol potentially a getter of a variable? diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index d7caebbb0a..690f9b7204 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -578,7 +578,7 @@ trait Types extends api.Types { self: SymbolTable => * T.asSeenFrom(ThisType(C), D) (where D is owner of m) * = Int */ - def asSeenFrom(pre: Type, clazz: Symbol): Type = + def asSeenFrom(pre: Type, clazz: Symbol): Type = { if (isTrivial || phase.erasedTypes && pre.typeSymbol != ArrayClass) this else { // scala.tools.nsc.util.trace.when(pre.isInstanceOf[ExistentialType])("X "+this+".asSeenfrom("+pre+","+clazz+" = ") { @@ -594,6 +594,7 @@ trait Types extends api.Types { self: SymbolTable => stopTimer(asSeenFromNanos, start) result } + } /** The info of `sym`, seen as a member of this type. * @@ -1623,29 +1624,40 @@ trait Types extends api.Types { self: SymbolTable => // (this can happen only for erroneous programs). } + private object enterRefs extends TypeMap { + private var tparam: Symbol = _ + + def apply(tp: Type): Type = { + tp match { + case TypeRef(_, sym, args) if args.nonEmpty => + if (settings.debug.value && !sameLength(sym.info.typeParams, args)) + debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + args) + + foreach2(sym.info.typeParams, args) { (tparam1, arg) => + if (arg contains tparam) { + addRef(NonExpansive, tparam, tparam1) + if (arg.typeSymbol != tparam) + addRef(Expansive, tparam, tparam1) + } + } + case _ => + } + mapOver(tp) + } + def enter(tparam0: Symbol, parent: Type) { + this.tparam = tparam0 + this(parent) + } + } + /** Compute initial (one-step) references and set state to `Initializing`. */ private def computeRefs() { refs = Array(Map(), Map()) - for (tparam <- typeSymbol.typeParams) { - val enterRefs = new TypeMap { - def apply(tp: Type): Type = { - tp match { - case TypeRef(_, sym, args) if args.nonEmpty => - if (settings.debug.value && !sameLength(sym.info.typeParams, args)) - debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + args) - - for ((tparam1, arg) <- sym.info.typeParams zip args; if arg contains tparam) { - addRef(NonExpansive, tparam, tparam1) - if (arg.typeSymbol != tparam) - addRef(Expansive, tparam, tparam1) - } - case _ => - } - mapOver(tp) - } + typeSymbol.typeParams foreach { tparam => + parents foreach { p => + enterRefs.enter(tparam, p) } - for (p <- parents) enterRefs(p) } state = Initializing } @@ -3592,9 +3604,9 @@ A type's typeSymbol should never be inspected directly. // val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1) def typeParamsToExistentials(clazz: Symbol, tparams: List[Symbol]): List[Symbol] = { - val eparams = for ((tparam, i) <- tparams.zipWithIndex) yield { - clazz.newExistential(clazz.pos, newTypeName("?"+i)).setInfo(tparam.info.bounds) - } + val eparams = mapWithIndex(tparams)((tparam, i) => + clazz.newExistential(clazz.pos, newTypeName("?"+i)) setInfo tparam.info.bounds) + eparams map (_ substInfo (tparams, eparams)) } @@ -4425,8 +4437,7 @@ A type's typeSymbol should never be inspected directly. case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => assert(sym1 == sym2) pre1 =:= pre2 && - ((args1, args2, sym1.typeParams).zipped forall { - (arg1, arg2, tparam) => + forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) => //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG if (tparam.variance == 0) arg1 =:= arg2 else if (arg1.isInstanceOf[TypeVar]) @@ -4436,7 +4447,7 @@ A type's typeSymbol should never be inspected directly. // also: think what happens if there are embedded typevars? if (tparam.variance < 0) arg1 <:< arg2 else arg2 <:< arg1 else true - }) + } case (et: ExistentialType, _) => et.withTypeVars(isConsistent(_, tp2)) case (_, et: ExistentialType) => @@ -4959,19 +4970,11 @@ A type's typeSymbol should never be inspected directly. // --> thus, cannot be subtypes (Any/Nothing has already been checked) })) - /** True if all three arguments have the same number of elements and - * the function is true for all the triples. - */ - @tailrec final def corresponds3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C], f: (A, B, C) => Boolean): Boolean = { - if (xs1.isEmpty) xs2.isEmpty && xs3.isEmpty - else !xs2.isEmpty && !xs3.isEmpty && f(xs1.head, xs2.head, xs3.head) && corresponds3(xs1.tail, xs2.tail, xs3.tail, f) - } - def isSubArg(t1: Type, t2: Type, variance: Int) = (variance > 0 || t2 <:< t1) && (variance < 0 || t1 <:< t2) def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean = - corresponds3(tps1, tps2, tparams map (_.variance), isSubArg) + corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg) def differentOrNone(tp1: Type, tp2: Type) = if (tp1 eq tp2) NoType else tp1 @@ -5343,7 +5346,6 @@ A type's typeSymbol should never be inspected directly. def solve(tvars: List[TypeVar], tparams: List[Symbol], variances: List[Int], upper: Boolean, depth: Int): Boolean = { - val config = tvars zip (tparams zip variances) def solveOne(tvar: TypeVar, tparam: Symbol, variance: Int) { if (tvar.constr.inst == NoType) { @@ -5352,15 +5354,17 @@ A type's typeSymbol should never be inspected directly. val bound: Type = if (up) tparam.info.bounds.hi else tparam.info.bounds.lo //Console.println("solveOne0(tv, tp, v, b)="+(tvar, tparam, variance, bound)) var cyclic = bound contains tparam - for ((tvar2, (tparam2, variance2)) <- config) { - if (tparam2 != tparam && - ((bound contains tparam2) || - up && (tparam2.info.bounds.lo =:= tparam.tpe) || - !up && (tparam2.info.bounds.hi =:= tparam.tpe))) { + foreach3(tvars, tparams, variances)((tvar2, tparam2, variance2) => { + val ok = (tparam2 != tparam) && ( + (bound contains tparam2) + || up && (tparam2.info.bounds.lo =:= tparam.tpe) + || !up && (tparam2.info.bounds.hi =:= tparam.tpe) + ) + if (ok) { if (tvar2.constr.inst eq null) cyclic = true solveOne(tvar2, tparam2, variance2) } - } + }) if (!cyclic) { if (up) { if (bound.typeSymbol != AnyClass) @@ -5399,9 +5403,7 @@ A type's typeSymbol should never be inspected directly. } // println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info))) - for ((tvar, (tparam, variance)) <- config) - solveOne(tvar, tparam, variance) - + foreach3(tvars, tparams, variances)(solveOne) tvars forall (tvar => tvar.constr.isWithinBounds(tvar.constr.inst)) } @@ -5684,8 +5686,8 @@ A type's typeSymbol should never be inspected directly. case List() => NothingClass.tpe case List(t) => t case ts @ PolyType(tparams, _) :: _ => - val tparams1 = (tparams, matchingBounds(ts, tparams).transpose).zipped map - ((tparam, bounds) => tparam.cloneSymbol.setInfo(glb(bounds, depth))) + val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) => + tparam.cloneSymbol.setInfo(glb(bounds, depth))) PolyType(tparams1, lub0(matchingInstTypes(ts, tparams1))) case ts @ MethodType(params, _) :: rest => MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe)))) @@ -5724,7 +5726,7 @@ A type's typeSymbol should never be inspected directly. if (syms contains NoSymbol) NoSymbol else { val symtypes = - (narrowts, syms).zipped map ((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)) + map2(narrowts, syms)((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType)) if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, decr(depth))) else if (symtypes.tail forall (symtypes.head =:=)) @@ -5829,8 +5831,8 @@ A type's typeSymbol should never be inspected directly. case List() => AnyClass.tpe case List(t) => t case ts @ PolyType(tparams, _) :: _ => - val tparams1 = (tparams, matchingBounds(ts, tparams).transpose).zipped map - ((tparam, bounds) => tparam.cloneSymbol.setInfo(lub(bounds, depth))) + val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) => + tparam.cloneSymbol.setInfo(lub(bounds, depth))) PolyType(tparams1, glbNorm(matchingInstTypes(ts, tparams1), depth)) case ts @ MethodType(params, _) :: rest => MethodType(params, glbNorm(matchingRestypes(ts, params map (_.tpe)), depth)) @@ -5961,38 +5963,39 @@ A type's typeSymbol should never be inspected directly. else if (args exists (arg => isValueClass(arg.typeSymbol))) Some(ObjectClass.tpe) else Some(typeRef(pre, sym, List(lub(args)))) } - } else { - val args = (sym.typeParams, argss.transpose).zipped map { (tparam, as) => - if (depth == 0) { - if (tparam.variance == variance) { - // Take the intersection of the upper bounds of the type parameters - // rather than falling all the way back to "Any", otherwise we end up not - // conforming to bounds. - val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass) - if (bounds0.isEmpty) AnyClass.tpe - else intersectionType(bounds0) - } - else if (tparam.variance == -variance) NothingClass.tpe - else NoType + } + else { + val args = map2(sym.typeParams, argss.transpose) { (tparam, as) => + if (depth == 0) { + if (tparam.variance == variance) { + // Take the intersection of the upper bounds of the type parameters + // rather than falling all the way back to "Any", otherwise we end up not + // conforming to bounds. + val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass) + if (bounds0.isEmpty) AnyClass.tpe + else intersectionType(bounds0) } + else if (tparam.variance == -variance) NothingClass.tpe + else NoType + } + else { + if (tparam.variance == variance) lub(as, decr(depth)) + else if (tparam.variance == -variance) glb(as, decr(depth)) else { - if (tparam.variance == variance) lub(as, decr(depth)) - else if (tparam.variance == -variance) glb(as, decr(depth)) - else { - val l = lub(as, decr(depth)) - val g = glb(as, decr(depth)) - if (l <:< g) l - else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we - // just err on the conservative side, i.e. with a bound that is too high. - // if(!(tparam.info.bounds contains tparam)){ //@M can't deal with f-bounds, see #2251 - - val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l) - capturedParams += qvar - qvar.tpe - } + val l = lub(as, decr(depth)) + val g = glb(as, decr(depth)) + if (l <:< g) l + else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we + // just err on the conservative side, i.e. with a bound that is too high. + // if(!(tparam.info.bounds contains tparam)) //@M can't deal with f-bounds, see #2251 + + val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l) + capturedParams += qvar + qvar.tpe } } } + } if (args contains NoType) None else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args))) } @@ -6077,148 +6080,6 @@ A type's typeSymbol should never be inspected directly. throw new NoCommonType(tps) } - - // TODO: this desperately needs to be cleaned up - // plan: split into kind inference and subkinding - // every Type has a (cached) Kind - def kindsConform(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): Boolean = - checkKindBounds0(tparams, targs, pre, owner, false).isEmpty - - /** Check well-kindedness of type application (assumes arities are already checked) -- @M - * - * This check is also performed when abstract type members become concrete (aka a "type alias") -- then tparams.length==1 - * (checked one type member at a time -- in that case, prefix is the name of the type alias) - * - * Type application is just like value application: it's "contravariant" in the sense that - * the type parameters of the supplied type arguments must conform to the type parameters of - * the required type parameters: - * - their bounds must be less strict - * - variances must match (here, variances are absolute, the variance of a type parameter does not influence the variance of its higher-order parameters) - * - @M TODO: are these conditions correct,sufficient&necessary? - * - * e.g. class Iterable[t, m[+x <: t]] --> the application Iterable[Int, List] is okay, since - * List's type parameter is also covariant and its bounds are weaker than <: Int - */ - def checkKindBounds0(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol, explainErrors: Boolean): List[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] = { - var error = false - - def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz) // instantiate type params that come from outside the abstract type we're currently checking - def transformedBounds(p: Symbol, o: Symbol) = transform(p.info.instantiateTypeParams(tparams, targs).bounds, o) - - /** Check whether `sym1`'s variance conforms to `sym2`'s variance. - * - * If `sym2` is invariant, `sym1`'s variance is irrelevant. Otherwise they must be equal. - */ - def variancesMatch(sym1: Symbol, sym2: Symbol): Boolean = (sym2.variance==0 || sym1.variance==sym2.variance) - - // check that the type parameters hkargs to a higher-kinded type conform to the expected params hkparams - def checkKindBoundsHK( - hkargs: List[Symbol], - arg: Symbol, - param: Symbol, - paramowner: Symbol, - underHKParams: List[Symbol], - withHKArgs: List[Symbol] - ): (List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)]) = { - - def bindHKParams(tp: Type) = tp.substSym(underHKParams, withHKArgs) - // @M sometimes hkargs != arg.typeParams, the symbol and the type may have very different type parameters - val hkparams = param.typeParams - - if (settings.debug.value) { - log("checkKindBoundsHK expected: "+ param +" with params "+ hkparams +" by definition in "+ paramowner) - log("checkKindBoundsHK supplied: "+ arg +" with params "+ hkargs +" from "+ owner) - log("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs) - } - - if (!sameLength(hkargs, hkparams)) { - if (arg == AnyClass || arg == NothingClass) (Nil, Nil, Nil) // Any and Nothing are kind-overloaded - else {error = true; (List((arg, param)), Nil, Nil) } // shortcut: always set error, whether explainTypesOrNot - } - else { - val _arityMismatches = if (explainErrors) new ListBuffer[(Symbol, Symbol)] else null - val _varianceMismatches = if (explainErrors) new ListBuffer[(Symbol, Symbol)] else null - val _stricterBounds = if (explainErrors) new ListBuffer[(Symbol, Symbol)] else null - - def varianceMismatch(a: Symbol, p: Symbol) { if(explainErrors) _varianceMismatches += ((a, p)) else error = true} - def stricterBound(a: Symbol, p: Symbol) { if(explainErrors) _stricterBounds += ((a, p)) else error = true } - def arityMismatches(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _arityMismatches ++= as } - def varianceMismatches(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _varianceMismatches ++= as } - def stricterBounds(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _stricterBounds ++= as } - - for ((hkarg, hkparam) <- hkargs zip hkparams) { - if (hkparam.typeParams.isEmpty && hkarg.typeParams.isEmpty) { // base-case: kind * - if (!variancesMatch(hkarg, hkparam)) - varianceMismatch(hkarg, hkparam) - - // instantiateTypeParams(tparams, targs) --> higher-order bounds may contain references to type arguments - // substSym(hkparams, hkargs) --> these types are going to be compared as types of kind * - // --> their arguments use different symbols, but are conceptually the same - // (could also replace the types by polytypes, but can't just strip the symbols, as ordering is lost then) - val declaredBounds = transformedBounds(hkparam, paramowner) - val declaredBoundsInst = bindHKParams(declaredBounds) - val argumentBounds = transform(hkarg.info.bounds, owner) - if (!(declaredBoundsInst <:< argumentBounds)) - stricterBound(hkarg, hkparam) - - debuglog( - "checkKindBoundsHK base case: " + hkparam + - " declared bounds: " + declaredBounds + - " after instantiating earlier hkparams: " + declaredBoundsInst + "\n" + - "checkKindBoundsHK base case: "+ hkarg + - " has bounds: " + argumentBounds - ) - } - else { - debuglog("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg) - val (am, vm, sb) = checkKindBoundsHK( - hkarg.typeParams, - hkarg, - hkparam, - paramowner, - underHKParams ++ hkparam.typeParams, - withHKArgs ++ hkarg.typeParams - ) - arityMismatches(am) - varianceMismatches(vm) - stricterBounds(sb) - } - if (!explainErrors && error) return (Nil, Nil, Nil) // stop as soon as we encountered an error - } - if (!explainErrors) (Nil, Nil, Nil) - else (_arityMismatches.toList, _varianceMismatches.toList, _stricterBounds.toList) - } - } - - val errors = new ListBuffer[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] - if (settings.debug.value &&(tparams.nonEmpty || targs.nonEmpty)) - log("checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", " + owner + ", " + explainErrors + ")") - - for { - (tparam, targ) <- tparams zip targs - // Prevent WildcardType from causing kind errors, as typevars may be higher-order - if (targ != WildcardType) && (targ.isHigherKinded || tparam.typeParams.nonEmpty) - } { - // @M must use the typeParams of the *type* targ, not of the *symbol* of targ!! - targ.typeSymbolDirect.info // force symbol load for #4205 - val tparamsHO = targ.typeParams - - val (arityMismatches, varianceMismatches, stricterBounds) = ( - // NOTE: *not* targ.typeSymbol, which normalizes - checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) - ) - if (explainErrors) { - if (arityMismatches.nonEmpty || varianceMismatches.nonEmpty || stricterBounds.nonEmpty) { - errors += ((targ, tparam, arityMismatches, varianceMismatches, stricterBounds)) - } - } - else if (error) - return List((NoType, NoSymbol, Nil, Nil, Nil)) - } - - errors.toList - } - // Errors and Diagnostics ----------------------------------------------------- /** A throwable signalling a type error */ diff --git a/src/compiler/scala/reflect/internal/util/Collections.scala b/src/compiler/scala/reflect/internal/util/Collections.scala new file mode 100644 index 0000000000..28a17c7821 --- /dev/null +++ b/src/compiler/scala/reflect/internal/util/Collections.scala @@ -0,0 +1,138 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.reflect.internal.util + +import scala.collection.{ mutable, immutable } +import scala.annotation.tailrec +import mutable.ListBuffer + +/** Profiler driven changes. + */ +trait Collections { + /** True if all three arguments have the same number of elements and + * the function is true for all the triples. + */ + @tailrec final def corresponds3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C]) + (f: (A, B, C) => Boolean): Boolean = ( + if (xs1.isEmpty) xs2.isEmpty && xs3.isEmpty + else !xs2.isEmpty && !xs3.isEmpty && f(xs1.head, xs2.head, xs3.head) && corresponds3(xs1.tail, xs2.tail, xs3.tail)(f) + ) + + final def map2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => C): List[C] = { + val lb = new ListBuffer[C] + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + lb += f(ys1.head, ys2.head) + ys1 = ys1.tail + ys2 = ys2.tail + } + lb.toList + } + final def map3[A, B, C, D](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => D): List[D] = { + if (xs1.isEmpty || xs2.isEmpty || xs3.isEmpty) Nil + else f(xs1.head, xs2.head, xs3.head) :: map3(xs1.tail, xs2.tail, xs3.tail)(f) + } + final def flatMap2[A, B, C](xs1: List[A], xs2: List[B])(f: (A, B) => List[C]): List[C] = { + val lb = new ListBuffer[C] + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + lb ++= f(ys1.head, ys2.head) + ys1 = ys1.tail + ys2 = ys2.tail + } + lb.toList + } + + final def mapWithIndex[A, B](xs: List[A])(f: (A, Int) => B): List[B] = { + val lb = new ListBuffer[B] + var index = 0 + var ys = xs + while (!ys.isEmpty) { + lb += f(ys.head, index) + ys = ys.tail + index += 1 + } + lb.toList + } + final def collectMap2[A, B, C](xs1: List[A], xs2: List[B])(p: (A, B) => Boolean): Map[A, B] = { + if (xs1.isEmpty || xs2.isEmpty) + return Map() + + val buf = immutable.Map.newBuilder[A, B] + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + val x1 = ys1.head + val x2 = ys2.head + if (p(x1, x2)) + buf += ((x1, x2)) + + ys1 = ys1.tail + ys2 = ys2.tail + } + buf.result + } + final def foreach2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Unit): Unit = { + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + f(ys1.head, ys2.head) + ys1 = ys1.tail + ys2 = ys2.tail + } + } + final def foreach3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Unit): Unit = { + var ys1 = xs1 + var ys2 = xs2 + var ys3 = xs3 + while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) { + f(ys1.head, ys2.head, ys3.head) + ys1 = ys1.tail + ys2 = ys2.tail + ys3 = ys3.tail + } + } + final def exists2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + if (f(ys1.head, ys2.head)) + return true + + ys1 = ys1.tail + ys2 = ys2.tail + } + false + } + final def forall2[A, B](xs1: List[A], xs2: List[B])(f: (A, B) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + while (!ys1.isEmpty && !ys2.isEmpty) { + if (!f(ys1.head, ys2.head)) + return false + + ys1 = ys1.tail + ys2 = ys2.tail + } + true + } + final def forall3[A, B, C](xs1: List[A], xs2: List[B], xs3: List[C])(f: (A, B, C) => Boolean): Boolean = { + var ys1 = xs1 + var ys2 = xs2 + var ys3 = xs3 + while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) { + if (!f(ys1.head, ys2.head, ys3.head)) + return false + + ys1 = ys1.tail + ys2 = ys2.tail + ys3 = ys3.tail + } + true + } +} diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index f3eaff8db0..30ee7fc885 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -77,16 +77,17 @@ trait Trees extends reflect.internal.Trees { self: Global => }}) val (edefs, rest) = body span treeInfo.isEarlyDef val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef - val (lvdefs, gvdefs) = evdefs map { + val gvdefs = evdefs map { case vdef @ ValDef(mods, name, tpt, rhs) => - val fld = treeCopy.ValDef( + treeCopy.ValDef( vdef.duplicate, mods, name, atPos(focusPos(vdef.pos)) { TypeTree() setOriginal tpt setPos focusPos(tpt.pos) }, // atPos in case EmptyTree) - val local = treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) - (local, fld) - } unzip - + } + val lvdefs = evdefs map { + case vdef @ ValDef(mods, name, tpt, rhs) => + treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) + } val constrs = { if (constrMods hasFlag TRAIT) { if (body forall treeInfo.isInterfaceMember) List() diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala index 9fbf649525..a47bfda8c1 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala @@ -7,7 +7,6 @@ package scala.tools.nsc package symtab import ast.{Trees, TreePrinters, DocComments} - import util._ -abstract class SymbolTable extends reflect.internal.SymbolTable +abstract class SymbolTable extends reflect.internal.SymbolTable \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index 9404f0f699..720509644b 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -202,7 +202,7 @@ abstract class LiftCode extends Transform with TypingTransformers { /** A method call with a by-name parameter represents escape. */ case Apply(fn, args) if fn.symbol.paramss.nonEmpty => traverse(fn) - for ((param, arg) <- treeInfo.zipMethodParamsAndArgs(tree)) { + treeInfo.foreachMethodParamAndArg(tree) { (param, arg) => if (param.tpe != null && isByNameParamType(param.tpe)) withEscaping(traverse(arg)) else diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 9c4889eba9..bbe803a3fb 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -102,7 +102,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def fromSpecialization(sym: Symbol, args: List[Type]): TypeEnv = { ifDebug(assert(sym.info.typeParams.length == args.length, sym + " args: " + args)) - emptyEnv ++ (sym.info.typeParams zip args filter (kv => isSpecialized(kv._1))) + emptyEnv ++ collectMap2(sym.info.typeParams, args)((k, v) => isSpecialized(k)) } /** Does typeenv `t1` include `t2`? All type variables in `t1` @@ -255,7 +255,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val pre1 = this(pre) // when searching for a specialized class, take care to map all // type parameters that are subtypes of AnyRef to AnyRef - val args1 = (args zip sym.typeParams) map { + val args1 = map2(args, sym.typeParams) { case (tp, orig) if isSpecializedAnyRefSubtype(tp, orig) => AnyRefClass.tpe case (tp, _) => tp } @@ -341,7 +341,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case set :: sets => for (x <- set ; xs <- loop(sets)) yield x :: xs } // zip the keys with each permutation to create a TypeEnv - loop(keys map concreteTypes) map (keys zip _ toMap) + loop(keys map concreteTypes) map (xss => Map(keys zip xss: _*)) } /** Does the given 'sym' need to be specialized in the environment 'env'? @@ -445,7 +445,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def produceTypeParameters(syms: List[Symbol], nowner: Symbol, env: TypeEnv) = { val cloned = for (s <- syms) yield if (!env.contains(s)) s.cloneSymbol(nowner) else env(s).typeSymbol // log("producing type params: " + cloned.map(t => (t, t.tpe.bounds.hi))) - for ((orig, cln) <- syms zip cloned) { + foreach2(syms, cloned) { (orig, cln) => cln.removeAnnotation(SpecializedClass) if (env.contains(orig)) cln modifyInfo (info => TypeBounds(info.bounds.lo, AnyRefClass.tpe)) @@ -889,7 +889,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ def needsSpecialOverride(overriding: Symbol): (Symbol, TypeEnv) = { def checkOverriddenTParams(overridden: Symbol) { - for ((baseTvar, derivedTvar) <- overridden.info.typeParams.zip(overriding.info.typeParams)) { + foreach2(overridden.info.typeParams, overriding.info.typeParams) { (baseTvar, derivedTvar) => val missing = concreteTypes(baseTvar).toSet -- concreteTypes(derivedTvar).toSet if (missing.nonEmpty) { reporter.error(derivedTvar.pos, @@ -1391,9 +1391,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val specMembers = makeSpecializedMembers(tree.symbol.enclClass) ::: (implSpecClasses(body) map localTyper.typed) if (!symbol.isPackageClass) (new CollectMethodBodies)(tree) - val parents1 = currentOwner.info.parents.zipWithIndex.map { - case (tpe, idx) => TypeTree(tpe) setPos parents(idx).pos - } + val parents1 = map2(currentOwner.info.parents, parents)((tpe, parent) => + TypeTree(tpe) setPos parent.pos) + treeCopy.Template(tree, parents1 /*currentOwner.info.parents.map(tpe => TypeTree(tpe) setPos parents.head.pos)*/ , self, diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 90f46206c5..13516037f5 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -461,7 +461,7 @@ abstract class UnCurry extends InfoTransform val args1 = if (isVarArgTypes(formals)) transformVarargs(formals.last.typeArgs.head) else args - (formals, args1).zipped map { (formal, arg) => + map2(formals, args1) { (formal, arg) => if (!isByNameParamType(formal)) { arg } else if (isByNameRef(arg)) { @@ -771,7 +771,7 @@ abstract class UnCurry extends InfoTransform case p => p.symbol.tpe } val forwresult = dd.symbol.tpe.finalResultType - val forwformsyms = (forwformals, flatparams).zipped map ((tp, oldparam) => + val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) => currentClass.newValueParameter(oldparam.symbol.pos, oldparam.name).setInfo(tp) ) def mono = MethodType(forwformsyms, forwresult) @@ -789,7 +789,7 @@ abstract class UnCurry extends InfoTransform // create the tree val forwtree = theTyper.typedPos(dd.pos) { - val locals = (forwsym ARGS, flatparams).zipped map { + val locals = map2(forwsym ARGS, flatparams) { case (_, fp) if !rpsymbols(fp.symbol) => null case (argsym, fp) => Block(Nil, @@ -799,7 +799,7 @@ abstract class UnCurry extends InfoTransform ) ) } - val seqargs = (locals, forwsym ARGS).zipped map { + val seqargs = map2(locals, forwsym ARGS) { case (null, argsym) => Ident(argsym) case (l, _) => l } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 67fa67b0f3..2bd307e31a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -9,7 +9,6 @@ package typechecker import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer import scala.util.control.ControlThrowable -import scala.tools.util.StringOps.{ countAsString, countElementsAsString } import symtab.Flags._ import scala.annotation.tailrec @@ -459,13 +458,14 @@ trait Infer { } val tvars = tparams map freshVar if (isConservativelyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt)) - (tparams, tvars).zipped map ((tparam, tvar) => + map2(tparams, tvars)((tparam, tvar) => instantiateToBound(tvar, varianceInTypes(formals)(tparam))) else tvars map (tvar => WildcardType) } object AdjustedTypeArgs { + val Result = collection.mutable.LinkedHashMap type Result = collection.mutable.LinkedHashMap[Symbol, Option[Type]] def unapply(m: Result): Some[(List[Symbol], List[Type])] = Some(toLists( @@ -508,24 +508,27 @@ trait Infer { * type parameters that are inferred as `scala.Nothing` and that are not covariant in restpe are taken to be undetermined */ def adjustTypeArgs(tparams: List[Symbol], tvars: List[TypeVar], targs: List[Type], restpe: Type = WildcardType): AdjustedTypeArgs.Result = { - @inline def keep(targ: Type, tparam: Symbol) = ( - targ.typeSymbol != NothingClass // definitely not retracting, it's not Nothing! - || (!restpe.isWildcard && (varianceInType(restpe)(tparam) & COVARIANT) != 0)) // occured covariantly --> don't retract - - @inline def adjusted(targ: Type, tvar: TypeVar) = - if (targ.typeSymbol == RepeatedParamClass) - targ.baseType(SeqClass) - else if (targ.typeSymbol == JavaRepeatedParamClass) - targ.baseType(ArrayClass) - // checks opt.virtPatmat directly so one need not run under -Xexperimental to use virtpatmat - else if (targ.typeSymbol.isModuleClass || ((opt.experimental || opt.virtPatmat) && tvar.constr.avoidWiden)) - targ // this infers Foo.type instead of "object Foo" (see also widenIfNecessary) - else - targ.widen + val buf = AdjustedTypeArgs.Result.newBuilder[Symbol, Option[Type]] + + foreach3(tparams, tvars, targs) { (tparam, tvar, targ) => + val retract = ( + targ.typeSymbol == NothingClass // only retract Nothings + && (restpe.isWildcard || (varianceInType(restpe)(tparam) & COVARIANT) == 0) // don't retract covariant occurrences + ) - (tparams, tvars, targs).zipped.map { (tparam, tvar, targ) => - tparam -> (if(keep(targ, tparam)) Some(adjusted(targ, tvar)) else None) - }(collection.breakOut) + // checks opt.virtPatmat directly so one need not run under -Xexperimental to use virtpatmat + buf += ((tparam, + if (retract) None + else Some( + if (targ.typeSymbol == RepeatedParamClass) targ.baseType(SeqClass) + else if (targ.typeSymbol == JavaRepeatedParamClass) targ.baseType(ArrayClass) + // this infers Foo.type instead of "object Foo" (see also widenIfNecessary) + else if (targ.typeSymbol.isModuleClass || ((opt.experimental || opt.virtPatmat) && tvar.constr.avoidWiden)) targ + else targ.widen + ) + )) + } + buf.result } /** Return inferred type arguments, given type parameters, formal parameters, @@ -584,7 +587,7 @@ trait Infer { if (!isFullyDefined(tvar)) tvar.constr.inst = NoType // Then define remaining type variables from argument types. - (argtpes, formals).zipped map { (argtpe, formal) => + map2(argtpes, formals) { (argtpe, formal) => val tp1 = argtpe.deconst.instantiateTypeParams(tparams, tvars) val pt1 = formal.instantiateTypeParams(tparams, tvars) @@ -756,7 +759,8 @@ trait Infer { typesCompatible(reorderArgs(argtpes1, argPos)) ) } - } else { + } + else { // not enough arguments, check if applicable using defaults val missing = missingParams[Type](argtpes0, params, { case NamedType(name, _) => Some(name) @@ -994,39 +998,13 @@ trait Infer { } } - def checkKindBounds(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): List[String] = { - // @M TODO this method is duplicated all over the place (varianceString) - def varStr(s: Symbol): String = - if (s.isCovariant) "covariant" - else if (s.isContravariant) "contravariant" - else "invariant"; - - def qualify(a0: Symbol, b0: Symbol): String = if (a0.toString != b0.toString) "" else { - if((a0 eq b0) || (a0.owner eq b0.owner)) "" - else { - var a = a0; var b = b0 - while (a.owner.name == b.owner.name) { a = a.owner; b = b.owner} - if (a.locationString ne "") " (" + a.locationString.trim + ")" else "" - } + checkKindBounds0(tparams, targs, pre, owner, true) map { + case (targ, tparam, kindErrors) => + kindErrors.errorMessage(targ, tparam) } - - val errors = checkKindBounds0(tparams, targs, pre, owner, true) - val errorMessages = new ListBuffer[String] - errors foreach {case (targ, tparam, arityMismatches, varianceMismatches, stricterBounds) => errorMessages += - (targ+"'s type parameters do not match "+tparam+"'s expected parameters: "+ - (for ((a, p) <- arityMismatches) - yield a+qualify(a,p)+ " has "+countElementsAsString(a.typeParams.length, "type parameter")+", but "+ - p+qualify(p,a)+" has "+countAsString(p.typeParams.length)).toList.mkString(", ") + - (for ((a, p) <- varianceMismatches) - yield a+qualify(a,p)+ " is "+varStr(a)+", but "+ - p+qualify(p,a)+" is declared "+varStr(p)).toList.mkString(", ") + - (for ((a, p) <- stricterBounds) - yield a+qualify(a,p)+"'s bounds "+a.info+" are stricter than "+ - p+qualify(p,a)+"'s declared bounds "+p.info).toList.mkString(", ")) - } - errorMessages.toList } + /** Substitute free type variables `undetparams` of polymorphic argument * expression `tree`, given two prototypes `strictPt`, and `lenientPt`. * `strictPt` is the first attempt prototype where type parameters diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 8611fafe52..a8dfea02ec 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -260,7 +260,7 @@ trait NamesDefaults { self: Analyzer => */ def argValDefs(args: List[Tree], paramTypes: List[Type], blockTyper: Typer): List[ValDef] = { val context = blockTyper.context - val symPs = (args, paramTypes).zipped map ((arg, tpe) => { + val symPs = map2(args, paramTypes)((arg, tpe) => { val byName = isByNameParamType(tpe) val (argTpe, repeated) = if (isScalaRepeatedParamType(tpe)) arg match { @@ -276,7 +276,7 @@ trait NamesDefaults { self: Analyzer => s.setInfo(valType) (context.scope.enter(s), byName, repeated) }) - (symPs, args).zipped map { + map2(symPs, args) { case ((sym, byName, repeated), arg) => val body = if (byName) { @@ -326,13 +326,15 @@ trait NamesDefaults { self: Analyzer => reorderArgsInv(formals, argPos), blockTyper) // refArgs: definition-site order again - val refArgs = (reorderArgs(valDefs, argPos), formals).zipped map ((vDef, tpe) => { + val refArgs = map2(reorderArgs(valDefs, argPos), formals)((vDef, tpe) => { val ref = gen.mkAttributedRef(vDef.symbol) atPos(vDef.pos.focus) { // for by-name parameters, the local value is a nullary function returning the argument - if (isByNameParamType(tpe)) Apply(ref, List()) - else if (isScalaRepeatedParamType(tpe)) Typed(ref, Ident(tpnme.WILDCARD_STAR)) - else ref + tpe.typeSymbol match { + case ByNameParamClass => Apply(ref, Nil) + case RepeatedParamClass => Typed(ref, Ident(tpnme.WILDCARD_STAR)) + case _ => ref + } } }) // cannot call blockTyper.typedBlock here, because the method expr might be partially applied only @@ -340,7 +342,7 @@ trait NamesDefaults { self: Analyzer => res.setPos(res.pos.makeTransparent) val block = Block(stats ::: valDefs, res).setType(res.tpe).setPos(tree.pos) context.namedApplyBlockInfo = - Some((block, NamedApplyInfo(qual, targs, vargss ::: List(refArgs), blockTyper))) + Some((block, NamedApplyInfo(qual, targs, vargss :+ refArgs, blockTyper))) block } } @@ -430,6 +432,80 @@ trait NamesDefaults { self: Analyzer => } } else NoSymbol } + + private def savingUndeterminedTParams[T](context: Context)(fn: List[Symbol] => T): T = { + val savedParams = context.extractUndetparams() + val savedReporting = context.reportAmbiguousErrors + + context.reportAmbiguousErrors = false + try fn(savedParams) + finally { + context.reportAmbiguousErrors = savedReporting + //@M note that we don't get here when an ambiguity was detected (during the computation of res), + // as errorTree throws an exception + context.undetparams = savedParams + } + } + + /** Fast path for ambiguous assignment check. + */ + private def isNameInScope(context: Context, name: Name) = ( + context.enclosingContextChain exists (ctx => + (ctx.scope.lookupEntry(name) != null) + || (ctx.owner.rawInfo.member(name) != NoSymbol) + ) + ) + + /** A full type check is very expensive; let's make sure there's a name + * somewhere which could potentially be ambiguous before we go that route. + */ + private def isAmbiguousAssignment(typer: Typer, param: Symbol, arg: Tree) = { + import typer.context + isNameInScope(context, param.name) && { + // for named arguments, check whether the assignment expression would + // typecheck. if it does, report an ambiguous error. + val paramtpe = param.tpe.cloneInfo(param) + // replace type parameters by wildcard. in the below example we need to + // typecheck (x = 1) with wildcard (not T) so that it succeeds. + // def f[T](x: T) = x + // var x = 0 + // f(x = 1) << "x = 1" typechecks with expected type WildcardType + savingUndeterminedTParams(context) { udp => + val subst = new SubstTypeMap(udp, udp map (_ => WildcardType)) { + override def apply(tp: Type): Type = super.apply(tp match { + case TypeRef(_, ByNameParamClass, x :: Nil) => x + case _ => tp + }) + } + // This throws an exception which is caught in `tryTypedApply` (as it + // uses `silent`) - unfortunately, tryTypedApply recovers from the + // exception if you use errorTree(arg, ...) and conforms is allowed as + // a view (see tryImplicit in Implicits) because it tries to produce a + // new qualifier (if the old one was P, the new one will be + // conforms.apply(P)), and if that works, it pretends nothing happened. + // + // To make sure tryTypedApply fails, we would like to pass EmptyTree + // instead of arg, but can't do that because eventually setType(ErrorType) + // is called, and EmptyTree can only be typed NoType. Thus we need to + // disable conforms as a view... + try typer.silent(_.typed(arg, subst(paramtpe))) match { + case t: Tree => !t.isErroneous + case _ => false + } + catch { + // `silent` only catches and returns TypeErrors which are not + // CyclicReferences. Fix for #3685 + case cr @ CyclicReference(sym, _) => + (sym.name == param.name) && sym.accessedOrSelf.isVariable && { + context.error(sym.pos, + "variable definition needs type because '%s' is used as a named argument in its body.".format(sym.name)) + typer.infer.setError(arg) + true + } + } + } + } + } /** * Removes name assignments from args. Additionally, returns an array mapping @@ -439,71 +515,38 @@ trait NamesDefaults { self: Analyzer => * after named ones. */ def removeNames(typer: Typer)(args: List[Tree], params: List[Symbol]): (List[Tree], Array[Int]) = { - import typer.infer.errorTree - - // maps indicies from (order written by user) to (order of definition) - val argPos = (new Array[Int](args.length)) map (x => -1) + import typer.context + // maps indices from (order written by user) to (order of definition) + val argPos = Array.fill(args.length)(-1) var positionalAllowed = true - val namelessArgs = for ((arg, index) <- (args.zipWithIndex)) yield arg match { - case a @ AssignOrNamedArg(Ident(name), rhs) => - val (pos, newName) = paramPos(params, name) - newName.foreach(n => { - typer.context.unit.deprecationWarning(arg.pos, "the parameter name "+ name +" has been deprecated. Use "+ n +" instead.") - }) - if (pos == -1) { - if (positionalAllowed) { - argPos(index) = index - // prevent isNamed from being true when calling doTypedApply recursively, - // treat the arg as an assignment of type Unit - Assign(a.lhs, rhs).setPos(arg.pos) - } else { - errorTree(arg, "unknown parameter name: "+ name) - } - } else if (argPos contains pos) { - errorTree(arg, "parameter specified twice: "+ name) - } else { - // for named arguments, check whether the assignment expression would - // typecheck. if it does, report an ambiguous error. - val param = params(pos) - val paramtpe = params(pos).tpe.cloneInfo(param) - // replace type parameters by wildcard. in the below example we need to - // typecheck (x = 1) with wildcard (not T) so that it succeeds. - // def f[T](x: T) = x - // var x = 0 - // f(x = 1) << "x = 1" typechecks with expected type WildcardType - val udp = typer.context.extractUndetparams() - val subst = new SubstTypeMap(udp, udp map (_ => WildcardType)) { - override def apply(tp: Type): Type = tp match { - case TypeRef(_, ByNameParamClass, List(arg)) => super.apply(arg) - case _ => super.apply(tp) + val namelessArgs = mapWithIndex(args) { (arg, index) => + def fail(msg: String) = typer.infer.errorTree(arg, msg) + arg match { + case arg @ AssignOrNamedArg(Ident(name), rhs) => + def matchesName(param: Symbol) = !param.isSynthetic && ( + (param.name == name) || (param.deprecatedParamName match { + case Some(`name`) => + context.unit.deprecationWarning(arg.pos, + "the parameter name "+ name +" has been deprecated. Use "+ param.name +" instead.") + true + case _ => false + }) + ) + val pos = params indexWhere matchesName + if (pos == -1) { + if (positionalAllowed) { + argPos(index) = index + // prevent isNamed from being true when calling doTypedApply recursively, + // treat the arg as an assignment of type Unit + Assign(arg.lhs, rhs) setPos arg.pos } + else fail("unknown parameter name: " + name) } - val reportAmbiguousErrors = typer.context.reportAmbiguousErrors - typer.context.reportAmbiguousErrors = false - - var variableNameClash = false - val typedAssign = try { - typer.silent(_.typed(arg, subst(paramtpe))) - } catch { - // `silent` only catches and returns TypeErrors which are not - // CyclicReferences. Fix for #3685 - case cr @ CyclicReference(sym, info) if sym.name == param.name => - if (sym.isVariable || sym.isGetter && sym.accessed.isVariable) { - // named arg not allowed - variableNameClash = true - typer.context.error(sym.pos, - "%s definition needs %s because '%s' is used as a named argument in its body.".format( - "variable", // "method" - "type", // "result type" - sym.name - ) - ) - typer.infer.setError(arg) - } - else cr - } - - def applyNamedArg = { + else if (argPos contains pos) + fail("parameter specified twice: " + name) + else if (isAmbiguousAssignment(typer, params(pos), arg)) + fail("reference to " + name + " is ambiguous; it is both a method parameter and a variable in scope.") + else { // if the named argument is on the original parameter // position, positional after named is allowed. if (index != pos) @@ -511,63 +554,13 @@ trait NamesDefaults { self: Analyzer => argPos(index) = pos rhs } - - val res = typedAssign match { - case _: TypeError => applyNamedArg - - case t: Tree => - if (t.isErroneous && !variableNameClash) { - applyNamedArg - } else if (t.isErroneous) { - t // name clash with variable. error was already reported above. - } else { - // This throws an exception which is caught in `tryTypedApply` (as it - // uses `silent`) - unfortunately, tryTypedApply recovers from the - // exception if you use errorTree(arg, ...) and conforms is allowed as - // a view (see tryImplicit in Implicits) because it tries to produce a - // new qualifier (if the old one was P, the new one will be - // conforms.apply(P)), and if that works, it pretends nothing happened. - // - // To make sure tryTypedApply fails, we would like to pass EmptyTree - // instead of arg, but can't do that because eventually setType(ErrorType) - // is called, and EmptyTree can only be typed NoType. Thus we need to - // disable conforms as a view... - errorTree(arg, "reference to "+ name +" is ambiguous; it is both, a parameter\n"+ - "name of the method and the name of a variable currently in scope.") - } - } - - typer.context.reportAmbiguousErrors = reportAmbiguousErrors - //@M note that we don't get here when an ambiguity was detected (during the computation of res), - // as errorTree throws an exception - typer.context.undetparams = udp - res - } - case _ => - argPos(index) = index - if (positionalAllowed) arg - else errorTree(arg, "positional after named argument.") - } - (namelessArgs, argPos) - } - - /** - * Returns - * - the position of the parameter named `name` - * - optionally, if `name` is @deprecatedName, the new name - */ - def paramPos(params: List[Symbol], name: Name): (Int, Option[Name]) = { - var i = 0 - var rest = params - while (!rest.isEmpty) { - val p = rest.head - if (!p.isSynthetic) { - if (p.name == name) return (i, None) - if (p.deprecatedParamName == Some(name)) return (i, Some(p.name)) + case _ => + argPos(index) = index + if (positionalAllowed) arg + else fail("positional after named argument.") } - i += 1 - rest = rest.tail } - (-1, None) + + (namelessArgs, argPos) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 59a1a254c6..ace38bb4cb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -410,8 +410,6 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } } - - def checkOverrideTypes() { if (other.isAliasType) { //if (!member.typeParams.isEmpty) (1.5) @MAT @@ -420,14 +418,14 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R // overrideError("may not override parameterized type"); // @M: substSym - if( !(sameLength(member.typeParams, other.typeParams) && (self.memberType(member).substSym(member.typeParams, other.typeParams) =:= self.memberType(other))) ) // (1.6) + if( !(sameLength(member.typeParams, other.typeParams) && (memberTp.substSym(member.typeParams, other.typeParams) =:= otherTp)) ) // (1.6) overrideTypeError(); - } else if (other.isAbstractType) { + } + else if (other.isAbstractType) { //if (!member.typeParams.isEmpty) // (1.7) @MAT // overrideError("may not be parameterized"); - - val memberTp = self.memberType(member) val otherTp = self.memberInfo(other) + if (!(otherTp.bounds containsType memberTp)) { // (1.7.1) overrideTypeError(); // todo: do an explaintypes with bounds here explainTypes(_.bounds containsType _, otherTp, memberTp) diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index c9991614e4..a0ef2f5e2e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -43,7 +43,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } private def transformArgs(params: List[Symbol], args: List[Tree]) = { - treeInfo.zipMethodParamsAndArgs(params, args) map { case (param, arg) => + treeInfo.mapMethodParamsAndArgs(params, args) { (param, arg) => if (isByNameParamType(param.tpe)) withInvalidOwner { checkPackedConforms(transform(arg), param.tpe.typeArgs.head) } else transform(arg) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a4c00e9f89..6b6b905e16 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1207,7 +1207,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (preSuperVals.isEmpty && preSuperStats.nonEmpty) debugwarn("Wanted to zip empty presuper val list with " + preSuperStats) else - (preSuperStats, preSuperVals).zipped map { case (ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe } + map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) case _ => if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments") @@ -1959,7 +1959,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (argpts.lengthCompare(numVparams) != 0) errorTree(fun, "wrong number of parameters; expected = " + argpts.length) else { - val vparamSyms = (fun.vparams, argpts).zipped map { (vparam, argpt) => + val vparamSyms = map2(fun.vparams, argpts) { (vparam, argpt) => if (vparam.tpt.isEmpty) { vparam.tpt.tpe = if (isFullyDefined(argpt)) argpt @@ -2195,15 +2195,16 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def needsInstantiation(tparams: List[Symbol], formals: List[Type], args: List[Tree]) = { def isLowerBounded(tparam: Symbol) = !tparam.info.bounds.lo.typeSymbol.isBottomClass - (formals, args).zipped exists { + exists2(formals, args) { case (formal, Function(vparams, _)) => (vparams exists (_.tpt.isEmpty)) && vparams.length <= MaxFunctionArity && (formal baseType FunctionClass(vparams.length) match { case TypeRef(_, _, formalargs) => - (formalargs, vparams).zipped.exists ((formalarg, vparam) => - vparam.tpt.isEmpty && (tparams exists (formalarg contains))) && - (tparams forall isLowerBounded) + ( exists2(formalargs, vparams)((formal, vparam) => + vparam.tpt.isEmpty && (tparams exists formal.contains)) + && (tparams forall isLowerBounded) + ) case _ => false }) @@ -2460,7 +2461,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } else { assert(!inPatternMode(mode)) // this case cannot arise for patterns val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt) - val strictTargs = (lenientTargs, tparams).zipped map ((targ, tparam) => + val strictTargs = map2(lenientTargs, tparams)((targ, tparam) => if (targ == WildcardType) tparam.tpe else targ) //@M TODO: should probably be .tpeHK var remainingParams = paramTypes def typedArgToPoly(arg: Tree, formal: Type): Tree = { //TR TODO: cleanup @@ -2477,7 +2478,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } arg1 } - val args1 = (args, formals).zipped map typedArgToPoly + val args1 = map2(args, formals)(typedArgToPoly) if (args1 exists (_.tpe.isError)) errTree else { debuglog("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info)) //debug @@ -2926,7 +2927,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { override val typeParams = tparams map (_.symbol) val typeSkolems = typeParams map (_.newTypeSkolem setInfo this) // Replace the symbols - def substitute() = (tparams, typeSkolems).zipped map (_ setSymbol _) + def substitute() = map2(tparams, typeSkolems)(_ setSymbol _) override def complete(sym: Symbol) { // The info of a skolem is the skolemized info of the // actual type parameter of the skolem @@ -3972,7 +3973,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } val argtypes = args1 map (_.tpe) - (args, tparams).zipped foreach { (arg, tparam) => arg match { + foreach2(args, tparams)((arg, tparam) => arg match { // note: can't use args1 in selector, because Bind's got replaced case Bind(_, _) => if (arg.symbol.isAbstractType) @@ -3981,7 +3982,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { lub(List(arg.symbol.info.bounds.lo, tparam.info.bounds.lo.subst(tparams, argtypes))), glb(List(arg.symbol.info.bounds.hi, tparam.info.bounds.hi.subst(tparams, argtypes)))) case _ => - }} + }) val original = treeCopy.AppliedTypeTree(tree, tpt1, args1) val result = TypeTree(appliedType(tpt1.tpe, argtypes)) setOriginal original if(tpt1.tpe.isInstanceOf[PolyType]) // did the type application (performed by appliedType) involve an unchecked beta-reduction? @@ -4079,7 +4080,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case UnApply(fun, args) => val fun1 = typed(fun) val tpes = formalTypes(unapplyTypeList(fun.symbol, fun1.tpe), args.length) - val args1 = (args, tpes).zipped map typedPattern + val args1 = map2(args, tpes)(typedPattern) treeCopy.UnApply(tree, fun1, args1) setType pt case ArrayValue(elemtpt, elems) => diff --git a/src/compiler/scala/tools/util/EditDistance.scala b/src/compiler/scala/tools/util/EditDistance.scala index b705a1eac4..5067dce384 100644 --- a/src/compiler/scala/tools/util/EditDistance.scala +++ b/src/compiler/scala/tools/util/EditDistance.scala @@ -30,23 +30,37 @@ object EditDistance { if (m == 0) return n val d = Array.ofDim[Int](n + 1, m + 1) - 0 to n foreach (x => d(x)(0) = x) - 0 to m foreach (x => d(0)(x) = x) + var i = 0 + val max = math.max(m, n) + while (i <= max) { + if (i <= n) + d(i)(0) = i + if (i <= m) + d(0)(i) = i + i += 1 + } + i = 1 - for (i <- 1 to n ; s_i = s(i - 1) ; j <- 1 to m) { - val t_j = t(j - 1) - val cost = if (s_i == t_j) 0 else 1 + while (i <= n) { + val s_i = s(i - 1) + var j = 1 + while (j <= m) { + val t_j = t(j - 1) + val cost = if (s_i == t_j) 0 else 1 - val c1 = d(i - 1)(j) + 1 - val c2 = d(i)(j - 1) + 1 - val c3 = d(i - 1)(j - 1) + cost + val c1 = d(i - 1)(j) + 1 + val c2 = d(i)(j - 1) + 1 + val c3 = d(i - 1)(j - 1) + cost - d(i)(j) = c1 min c2 min c3 + d(i)(j) = c1 min c2 min c3 - if (transpositions) { - if (i > 1 && j > 1 && s(i - 1) == t(j - 2) && s(i - 2) == t(j - 1)) - d(i)(j) = d(i)(j) min (d(i - 2)(j - 2) + cost) + if (transpositions) { + if (i > 1 && j > 1 && s(i - 1) == t(j - 2) && s(i - 2) == t(j - 1)) + d(i)(j) = d(i)(j) min (d(i - 2)(j - 2) + cost) + } + j += 1 } + i += 1 } d(n)(m) diff --git a/src/library/scala/collection/LinearSeqLike.scala b/src/library/scala/collection/LinearSeqLike.scala index 75c1edac66..ceb980ff80 100644 --- a/src/library/scala/collection/LinearSeqLike.scala +++ b/src/library/scala/collection/LinearSeqLike.scala @@ -13,6 +13,7 @@ import generic._ import mutable.ListBuffer import immutable.List import scala.util.control.Breaks._ +import annotation.tailrec /** A template trait for linear sequences of type `LinearSeq[A]`. * @@ -69,4 +70,9 @@ trait LinearSeqLike[+A, +Repr <: LinearSeqLike[A, Repr]] extends SeqLike[A, Repr xs } } + + @tailrec override final def corresponds[B](that: GenSeq[B])(p: (A,B) => Boolean): Boolean = { + if (this.isEmpty) that.isEmpty + else that.nonEmpty && p(head, that.head) && (tail corresponds that.tail)(p) + } } diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index 03e44f745d..01ef54e0ea 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -10,8 +10,7 @@ names-defaults-neg.scala:5: error: type mismatch; names-defaults-neg.scala:8: error: positional after named argument. test1(b = "(*", 23) ^ -names-defaults-neg.scala:13: error: reference to x is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:13: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. test2(x = 1) ^ names-defaults-neg.scala:15: error: not found: value c @@ -26,8 +25,7 @@ names-defaults-neg.scala:17: error: not found: value m names-defaults-neg.scala:18: error: not found: value m test7 { m = 1 } // no named arguments in argument block ^ -names-defaults-neg.scala:19: error: reference to x is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:19: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. test8(x = 1) ^ names-defaults-neg.scala:22: error: parameter specified twice: a @@ -118,8 +116,7 @@ names-defaults-neg.scala:93: error: parameter specified twice: b names-defaults-neg.scala:98: error: unknown parameter name: m f3818(y = 1, m = 1) ^ -names-defaults-neg.scala:131: error: reference to var2 is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:131: error: reference to var2 is ambiguous; it is both a method parameter and a variable in scope. delay(var2 = 40) ^ names-defaults-neg.scala:134: error: missing parameter type for expanded function ((x$1) => a = x$1) @@ -146,15 +143,13 @@ names-defaults-neg.scala:164: error: variable definition needs type because 'x' names-defaults-neg.scala:167: error: variable definition needs type because 'x' is used as a named argument in its body. def u6 { var x = u.f(x = "32") } ^ -names-defaults-neg.scala:170: error: reference to x is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:170: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. def u9 { var x: Int = u.f(x = 1) } ^ names-defaults-neg.scala:177: error: variable definition needs type because 'x' is used as a named argument in its body. class u15 { var x = u.f(x = 1) } ^ -names-defaults-neg.scala:180: error: reference to x is ambiguous; it is both, a parameter -name of the method and the name of a variable currently in scope. +names-defaults-neg.scala:180: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. class u18 { var x: Int = u.f(x = 1) } ^ one warning found -- cgit v1.2.3 From 451e1dc2da16c1bb5a7a59488865df9294eeaf3e Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 2 Jan 2012 06:41:31 -0800 Subject: Added -Xlog-implicit-conversions. New command line option prints a message whenever the compiler inserts an implicit conversion. Implicit parameters are not under consideration here, since the primary motivation is to make it easy to inspect your code for unintentional conversions, since they can have dramatic performance implications. class A { def f(xs: Array[Byte]) = xs.size def g(xs: Array[Byte]) = xs.length } % scalac -Xlog-implicit-conversions logImplicits.scala logImplicits.scala:2: applied implicit conversion from xs.type to ?{val size: ?} = implicit def byteArrayOps(xs: Array[Byte]): scala.collection.mutable.ArrayOps[Byte] def f(xs: Array[Byte]) = xs.size ^ --- .../scala/tools/nsc/CompilationUnits.scala | 3 +++ src/compiler/scala/tools/nsc/CompileServer.scala | 4 ++-- src/compiler/scala/tools/nsc/Driver.scala | 8 +++---- src/compiler/scala/tools/nsc/Global.scala | 2 +- src/compiler/scala/tools/nsc/ScalaDoc.scala | 8 +++---- src/compiler/scala/tools/nsc/doc/DocFactory.scala | 2 +- .../scala/tools/nsc/interactive/REPL.scala | 4 ++-- .../scala/tools/nsc/reporters/Reporter.scala | 23 ++++++++++++++------ .../scala/tools/nsc/reporters/ReporterTimer.scala | 2 -- .../scala/tools/nsc/settings/ScalaSettings.scala | 1 + .../scala/tools/nsc/typechecker/Typers.scala | 14 ++++++++++-- test/files/neg/logImplicits.check | 19 ++++++++++++++++ test/files/neg/logImplicits.flags | 1 + test/files/neg/logImplicits.scala | 25 ++++++++++++++++++++++ 14 files changed, 91 insertions(+), 25 deletions(-) create mode 100644 test/files/neg/logImplicits.check create mode 100644 test/files/neg/logImplicits.flags create mode 100644 test/files/neg/logImplicits.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 470207fd35..940d115b2f 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -74,6 +74,9 @@ trait CompilationUnits { self: Global => * It is empty up to phase 'icode'. */ val icode: LinkedHashSet[icodes.IClass] = new LinkedHashSet + + def echo(pos: Position, msg: String) = + reporter.echo(pos, msg) def error(pos: Position, msg: String) = reporter.error(pos, msg) diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index b10ac78ac7..6393ade146 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -136,9 +136,9 @@ class StandardCompileServer extends SocketServer { } if (command.shouldStopWithInfo) - reporter.info(null, command.getInfoMessage(newGlobal(newSettings, reporter)), true) + reporter.echo(command.getInfoMessage(newGlobal(newSettings, reporter))) else if (command.files.isEmpty) - reporter.info(null, command.usageMsg, true) + reporter.echo(command.usageMsg) else { if (isCompilerReusable) { info("[Reusing existing Global instance.]") diff --git a/src/compiler/scala/tools/nsc/Driver.scala b/src/compiler/scala/tools/nsc/Driver.scala index db95c1442b..0c52954a0b 100644 --- a/src/compiler/scala/tools/nsc/Driver.scala +++ b/src/compiler/scala/tools/nsc/Driver.scala @@ -24,8 +24,8 @@ abstract class Driver { protected def doCompile(compiler: Global) { if (command.files.isEmpty) { - reporter.info(null, command.usageMsg, true) - reporter.info(null, compiler.pluginOptionsHelp, true) + reporter.echo(command.usageMsg) + reporter.echo(compiler.pluginOptionsHelp) } else { val run = new compiler.Run() run compile command.files @@ -40,14 +40,14 @@ abstract class Driver { settings = command.settings if (settings.version.value) { - reporter.info(null, versionMsg, true) + reporter.echo(versionMsg) } else if (processSettingsHook()) { val compiler = newCompiler() try { if (reporter.hasErrors) reporter.flush() else if (command.shouldStopWithInfo) - reporter.info(null, command.getInfoMessage(compiler), true) + reporter.echo(command.getInfoMessage(compiler)) else doCompile(compiler) } catch { diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 2dd32e355b..c388a62644 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -159,7 +159,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb // nearly every trait really must go. For now using globalError. def error(msg: String) = globalError(msg) def globalError(msg: String) = reporter.error(NoPosition, msg) - def inform(msg: String) = reporter.info(NoPosition, msg, true) + def inform(msg: String) = reporter.echo(msg) def warning(msg: String) = if (opt.fatalWarnings) globalError(msg) else reporter.warning(NoPosition, msg) diff --git a/src/compiler/scala/tools/nsc/ScalaDoc.scala b/src/compiler/scala/tools/nsc/ScalaDoc.scala index a9330b053b..4fa2cc71e5 100644 --- a/src/compiler/scala/tools/nsc/ScalaDoc.scala +++ b/src/compiler/scala/tools/nsc/ScalaDoc.scala @@ -30,17 +30,17 @@ class ScalaDoc { def hasFiles = command.files.nonEmpty || docSettings.uncompilableFiles.nonEmpty if (docSettings.version.value) - reporter.info(null, versionMsg, true) + reporter.echo(versionMsg) else if (docSettings.Xhelp.value) - reporter.info(null, command.xusageMsg, true) + reporter.echo(command.xusageMsg) else if (docSettings.Yhelp.value) - reporter.info(null, command.yusageMsg, true) + reporter.echo(command.yusageMsg) else if (docSettings.showPlugins.value) reporter.warning(null, "Plugins are not available when using Scaladoc") else if (docSettings.showPhases.value) reporter.warning(null, "Phases are restricted when using Scaladoc") else if (docSettings.help.value || !hasFiles) - reporter.info(null, command.usageMsg, true) + reporter.echo(command.usageMsg) else try { if (docSettings.target.value == "msil") msilLibPath foreach (x => docSettings.assemrefs.value += (pathSeparator + x)) diff --git a/src/compiler/scala/tools/nsc/doc/DocFactory.scala b/src/compiler/scala/tools/nsc/doc/DocFactory.scala index 5a510803ed..9a025b0d14 100644 --- a/src/compiler/scala/tools/nsc/doc/DocFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/DocFactory.scala @@ -96,7 +96,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor val documentError: PartialFunction[Throwable, Unit] = { case NoCompilerRunException => - reporter.info(NoPosition, "No documentation generated with unsucessful compiler run", false) + reporter.info(null, "No documentation generated with unsucessful compiler run", false) case _: ClassNotFoundException => () } diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala index 81d4faa36e..1d78cc6e1c 100644 --- a/src/compiler/scala/tools/nsc/interactive/REPL.scala +++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala @@ -37,7 +37,7 @@ object REPL { reporter = new ConsoleReporter(settings) val command = new CompilerCommand(args.toList, settings) if (command.settings.version.value) - reporter.info(null, versionMsg, true) + reporter.echo(versionMsg) else { try { object compiler extends Global(command.settings, reporter) { @@ -48,7 +48,7 @@ object REPL { return } if (command.shouldStopWithInfo) { - reporter.info(null, command.getInfoMessage(compiler), true) + reporter.echo(command.getInfoMessage(compiler)) } else { run(compiler) } diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index 12306606e4..f19a285d7c 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -47,14 +47,23 @@ abstract class Reporter { finally incompleteHandler = saved } - var cancelled = false - def hasErrors = ERROR.count > 0 || cancelled - def hasWarnings = WARNING.count > 0 + var cancelled = false + def hasErrors = ERROR.count > 0 || cancelled + def hasWarnings = WARNING.count > 0 - def info(pos: Position, msg: String, force: Boolean) { info0(pos, msg, INFO, force) } - def warning(pos: Position, msg: String ) { withoutTruncating(info0(pos, msg, WARNING, false)) } - def error(pos: Position, msg: String ) { withoutTruncating(info0(pos, msg, ERROR, false)) } - def incompleteInputError(pos: Position, msg: String ) { + /** For sending a message which should not be labeled as a warning/error, + * but also shouldn't require -verbose to be visible. + */ + def echo(msg: String): Unit = info(NoPosition, msg, true) + def echo(pos: Position, msg: String): Unit = info(pos, msg, true) + + /** Informational messages, suppressed unless -verbose or force=true. */ + def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force) + + /** Warnings and errors. */ + def warning(pos: Position, msg: String): Unit = withoutTruncating(info0(pos, msg, WARNING, false)) + def error(pos: Position, msg: String): Unit = withoutTruncating(info0(pos, msg, ERROR, false)) + def incompleteInputError(pos: Position, msg: String): Unit = { if (incompleteHandled) incompleteHandler(pos, msg) else error(pos, msg) } diff --git a/src/compiler/scala/tools/nsc/reporters/ReporterTimer.scala b/src/compiler/scala/tools/nsc/reporters/ReporterTimer.scala index 800af55861..f55d0684c8 100644 --- a/src/compiler/scala/tools/nsc/reporters/ReporterTimer.scala +++ b/src/compiler/scala/tools/nsc/reporters/ReporterTimer.scala @@ -13,8 +13,6 @@ import scala.tools.util.AbstractTimer * timings. */ class ReporterTimer(reporter: Reporter) extends AbstractTimer { - def issue(msg: String, duration: Long) = reporter.info(null, "[" + msg + " in " + duration + "ms]", false) - } diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 7fcfb6fc6d..a712f4cba2 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -67,6 +67,7 @@ trait ScalaSettings extends AbsScalaSettings val future = BooleanSetting ("-Xfuture", "Turn on future language features.") val genPhaseGraph = StringSetting ("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot.", "") val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more detail on why some implicits are not applicable.") + val logImplicitConv = BooleanSetting ("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.") val maxClassfileName = IntSetting ("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, Some((72, 255)), _ => None) val Xmigration28 = BooleanSetting ("-Xmigration", "Warn about constructs whose behavior may have changed between 2.7 and 2.8.") val nouescape = BooleanSetting ("-Xno-uescape", "Disable handling of \\u unicode escapes.") diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9991836344..a7ad140fc1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -969,7 +969,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { return typed(Select(tree, meth), mode, pt) } if (coercion != EmptyTree) { - debuglog("inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe) + def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe + if (settings.logImplicitConv.value) + unit.echo(tree.pos, msg) + + debuglog(msg) return newTyper(context.makeImplicit(context.reportAmbiguousErrors)).typed( new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt) } @@ -1056,7 +1060,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } inferView(qual, qual.tpe, searchTemplate, true) match { case EmptyTree => qual - case coercion => typedQualifier(atPos(qual.pos)(new ApplyImplicitView(coercion, List(qual)))) + case coercion => + if (settings.logImplicitConv.value) + unit.echo(qual.pos, + "applied implicit conversion from %s to %s = %s".format( + qual.tpe, searchTemplate, coercion.symbol.defString)) + + typedQualifier(atPos(qual.pos)(new ApplyImplicitView(coercion, List(qual)))) } } else qual diff --git a/test/files/neg/logImplicits.check b/test/files/neg/logImplicits.check new file mode 100644 index 0000000000..d98422dacb --- /dev/null +++ b/test/files/neg/logImplicits.check @@ -0,0 +1,19 @@ +logImplicits.scala:2: applied implicit conversion from xs.type to ?{val size: ?} = implicit def byteArrayOps(xs: Array[Byte]): scala.collection.mutable.ArrayOps[Byte] + def f(xs: Array[Byte]) = xs.size + ^ +logImplicits.scala:7: applied implicit conversion from String("abc") to ?{val map: ?} = implicit def augmentString(x: String): scala.collection.immutable.StringOps + def f = "abc" map (_ + 1) + ^ +logImplicits.scala:15: inferred view from String("abc") to Int = C.this.convert:(p: String("abc"))Int + math.max(122, x: Int) + ^ +logImplicits.scala:19: applied implicit conversion from Int(1) to ?{val ->: ?} = implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] + def f = (1 -> 2) + "c" + ^ +logImplicits.scala:19: applied implicit conversion from (Int, Int) to ?{val +: ?} = implicit def any2stringadd(x: Any): scala.runtime.StringAdd + def f = (1 -> 2) + "c" + ^ +logImplicits.scala:22: error: class Un needs to be abstract, since method unimplemented is not defined +class Un { + ^ +one error found diff --git a/test/files/neg/logImplicits.flags b/test/files/neg/logImplicits.flags new file mode 100644 index 0000000000..97e5ae94ef --- /dev/null +++ b/test/files/neg/logImplicits.flags @@ -0,0 +1 @@ +-Xlog-implicit-conversions \ No newline at end of file diff --git a/test/files/neg/logImplicits.scala b/test/files/neg/logImplicits.scala new file mode 100644 index 0000000000..fb5dd8a025 --- /dev/null +++ b/test/files/neg/logImplicits.scala @@ -0,0 +1,25 @@ +class A { + def f(xs: Array[Byte]) = xs.size + def g(xs: Array[Byte]) = xs.length +} + +class B { + def f = "abc" map (_ + 1) +} + +object C { + final val x = "abc" + + implicit def convert(p: x.type): Int = 123 + + math.max(122, x: Int) +} + +class D { + def f = (1 -> 2) + "c" +} + +class Un { + // forcing post-typer failure, since we're only interested in the output from the above + def unimplemented: Int +} \ No newline at end of file -- cgit v1.2.3 From 6975b4888da9b56e2c06d45da8f483f2e33a102b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 4 Jan 2012 07:05:19 +0100 Subject: Closes SI-5354. The reason why the test case compiled without error is pretty devious: When checking the `Foo.x' implicit, a CyclicReference error occurs which causes the alternative to be discarded. Why a CylicReference? Because the inferencer tries to decide whether the owner of `z` is a subclass of the owner od `x`. To do this, it computed the info of the owner of `z1`, which is not complete because no result type for `f1` was given. Hence a CyclicReference error. The fix is twofold: (1) We make isNonBottomSubClass smarter so that it always returns false if the symbol in question is not a type; hence the info need not be computed. (2) It's dubious to swallow CyclicReference errors anywhere, but I deemed it too risky to propagate them. But at least the CyclicReference is now logged if -Ylog-implicit is true. This hopefully spares future maintainers the same detective work I had to go through when digging this out. --- src/compiler/scala/reflect/internal/Symbols.scala | 15 +++++++++------ src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 9 ++++++++- test/files/neg/t5354.check | 7 +++++++ test/files/neg/t5354.scala | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 test/files/neg/t5354.check create mode 100644 test/files/neg/t5354.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 0c57f0c43a..e629b0ed43 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -1244,12 +1244,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def isNestedIn(that: Symbol): Boolean = owner == that || owner != NoSymbol && (owner isNestedIn that) - - /** Is this class symbol a subclass of that symbol? */ - final def isNonBottomSubClass(that: Symbol): Boolean = ( - (this eq that) || this.isError || that.isError || - info.baseTypeIndex(that) >= 0 - ) + + /** Is this class symbol a subclass of that symbol, + * and is this class symbol also different from Null or Nothing? */ + def isNonBottomSubClass(that: Symbol): Boolean = false /** Overridden in NullClass and NothingClass for custom behavior. */ @@ -2226,6 +2224,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => super.info_=(tp) } + final override def isNonBottomSubClass(that: Symbol): Boolean = ( + (this eq that) || this.isError || that.isError || + info.baseTypeIndex(that) >= 0 + ) + override def reset(completer: Type) { super.reset(completer) tpePeriod = NoPeriod diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index d54cb248cf..77dde88a80 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -816,7 +816,14 @@ trait Implicits { val newPending = undoLog undo { is filterNot (alt => alt == i || { try improves(i, alt) - catch { case e: CyclicReference => true } + catch { + case e: CyclicReference => + if (printInfers) { + println(i+" discarded because cyclic reference occurred") + e.printStackTrace() + } + true + } }) } rankImplicits(newPending, i :: acc) diff --git a/test/files/neg/t5354.check b/test/files/neg/t5354.check new file mode 100644 index 0000000000..e47cecb5fe --- /dev/null +++ b/test/files/neg/t5354.check @@ -0,0 +1,7 @@ +t5354.scala:9: error: ambiguous implicit values: + both method x123 in package foo of type => foo.Bippy + and method z of type => foo.Bippy + match expected type foo.Bippy + implicitly[Bippy] + ^ +one error found diff --git a/test/files/neg/t5354.scala b/test/files/neg/t5354.scala new file mode 100644 index 0000000000..99b5650155 --- /dev/null +++ b/test/files/neg/t5354.scala @@ -0,0 +1,15 @@ +package object foo { + implicit def x123: Bippy = new Bippy("x") +} +package foo { + class Bippy(override val toString: String){ } + class Dingus { + def f1 = { + implicit def z: Bippy = new Bippy("z") + implicitly[Bippy] + } + } + object Test extends App { + println(new Dingus().f1) + } +} -- cgit v1.2.3 From 97f20afa4d35e629d0926a2e2cc0f20fd7f32d33 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 5 Jan 2012 08:59:27 -0800 Subject: Optimization in Constructors. Reworked some old code which was far too expensive for the job it was performing. --- .../scala/tools/nsc/transform/Constructors.scala | 30 ++++++++-------------- test/files/neg/t1960.check | 2 +- 2 files changed, 12 insertions(+), 20 deletions(-) (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 342c298e1d..e03f329577 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -254,26 +254,18 @@ abstract class Constructors extends Transform with ast.TreeDSL { for ((accSym, accBody) <- outerAccessors) if (mustbeKept(accSym)) accessTraverser.traverse(accBody) - // Conflicting symbol list from parents: see bug #1960. - // It would be better to mangle the constructor parameter name since - // it can only be used internally, but I think we need more robust name - // mangling before we introduce more of it. - val parentSymbols = Map((for { - p <- impl.parents - if p.symbol.isTrait - sym <- p.symbol.info.nonPrivateMembers - if sym.isGetter && !sym.isOuterField - } yield sym.name -> p): _*) - // Initialize all parameters fields that must be kept. - val paramInits = - for (acc <- paramAccessors if mustbeKept(acc)) yield { - if (parentSymbols contains acc.name) - unit.error(acc.pos, "parameter '%s' requires field but conflicts with %s in '%s'".format( - acc.name, acc.name, parentSymbols(acc.name))) - - copyParam(acc, parameter(acc)) - } + val paramInits = paramAccessors filter mustbeKept map { acc => + // Check for conflicting symbol amongst parents: see bug #1960. + // It would be better to mangle the constructor parameter name since + // it can only be used internally, but I think we need more robust name + // mangling before we introduce more of it. + val conflict = clazz.info.nonPrivateMember(acc.name) filter (s => s.isGetter && !s.isOuterField && s.enclClass.isTrait) + if (conflict ne NoSymbol) + unit.error(acc.pos, "parameter '%s' requires field but conflicts with %s".format(acc.name, conflict.fullLocationString)) + + copyParam(acc, parameter(acc)) + } /** Return a single list of statements, merging the generic class constructor with the * specialized stats. The original statements are retyped in the current class, and diff --git a/test/files/neg/t1960.check b/test/files/neg/t1960.check index dabf53f126..5238141c4e 100644 --- a/test/files/neg/t1960.check +++ b/test/files/neg/t1960.check @@ -1,4 +1,4 @@ -t1960.scala:5: error: parameter 'p' requires field but conflicts with p in 'TBase' +t1960.scala:5: error: parameter 'p' requires field but conflicts with method p in trait TBase class Aclass (p: Int) extends TBase { def g() { f(p) } } ^ one error found -- cgit v1.2.3 From 3192048a4bfb59966f93bb87a3c4f6b7ccfc80b2 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 5 Jan 2012 00:24:59 -0800 Subject: Error message improvement. % scalac files/neg/t5357.scala files/neg/t5357.scala:5: error: '=>' expected but ':' found. case A: N => 1 ^ one error found That's uggo! Now it says: % scalac files/neg/t5357.scala files/neg/t5357.scala:5: error: Pattern variables must start with a lower-case letter. (SLS 8.1.1.) case A: N => 1 ^ one error found --- src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 13 +++++++++---- test/files/neg/t5357.check | 4 ++++ test/files/neg/t5357.scala | 9 +++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 test/files/neg/t5357.check create mode 100644 test/files/neg/t5357.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 5881821ab3..d7bfcfc314 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1745,11 +1745,16 @@ self => * }}} */ def pattern1(): Tree = pattern2() match { - case p @ Ident(name) if treeInfo.isVarPattern(p) && in.token == COLON => - atPos(p.pos.startOrPoint, in.skipToken()) { Typed(p, compoundType()) } - case p => - p + case p @ Ident(name) if in.token == COLON => + if (treeInfo.isVarPattern(p)) + atPos(p.pos.startOrPoint, in.skipToken())(Typed(p, compoundType())) + else { + syntaxError(in.offset, "Pattern variables must start with a lower-case letter. (SLS 8.1.1.)") + p + } + case p => p } + /** {{{ * Pattern2 ::= varid [ @ Pattern3 ] * | Pattern3 diff --git a/test/files/neg/t5357.check b/test/files/neg/t5357.check new file mode 100644 index 0000000000..3385559071 --- /dev/null +++ b/test/files/neg/t5357.check @@ -0,0 +1,4 @@ +t5357.scala:5: error: Pattern variables must start with a lower-case letter. (SLS 8.1.1.) + case A: N => 1 + ^ +one error found diff --git a/test/files/neg/t5357.scala b/test/files/neg/t5357.scala new file mode 100644 index 0000000000..369a5568a4 --- /dev/null +++ b/test/files/neg/t5357.scala @@ -0,0 +1,9 @@ +trait M + +case class N() extends M { + def mytest(x: M) = x match { + case A: N => 1 + case _ => 0 + } +} + -- cgit v1.2.3 From dd14b6a9b8b3355fae847f7fc8c1fc7d41babaa5 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 6 Jan 2012 07:29:20 -0800 Subject: TypeVar tracing. % scala -Dscalac.debug.tvar scala> class Foo[CC[X] <: Traversable[X]] { def bar[T](xs: CC[T]) = xs.head } defined class Foo scala> new Foo bar List(1,2,3) [ create] ?CC ( In Foo[CC[X] <: Traversable[X]] ) [ create] ?CC ( In Foo[CC[X] <: Traversable[X]] ) [ setInst] Nothing ( In Foo[CC[X] <: Traversable[X]], CC=Nothing ) [ create] ?CC ( In Foo[CC[X] <: Traversable[X]] ) [ create] ?T ( In Foo[CC[X] <: Traversable[X]]#bar[T] ) [ create] ?A ( In List#apply[A] ) [ create] ?A ( In List#apply[A] ) [ setInst] Int ( In List#apply[A], A=Int ) [ create] ?CC ( In Foo[CC[X] <: Traversable[X]] ) [ create] ?T ( In Foo[CC[X] <: Traversable[X]]#bar[T] ) [ create] ?CC ( In Foo[CC[X] <: Traversable[X]] ) [ applyArgs] ?CC ( In Foo[CC[X] <: Traversable[X]], apply args ?T to CC ) [ setInst] List ( In Foo[CC[X] <: Traversable[X]], CC=List ) [ setInst] Int ( In Foo[CC[X] <: Traversable[X]]#bar[T], T=Int ) res0: Int = 1 Also, I gave TypeVar some polymorphism. Review by @moors. --- .../scala/reflect/internal/Importers.scala | 2 +- src/compiler/scala/reflect/internal/Types.scala | 245 ++++++++++++++------- test/files/neg/names-defaults-neg.check | 2 +- 3 files changed, 163 insertions(+), 86 deletions(-) (limited to 'test/files/neg') diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index 6683778671..38f808cef9 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -167,7 +167,7 @@ trait Importers { self: SymbolTable => case from.AntiPolyType(pre, targs) => AntiPolyType(importType(pre), targs map importType) case x: from.TypeVar => - new TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol) + TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol) case from.NotNullType(tpe) => NotNullType(importType(tpe)) case from.AnnotatedType(annots, tpe, selfsym) => diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 6b5ba05c6d..b26c78677d 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -87,6 +87,7 @@ trait Types extends api.Types { self: SymbolTable => private final def decr(depth: Int) = if (depth == AnyDepth) AnyDepth else depth - 1 private final val printLubs = sys.props contains "scalac.debug.lub" + private final val traceTypeVars = sys.props contains "scalac.debug.tvar" /** In case anyone wants to turn off lub verification without reverting anything. */ private final val verifyLubs = true @@ -2431,51 +2432,56 @@ A type's typeSymbol should never be inspected directly. // but pattern-matching returned the original constr0 (a bug) // now, pattern-matching returns the most recent constr object TypeVar { - // encapsulate suspension so we can automatically link the suspension of cloned - // typevars to their original if this turns out to be necessary -/* - def Suspension = new Suspension - class Suspension { - private val suspended = mutable.HashSet[TypeVar]() - def suspend(tv: TypeVar): Unit = { - tv.suspended = true - suspended += tv - } - def resumeAll(): Unit = { - for (tv <- suspended) { - tv.suspended = false + @inline final def trace[T](action: String, msg: => String)(value: T): T = { + if (traceTypeVars) { + val s = msg match { + case "" => "" + case str => "( " + str + " )" } - suspended.clear() + Console.err.println("[%10s] %-25s%s".format(action, value, s)) } + value } -*/ - def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr)) - def apply(origin: Type, constr: TypeConstraint) = new TypeVar(origin, constr, List(), List()) - // See pos/tcpoly_infer_implicit_tuple_wrapper for the test which - // fails if I initialize the type constraint with the type parameter - // bounds. It seems that in that instance it interferes with the - // inference. Thus, the isHigherOrderTypeParameter condition. - def apply(tparam: Symbol) = { - val constr = ( - if (tparam.isAbstractType && tparam.typeParams.nonEmpty) { - // Force the info of a higher-order tparam's parameters. - // Otherwise things don't end well. See SI-5359. - val info = tparam.info - if (info.bounds exists (t => t.typeSymbol.isHigherOrderTypeParameter)) { - log("TVar(" + tparam + ") receives empty constraint due to higher order type parameter in bounds " + info.bounds) - new TypeConstraint - } - else { - log("TVar(" + tparam + ") constraint initialized with bounds " + info.bounds) - new TypeConstraint(info.bounds) - } - } + + /** Create a new TypeConstraint based on the given symbol. + */ + private def deriveConstraint(tparam: Symbol): TypeConstraint = { + // Force the info of a higher-order tparam's parameters. + // Otherwise things don't end well. See SI-5359. However + // we can't force all info, so we have to discriminate + // carefully. + val isHigher = tparam.isAbstractType && tparam.typeParams.nonEmpty + // See pos/tcpoly_infer_implicit_tuple_wrapper for the test which + // fails if I initialize the type constraint with the type parameter + // bounds. It seems that in that instance it interferes with the + // inference. Thus, the isHigherOrderTypeParameter condition. + val isExclude = isHigher && tparam.info.bounds.exists(_.typeSymbol.isHigherOrderTypeParameter) + + def message = "" + tparam.name + " in " + tparam.owner + ( + if (isExclude) ", empty due to higher order type parameter in bounds" + else "" + ) + /*TypeVar.trace[TypeConstraint]("constr", message)*/( + if (isHigher && !isExclude) new TypeConstraint(tparam.info.bounds) else new TypeConstraint ) - new TypeVar(tparam.tpeHK, constr, Nil, tparam.typeParams) } - def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]) = - new TypeVar(origin, constr, args, params) + def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr)) + def apply(origin: Type, constr: TypeConstraint): TypeVar = apply(origin, constr, Nil, Nil) + def apply(tparam: Symbol): TypeVar = apply(tparam.tpeHK, deriveConstraint(tparam), Nil, tparam.typeParams) + + /** This is the only place TypeVars should be instantiated. + */ + def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]): TypeVar = { + val tv = ( + if (args.isEmpty && params.isEmpty) new TypeVar(origin, constr) + else if (args.size == params.size) new AppliedTypeVar(origin, constr, params zip args) + else if (args.isEmpty) new HKTypeVar(origin, constr, params) + else throw new TypeError("Invalid TypeVar construction: " + ((origin, constr, args, params))) + ) + + trace("create", "In " + tv.originLocation)(tv) + } } // TODO: I don't really know why this happens -- maybe because @@ -2502,22 +2508,53 @@ A type's typeSymbol should never be inspected directly. tp.typeSymbol ) + /** Precondition: params.nonEmpty. (args.nonEmpty enforced structurally.) + */ + class HKTypeVar( + _origin: Type, + _constr: TypeConstraint, + override val params: List[Symbol] + ) extends TypeVar(_origin, _constr) { + + require(params.nonEmpty, this) + override def isHigherKinded = true + override protected def typeVarString = params.map(_.name).mkString("[", ", ", "]=>" + originName) + } + + /** Precondition: zipped params/args nonEmpty. (Size equivalence enforced structurally.) + */ + class AppliedTypeVar( + _origin: Type, + _constr: TypeConstraint, + zippedArgs: List[(Symbol, Type)] + ) extends TypeVar(_origin, _constr) { + + require(zippedArgs.nonEmpty, this) + + override def params: List[Symbol] = zippedArgs map (_._1) + override def typeArgs: List[Type] = zippedArgs map (_._2) + + override protected def typeVarString = ( + zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]") + ) + } + /** A class representing a type variable: not used after phase `typer`. * * A higher-kinded TypeVar has params (Symbols) and typeArgs (Types). * A TypeVar with nonEmpty typeArgs can only be instantiated by a higher-kinded * type that can be applied to those args. A TypeVar is much like a TypeRef, * except it has special logic for equality and subtyping. + * + * Precondition for this class, enforced structurally: args.isEmpty && params.isEmpty. */ class TypeVar( val origin: Type, - val constr0: TypeConstraint, - override val typeArgs: List[Type], - override val params: List[Symbol] + val constr0: TypeConstraint ) extends Type { - // params are needed to keep track of variance (see mapOverArgs in SubstMap) - assert(typeArgs.isEmpty || sameLength(typeArgs, params), - "%s / params=%s / args=%s".format(origin, params, typeArgs)) + override def params: List[Symbol] = Nil + override def typeArgs: List[Type] = Nil + override def isHigherKinded = false /** The constraint associated with the variable */ var constr = constr0 @@ -2525,7 +2562,38 @@ A type's typeSymbol should never be inspected directly. /** The variable's skolemization level */ val level = skolemizationLevel - + + /** Two occurrences of a higher-kinded typevar, e.g. `?CC[Int]` and `?CC[String]`, correspond to + * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`. + * + * `constr` for `?CC` only tracks type constructors anyway, + * so when `?CC[Int] <:< List[Int]` and `?CC[String] <:< Iterable[String]` + * `?CC's` hibounds contains List and Iterable. + */ + def applyArgs(newArgs: List[Type]): TypeVar = ( + if (newArgs.isEmpty && typeArgs.isEmpty) + this + else if (newArgs.size == params.size) { + val tv = TypeVar(origin, constr, newArgs, params) + TypeVar.trace("applyArgs", "In " + originLocation + ", apply args " + newArgs.mkString(", ") + " to " + originName)(tv) + } + else + throw new TypeError("Invalid type application in TypeVar: " + params + ", " + newArgs) + ) + // newArgs.length may differ from args.length (could've been empty before) + // + // !!! @PP - I need an example of this, since this exception never triggers + // even though I am requiring the size match. + // + // example: when making new typevars, you start out with C[A], then you replace C by ?C, which should yield ?C[A], then A by ?A, ?C[?A] + // we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver) + // TypeVars get applied to different arguments over time (in asSeenFrom) + // -- see pos/tcpoly_infer_implicit_tuplewrapper.scala + // thus: make new TypeVar's for every application of a TV to args, + // inference may generate several TypeVar's for a single type parameter that must be inferred, + // only one of them is in the set of tvars that need to be solved, but + // they share the same TypeConstraint instance + // When comparing to types containing skolems, remember the highest level // of skolemization. If that highest level is higher than our initial // skolemizationLevel, we can't re-use those skolems as the solution of this @@ -2536,26 +2604,6 @@ A type's typeSymbol should never be inspected directly. private var encounteredHigherLevel = false private def shouldRepackType = enableTypeVarExperimentals && encounteredHigherLevel - /** Two occurrences of a higher-kinded typevar, e.g. `?CC[Int]` and `?CC[String]`, correspond to - * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`. - * - * `constr` for `?CC` only tracks type constructors anyway, - * so when `?CC[Int] <:< List[Int]` and `?CC[String] <:< Iterable[String]` - * `?CC's` hibounds contains List and Iterable. - */ - def applyArgs(newArgs: List[Type]): TypeVar = - if (newArgs.isEmpty) this // SubstMap relies on this (though this check is redundant when called from appliedType...) - else TypeVar(origin, constr, newArgs, params) // @M TODO: interaction with undoLog?? - // newArgs.length may differ from args.length (could've been empty before) - // example: when making new typevars, you start out with C[A], then you replace C by ?C, which should yield ?C[A], then A by ?A, ?C[?A] - // we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver) - // TypeVars get applied to different arguments over time (in asSeenFrom) - // -- see pos/tcpoly_infer_implicit_tuplewrapper.scala - // thus: make new TypeVar's for every application of a TV to args, - // inference may generate several TypeVar's for a single type parameter that must be inferred, - // only one of them is in the set of tvars that need to be solved, but - // they share the same TypeConstraint instance - // // invariant: before mutating constr, save old state in undoLog // (undoLog is used to reset constraints to avoid piling up unrelated ones) @@ -2564,7 +2612,8 @@ A type's typeSymbol should never be inspected directly. undoLog record this // if we were compared against later typeskolems, repack the existential, // because skolems are only compatible if they were created at the same level - constr.inst = if (shouldRepackType) repackExistential(tp) else tp + val res = if (shouldRepackType) repackExistential(tp) else tp + constr.inst = TypeVar.trace("setInst", "In " + originLocation + ", " + originName + "=" + res)(res) } def addLoBound(tp: Type, isNumericBound: Boolean = false) { @@ -2641,11 +2690,10 @@ A type's typeSymbol should never be inspected directly. * type parameter we're trying to infer (the result will be sanity-checked later). */ def unifyFull(tpe: Type) = { - // Since the alias/widen variations are often no-ops, this - // keenly collects them in a Set to avoid redundant tests. + // The alias/widen variations are often no-ops. val tpes = ( - if (isLowerBound) Set(tpe, tpe.widen, tpe.dealias, tpe.widen.dealias) - else Set(tpe) + if (isLowerBound) List(tpe, tpe.widen, tpe.dealias, tpe.widen.dealias).distinct + else List(tpe) ) tpes exists { tp => val lhs = if (isLowerBound) tp.typeArgs else typeArgs @@ -2745,33 +2793,54 @@ A type's typeSymbol should never be inspected directly. || !containsSkolemAboveLevel(tp) // side-effects tracking boolean || enableTypeVarExperimentals // -Xexperimental: always say we're relatable, track consequences ) - override val isHigherKinded = typeArgs.isEmpty && params.nonEmpty - override def normalize: Type = + override def normalize: Type = ( if (constr.instValid) constr.inst // get here when checking higher-order subtyping of the typevar by itself // TODO: check whether this ever happens? else if (isHigherKinded) typeFun(params, applyArgs(params map (_.typeConstructor))) else super.normalize - + ) override def typeSymbol = origin.typeSymbol override def isStable = origin.isStable override def isVolatile = origin.isVolatile + private def tparamsOfSym(sym: Symbol) = sym.info match { + case PolyType(tparams, _) if tparams.nonEmpty => + tparams map (_.defString) mkString("[", ",", "]") + case _ => "" + } + def originName = { + val name = origin.typeSymbolDirect.decodedName + if (name startsWith "_$") origin.typeSymbol.decodedName else name + } + def originLocation = { + val sym = origin.typeSymbolDirect + val owner = sym.owner + val clazz = owner.enclClass + val ownsString = ( + if (owner.isMethod) "#" + owner.name + tparamsOfSym(owner) + else if (owner.isAbstractType) "#" + owner.defString + else "" + ) + clazz.decodedName + tparamsOfSym(clazz) + ownsString + } private def levelString = if (settings.explaintypes.value) level else "" + protected def typeVarString = originName override def safeToString = ( - if (constr eq null) "TVar<%s,constr=null>".format(origin) - else if (constr.inst eq null) "TVar<%s,constr.inst=null>".format(origin) - else if (constr.inst eq NoType) "?" + levelString + origin + typeArgsString(this) - else "" + constr.inst + if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>" + else if (constr.inst ne NoType) "" + constr.inst + else "?" + levelString + originName ) override def kind = "TypeVar" def cloneInternal = { // cloning a suspended type variable when it's suspended will cause the clone // to never be resumed with the current implementation - assert(!suspended) - TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params? + assert(!suspended, this) + TypeVar.trace("clone", originLocation)( + TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params? + ) } } @@ -3326,10 +3395,18 @@ A type's typeSymbol should never be inspected directly. tc } - override def toString = - (loBounds map (_.safeToString)).mkString("[ _>:(", ",", ") ") + - (hiBounds map (_.safeToString)).mkString("| _<:(", ",", ") ] _= ") + - inst.safeToString + override def toString = { + val boundsStr = ( + if (loBounds.isEmpty && hiBounds.isEmpty) "[]" + else { + val lostr = if (loBounds.isEmpty) "" else loBounds map (_.safeToString) mkString("_>:(", ", ", ")") + val histr = if (hiBounds.isEmpty) "" else hiBounds map (_.safeToString) mkString("_<:(", ", ", ")") + List(lostr, histr) filterNot (_ == "") mkString ("[", " | ", "]") + } + ) + if (inst eq NoType) boundsStr + else boundsStr + " _= " + inst.safeToString + } } trait AnnotationFilter extends TypeMap { diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index 01ef54e0ea..01bbe2de4e 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -83,7 +83,7 @@ names-defaults-neg.scala:76: error: no type parameters for method test4: (x: T[T --- because --- argument expression's type is not compatible with formal parameter type; found : List[Int] - required: ?T[?T[List[?T[X forSome { type X }]]]] + required: ?T Error occurred in an application involving default arguments. test4() ^ -- cgit v1.2.3 From 2064372659156e2637eac4d092321818a30abb41 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 2 Jan 2012 11:48:22 -0800 Subject: Better error reporting regarding main methods. Now notices most things which look like main methods and says something useful if they aren't usable as entry points. Closes SI-4749. --- .../scala/reflect/internal/Definitions.scala | 17 +++--- .../scala/reflect/internal/transform/Erasure.scala | 2 +- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 68 ++++++++++++++-------- test/files/neg/main1.check | 20 +++---- test/files/neg/t4749.check | 28 +++++++++ test/files/neg/t4749.flags | 1 + test/files/neg/t4749.scala | 44 ++++++++++++++ 7 files changed, 137 insertions(+), 43 deletions(-) create mode 100644 test/files/neg/t4749.check create mode 100644 test/files/neg/t4749.flags create mode 100644 test/files/neg/t4749.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index d3af8e2623..cc6ba32f9c 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -443,15 +443,11 @@ trait Definitions extends reflect.api.StandardDefinitions { def isStringAddition(sym: Symbol) = sym == String_+ || sym == StringAdd_+ def isArrowAssoc(sym: Symbol) = ArrowAssocClass.tpe.decls.toList contains sym - // The given symbol is a method with the right signature to be a runnable java program. - def isJavaMainMethod(sym: Symbol) = sym.tpe match { - case MethodType(param :: Nil, restpe) if restpe.typeSymbol == UnitClass => - param.tpe match { - case TypeRef(_, ArrayClass, arg :: Nil) => arg.typeSymbol == StringClass - case _ => false - } - case _ => false - } + // The given symbol is a method with the right name and signature to be a runnable java program. + def isJavaMainMethod(sym: Symbol) = (sym.name == nme.main) && (sym.info match { + case MethodType(p :: Nil, restpe) => isArrayOfSymbol(p.tpe, StringClass) && restpe.typeSymbol == UnitClass + case _ => false + }) // The given class has a main method. def hasJavaMainMethod(sym: Symbol): Boolean = (sym.tpe member nme.main).alternatives exists isJavaMainMethod @@ -595,6 +591,9 @@ trait Definitions extends reflect.api.StandardDefinitions { def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg)) def iteratorOfType(tp: Type) = appliedType(IteratorClass.typeConstructor, List(tp)) + lazy val StringArray = arrayType(StringClass.tpe) + lazy val ObjectArray = arrayType(ObjectClass.tpe) + def ClassType(arg: Type) = if (phase.erasedTypes || forMSIL) ClassClass.tpe else appliedType(ClassClass.typeConstructor, List(arg)) diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala index c8cb6febfa..1e0ba17e15 100644 --- a/src/compiler/scala/reflect/internal/transform/Erasure.scala +++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala @@ -75,7 +75,7 @@ trait Erasure { case TypeRef(pre, sym, args) => if (sym == ArrayClass) if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe - else if (args.head.typeSymbol.isBottomClass) arrayType(ObjectClass.tpe) + else if (args.head.typeSymbol.isBottomClass) ObjectArray else typeRef(apply(pre), sym, args map this) else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass) else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 03d1bc3ad2..4ec3ef5ae6 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -30,13 +30,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with import global._ import icodes._ import icodes.opcodes._ - import definitions.{ - AnyClass, ObjectClass, ThrowsClass, ThrowableClass, ClassfileAnnotationClass, - SerializableClass, StringClass, ClassClass, FunctionClass, - DeprecatedAttr, SerializableAttr, SerialVersionUIDAttr, VolatileAttr, - TransientAttr, CloneableAttr, RemoteAttr, JavaCloneableClass, - RemoteInterfaceClass, RemoteExceptionClass, hasJavaMainMethod - } + import definitions._ val phaseName = "jvm" @@ -68,10 +62,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with def isJavaEntryPoint(clasz: IClass) = { val sym = clasz.symbol - def fail(msg: String) = { + def fail(msg: String, pos: Position = sym.pos) = { clasz.cunit.warning(sym.pos, - sym.name + " has a main method, but " + sym.fullName('.') + " will not be a runnable program.\n" + - " " + msg + ", which means no static forwarder can be generated.\n" + sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" + + " Reason: " + msg // TODO: make this next claim true, if possible // by generating valid main methods as static in module classes // not sure what the jvm allows here @@ -79,19 +73,47 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with ) false } - sym.hasModuleFlag && hasJavaMainMethod(sym) && { - // At this point we've seen a module with a main method, so if this - // doesn't turn out to be a valid entry point, issue a warning. - val companion = sym.linkedClassOfClass - if (companion.isTrait) - fail("Its companion is a trait") - else if (hasJavaMainMethod(companion) && !(sym isSubClass companion)) - fail("Its companion contains its own main method") - // this is only because forwarders aren't smart enough yet - else if (companion.tpe.member(nme.main) != NoSymbol) - fail("Its companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") - else - true + def failNoForwarder(msg: String) = { + fail(msg + ", which means no static forwarder can be generated.\n") + } + val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil + val hasApproximate = possibles exists { m => + m.info match { + case MethodType(p :: Nil, _) => p.tpe.typeSymbol == ArrayClass + case _ => false + } + } + // At this point it's a module with a main-looking method, so either + // succeed or warn that it isn't. + hasApproximate && { + // Before erasure so we can identify generic mains. + atPhase(currentRun.erasurePhase) { + val companion = sym.linkedClassOfClass + val companionMain = companion.tpe.member(nme.main) + + if (hasJavaMainMethod(companion)) + failNoForwarder("companion contains its own main method") + else if (companion.tpe.member(nme.main) != NoSymbol) + // this is only because forwarders aren't smart enough yet + failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") + else if (companion.isTrait) + failNoForwarder("companion is a trait") + // Now either succeeed, or issue some additional warnings for things which look like + // attempts to be java main methods. + else possibles exists { m => + m.info match { + case PolyType(_, _) => + fail("main methods cannot be generic.") + case MethodType(params, res) => + if (res.typeSymbol :: params exists (_.isAbstractType)) + fail("main methods cannot refer to type parameters or abstract types.", m.pos) + else + isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos) + case tp => + fail("don't know what this is: " + tp, m.pos) + } + } + } } } diff --git a/test/files/neg/main1.check b/test/files/neg/main1.check index 734c78e54d..1a7a13e1e9 100644 --- a/test/files/neg/main1.check +++ b/test/files/neg/main1.check @@ -1,25 +1,25 @@ -main1.scala:3: error: Foo has a main method, but foo1.Foo will not be a runnable program. - Its companion is a trait, which means no static forwarder can be generated. +main1.scala:3: error: Foo has a main method with parameter type Array[String], but foo1.Foo will not be a runnable program. + Reason: companion is a trait, which means no static forwarder can be generated. object Foo { // companion is trait ^ -main1.scala:10: error: Foo has a main method, but foo2.Foo will not be a runnable program. - Its companion contains its own main method, which means no static forwarder can be generated. +main1.scala:10: error: Foo has a main method with parameter type Array[String], but foo2.Foo will not be a runnable program. + Reason: companion contains its own main method, which means no static forwarder can be generated. object Foo { // companion has its own main ^ -main1.scala:22: error: Foo has a main method, but foo3.Foo will not be a runnable program. - Its companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. +main1.scala:22: error: Foo has a main method with parameter type Array[String], but foo3.Foo will not be a runnable program. + Reason: companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. object Foo { // Companion contains main, but not an interfering main. ^ -main1.scala:31: error: Foo has a main method, but foo4.Foo will not be a runnable program. - Its companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. +main1.scala:31: error: Foo has a main method with parameter type Array[String], but foo4.Foo will not be a runnable program. + Reason: companion contains its own main method, which means no static forwarder can be generated. object Foo extends Foo { // Inherits main from the class ^ -main1.scala:39: error: Foo has a main method, but foo5.Foo will not be a runnable program. - Its companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. +main1.scala:39: error: Foo has a main method with parameter type Array[String], but foo5.Foo will not be a runnable program. + Reason: companion contains its own main method, which means no static forwarder can be generated. object Foo extends Foo { // Overrides main from the class ^ diff --git a/test/files/neg/t4749.check b/test/files/neg/t4749.check new file mode 100644 index 0000000000..93ad3935fa --- /dev/null +++ b/test/files/neg/t4749.check @@ -0,0 +1,28 @@ +t4749.scala:2: error: Fail1 has a main method with parameter type Array[String], but bippy.Fail1 will not be a runnable program. + Reason: main method must have exact signature (Array[String])Unit + object Fail1 { + ^ +t4749.scala:6: error: Fail2 has a main method with parameter type Array[String], but bippy.Fail2 will not be a runnable program. + Reason: main methods cannot be generic. + object Fail2 { + ^ +t4749.scala:13: error: Fail3 has a main method with parameter type Array[String], but bippy.Fail3 will not be a runnable program. + Reason: main methods cannot refer to type parameters or abstract types. + object Fail3 extends Bippy[Unit] { } + ^ +t4749.scala:16: error: Fail4 has a main method with parameter type Array[String], but bippy.Fail4 will not be a runnable program. + Reason: companion is a trait, which means no static forwarder can be generated. + + object Fail4 { + ^ +t4749.scala:21: error: Fail5 has a main method with parameter type Array[String], but bippy.Fail5 will not be a runnable program. + Reason: companion contains its own main method, which means no static forwarder can be generated. + + object Fail5 extends Fail5 { } + ^ +t4749.scala:26: error: Fail6 has a main method with parameter type Array[String], but bippy.Fail6 will not be a runnable program. + Reason: companion contains its own main method (implementation restriction: no main is allowed, regardless of signature), which means no static forwarder can be generated. + + object Fail6 { + ^ +6 errors found diff --git a/test/files/neg/t4749.flags b/test/files/neg/t4749.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t4749.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/test/files/neg/t4749.scala b/test/files/neg/t4749.scala new file mode 100644 index 0000000000..0973c36097 --- /dev/null +++ b/test/files/neg/t4749.scala @@ -0,0 +1,44 @@ +package bippy { + object Fail1 { + def main(args: Array[String]): Any = () + } + + object Fail2 { + def main[T](args: Array[String]): T = null.asInstanceOf[T] + } + + abstract class Bippy[T] { + def main(args: Array[String]): T = null.asInstanceOf[T] + } + object Fail3 extends Bippy[Unit] { } + + + object Fail4 { + def main(args: Array[String]): Unit = () + } + trait Fail4 { } + + object Fail5 extends Fail5 { } + class Fail5 { + def main(args: Array[String]): Unit = () + } + + object Fail6 { + def main(args: Array[String]): Unit = () + } + class Fail6 { + def main = "bippy" + } + + object Win1 { + def main(args: Array[String]): Unit = () + } + object Win2 extends Bippy[Unit] { + override def main(args: Array[String]): Unit = () + } + trait WinBippy[T] { + def main(args: Array[String]): T = null.asInstanceOf[T] + } + object Win3 extends WinBippy[Unit] { } +} + -- cgit v1.2.3 From 5f5029d2ac6348ecb07fc11f6656621c662ced92 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 10 Jan 2012 07:10:05 -0800 Subject: Optimizing TypeRef, starting with Symbols. There are too many potential optimizations unavailable to us due to the lack of bright lines among different kinds of symbols. For instance the difference between a TypeSymbol which represents a type alias and one which represents an abstract type is only whether the DEFERRED flag is set. This creates issues. 1) There are many (many) places where tests are performed on every symbol which could be done more efficiently and (especially) more verifiably correctly with polymorphism. 2) TypeRefs based on those symbols are also checking that flag constantly, in perpetuity. A symbol created as an alias is never (to the best of my knowledge) going to intentionally morph into one representing an abstract type, nor vice versa. 3) One has no guarantees, because anyone can set or reset the DEFERRED flag at any time. So tackling more than one problem at once herein: 1) I created canonical symbol creation points which take the flags as an argument, so that there can be a difference between initializing a symbol's flags and setting/resetting them at arbitrary times. 2) I structured all the symbol creators to take arguments in the same order, which is: def newXXX(name: Name, ..., pos: Position = NoPosition, flags: Long = 0L) (Where "..." is for those symbols which require something beyond the name to create, such as a TypeSkolem's origin.) The name is first because it's the only always required argument. I left but deprecated the variations which take (pos, name). 3) I created subclasses of TypeRef based on the information which should be stable from creation time onward: - args or no args? - abstract type, type alias, or class? 2x3 == 6 and that's how many subclasses of TypeRef there are now. So now, for example, every TypeRef doesn't have to carry null symInfoCache and thisInfoCache fields for the benefit of the minority which use them. I still intend to realize the gain possible once we can evade the fields for pre and args without losing pattern matcher efficiency. --- .../scala/reflect/internal/Definitions.scala | 98 ++-- .../scala/reflect/internal/Importers.scala | 24 +- src/compiler/scala/reflect/internal/StdNames.scala | 25 + src/compiler/scala/reflect/internal/Symbols.scala | 264 +++++----- src/compiler/scala/reflect/internal/Trees.scala | 3 +- src/compiler/scala/reflect/internal/Types.scala | 571 ++++++++++----------- .../reflect/internal/pickling/UnPickler.scala | 8 +- .../scala/reflect/runtime/JavaToScala.scala | 4 +- src/compiler/scala/reflect/runtime/Loaders.scala | 4 +- src/compiler/scala/reflect/runtime/ToolBoxes.scala | 6 +- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 16 +- .../scala/tools/nsc/backend/icode/GenICode.scala | 6 +- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 2 +- .../scala/tools/nsc/backend/opt/Inliners.scala | 4 +- .../scala/tools/nsc/javac/JavaParsers.scala | 10 +- src/compiler/scala/tools/nsc/matching/Matrix.scala | 3 +- .../tools/nsc/matching/ParallelMatching.scala | 2 +- .../scala/tools/nsc/symtab/SymbolLoaders.scala | 4 +- .../nsc/symtab/classfile/ClassfileParser.scala | 8 +- .../tools/nsc/symtab/classfile/ICodeReader.scala | 4 +- .../tools/nsc/symtab/classfile/MetaParser.scala | 2 +- .../scala/tools/nsc/symtab/clr/TypeParser.scala | 8 +- .../scala/tools/nsc/transform/CleanUp.scala | 19 +- .../scala/tools/nsc/transform/ExplicitOuter.scala | 4 +- .../scala/tools/nsc/transform/LazyVals.scala | 2 +- src/compiler/scala/tools/nsc/transform/Mixin.scala | 11 +- .../tools/nsc/transform/SpecializeTypes.scala | 2 +- .../scala/tools/nsc/transform/TailCalls.scala | 2 +- .../scala/tools/nsc/transform/UnCurry.scala | 12 +- .../scala/tools/nsc/typechecker/Infer.scala | 5 +- .../tools/nsc/typechecker/MethodSynthesis.scala | 6 +- .../scala/tools/nsc/typechecker/Namers.scala | 31 +- .../tools/nsc/typechecker/NamesDefaults.scala | 2 +- .../tools/nsc/typechecker/PatMatVirtualiser.scala | 4 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 1 + .../tools/nsc/typechecker/SyntheticMethods.scala | 2 +- .../tools/nsc/typechecker/TypeDiagnostics.scala | 5 +- .../scala/tools/nsc/typechecker/Typers.scala | 12 +- .../scala/tools/nsc/typechecker/Unapplies.scala | 2 +- .../tools/selectivecps/SelectiveCPSTransform.scala | 8 +- test/files/neg/t692.check | 7 +- 41 files changed, 617 insertions(+), 596 deletions(-) (limited to 'test/files/neg') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index cc6ba32f9c..f4abb8cad3 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -14,6 +14,18 @@ import PartialFunction._ trait Definitions extends reflect.api.StandardDefinitions { self: SymbolTable => + private def newClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): Symbol = { + val clazz = owner.newClassSymbol(name, NoPosition, flags) + clazz setInfo ClassInfoType(parents, new Scope, clazz) + owner.info.decls enter clazz + } + private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): Symbol = { + val msym = owner.newMethod(name.encode, NoPosition, flags) + val params = msym.newSyntheticValueParams(formals) + msym setInfo MethodType(params, restpe) + owner.info.decls enter msym + } + // the scala value classes trait ValueClassDefinitions { self: definitions.type => @@ -66,13 +78,6 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val boxMethod = classesMap(x => valueModuleMethod(x, nme.box)) lazy val unboxMethod = classesMap(x => valueModuleMethod(x, nme.unbox)) - private def newClass(owner: Symbol, name: TypeName, parents: List[Type]): Symbol = { - val clazz = owner.newClass(NoPosition, name) - clazz.setInfo(ClassInfoType(parents, new Scope, clazz)) - owner.info.decls.enter(clazz) - clazz - } - def isNumericSubClass(sub: Symbol, sup: Symbol) = ( (numericWeight contains sub) && (numericWeight contains sup) @@ -124,21 +129,21 @@ trait Definitions extends reflect.api.StandardDefinitions { // This is the package _root_. The actual root cannot be referenced at // the source level, but _root_ is essentially a function () => . lazy val RootPackage: Symbol = { - val rp = NoSymbol.newValue(NoPosition, nme.ROOTPKG) - .setFlag(FINAL | MODULE | PACKAGE | JAVA) - .setInfo(NullaryMethodType(RootClass.tpe)) + val rp = ( + NoSymbol.newValue(nme.ROOTPKG, flags = FINAL | MODULE | PACKAGE | JAVA) + setInfo NullaryMethodType(RootClass.tpe) + ) RootClass.sourceModule = rp rp } // This is the actual root of everything, including the package _root_. lazy val RootClass: ModuleClassSymbol = ( - NoSymbol.newModuleClass(NoPosition, tpnme.ROOT) - setFlag (FINAL | MODULE | PACKAGE | JAVA) + NoSymbol.newModuleClassSymbol(tpnme.ROOT, flags = FINAL | MODULE | PACKAGE | JAVA) setInfo rootLoader ) // The empty package, which holds all top level types without given packages. - lazy val EmptyPackage = RootClass.newPackage(NoPosition, nme.EMPTY_PACKAGE_NAME).setFlag(FINAL) + lazy val EmptyPackage = RootClass.newPackage(nme.EMPTY_PACKAGE_NAME, flags = FINAL) lazy val EmptyPackageClass = EmptyPackage.moduleClass lazy val JavaLangPackage = getModule(sn.JavaLang) @@ -190,11 +195,11 @@ trait Definitions extends reflect.api.StandardDefinitions { } // top types - lazy val AnyClass = newClass(ScalaPackageClass, tpnme.Any, Nil) setFlag (ABSTRACT) + lazy val AnyClass = newClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.typeConstructor) lazy val ObjectClass = getClass(sn.Object) - lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") setFlag (SEALED | ABSTRACT | TRAIT) - lazy val AnyValCompanionClass = getRequiredClass("scala.AnyValCompanion") setFlag (SEALED | ABSTRACT | TRAIT) + lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") initFlags (SEALED | ABSTRACT | TRAIT) + lazy val AnyValCompanionClass = getRequiredClass("scala.AnyValCompanion") initFlags (SEALED | ABSTRACT | TRAIT) // bottom types lazy val RuntimeNothingClass = getClass(fulltpnme.RuntimeNothing) @@ -202,7 +207,7 @@ trait Definitions extends reflect.api.StandardDefinitions { sealed abstract class BottomClassSymbol(name: TypeName, parent: Symbol) extends ClassSymbol(ScalaPackageClass, NoPosition, name) { locally { - this setFlag ABSTRACT | TRAIT | FINAL + this initFlags ABSTRACT | TRAIT | FINAL this setInfo ClassInfoType(List(parent.tpe), new Scope, this) owner.info.decls enter this } @@ -296,7 +301,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // .setInfo(UnitClass.tpe) lazy val TypeConstraintClass = getRequiredClass("scala.annotation.TypeConstraint") - lazy val SingletonClass = newClass(ScalaPackageClass, tpnme.Singleton, anyparam) setFlag (ABSTRACT | TRAIT | FINAL) + lazy val SingletonClass = newClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL) lazy val SerializableClass = getRequiredClass("scala.Serializable") lazy val JavaSerializableClass = getClass(sn.JavaSerializable) lazy val ComparableClass = getRequiredClass("java.lang.Comparable") @@ -808,13 +813,6 @@ trait Definitions extends reflect.api.StandardDefinitions { */ private def getModuleOrClass(path: Name): Symbol = getModuleOrClass(path, path.length) - private def newClass(owner: Symbol, name: TypeName, parents: List[Type]): Symbol = { - val clazz = owner.newClass(NoPosition, name) - clazz.setInfo(ClassInfoType(parents, new Scope, clazz)) - owner.info.decls.enter(clazz) - clazz - } - private def newCovariantPolyClass(owner: Symbol, name: TypeName, parent: Symbol => Type): Symbol = { val clazz = newClass(owner, name, List()) val tparam = newTypeParam(clazz, 0) setFlag COVARIANT @@ -832,40 +830,26 @@ trait Definitions extends reflect.api.StandardDefinitions { } private def newAlias(owner: Symbol, name: TypeName, alias: Type): Symbol = { - val tpsym = owner.newAliasType(NoPosition, name) + val tpsym = owner.newAliasType(name) tpsym.setInfo(alias) owner.info.decls.enter(tpsym) tpsym } - private def newMethod(owner: Symbol, name: TermName): Symbol = { - val msym = owner.newMethod(NoPosition, name.encode) - owner.info.decls.enter(msym) - msym - } - - private[Definitions] def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type): Symbol = { - val msym = newMethod(owner, name) - val params = msym.newSyntheticValueParams(formals) - msym.setInfo(MethodType(params, restpe)) - } - /** tcon receives the type parameter symbol as argument */ private def newPolyMethod(owner: Symbol, name: TermName, tcon: Symbol => Type): Symbol = newPolyMethodCon(owner, name, tparam => msym => tcon(tparam)) /** tcon receives the type parameter symbol and the method symbol as arguments */ private def newPolyMethodCon(owner: Symbol, name: TermName, tcon: Symbol => Symbol => Type): Symbol = { - val msym = newMethod(owner, name) + val msym = owner.info.decls enter owner.newMethod(name.encode) val tparam = newTypeParam(msym, 0) - msym.setInfo(polyType(List(tparam), tcon(tparam)(msym))) - } - private def newParameterlessMethod(owner: Symbol, name: TermName, restpe: Type) = - newMethod(owner, name).setInfo(NullaryMethodType(restpe)) + msym setInfo polyType(List(tparam), tcon(tparam)(msym)) + } private def newTypeParam(owner: Symbol, index: Int): Symbol = - owner.newTypeParameter(NoPosition, newTypeName("T" + index)) setInfo TypeBounds.empty + owner.newTypeParameter(newTypeName("T" + index)) setInfo TypeBounds.empty lazy val boxedClassValues = boxedClass.values.toSet lazy val isUnbox = unboxMethod.values.toSet @@ -965,12 +949,12 @@ trait Definitions extends reflect.api.StandardDefinitions { RootClass.info.decls enter RootPackage // members of class scala.Any - Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype) setFlag FINAL - Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype) setFlag FINAL + Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) + Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) Any_equals = newMethod(AnyClass, nme.equals_, anyparam, booltype) Any_hashCode = newMethod(AnyClass, nme.hashCode_, Nil, inttype) Any_toString = newMethod(AnyClass, nme.toString_, Nil, stringtype) - Any_## = newMethod(AnyClass, nme.HASHHASH, Nil, inttype) setFlag FINAL + Any_## = newMethod(AnyClass, nme.HASHHASH, Nil, inttype, FINAL) // Any_getClass requires special handling. The return type is determined on // a per-call-site basis as if the function being called were actually: @@ -981,26 +965,24 @@ trait Definitions extends reflect.api.StandardDefinitions { // Since getClass is not actually a polymorphic method, this requires compiler // participation. At the "Any" level, the return type is Class[_] as it is in // java.lang.Object. Java also special cases the return type. - Any_getClass = ( - newMethod(AnyClass, nme.getClass_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType) - setFlag DEFERRED - ) + Any_getClass = + newMethod(AnyClass, nme.getClass_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType, DEFERRED) Any_isInstanceOf = newPolyMethod( AnyClass, nme.isInstanceOf_, tparam => NullaryMethodType(booltype)) setFlag FINAL Any_asInstanceOf = newPolyMethod( AnyClass, nme.asInstanceOf_, tparam => NullaryMethodType(tparam.typeConstructor)) setFlag FINAL // members of class java.lang.{ Object, String } - Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype) setFlag FINAL - Object_== = newMethod(ObjectClass, nme.EQ, anyrefparam, booltype) setFlag FINAL - Object_!= = newMethod(ObjectClass, nme.NE, anyrefparam, booltype) setFlag FINAL - Object_eq = newMethod(ObjectClass, nme.eq, anyrefparam, booltype) setFlag FINAL - Object_ne = newMethod(ObjectClass, nme.ne, anyrefparam, booltype) setFlag FINAL + Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL) + Object_== = newMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL) + Object_!= = newMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL) + Object_eq = newMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL) + Object_ne = newMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL) Object_synchronized = newPolyMethodCon( ObjectClass, nme.synchronized_, tparam => msym => MethodType(msym.newSyntheticValueParams(List(tparam.typeConstructor)), tparam.typeConstructor)) setFlag FINAL - String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype) setFlag FINAL + String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL) val forced = List( // force initialization of every symbol that is entered as a side effect AnnotationDefaultAttr, // #2264 @@ -1037,7 +1019,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // tparam => resultType, which is the resultType of PolyType, i.e. the result type after applying the // type parameter =-> a MethodType in this case // TODO: set type bounds manually (-> MulticastDelegate), see newTypeParam - val newCaller = newMethod(DelegateClass, name, paramTypes, delegateType) setFlag (FINAL | STATIC) + val newCaller = newMethod(DelegateClass, name, paramTypes, delegateType, FINAL | STATIC) // val newCaller = newPolyMethod(DelegateClass, name, // tparam => MethodType(paramTypes, tparam.typeConstructor)) setFlag (FINAL | STATIC) Delegate_scalaCallers = Delegate_scalaCallers ::: List(newCaller) diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index 38f808cef9..53380952c0 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -22,6 +22,7 @@ trait Importers { self: SymbolTable => val myowner = importSymbol(sym.owner) val mypos = importPosition(sym.pos) val myname = importName(sym.name).toTermName + val myflags = sym.flags def linkReferenced(mysym: TermSymbol, x: from.TermSymbol, op: from.Symbol => Symbol): Symbol = { symMap(x) = mysym mysym.referenced = op(x.referenced) @@ -29,19 +30,20 @@ trait Importers { self: SymbolTable => } val mysym = sym match { case x: from.MethodSymbol => - linkReferenced(new MethodSymbol(myowner, mypos, myname), x, importSymbol) + linkReferenced(myowner.newMethod(myname, mypos, myflags), x, importSymbol) case x: from.ModuleSymbol => - linkReferenced(new ModuleSymbol(myowner, mypos, myname), x, doImport) + linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, doImport) case x: from.FreeVar => - new FreeVar(importName(x.name).toTermName, importType(x.tpe), x.value) + newFreeVar(importName(x.name).toTermName, importType(x.tpe), x.value, myflags) case x: from.TermSymbol => - linkReferenced(new TermSymbol(myowner, mypos, myname), x, importSymbol) + linkReferenced(myowner.newValue(myname, mypos, myflags), x, importSymbol) case x: from.TypeSkolem => - new TypeSkolem(myowner, mypos, myname.toTypeName, x.unpackLocation match { - case null => null - case y: from.Tree => importTree(y) + val origin = x.unpackLocation match { + case null => null + case y: from.Tree => importTree(y) case y: from.Symbol => importSymbol(y) - }) + } + myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags) /* case x: from.ModuleClassSymbol => val mysym = new ModuleClassSymbol(myowner, mypos, myname.toTypeName) @@ -49,17 +51,17 @@ trait Importers { self: SymbolTable => mysym */ case x: from.ClassSymbol => - val mysym = new ClassSymbol(myowner, mypos, myname.toTypeName) + val mysym = myowner.newClassSymbol(myname.toTypeName, mypos, myflags) if (sym.thisSym != sym) { mysym.typeOfThis = importType(sym.typeOfThis) mysym.thisSym.name = importName(sym.thisSym.name) } mysym case x: from.TypeSymbol => - new TypeSymbol(myowner, mypos, myname.toTypeName) + myowner.newTypeSymbol(myname.toTypeName, mypos, myflags) } symMap(sym) = mysym - mysym setFlag sym.flags | Flags.LOCKED + mysym setFlag Flags.LOCKED mysym setInfo { val mytypeParams = sym.typeParams map doImport new LazyPolyType(mytypeParams) { diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index ea5565c581..2871ba59f6 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -230,6 +230,31 @@ trait StdNames extends NameManglers { self: SymbolTable => val _20 : NameType = "_20" val _21 : NameType = "_21" val _22 : NameType = "_22" + + val x_0 : NameType = "x$0" + val x_1 : NameType = "x$1" + val x_2 : NameType = "x$2" + val x_3 : NameType = "x$3" + val x_4 : NameType = "x$4" + val x_5 : NameType = "x$5" + val x_6 : NameType = "x$6" + val x_7 : NameType = "x$7" + val x_8 : NameType = "x$8" + val x_9 : NameType = "x$9" + + @switch def syntheticParamName(i: Int): TermName = i match { + case 0 => nme.x_0 + case 1 => nme.x_1 + case 2 => nme.x_2 + case 3 => nme.x_3 + case 4 => nme.x_4 + case 5 => nme.x_5 + case 6 => nme.x_6 + case 7 => nme.x_7 + case 8 => nme.x_8 + case 9 => nme.x_9 + case _ => newTermName("x$" + i) + } val wrapRefArray: NameType = "wrapRefArray" val wrapByteArray: NameType = "wrapByteArray" diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 6ee061392c..d969cb43bb 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -35,6 +35,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => nextexid += 1 newTypeName("_" + nextexid + suffix) } + + // Set the fields which point companions at one another. Returns the module. + def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = { + moduleClass.sourceModule = m + m setModuleClass moduleClass + m + } /** The original owner of a class. Used by the backend to generate * EnclosingMethod attributes. @@ -43,8 +50,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => abstract class AbsSymbolImpl extends AbsSymbol { this: Symbol => def newNestedSymbol(pos: Position, name: Name) = name match { - case n: TermName => newValue(pos, n) - case n: TypeName => newAliasType(pos, n) + case n: TermName => newTermSymbol(n, pos) + case n: TypeName => newTypeSymbol(n, pos) } def typeSig: Type = info def typeSigIn(site: Type): Type = site.memberInfo(this) @@ -89,64 +96,80 @@ trait Symbols extends api.Symbols { self: SymbolTable => // ------ creators ------------------------------------------------------------------- - final def newValue(pos: Position, name: TermName) = - new TermSymbol(this, pos, name) - final def newValue(name: TermName, pos: Position = NoPosition) = - new TermSymbol(this, pos, name) - final def newVariable(pos: Position, name: TermName) = - newValue(pos, name).setFlag(MUTABLE) - final def newValueParameter(pos: Position, name: TermName) = - newValue(pos, name).setFlag(PARAM) + final def newValue(name: TermName, pos: Position = NoPosition, flags: Long = 0L): TermSymbol = + newTermSymbol(name, pos, flags) + final def newVariable(name: TermName, pos: Position = NoPosition, flags: Long = 0L): TermSymbol = + newTermSymbol(name, pos, MUTABLE | flags) + final def newValueParameter(name: TermName, pos: Position = NoPosition, flags: Long = 0L): TermSymbol = + newTermSymbol(name, pos, PARAM | flags) + /** Create local dummy for template (owner of local blocks) */ final def newLocalDummy(pos: Position) = - newValue(pos, nme.localDummyName(this)).setInfo(NoType) - final def newMethod(pos: Position, name: TermName) = - new MethodSymbol(this, pos, name).setFlag(METHOD) - final def newMethod(name: TermName, pos: Position = NoPosition) = - new MethodSymbol(this, pos, name).setFlag(METHOD) - final def newLabel(pos: Position, name: TermName) = - newMethod(pos, name).setFlag(LABEL) + newTermSymbol(nme.localDummyName(this), pos) setInfo NoType + final def newMethod(name: TermName, pos: Position = NoPosition, flags: Long = 0L): MethodSymbol = + newMethodSymbol(name, pos, METHOD | flags) + final def newLabel(name: TermName, pos: Position = NoPosition): MethodSymbol = + newMethod(name, pos, LABEL) /** Propagates ConstrFlags (JAVA, specifically) from owner to constructor. */ - final def newConstructor(pos: Position) = - newMethod(pos, nme.CONSTRUCTOR) setFlag getFlag(ConstrFlags) + final def newConstructor(pos: Position, flags: Long = 0L) = + newMethod(nme.CONSTRUCTOR, pos, getFlag(ConstrFlags) | flags) + /** Static constructor with info set. */ def newStaticConstructor(pos: Position) = - newConstructor(pos) setFlag STATIC setInfo UnitClass.tpe + newConstructor(pos, STATIC) setInfo UnitClass.tpe /** Instance constructor with info set. */ def newClassConstructor(pos: Position) = newConstructor(pos) setInfo MethodType(Nil, this.tpe) - private def finishModule(m: ModuleSymbol, clazz: ClassSymbol): ModuleSymbol = { - // Top-level objects can be automatically marked final, but others - // must be explicitly marked final if overridable objects are enabled. - val flags = if (isPackage || !settings.overrideObjects.value) MODULE | FINAL else MODULE - m setFlag flags - m setModuleClass clazz - m + // Top-level objects can be automatically marked final, but others + // must be explicitly marked final if overridable objects are enabled. + private def ModuleFlags = ( + if (isPackage || !settings.overrideObjects.value) MODULE | FINAL + else MODULE + ) + def newLinkedModule(clazz: Symbol, flags: Long = 0L): ModuleSymbol = { + val m = newModuleSymbol(clazz.name.toTermName, clazz.pos, ModuleFlags | flags) + connectModuleToClass(m, clazz.asInstanceOf[ClassSymbol]) + } + final def newModule(name: TermName, pos: Position = NoPosition, flags: Long = 0L): ModuleSymbol = { + val m = newModuleSymbol(name, pos, flags | ModuleFlags) + val clazz = newModuleClassSymbol(name.toTypeName, pos, (m getFlag ModuleToClassFlags) | MODULE) + connectModuleToClass(m, clazz) } - private def finishModule(m: ModuleSymbol): ModuleSymbol = - finishModule(m, new ModuleClassSymbol(m)) - - final def newModule(pos: Position, name: TermName, clazz: ClassSymbol): ModuleSymbol = - finishModule(new ModuleSymbol(this, pos, name), clazz) - - final def newModule(name: TermName, clazz: Symbol, pos: Position = NoPosition): ModuleSymbol = - newModule(pos, name, clazz.asInstanceOf[ClassSymbol]) - - final def newModule(pos: Position, name: TermName): ModuleSymbol = - finishModule(new ModuleSymbol(this, pos, name)) - final def newPackage(pos: Position, name: TermName): ModuleSymbol = { - assert(name == nme.ROOT || isPackageClass) - val m = newModule(pos, name).setFlag(JAVA | PACKAGE) - m.moduleClass setFlag (JAVA | PACKAGE) - m + final def newPackage(name: TermName, pos: Position = NoPosition, flags: Long = 0L): ModuleSymbol = { + assert(name == nme.ROOT || isPackageClass, this) + newModule(name, pos, JAVA | PACKAGE | flags) } final def newThisSym(pos: Position) = - newValue(pos, nme.this_).setFlag(SYNTHETIC) + newTermSymbol(nme.this_, pos, SYNTHETIC) final def newImport(pos: Position) = - newValue(pos, nme.IMPORT) + newTermSymbol(nme.IMPORT, pos) + + /** Direct symbol factories. + * For internal use; these are unlikely to be what you want. + */ + def newTermSymbol(name: TermName, pos: Position = NoPosition, flags: Long = 0L): TermSymbol = + new TermSymbol(this, pos, name) initFlags flags + + def newTypeSymbol(name: TypeName, pos: Position = NoPosition, flags: Long = 0L): TypeSymbol = + new TypeSymbol(this, pos, name) initFlags flags + + def newModuleSymbol(name: TermName, pos: Position = NoPosition, flags: Long = 0L): ModuleSymbol = + new ModuleSymbol(this, pos, name) initFlags flags + + def newMethodSymbol(name: TermName, pos: Position = NoPosition, flags: Long = 0L): MethodSymbol = + new MethodSymbol(this, pos, name) initFlags flags + + def newClassSymbol(name: TypeName, pos: Position = NoPosition, flags: Long = 0L): ClassSymbol = + new ClassSymbol(this, pos, name) initFlags flags + + def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, flags: Long = 0L): ModuleClassSymbol = + new ModuleClassSymbol(this, pos, name) initFlags flags + + def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, flags: Long = 0L): TypeSkolem = + new TypeSkolem(this, pos, name, origin) initFlags flags /** @param pre type relative to which alternatives are seen. * for instance: @@ -166,55 +189,50 @@ trait Symbols extends api.Symbols { self: SymbolTable => * * pre.memberType(m) */ - final def newOverloaded(pre: Type, alternatives: List[Symbol]): Symbol = - newValue(alternatives.head.pos, alternatives.head.name.toTermName) - .setFlag(OVERLOADED) - .setInfo(OverloadedType(pre, alternatives)) + final def newOverloaded(pre: Type, alternatives: List[Symbol]): Symbol = ( + newTermSymbol(alternatives.head.name.toTermName, alternatives.head.pos, OVERLOADED) + setInfo OverloadedType(pre, alternatives) + ) /** for explicit outer phase */ final def newOuterAccessor(pos: Position) = { - val sym = newMethod(pos, nme.OUTER) - sym setFlag (STABLE | SYNTHETIC) - if (isTrait) sym setFlag DEFERRED + val accFlags = METHOD | STABLE | SYNTHETIC | ( + if (isTrait) DEFERRED else 0 + ) + val sym = newMethodSymbol(nme.OUTER, pos, accFlags) sym.expandName(this) sym.referenced = this sym } final def newErrorValue(name: TermName) = - newValue(pos, name).setFlag(SYNTHETIC | IS_ERROR).setInfo(ErrorType) + newTermSymbol(name, pos, SYNTHETIC | IS_ERROR) setInfo ErrorType /** Symbol of a type definition type T = ... */ - final def newAliasType(pos: Position, name: TypeName) = - new TypeSymbol(this, pos, name) - final def newAliasType(name: TypeName, pos: Position = NoPosition) = - new TypeSymbol(this, pos, name) - + final def newAliasType(name: TypeName, pos: Position = NoPosition, flags: Long = 0L): Symbol = + newTypeSymbol(name, pos, flags) + /** Symbol of an abstract type type T >: ... <: ... */ - final def newAbstractType(pos: Position, name: TypeName) = - new TypeSymbol(this, pos, name).setFlag(DEFERRED) - final def newAbstractType(name: TypeName, pos: Position = NoPosition) = - new TypeSymbol(this, pos, name).setFlag(DEFERRED) + final def newAbstractType(name: TypeName, pos: Position = NoPosition, flags: Long = 0L): Symbol = + newTypeSymbol(name, pos, DEFERRED | flags) /** Symbol of a type parameter */ - final def newTypeParameter(pos: Position, name: TypeName) = - newAbstractType(pos, name).setFlag(PARAM) + final def newTypeParameter(name: TypeName, pos: Position = NoPosition, flags: Long = 0L) = + newAbstractType(name, pos, PARAM | flags) /** Synthetic value parameters when parameter symbols are not available */ final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[Symbol]] = { var cnt = 0 - def freshName() = { cnt += 1; newTermName("x$" + cnt) } - def param(tp: Type) = - newValueParameter(focusPos(owner.pos), freshName()).setFlag(SYNTHETIC).setInfo(tp) - argtypess map (_.map(param)) + def freshName() = { cnt += 1; nme.syntheticParamName(cnt) } + mmap(argtypess)(tp => newValueParameter(freshName(), focusPos(owner.pos), SYNTHETIC) setInfo tp) } - final def newExistential(pos: Position, name: TypeName): Symbol = - newAbstractType(pos, name).setFlag(EXISTENTIAL) + final def newExistential(name: TypeName, pos: Position = NoPosition, flags: Long = 0L): Symbol = + newAbstractType(name, pos, EXISTENTIAL | flags) final def freshExistential(suffix: String): Symbol = newExistential(pos, freshExistentialName(suffix)) @@ -237,45 +255,40 @@ trait Symbols extends api.Symbols { self: SymbolTable => * body of the method, there's a local copy of `T` which is a TypeSkolem. */ final def newTypeSkolem: Symbol = - new TypeSkolem(owner, pos, name.toTypeName, this) - .setFlag(flags) + owner.newTypeSkolemSymbol(name.toTypeName, this, pos, flags) - final def newClass(pos: Position, name: TypeName) = - new ClassSymbol(this, pos, name) final def newClass(name: TypeName, pos: Position = NoPosition) = - new ClassSymbol(this, pos, name) + newClassSymbol(name, pos) - final def newModuleClass(pos: Position, name: TypeName) = - new ModuleClassSymbol(this, pos, name) final def newModuleClass(name: TypeName, pos: Position = NoPosition) = - new ModuleClassSymbol(this, pos, name) + newModuleClassSymbol(name, pos) final def newAnonymousClass(pos: Position) = - newClass(pos, tpnme.ANON_CLASS_NAME) - final def newAnonymousFunctionClass(pos: Position) = - newClass(pos, tpnme.ANON_FUN_NAME) + newClassSymbol(tpnme.ANON_CLASS_NAME, pos) + + final def newAnonymousFunctionClass(pos: Position, flags: Long = 0L) = + newClassSymbol(tpnme.ANON_FUN_NAME, pos, FINAL | SYNTHETIC | flags) + + final def newAnonymousFunctionValue(pos: Position, flags: Long = 0L) = + newTermSymbol(nme.ANON_FUN_NAME, pos, SYNTHETIC | flags) setInfo NoType /** Refinement types P { val x: String; type T <: Number } * also have symbols, they are refinementClasses */ final def newRefinementClass(pos: Position) = - newClass(pos, tpnme.REFINE_CLASS_NAME) + newClass(tpnme.REFINE_CLASS_NAME, pos) /** Create a new getter for current symbol (which must be a field) */ final def newGetter: Symbol = ( - owner.newMethod(focusPos(pos), nme.getterName(name.toTermName)) - setFlag getterFlags(flags) + owner.newMethod(nme.getterName(name.toTermName), flags = getterFlags(flags)) setPrivateWithin privateWithin setInfo MethodType(Nil, tpe) ) final def newErrorClass(name: TypeName) = { - val clazz = newClass(pos, name) - ( clazz - setFlag (SYNTHETIC | IS_ERROR) - setInfo ClassInfoType(Nil, new ErrorScope(this), clazz) - ) + val clazz = newClassSymbol(name, pos, SYNTHETIC | IS_ERROR) + clazz setInfo ClassInfoType(Nil, new ErrorScope(this), clazz) } final def newErrorSymbol(name: Name): Symbol = name match { @@ -283,6 +296,23 @@ trait Symbols extends api.Symbols { self: SymbolTable => case x: TermName => newErrorValue(x) } + @deprecated("Use the other signature", "2.10.0") + def newClass(pos: Position, name: TypeName): Symbol = newClass(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newModuleClass(pos: Position, name: TypeName): Symbol = newModuleClass(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newLabel(pos: Position, name: TermName): MethodSymbol = newLabel(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newValue(pos: Position, name: TermName): TermSymbol = newTermSymbol(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newAliasType(pos: Position, name: TypeName): Symbol = newAliasType(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newAbstractType(pos: Position, name: TypeName): Symbol = newAbstractType(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newExistential(pos: Position, name: TypeName): Symbol = newExistential(name, pos) + @deprecated("Use the other signature", "2.10.0") + def newMethod(pos: Position, name: TermName): MethodSymbol = newMethod(name, pos) + // ----- locking and unlocking ------------------------------------------------------ // True if the symbol is unlocked. @@ -808,8 +838,17 @@ trait Symbols extends api.Symbols { self: SymbolTable => (fs | ((fs & LateFlags) >>> LateShift)) & ~(fs >>> AntiShift) } final def flags_=(fs: Long) = rawflags = fs - final def setFlag(mask: Long): this.type = { rawflags = rawflags | mask; this } - final def resetFlag(mask: Long): this.type = { rawflags = rawflags & ~mask; this } + + /** Set the symbol's flags to the given value, asserting + * that the previous value was 0. + */ + def initFlags(mask: Long): this.type = { + assert(rawflags == 0L, this) + rawflags = mask + this + } + def setFlag(mask: Long): this.type = { rawflags = rawflags | mask ; this } + def resetFlag(mask: Long): this.type = { rawflags = rawflags & ~mask ; this } final def getFlag(mask: Long): Long = flags & mask final def resetFlags() { rawflags = rawflags & TopLevelCreationFlags } @@ -1149,7 +1188,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (this.isTerm) singletonBounds(this.tpe) else - abort("unexpected alias type: "+this) + abort("unexpected alias type: "+this.ownerChain+ " " + hasFlagsToString(-1L)) /** Reset symbol to initial state */ @@ -1285,9 +1324,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def cloneSymbol(owner: Symbol): Symbol = { val newSym = cloneSymbolImpl(owner) ( newSym + initFlags this.rawflags setPrivateWithin privateWithin setInfo (info cloneInfo newSym) - setFlag this.rawflags setAnnotations this.annotations ) } @@ -1999,7 +2038,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => var referenced: Symbol = NoSymbol def cloneSymbolImpl(owner: Symbol): Symbol = - new TermSymbol(owner, pos, name).copyAttrsFrom(this) + owner.newTermSymbol(name, pos).copyAttrsFrom(this) def copyAttrsFrom(original: TermSymbol): this.type = { referenced = original.referenced @@ -2029,13 +2068,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (hasFlag(MODULE)) referenced else NoSymbol def setModuleClass(clazz: Symbol): TermSymbol = { - assert(hasFlag(MODULE)) + assert(hasFlag(MODULE), this) referenced = clazz this } def setLazyAccessor(sym: Symbol): TermSymbol = { - assert(isLazy && (referenced == NoSymbol || referenced == sym), this) + assert(isLazy && (referenced == NoSymbol || referenced == sym), (this, hasFlagsToString(-1L), referenced, sym)) referenced = sym this } @@ -2096,7 +2135,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => ) override def cloneSymbolImpl(owner: Symbol): Symbol = - new ModuleSymbol(owner, pos, name).copyAttrsFrom(this) + owner.newModuleSymbol(name, pos).copyAttrsFrom(this) } /** A class for method symbols */ @@ -2108,7 +2147,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private var mtpeInfo: Type = _ override def cloneSymbolImpl(owner: Symbol): Symbol = - new MethodSymbol(owner, pos, name).copyAttrsFrom(this) + owner.newMethodSymbol(name, pos).copyAttrsFrom(this) def typeAsMemberOf(pre: Type): Type = { if (mtpePeriod == currentPeriod) { @@ -2198,9 +2237,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ override def tpeHK = typeConstructor // @M! used in memberType - // needed for experimental code for early types as type parameters - // def refreshType() { tpePeriod = NoPeriod } - override def typeConstructor: Type = { if ((tyconCache eq null) || tyconRunId != currentRunId) { tyconCache = newTypeRef(Nil) @@ -2242,8 +2278,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } } - def cloneSymbolImpl(owner: Symbol): Symbol = - new TypeSymbol(owner, pos, name) + def cloneSymbolImpl(owner: Symbol): Symbol = owner.newTypeSymbol(name, pos) incCounter(typeSymbolCount) } @@ -2282,7 +2317,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def typeParams = info.typeParams override def cloneSymbolImpl(owner: Symbol): Symbol = - new TypeSkolem(owner, pos, name, origin) + owner.newTypeSkolemSymbol(name, origin, pos) override def nameString: String = if (settings.debug.value) (super.nameString + "&" + level) @@ -2363,7 +2398,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } override def cloneSymbolImpl(owner: Symbol): Symbol = { - val clone = new ClassSymbol(owner, pos, name) + val clone = owner.newClassSymbol(name, pos) if (thisSym != this) { clone.typeOfThis = typeOfThis clone.thisSym.name = thisSym.name @@ -2388,15 +2423,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => class ModuleClassSymbol(owner: Symbol, pos: Position, name: TypeName) extends ClassSymbol(owner, pos, name) { private var module: Symbol = null - def this(module: TermSymbol) = { - this(module.owner, module.pos, module.name.toTypeName) - setFlag(module.getFlag(ModuleToClassFlags) | MODULE) - sourceModule = module - } - override def sourceModule = module private var implicitMembersCacheValue: List[Symbol] = List() private var implicitMembersCacheKey1: Type = NoType private var implicitMembersCacheKey2: ScopeEntry = null + def implicitMembers: List[Symbol] = { val tp = info if ((implicitMembersCacheKey1 ne tp) || (implicitMembersCacheKey2 ne tp.decls.elems)) { @@ -2406,8 +2436,12 @@ trait Symbols extends api.Symbols { self: SymbolTable => } implicitMembersCacheValue } + override def sourceModule = module override def sourceModule_=(module: Symbol) { this.module = module } } + + def newFreeVar(name0: TermName, tpe: Type, value: Any, flags: Long = 0L) = + new FreeVar(name0, tpe, value) initFlags flags class FreeVar(name0: TermName, tpe: Type, val value: Any) extends TermSymbol(definitions.RootClass, NoPosition, name0) { setInfo(tpe) @@ -2521,12 +2555,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Create a new existential type skolem with the given owner and origin. */ def newExistentialSkolem(sym: Symbol, owner: Symbol, origin: AnyRef): TypeSkolem = { - val skolem = new TypeSkolem(owner, sym.pos, sym.name.toTypeName, origin) - ( skolem - setInfo (sym.info cloneInfo skolem) - setFlag (sym.flags | EXISTENTIAL) - resetFlag PARAM - ) + val skolem = owner.newTypeSkolemSymbol(sym.name.toTypeName, origin, sym.pos, (sym.flags | EXISTENTIAL) & ~PARAM) + skolem setInfo (sym.info cloneInfo skolem) } /** An exception for cyclic references of symbol definitions */ diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 96f2c5cc45..1cefc07c3d 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -198,9 +198,8 @@ trait Trees extends api.Trees { self: SymbolTable => def DefDef(sym: Symbol, rhs: Tree): DefDef = DefDef(sym, Modifiers(sym.flags), rhs) - def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = { + def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = DefDef(sym, rhs(sym.info.paramss)) - } /** A TypeDef node which defines given `sym` with given tight hand side `rhs`. */ def TypeDef(sym: Symbol, rhs: Tree): TypeDef = diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 4630733db4..43905ee344 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -322,13 +322,20 @@ trait Types extends api.Types { self: SymbolTable => /** The type symbol associated with the type * Note that the symbol of the normalized type is returned (@see normalize) + * A type's typeSymbol should if possible not be inspected directly, due to + * the likelihood that what is true for tp.typeSymbol is not true for + * tp.sym, due to normalization. */ def typeSymbol: Symbol = NoSymbol - /** The term symbol ''directly'' associated with the type. */ + /** The term symbol ''directly'' associated with the type. + */ def termSymbolDirect: Symbol = termSymbol - /** The type symbol ''directly'' associated with the type. */ + /** The type symbol ''directly'' associated with the type. + * In other words, no normalization is performed: if this is an alias type, + * the symbol returned is that of the alias, not the underlying type. + */ def typeSymbolDirect: Symbol = typeSymbol /** The base type underlying a type proxy, identity on all other types */ @@ -412,6 +419,11 @@ trait Types extends api.Types { self: SymbolTable => /** For a typeref, its arguments. The empty list for all other types */ def typeArgs: List[Type] = List() + + /** A list of placeholder types derived from the type parameters. + * Used by RefinedType and TypeRef. + */ + protected def dummyArgs: List[Type] = typeParams map (_.typeConstructor) /** For a (nullary) method or poly type, its direct result type, * the type itself for all other types. */ @@ -1504,8 +1516,6 @@ trait Types extends api.Types { self: SymbolTable => override def typeConstructor = copyRefinedType(this, parents map (_.typeConstructor), decls) - private def dummyArgs = typeParams map (_.typeConstructor) - /* MO to AM: This is probably not correct * If they are several higher-kinded parents with different bounds we need * to take the intersection of their bounds @@ -1650,11 +1660,12 @@ trait Types extends api.Types { self: SymbolTable => def apply(tp: Type): Type = { tp match { - case TypeRef(_, sym, args) if args.nonEmpty => - if (settings.debug.value && !sameLength(sym.info.typeParams, args)) + case tr @ TypeRef(_, sym, args) if args.nonEmpty => + val tparams = tr.initializedTypeParams + if (settings.debug.value && !sameLength(tparams, args)) debugwarn("Mismatched zip in computeRefs(): " + sym.info.typeParams + ", " + args) - foreach2(sym.info.typeParams, args) { (tparam1, arg) => + foreach2(tparams, args) { (tparam1, arg) => if (arg contains tparam) { addRef(NonExpansive, tparam, tparam1) if (arg.typeSymbol != tparam) @@ -1759,253 +1770,289 @@ trait Types extends api.Types { self: SymbolTable => private var volatileRecursions: Int = 0 private val pendingVolatiles = new mutable.HashSet[Symbol] + + class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) with UniqueType { + require(args0.nonEmpty, this) - /** A class for named types of the form - * `.[args]` - * Cannot be created directly; one should always use `typeRef` - * for creation. (@M: Otherwise hashing breaks) - * - * @M: a higher-kinded type is represented as a TypeRef with sym.info.typeParams.nonEmpty, but args.isEmpty - * @param pre ... - * @param sym ... - * @param args ... - */ - abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type { -// assert(!sym.isAbstractType || pre.isStable || pre.isError) -// assert(!pre.isInstanceOf[ClassInfoType], this) -// assert(!(sym hasFlag (PARAM | EXISTENTIAL)) || pre == NoPrefix, this) -// assert(args.isEmpty || !sym.info.typeParams.isEmpty, this) -// assert(args.isEmpty || ((sym ne AnyClass) && (sym ne NothingClass)) - - private var parentsCache: List[Type] = _ - private var parentsPeriod = NoPeriod - - private var baseTypeSeqCache: BaseTypeSeq = _ - private var baseTypeSeqPeriod = NoPeriod - - private var symInfoCache: Type = _ - private var memberInfoCache: Type = _ - private var thisInfoCache: Type = _ - private var relativeInfoCache: Type = _ - - private var normalized: Type = null - - override def isStable: Boolean = { - sym == NothingClass || - sym == SingletonClass || - sym.isAliasType && normalize.isStable || - sym.isAbstractType && (bounds.hi.typeSymbol isSubClass SingletonClass) - } - - override def isVolatile: Boolean = { - sym.isAliasType && normalize.isVolatile || - sym.isAbstractType && { - // need to be careful not to fall into an infinite recursion here - // because volatile checking is done before all cycles are detected. - // the case to avoid is an abstract type directly or - // indirectly upper-bounded by itself. See #2918 - try { - volatileRecursions += 1 - if (volatileRecursions < LogVolatileThreshold) - bounds.hi.isVolatile - else if (pendingVolatiles(sym)) - true // we can return true here, because a cycle will be detected - // here afterwards and an error will result anyway. - else - try { - pendingVolatiles += sym - bounds.hi.isVolatile - } finally { - pendingVolatiles -= sym - } - } finally { - volatileRecursions -= 1 - } - } - } - - override lazy val isTrivial: Boolean = - !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial) + /** No unapplied type params size it has (should have) equally as many args. */ + override def isHigherKinded = false + override def typeParams = Nil - override def isNotNull = - sym.isModuleClass || sym == NothingClass || isValueClass(sym) || super.isNotNull + override def transform(tp: Type): Type = { + // This situation arises when a typevar is encountered for which + // too little information is known to determine its kind, and + // it later turns out not to have kind *. See SI-4070. Only + // logging it for now. + if (sym.typeParams.size != args.size) + log("!!! %s.transform(%s), but tparams.isEmpty and args=".format(this, tp, args)) - // @M: propagate actual type params (args) to `tp`, by replacing formal type parameters with actual ones - // if tp is higher kinded, the "actual" type arguments are types that simply reference the corresponding type parameters (unbound type variables) - def transform(tp: Type): Type = { - val res = tp.asSeenFrom(pre, sym.owner) - if (sym.typeParams.isEmpty || (args exists (_.isError)) || isRaw(sym, args)/*#2266/2305*/) res - else res.instantiateTypeParams(sym.typeParams, typeArgsOrDummies) + asSeenFromOwner(tp).instantiateTypeParams(sym.typeParams, args) } - - //@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs) - def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies) - - def thisInfo: Type = - if (sym.isAliasType) normalize - else if (!sym.isNonClassType) sym.info - else { - val symInfo = sym.info - if (thisInfoCache == null || (symInfo ne symInfoCache)) { - symInfoCache = symInfo - thisInfoCache = transformInfo(symInfo) match { - // If a subtyping cycle is not detected here, we'll likely enter an infinite - // loop before a sensible error can be issued. SI-5093 is one example. - case x: SubType if x.supertype eq this => - throw new TypeError("illegal cyclic reference involving " + sym) - case tp => tp - } - } - thisInfoCache - } - - def relativeInfo: Type = - if (!sym.isNonClassType) pre.memberInfo(sym) - else { - val memberInfo = pre.memberInfo(sym) - if (relativeInfoCache == null || (memberInfo ne memberInfoCache)) { - memberInfoCache = memberInfo - relativeInfoCache = transformInfo(memberInfo) - } - relativeInfoCache + + // note: does not go through typeRef. There's no need to because + // neither `pre` nor `sym` changes. And there's a performance + // advantage to call TypeRef directly. + override def typeConstructor = TypeRef(pre, sym, Nil) + } + class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) with UniqueType { + // A reference (in a Scala program) to a type that has type parameters, but where the reference + // does not include type arguments. Note that it doesn't matter whether the symbol refers + // to a java or scala symbol, but it does matter whether it occurs in java or scala code. + // TypeRefs w/o type params that occur in java signatures/code are considered raw types, and are + // represented as existential types. + override def isHigherKinded = typeParams.nonEmpty + override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams + private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym) + + override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = + if (isHigherKinded) { + if (sameLength(formals intersect typeParams, typeParams)) + copyTypeRef(this, pre, sym, actuals) + // partial application (needed in infer when bunching type arguments from classes and methods together) + else + copyTypeRef(this, pre, sym, dummyArgs).instantiateTypeParams(formals, actuals) } + else + super.instantiateTypeParams(formals, actuals) - override def typeSymbol = if (sym.isAliasType && (this ne normalize)) normalize.typeSymbol else sym - override def termSymbol = if (sym.isAliasType && (this ne normalize)) normalize.termSymbol else super.termSymbol - override def typeSymbolDirect = sym - override def termSymbolDirect = super.termSymbol - -/* @MAT -whenever you see `tp.typeSymbol.isXXXX` and then act on tp based on that predicate, you're on thin ice, -as `typeSymbol` (and `prefix`) automatically normalize, but the other inspectors don't. -In other words, even if `tp.normalize.sym.isXXX` is true, `tp.sym.isXXX` may be false (if sym were a public method to access the non-normalized typeSymbol)... - -In retrospect, I think `tp.typeSymbol.isXXX` or (worse) `tp.typeSymbol==XXX` should be replaced by `val tp = tp0.asXXX`. -A type's typeSymbol should never be inspected directly. -*/ - - override def bounds: TypeBounds = - if (sym.isAbstractType) thisInfo.bounds // transform(thisInfo.bounds).asInstanceOf[TypeBounds] // ??? seems to be doing asSeenFrom twice - else super.bounds - - override def parents: List[Type] = { - val period = parentsPeriod - if (period != currentPeriod) { - parentsPeriod = currentPeriod - if (!isValidForBaseClasses(period)) { - parentsCache = thisInfo.parents map transform - } else if (parentsCache == null) { // seems this can happen if things are currupted enough, see #2641 - parentsCache = List(AnyClass.tpe) - } - } - parentsCache + override def transform(tp: Type): Type = { + val res = asSeenFromOwner(tp) + if (isHigherKinded && !isRaw) + res.instantiateTypeParams(typeParams, dummyArgs) + else + res } - override def typeOfThis = transform(sym.typeOfThis) -/* - override def narrow = - if (sym.isModuleClass) transform(sym.thisType) - else if (sym.isAliasType) normalize.narrow - else super.narrow -*/ + override def transformInfo(tp: Type): Type = + appliedType(asSeenFromOwner(tp), dummyArgs) + override def narrow = if (sym.isModuleClass) singleType(pre, sym.sourceModule) - else if (sym.isAliasType) normalize.narrow else super.narrow - override def prefix: Type = - if (sym.isAliasType) normalize.prefix - else pre - - override def typeArgs: List[Type] = args - private def typeArgsOrDummies = if (!isHigherKinded) args else dummyArgs - // def hasFishyArgs = args == dummyArgs - private def argsMatchTypeParams = sameLength(sym.info.typeParams, args) + override def typeConstructor = this + // eta-expand, subtyping relies on eta-expansion of higher-kinded types + // override protected def normalizeImpl: Type = + // if (isHigherKinded) etaExpand else super.normalizeImpl + } + + trait ClassTypeRef extends TypeRef { + // !!! There are scaladoc-created symbols arriving which violate this require. + // require(sym.isClass, sym) - // @MAT was typeSymbol.unsafeTypeParams, but typeSymbol normalizes now - private def typeParamsDirect = - if (isDefinitionsInitialized) sym.typeParams - else sym.unsafeTypeParams + override def baseType(clazz: Symbol): Type = + if (sym == clazz) this + else transform(sym.info.baseType(clazz)) + } + trait NonClassTypeRef extends TypeRef { + require(sym.isNonClassType, sym) - // placeholders derived from type params - private def dummyArgs = { - // @PP to @AM: this appears to me a place where - // higher-order tparams are going off the beam. - // if (sym.isAbstractType) { something goes wrong } + private var relativeInfoCache: Type = _ + private var memberInfoCache: Type = _ - //@M must be .typeConstructor - typeParamsDirect map (_.typeConstructor) + private def relativeInfo = { + val memberInfo = pre.memberInfo(sym) + if (relativeInfoCache == null || (memberInfo ne memberInfoCache)) { + memberInfoCache = memberInfo + relativeInfoCache = transformInfo(memberInfo) + } + relativeInfoCache } + + override def baseType(clazz: Symbol): Type = ( + if (sym == clazz) this else try { + basetypeRecursions += 1 + if (basetypeRecursions < LogPendingBaseTypesThreshold) + relativeInfo.baseType(clazz) + else if (pendingBaseTypes contains this) + if (clazz == AnyClass) clazz.tpe else NoType + else + try { + pendingBaseTypes += this + relativeInfo.baseType(clazz) + } finally { + pendingBaseTypes -= this + } + } finally { + basetypeRecursions -= 1 + } + ) + } + trait AliasTypeRef extends NonClassTypeRef { + require(sym.isAliasType, sym) - // (!result.isEmpty) IFF isHigherKinded - override def typeParams: List[Symbol] = if (isHigherKinded) typeParamsDirect else List() - - // note: does not go through typeRef. There's no need to because - // neither `pre` nor `sym` changes. And there's a performance - // advantage to call TypeRef directly. - override def typeConstructor = if (args.isEmpty) this else TypeRef(pre, sym, Nil) + override def dealias = if (typeParamsMatchArgs) betaReduce.dealias else super.dealias + override def isStable = normalize.isStable + override def isVolatile = normalize.isVolatile + override def narrow = normalize.narrow + override def thisInfo = normalize + // override def prefix = normalize.prefix + // override def termSymbol = if (this ne normalize) normalize.termSymbol else super.termSymbol + // override def typeSymbol = if (this ne normalize) normalize.typeSymbol else sym + // beta-reduce, but don't do partial application -- cycles have been checked in typeRef + // override protected zzImpl = + // if (typeParamsMatchArgs) betaReduce.normalize else ErrorType + } - // A reference (in a Scala program) to a type that has type - // parameters, but where the reference does not include type - // arguments. Note that it doesn't matter whether the symbol refers - // to a java or scala symbol, but it does matter whether it occurs in - // java or scala code. TypeRefs w/o type params that occur in java - // signatures/code are considered raw types, and are represented as - // existential types. - override def isHigherKinded = args.isEmpty && typeParamsDirect.nonEmpty + trait AbstractTypeRef extends NonClassTypeRef { + require(sym.isAbstractType, sym) + + private var symInfoCache: Type = _ + private var thisInfoCache: Type = _ - override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = - if (isHigherKinded) { - if (sameLength(formals intersect typeParams, typeParams)) - copyTypeRef(this, pre, sym, actuals) - // partial application (needed in infer when bunching type arguments from classes and methods together) + override def isVolatile = { + // need to be careful not to fall into an infinite recursion here + // because volatile checking is done before all cycles are detected. + // the case to avoid is an abstract type directly or + // indirectly upper-bounded by itself. See #2918 + try { + volatileRecursions += 1 + if (volatileRecursions < LogVolatileThreshold) + bounds.hi.isVolatile + else if (pendingVolatiles(sym)) + true // we can return true here, because a cycle will be detected + // here afterwards and an error will result anyway. else - copyTypeRef(this, pre, sym, dummyArgs).instantiateTypeParams(formals, actuals) + try { + pendingVolatiles += sym + bounds.hi.isVolatile + } finally { + pendingVolatiles -= sym + } + } finally { + volatileRecursions -= 1 } - else - super.instantiateTypeParams(formals, actuals) - - /** @pre: argsMatchTypeParams */ - @inline private def betaReduce: Type = { - // isHKSubType0 introduces synthetic type params so that - // betaReduce can first apply sym.info to typeArgs before calling - // asSeenFrom. asSeenFrom then skips synthetic type params, which - // are used to reduce HO subtyping to first-order subtyping, but - // which can't be instantiated from the given prefix and class. - transform(sym.info.resultType) - // this crashes pos/depmet_implicit_tpbetareduce.scala - // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) - } - private def isBetaReducible = sym.isAliasType && argsMatchTypeParams - - // @M: initialize (by sym.info call) needed (see test/files/pos/ticket0137.scala) - @inline private def etaExpand: Type = { - val tpars = sym.info.typeParams // must go through sym.info for typeParams to initialise symbol - if (tpars.isEmpty) this - else typeFunAnon(tpars, copyTypeRef(this, pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce? } + override def thisInfo = { + val symInfo = sym.info + if (thisInfoCache == null || (symInfo ne symInfoCache)) { + symInfoCache = symInfo + thisInfoCache = transformInfo(symInfo) match { + // If a subtyping cycle is not detected here, we'll likely enter an infinite + // loop before a sensible error can be issued. SI-5093 is one example. + case x: SubType if x.supertype eq this => + throw new TypeError("illegal cyclic reference involving " + sym) + case tp => tp + } + } + thisInfoCache + } + override def isStable = bounds.hi.typeSymbol isSubClass SingletonClass + override def bounds = if (sym.isAbstractType) thisInfo.bounds else super.bounds + // def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies) + override protected def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this + } + + /** A class for named types of the form + * `.[args]` + * Cannot be created directly; one should always use `typeRef` + * for creation. (@M: Otherwise hashing breaks) + * + * @M: a higher-kinded type is represented as a TypeRef with sym.typeParams.nonEmpty, but args.isEmpty + */ + abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type { + private var parentsCache: List[Type] = _ + private var parentsPeriod = NoPeriod + private var baseTypeSeqCache: BaseTypeSeq = _ + private var baseTypeSeqPeriod = NoPeriod + private var normalized: Type = _ - override def dealias = if (isBetaReducible) betaReduce.dealias else this + // @M: propagate actual type params (args) to `tp`, by replacing + // formal type parameters with actual ones. If tp is higher kinded, + // the "actual" type arguments are types that simply reference the + // corresponding type parameters (unbound type variables) + def transform(tp: Type): Type private def normalize0: Type = ( if (pre eq WildcardType) WildcardType // arises when argument-dependent types are approximated (see def depoly in implicits) else if (isHigherKinded) etaExpand // eta-expand, subtyping relies on eta-expansion of higher-kinded types - else if (isBetaReducible) betaReduce.normalize // beta-reduce, but don't do partial application -- cycles have been checked in typeRef + else if (sym.isAliasType && typeParamsMatchArgs) betaReduce.normalize // beta-reduce, but don't do partial application -- cycles have been checked in typeRef else if (sym.isRefinementClass) sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers else if (sym.isAliasType) ErrorType //println("!!error: "+(pre, sym, sym.info, sym.info.typeParams, args)) else super.normalize ) - // TODO: test case that is compiled in a specific order and in different runs + // TODO: test case that is compiled in a specific order and in different runs override def normalize: Type = { if (phase.erasedTypes) normalize0 else { - if (normalized == null) + if (normalized eq null) normalized = normalize0 - normalized } } + // isHKSubType0 introduces synthetic type params so that + // betaReduce can first apply sym.info to typeArgs before calling + // asSeenFrom. asSeenFrom then skips synthetic type params, which + // are used to reduce HO subtyping to first-order subtyping, but + // which can't be instantiated from the given prefix and class. + // + // this crashes pos/depmet_implicit_tpbetareduce.scala + // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) + def betaReduce = transform(sym.info.resultType) + + def etaExpand: Type = { + // must initialise symbol, see test/files/pos/ticket0137.scala + val tpars = initializedTypeParams + if (tpars.isEmpty) this + else typeFunAnon(tpars, copyTypeRef(this, pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce? + } + + // #3731: return sym1 for which holds: pre bound sym.name to sym and + // pre1 now binds sym.name to sym1, conceptually exactly the same + // symbol as sym. The selection of sym on pre must be updated to the + // selection of sym1 on pre1, since sym's info was probably updated + // by the TypeMap to yield a new symbol, sym1 with transformed info. + // @returns sym1 + // + // only need to rebind type aliases, as typeRef already handles abstract types + // (they are allowed to be rebound more liberally) + def coevolveSym(pre1: Type): Symbol = + if (!sym.isAliasType || (pre eq pre1)) sym + else (pre, pre1) match { + // don't look at parents -- it would be an error to override alias types anyway + case (RefinedType(_, _), RefinedType(_, decls1)) => decls1 lookup sym.name + // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? + case _ => sym + } + + //@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs) + def transformInfo(tp: Type): Type = appliedType(asSeenFromOwner(tp), args) + + def thisInfo = sym.info + def initializedTypeParams = sym.info.typeParams + def typeParamsMatchArgs = sameLength(initializedTypeParams, args) + def asSeenFromOwner(tp: Type) = tp.asSeenFrom(pre, sym.owner) + + override def baseClasses = thisInfo.baseClasses + override def baseTypeSeqDepth = baseTypeSeq.maxDepth + override def isStable = (sym eq NothingClass) || (sym eq SingletonClass) + override def prefix = if (sym.isAliasType && (this ne normalize)) normalize.prefix else pre + override def typeArgs = args + override def typeOfThis = transform(sym.typeOfThis) + override def termSymbol = if (sym.isAliasType && (this ne normalize)) normalize.termSymbol else super.termSymbol + override def typeSymbol = if (sym.isAliasType && (this ne normalize)) normalize.typeSymbol else sym + override def typeSymbolDirect = sym + override def termSymbolDirect = super.termSymbol + + override lazy val isTrivial: Boolean = + !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial) + + override def isNotNull = + sym.isModuleClass || sym == NothingClass || isValueClass(sym) || super.isNotNull + + override def parents: List[Type] = { + val period = parentsPeriod + if (period != currentPeriod) { + parentsPeriod = currentPeriod + if (!isValidForBaseClasses(period)) { + parentsCache = thisInfo.parents map transform + } else if (parentsCache == null) { // seems this can happen if things are corrupted enough, see #2641 + parentsCache = List(AnyClass.tpe) + } + } + parentsCache + } override def decls: Scope = { sym.info match { @@ -2015,27 +2062,8 @@ A type's typeSymbol should never be inspected directly. } thisInfo.decls } - - override def baseType(clazz: Symbol): Type = - if (sym == clazz) this - else if (sym.isClass) transform(sym.info.baseType(clazz)) - else - try { - basetypeRecursions += 1 - if (basetypeRecursions < LogPendingBaseTypesThreshold) - relativeInfo.baseType(clazz) - else if (pendingBaseTypes contains this) - if (clazz == AnyClass) clazz.tpe else NoType - else - try { - pendingBaseTypes += this - relativeInfo.baseType(clazz) - } finally { - pendingBaseTypes -= this - } - } finally { - basetypeRecursions -= 1 - } + + protected def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform override def baseTypeSeq: BaseTypeSeq = { val period = baseTypeSeqPeriod @@ -2044,9 +2072,7 @@ A type's typeSymbol should never be inspected directly. if (!isValidForBaseClasses(period)) { incCounter(typerefBaseTypeSeqCount) baseTypeSeqCache = undetBaseTypeSeq - baseTypeSeqCache = - if (sym.isAbstractType) transform(bounds.hi).baseTypeSeq prepend this - else sym.info.baseTypeSeq map transform + baseTypeSeqCache = baseTypeSeqImpl } } if (baseTypeSeqCache == undetBaseTypeSeq) @@ -2054,11 +2080,6 @@ A type's typeSymbol should never be inspected directly. baseTypeSeqCache } - override def baseTypeSeqDepth: Int = baseTypeSeq.maxDepth - - override def baseClasses: List[Symbol] = thisInfo.baseClasses - - // override def isNullable: Boolean = sym.info.isNullable private def preString = ( // ensure that symbol is not a local copy with a name coincidence if (!settings.debug.value && shorthands(sym.fullName) && sym.ownerChain.forall(_.isClass)) "" @@ -2073,7 +2094,6 @@ A type's typeSymbol should never be inspected directly. ) else "" ) - private def finishPrefix(rest: String) = ( if (sym.isPackageClass) packagePrefix + rest else if (sym.isModuleClass) objectPrefix + rest @@ -2126,12 +2146,19 @@ A type's typeSymbol should never be inspected directly. override def kind = "TypeRef" } - final class UniqueTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends TypeRef(pre, sym, args) with UniqueType { } - object TypeRef extends TypeRefExtractor { - def apply(pre: Type, sym: Symbol, args: List[Type]): Type = { - unique(new UniqueTypeRef(pre, sym, args)) - } + def apply(pre: Type, sym: Symbol, args: List[Type]): Type = unique({ + if (args.nonEmpty) { + if (sym.isAliasType) new ArgsTypeRef(pre, sym, args) with AliasTypeRef + else if (sym.isAbstractType) new ArgsTypeRef(pre, sym, args) with AbstractTypeRef + else new ArgsTypeRef(pre, sym, args) with ClassTypeRef + } + else { + if (sym.isAliasType) new NoArgsTypeRef(pre, sym) with AliasTypeRef + else if (sym.isAbstractType) new NoArgsTypeRef(pre, sym) with AbstractTypeRef + else new NoArgsTypeRef(pre, sym) with ClassTypeRef + } + }) } /** A class representing a method type with parameters. @@ -2410,7 +2437,7 @@ A type's typeSymbol should never be inspected directly. object HasTypeMember { def apply(name: TypeName, tp: Type): Type = { val bound = refinedType(List(WildcardType), NoSymbol) - val bsym = bound.typeSymbol.newAliasType(NoPosition, name) + val bsym = bound.typeSymbol.newAliasType(name) bsym setInfo tp bound.decls enter bsym bound @@ -3298,8 +3325,8 @@ A type's typeSymbol should never be inspected directly. case DeBruijnBinder(pnames, ptypes, restpe) => val isType = pnames.head.isTypeName val newParams = for (name <- pnames) yield - if (isType) owner.newTypeParameter(NoPosition, name.toTypeName) - else owner.newValueParameter(NoPosition, name.toTermName) + if (isType) owner.newTypeParameter(name.toTypeName) + else owner.newValueParameter(name.toTermName) paramStack = newParams :: paramStack try { (newParams, ptypes).zipped foreach ((p, t) => p setInfo this(t)) @@ -3482,7 +3509,7 @@ A type's typeSymbol should never be inspected directly. val hi1 = this(hi) if ((lo1 eq lo) && (hi1 eq hi)) tp else TypeBounds(lo1, hi1) - case TypeRef(pre, sym, args) => + case tr @ TypeRef(pre, sym, args) => val pre1 = this(pre) val args1 = if (args.isEmpty) @@ -3495,7 +3522,7 @@ A type's typeSymbol should never be inspected directly. else mapOverArgs(args, tparams) } if ((pre1 eq pre) && (args1 eq args)) tp - else copyTypeRef(tp, pre1, coevolveSym(pre, pre1, sym), args1) + else copyTypeRef(tp, pre1, tr.coevolveSym(pre1), args1) case _ => super.mapOver(tp) } @@ -3510,37 +3537,13 @@ A type's typeSymbol should never be inspected directly. */ def variance = 0 - // #3731: return sym1 for which holds: pre bound sym.name to sym and - // pre1 now binds sym.name to sym1, conceptually exactly the same - // symbol as sym. The selection of sym on pre must be updated to the - // selection of sym1 on pre1, since sym's info was probably updated - // by the TypeMap to yield a new symbol, sym1 with transformed info. - // @returns sym1 - protected def coevolveSym(pre: Type, pre1: Type, sym: Symbol): Symbol = - if((pre ne pre1) && sym.isAliasType) // only need to rebind type aliases here, as typeRef already handles abstract types (they are allowed to be rebound more liberally) - (pre, pre1) match { - case (RefinedType(_, decls), RefinedType(_, decls1)) => // don't look at parents -- it would be an error to override alias types anyway - //val sym1 = - decls1.lookup(sym.name) -// assert(decls.lookupAll(sym.name).toList.length == 1) -// assert(decls1.lookupAll(sym.name).toList.length == 1) -// assert(sym1.isAliasType) -// println("coevolved "+ sym +" : "+ sym.info +" to "+ sym1 +" : "+ sym1.info +" with "+ pre +" -> "+ pre1) -// sym1 - case _ => // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? -// val sym1 = pre1.nonPrivateMember(sym.name).suchThat(sym => sym.isAliasType) -// println("??coevolve "+ sym +" : "+ sym.info +" to "+ sym1 +" : "+ sym1.info +" with "+ pre +" -> "+ pre1) - sym - } - else sym - /** Map this function over given type */ def mapOver(tp: Type): Type = tp match { - case TypeRef(pre, sym, args) => + case tr @ TypeRef(pre, sym, args) => val pre1 = this(pre) val args1 = args mapConserve this if ((pre1 eq pre) && (args1 eq args)) tp - else copyTypeRef(tp, pre1, coevolveSym(pre, pre1, sym), args1) + else copyTypeRef(tp, pre1, tr.coevolveSym(pre1), args1) case ThisType(_) => tp case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path @@ -4599,7 +4602,7 @@ A type's typeSymbol should never be inspected directly. */ def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = { def createDummyClone(pre: Type): Type = { - val dummy = currentOwner.enclClass.newValue(NoPosition, nme.ANYNAME).setInfo(pre.widen) + val dummy = currentOwner.enclClass.newValue(nme.ANYNAME).setInfo(pre.widen) singleType(ThisType(currentOwner.enclClass), dummy) } def maybeCreateDummyClone(pre: Type, sym: Symbol): Type = pre match { @@ -5539,10 +5542,6 @@ A type's typeSymbol should never be inspected directly. } /** Do type arguments `targs` conform to formal parameters `tparams`? - * - * @param tparams ... - * @param targs ... - * @return ... */ def isWithinBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): Boolean = { var bounds = instantiatedBounds(pre, owner, tparams, targs) diff --git a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala index 0789f9c774..3fddc990e4 100644 --- a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala @@ -282,7 +282,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { finishSym(tag match { case TYPEsym => owner.newAbstractType(name.toTypeName) - case ALIASsym => owner.newAliasType(name.toTypeName) + case ALIASsym => owner.newTypeSymbol(name.toTypeName) case CLASSsym => val sym = (isClassRoot, isModuleFlag) match { case (true, true) => moduleRoot.moduleClass @@ -297,11 +297,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { case MODULEsym => val clazz = at(inforef, () => readType()).typeSymbol // after the NMT_TRANSITION period, we can leave off the () => ... () if (isModuleRoot) moduleRoot - else { - val m = owner.newModule(name.toTermName, clazz) - clazz.sourceModule = m - m - } + else owner.newLinkedModule(clazz) case VALsym => if (isModuleRoot) { assert(false); NoSymbol } else if (isMethodFlag) owner.newMethod(name.toTermName) diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala index 9da75bf2b0..fd3b9b9aa0 100644 --- a/src/compiler/scala/reflect/runtime/JavaToScala.scala +++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala @@ -115,7 +115,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => * @param jtvar The Java type variable */ private def createTypeParameter(jtvar: jTypeVariable[_ <: GenericDeclaration]): Symbol = { - val tparam = sOwner(jtvar).newTypeParameter(NoPosition, newTypeName(jtvar.getName)) + val tparam = sOwner(jtvar).newTypeParameter(newTypeName(jtvar.getName)) .setInfo(new TypeParamCompleter(jtvar)) tparamCache enter (jtvar, tparam) tparam @@ -335,7 +335,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => val name = newTermName(fullname drop (split + 1)) var pkg = owner.info decl name if (pkg == NoSymbol) { - pkg = owner.newPackage(NoPosition, name) + pkg = owner.newPackage(name) pkg.moduleClass setInfo new LazyPackageType pkg setInfo pkg.moduleClass.tpe owner.info.decls enter pkg diff --git a/src/compiler/scala/reflect/runtime/Loaders.scala b/src/compiler/scala/reflect/runtime/Loaders.scala index 35b3a16dc2..7aca052fa9 100644 --- a/src/compiler/scala/reflect/runtime/Loaders.scala +++ b/src/compiler/scala/reflect/runtime/Loaders.scala @@ -63,8 +63,8 @@ trait Loaders { self: SymbolTable => */ protected def createClassModule(owner: Symbol, name: TypeName, completer: (Symbol, Symbol) => LazyType) = { assert(!(name.toString endsWith "[]"), name) - val clazz = owner.newClass(NoPosition, name) - val module = owner.newModule(NoPosition, name.toTermName) + val clazz = owner.newClass(name) + val module = owner.newModule(name.toTermName) owner.info.decls enter clazz owner.info.decls enter module initClassModule(clazz, module, completer(clazz, module)) diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala index 231bcdbc0e..11563fa4cc 100644 --- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala +++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala @@ -53,12 +53,12 @@ trait ToolBoxes extends { self: Universe => } def wrapInObject(expr: Tree, fvs: List[Symbol]): ModuleDef = { - val obj = EmptyPackageClass.newModule(NoPosition, nextWrapperModuleName()) + val obj = EmptyPackageClass.newModule(nextWrapperModuleName()) val minfo = ClassInfoType(List(ObjectClass.tpe, ScalaObjectClass.tpe), new Scope, obj.moduleClass) obj.moduleClass setInfo minfo obj setInfo obj.moduleClass.tpe - val meth = obj.moduleClass.newMethod(NoPosition, newTermName(wrapperMethodName)) - def makeParam(fv: Symbol) = meth.newValueParameter(NoPosition, fv.name.toTermName) setInfo fv.tpe + val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName)) + def makeParam(fv: Symbol) = meth.newValueParameter(fv.name.toTermName) setInfo fv.tpe meth setInfo MethodType(fvs map makeParam, expr.tpe) minfo.decls enter meth trace("wrapping ")(defOwner(expr) -> meth) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 144322e4f5..55d5efda1f 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -96,17 +96,17 @@ abstract class TreeGen extends reflect.internal.TreeGen { } def mkModuleVarDef(accessor: Symbol) = { + val inClass = accessor.owner.isClass + val extraFlags = if (inClass) PrivateLocal | SYNTHETIC else 0 + val mval = ( - accessor.owner.newVariable(accessor.pos.focus, nme.moduleVarName(accessor.name)) - setInfo accessor.tpe.finalResultType - setFlag (MODULEVAR) + accessor.owner.newVariable(nme.moduleVarName(accessor.name), accessor.pos.focus, MODULEVAR | extraFlags) + setInfo accessor.tpe.finalResultType + addAnnotation VolatileAttr ) + if (inClass) + mval.owner.info.decls enter mval - mval addAnnotation VolatileAttr - if (mval.owner.isClass) { - mval setFlag (PrivateLocal | SYNTHETIC) - mval.owner.info.decls.enter(mval) - } ValDef(mval) } diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 803bd05031..15b4c8c708 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1755,7 +1755,7 @@ abstract class GenICode extends SubComponent { val sym = t.symbol def getLabel(pos: Position, name: Name) = labels.getOrElseUpdate(sym, - method.newLabel(sym.pos, unit.freshTermName(name.toString)) setInfo sym.tpe + method.newLabel(unit.freshTermName(name.toString), sym.pos) setInfo sym.tpe ) t match { @@ -2005,9 +2005,7 @@ abstract class GenICode extends SubComponent { /** Make a fresh local variable. It ensures the 'name' is unique. */ def makeLocal(pos: Position, tpe: Type, name: String): Local = { - val sym = method.symbol.newVariable(pos, unit.freshTermName(name)) - .setInfo(tpe) - .setFlag(Flags.SYNTHETIC) + val sym = method.symbol.newVariable(unit.freshTermName(name), pos, Flags.SYNTHETIC) setInfo tpe this.method.addLocal(new Local(sym, toTypeKind(tpe), false)) } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 4ec3ef5ae6..309d8f26fb 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -876,7 +876,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if (outerField != NoSymbol) { log("Adding fake local to represent outer 'this' for closure " + clasz) val _this = new Local( - method.symbol.newVariable(NoPosition, nme.FAKE_LOCAL_THIS), toTypeKind(outerField.tpe), false) + method.symbol.newVariable(nme.FAKE_LOCAL_THIS), toTypeKind(outerField.tpe), false) m.locals = m.locals ::: List(_this) computeLocalVarsIndex(m) // since we added a new local, we need to recompute indexes diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index e3d21011d1..88bbb16e34 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -348,7 +348,7 @@ abstract class Inliners extends SubComponent { def blockEmit(i: Instruction) = block.emit(i, targetPos) def newLocal(baseName: String, kind: TypeKind) = - new Local(caller.sym.newVariable(targetPos, freshName(baseName)), kind, false) + new Local(caller.sym.newVariable(freshName(baseName), targetPos), kind, false) val a = new analysis.MethodTFA(inc.m) @@ -400,7 +400,7 @@ abstract class Inliners extends SubComponent { /** alfa-rename `l` in caller's context. */ def dupLocal(l: Local): Local = { - val sym = caller.sym.newVariable(l.sym.pos, freshName(l.sym.name.toString)) + val sym = caller.sym.newVariable(freshName(l.sym.name.toString), l.sym.pos) // sym.setInfo(l.sym.tpe) val dupped = new Local(sym, l.kind, false) inlinedLocals(l) = dupped diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 0d7afdc4ec..0c94e40d68 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -126,11 +126,15 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { if (treeInfo.firstConstructor(stats) == EmptyTree) makeConstructor(List()) :: stats else stats) - def makeParam(name: String, tpt: Tree) = - ValDef(Modifiers(Flags.JAVA | Flags.PARAM), newTermName(name), tpt, EmptyTree) + def makeSyntheticParam(count: Int, tpt: Tree): ValDef = + makeParam(nme.syntheticParamName(count), tpt) + def makeParam(name: String, tpt: Tree): ValDef = + makeParam(newTypeName(name), tpt) + def makeParam(name: TermName, tpt: Tree): ValDef = + ValDef(Modifiers(Flags.JAVA | Flags.PARAM), name, tpt, EmptyTree) def makeConstructor(formals: List[Tree]) = { - val vparams = formals.zipWithIndex map { case (p, i) => makeParam("x$" + (i + 1), p) } + val vparams = mapWithIndex(formals)((p, i) => makeSyntheticParam(i + 1, p)) DefDef(Modifiers(Flags.JAVA), nme.CONSTRUCTOR, List(), List(vparams), TypeTree(), blankExpr) } diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index 61864f0c8a..d81f05cd51 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -252,7 +252,8 @@ trait Matrix extends MatrixAdditions { { val n = if (name == null) cunit.freshTermName("temp") else name // careful: pos has special meaning - recordSyntheticSym(owner.newVariable(pos, n) setInfo tpe setFlag (SYNTHETIC.toLong /: flags)(_|_)) + val flagsLong = (SYNTHETIC.toLong /: flags)(_|_) + recordSyntheticSym(owner.newVariable(n, pos, flagsLong) setInfo tpe) } } } \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 11d829eadb..9d4c9b4411 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -54,7 +54,7 @@ trait ParallelMatching extends ast.TreeDSL } def createLabelDef(namePrefix: String, body: Tree, params: List[Symbol] = Nil, restpe: Type = matchResultType) = { val labelName = cunit.freshTermName(namePrefix) - val labelSym = owner.newLabel(owner.pos, labelName) + val labelSym = owner.newLabel(labelName, owner.pos) val labelInfo = MethodType(params, restpe) LabelDef(labelSym setInfo labelInfo, params, body setType restpe) diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 340e1d1d08..5d419320ac 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -49,7 +49,7 @@ abstract class SymbolLoaders { */ def enterModule(root: Symbol, name: String, completer: SymbolLoader): Symbol = { val owner = realOwner(root) - val module = owner.newModule(NoPosition, newTermName(name)) + val module = owner.newModule(newTermName(name)) module setInfo completer module.moduleClass setInfo moduleClassLoader enterIfNew(owner, module, completer) @@ -199,7 +199,7 @@ abstract class SymbolLoaders { return } } - val pkg = root.newPackage(NoPosition, newTermName(name)) + val pkg = root.newPackage(newTermName(name)) pkg.moduleClass.setInfo(completer) pkg.setInfo(pkg.moduleClass.tpe) root.info.decls.enter(pkg) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index a158012f9f..61521ea250 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -455,7 +455,7 @@ abstract class ClassfileParser { ss = name.subName(start, end) sym = owner.info.decls lookup ss if (sym == NoSymbol) { - sym = owner.newPackage(NoPosition, ss) setInfo completer + sym = owner.newPackage(ss) setInfo completer sym.moduleClass setInfo completer owner.info.decls enter sym } @@ -813,7 +813,7 @@ abstract class ClassfileParser { val start = index while (sig(index) != '>') { val tpname = subName(':'.==).toTypeName - val s = sym.newTypeParameter(NoPosition, tpname) + val s = sym.newTypeParameter(tpname) tparams = tparams + (tpname -> s) sig2typeBounds(tparams, true) newTParams += s @@ -1076,8 +1076,8 @@ abstract class ClassfileParser { val name = entry.originalName var sflags = toScalaFlags(jflags, isClass = true) - val innerClass = getOwner(jflags).newClass(NoPosition, name.toTypeName).setInfo(completer).setFlag(sflags) - val innerModule = getOwner(jflags).newModule(NoPosition, name.toTermName).setInfo(completer).setFlag(sflags) + val innerClass = getOwner(jflags).newClass(name.toTypeName).setInfo(completer).setFlag(sflags) + val innerModule = getOwner(jflags).newModule(name.toTermName).setInfo(completer).setFlag(sflags) innerModule.moduleClass setInfo global.loaders.moduleClassLoader getScope(jflags) enter innerClass diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 0b64a49a2c..288e19af06 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -988,7 +988,7 @@ abstract class ICodeReader extends ClassfileParser { /** Return a fresh Local variable for the given index. */ private def freshLocal(idx: Int, kind: TypeKind, isArg: Boolean) = { - val sym = method.symbol.newVariable(NoPosition, newTermName("loc" + idx)).setInfo(kind.toType); + val sym = method.symbol.newVariable(newTermName("loc" + idx)).setInfo(kind.toType); val l = new Local(sym, kind, isArg) method.addLocal(l) l @@ -1005,7 +1005,7 @@ abstract class ICodeReader extends ClassfileParser { /** add a method param with the given index. */ def enterParam(idx: Int, kind: TypeKind) = { - val sym = method.symbol.newVariable(NoPosition, newTermName("par" + idx)).setInfo(kind.toType) + val sym = method.symbol.newVariable(newTermName("par" + idx)).setInfo(kind.toType) val l = new Local(sym, kind, true) assert(!locals.isDefinedAt(idx)) locals += (idx -> List((l, kind))) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala index 676c8f09da..ead431c8d7 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/MetaParser.scala @@ -68,7 +68,7 @@ abstract class MetaParser{ else if (token == "-") { nextToken(); Flags.CONTRAVARIANT } else 0; assert(token startsWith "?", token) - val sym = owner.newTypeParameter(NoPosition, newTypeName(token)).setFlag(vflag) + val sym = owner.newTypeParameter(newTypeName(token)).setFlag(vflag) nextToken() val lo = if (token == ">") { nextToken(); parseType() } diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index e0cb0848be..6c238f52cc 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -175,7 +175,7 @@ abstract class TypeParser { // first pass for (tvarCILDef <- typ.getSortedTVars() ) { val tpname = newTypeName(tvarCILDef.Name.replaceAll("!", "")) // TODO are really all type-params named in all assemblies out there? (NO) - val tpsym = clazz.newTypeParameter(NoPosition, tpname) + val tpsym = clazz.newTypeParameter(tpname) classTParams.put(tvarCILDef.Number, tpsym) newTParams += tpsym // TODO wouldn't the following also be needed later, i.e. during getCLRType @@ -259,8 +259,8 @@ abstract class TypeParser { || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ ) { val loader = new loaders.MsilFileLoader(new MsilFile(ntype)) - val nclazz = statics.newClass(NoPosition, ntype.Name.toTypeName) - val nmodule = statics.newModule(NoPosition, ntype.Name) + val nclazz = statics.newClass(ntype.Name.toTypeName) + val nmodule = statics.newModule(ntype.Name) nclazz.setInfo(loader) nmodule.setInfo(loader) staticDefs.enter(nclazz) @@ -449,7 +449,7 @@ abstract class TypeParser { // first pass for (mvarCILDef <- method.getSortedMVars() ) { val mtpname = newTypeName(mvarCILDef.Name.replaceAll("!", "")) // TODO are really all method-level-type-params named in all assemblies out there? (NO) - val mtpsym = methodSym.newTypeParameter(NoPosition, mtpname) + val mtpsym = methodSym.newTypeParameter(mtpname) methodTParams.put(mvarCILDef.Number, mtpsym) newMethodTParams += mtpsym // TODO wouldn't the following also be needed later, i.e. during getCLRType diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 034628e95f..0bc137f3e8 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -143,13 +143,13 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* ### CREATING THE METHOD CACHE ### */ def addStaticVariableToClass(forName: TermName, forType: Type, forInit: Tree, isFinal: Boolean): Symbol = { - val varSym = ( - currentClass.newVariable(ad.pos, mkTerm("" + forName)) - setFlag PRIVATE | STATIC | SYNTHETIC - setInfo forType + val flags = PRIVATE | STATIC | SYNTHETIC | ( + if (isFinal) FINAL else 0 ) - if (isFinal) varSym setFlag FINAL - else varSym.addAnnotation(VolatileAttr) + + val varSym = currentClass.newVariable(mkTerm("" + forName), ad.pos, flags) setInfo forType + if (!isFinal) + varSym.addAnnotation(VolatileAttr) currentClass.info.decls enter varSym val varDef = typedPos( VAL(varSym) === forInit ) @@ -280,7 +280,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { addStaticMethodToClass(nme.reflMethodName, List(ClassClass.tpe), MethodClass.tpe) { case Pair(reflMethodSym, List(forReceiverSym)) => - val methodSym = reflMethodSym.newVariable(ad.pos, mkTerm("method")) setInfo MethodClass.tpe + val methodSym = reflMethodSym.newVariable(mkTerm("method"), ad.pos) setInfo MethodClass.tpe BLOCK( IF (getPolyCache OBJ_EQ NULL) THEN (safeREF(reflPolyCacheSym) === mkNewPolyCache) ENDIF, @@ -565,7 +565,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { case theTry @ Try(block, catches, finalizer) if theTry.tpe.typeSymbol != definitions.UnitClass && theTry.tpe.typeSymbol != definitions.NothingClass => val tpe = theTry.tpe.widen - val tempVar = currentOwner.newVariable(theTry.pos, mkTerm(nme.EXCEPTION_RESULT_PREFIX)).setInfo(tpe) + val tempVar = currentOwner.newVariable(mkTerm(nme.EXCEPTION_RESULT_PREFIX), theTry.pos).setInfo(tpe) def assignBlock(rhs: Tree) = super.transform(BLOCK(Ident(tempVar) === transform(rhs))) val newBlock = assignBlock(block) @@ -637,8 +637,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { // create a symbol for the static field val stfieldSym = ( - currentClass.newVariable(pos, mkTerm("symbol$")) - setFlag PRIVATE | STATIC | SYNTHETIC | FINAL + currentClass.newVariable(mkTerm("symbol$"), pos, PRIVATE | STATIC | SYNTHETIC | FINAL) setInfo SymbolClass.tpe ) currentClass.info.decls enter stfieldSym diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index cf7d6c94fe..701fda1035 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -136,7 +136,7 @@ abstract class ExplicitOuter extends InfoTransform } if (sym.owner.isTrait) sym setNotFlag PROTECTED // 6 if (sym.isClassConstructor && isInner(sym.owner)) { // 1 - val p = sym.newValueParameter(sym.pos, innerClassConstructorParamName) + val p = sym.newValueParameter(innerClassConstructorParamName, sym.pos) .setInfo(sym.owner.outerClass.thisType) MethodType(p :: params, restpe) } else if (restpe ne restpe1) @@ -475,7 +475,7 @@ abstract class ExplicitOuter extends InfoTransform val vparamss1 = if (isInner(clazz)) { // (4) val outerParam = - sym.newValueParameter(sym.pos, nme.OUTER) setInfo outerField(clazz).info + sym.newValueParameter(nme.OUTER, sym.pos) setInfo outerField(clazz).info ((ValDef(outerParam) setType NoType) :: vparamss.head) :: vparamss.tail } else vparamss super.transform(treeCopy.DefDef(tree, mods, name, tparams, vparamss1, tpt, rhs)) diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index 5452087aa3..f8c5f5bfc6 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -246,7 +246,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD if (bmps.length > n) bmps(n) else { - val sym = meth.newVariable(meth.pos, nme.newBitmapName(nme.BITMAP_NORMAL, n)).setInfo(IntClass.tpe) + val sym = meth.newVariable(nme.newBitmapName(nme.BITMAP_NORMAL, n), meth.pos).setInfo(IntClass.tpe) atPhase(currentRun.typerPhase) { sym addAnnotation VolatileAttr } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index c7d3b331a6..d011c15494 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -396,9 +396,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { if (sourceModule != NoSymbol) { sourceModule setPos sym.pos sourceModule.flags = MODULE | FINAL - } else { - sourceModule = clazz.owner.newModule( - sym.pos, sym.name.toTermName, sym.asInstanceOf[ClassSymbol]) + } + else { + sourceModule = ( + clazz.owner.newModuleSymbol(sym.name.toTermName, sym.pos, MODULE | FINAL) + setModuleClass sym.asInstanceOf[ClassSymbol] + ) clazz.owner.info.decls enter sourceModule } sourceModule setInfo sym.tpe @@ -742,7 +745,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { assert(!sym.isOverloaded, sym) def createBitmap: Symbol = { - val sym = clazz0.newVariable(clazz0.pos, bitmapName) setInfo IntClass.tpe + val sym = clazz0.newVariable(bitmapName, clazz0.pos) setInfo IntClass.tpe atPhase(currentRun.typerPhase)(sym addAnnotation VolatileAttr) category match { diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 99b0a82690..5d13f80897 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -407,7 +407,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ private def typeParamSubAnyRef(sym: Symbol, cls: Symbol) = ( anyrefSpecCache.getOrElseUpdate(sym, - cls.newTypeParameter(sym.pos, sym.name append nme.SPECIALIZED_SUFFIX_NAME toTypeName) + cls.newTypeParameter(sym.name append nme.SPECIALIZED_SUFFIX_NAME toTypeName, sym.pos) setInfo TypeBounds(sym.info.bounds.lo, AnyRefClass.tpe) ).tpe ) diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index e2cd0a8402..da767b6bce 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -128,7 +128,7 @@ abstract class TailCalls extends Transform { * the label field. */ this.label = { - val label = method.newLabel(method.pos, newTermName("_" + method.name)) + val label = method.newLabel(newTermName("_" + method.name), method.pos) val thisParam = method.newSyntheticValueParam(currentClass.typeOfThis) label setInfo MethodType(thisParam :: method.tpe.params, method.tpe.finalResultType) } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index adb408f7e4..4ae4042cc7 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -133,11 +133,9 @@ abstract class UnCurry extends InfoTransform /** Return non-local return key for given method */ private def nonLocalReturnKey(meth: Symbol) = - nonLocalReturnKeys.getOrElseUpdate(meth, { - meth.newValue(meth.pos, unit.freshTermName("nonLocalReturnKey")) - .setFlag (SYNTHETIC) - .setInfo (ObjectClass.tpe) - }) + nonLocalReturnKeys.getOrElseUpdate(meth, + meth.newValue(unit.freshTermName("nonLocalReturnKey"), meth.pos, SYNTHETIC) setInfo ObjectClass.tpe + ) /** Generate a non-local return throw with given return expression from given method. * I.e. for the method's non-local return key, generate: @@ -255,7 +253,7 @@ abstract class UnCurry extends InfoTransform if (fun1 ne fun) fun1 else { val (formals, restpe) = (targs.init, targs.last) - val anonClass = owner newAnonymousFunctionClass fun.pos setFlag (FINAL | SYNTHETIC | inConstructorFlag) + val anonClass = owner.newAnonymousFunctionClass(fun.pos, inConstructorFlag) def parents = if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe) @@ -772,7 +770,7 @@ abstract class UnCurry extends InfoTransform } val forwresult = dd.symbol.tpe.finalResultType val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) => - currentClass.newValueParameter(oldparam.symbol.pos, oldparam.name).setInfo(tp) + currentClass.newValueParameter(oldparam.name, oldparam.symbol.pos).setInfo(tp) ) def mono = MethodType(forwformsyms, forwresult) val forwtype = dd.symbol.tpe match { diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 295b66b17f..23dd28aac4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -363,10 +363,7 @@ trait Infer { def makeFullyDefined(tp: Type): Type = { val tparams = new ListBuffer[Symbol] def addTypeParam(bounds: TypeBounds): Type = { - val tparam = - context.owner.newAbstractType(context.tree.pos.focus, newTypeName("_"+tparams.size)) - .setFlag(EXISTENTIAL) - .setInfo(bounds) + val tparam = context.owner.newExistential(newTypeName("_"+tparams.size), context.tree.pos.focus) setInfo bounds tparams += tparam tparam.tpe } diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 62393befd2..29dffd99d6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -125,11 +125,7 @@ trait MethodSynthesis { def keepClean = false // whether annotations whose definitions are not meta-annotated should be kept. def validate() { } def createAndEnterSymbol(): Symbol = { - val sym = ( - owner.newMethod(tree.pos.focus, name) - setFlag tree.mods.flags & flagsMask - setFlag flagsExtra - ) + val sym = owner.newMethod(name, tree.pos.focus, (tree.mods.flags & flagsMask) | flagsExtra) setPrivateWithin(tree, sym) enterInScope(sym) sym setInfo completer(sym) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 200191fa13..71c0de10ff 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -293,23 +293,22 @@ trait Namers extends MethodSynthesis { private def createMemberSymbol(tree: MemberDef, name: Name, mask: Long): Symbol = { val pos = tree.pos val isParameter = tree.mods.isParameter - val sym = tree match { - case TypeDef(_, _, _, _) if isParameter => owner.newTypeParameter(pos, name.toTypeName) - case TypeDef(_, _, _, _) => owner.newAliasType(pos, name.toTypeName) - case DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => owner.newConstructor(pos) - case DefDef(_, _, _, _, _, _) => owner.newMethod(pos, name.toTermName) - case ClassDef(_, _, _, _) => owner.newClass(pos, name.toTypeName) - case ModuleDef(_, _, _) => owner.newModule(pos, name) - case ValDef(_, _, _, _) if isParameter => owner.newValueParameter(pos, name) + val flags = tree.mods.flags & mask + + tree match { + case TypeDef(_, _, _, _) if isParameter => owner.newTypeParameter(name.toTypeName, pos, flags) + case TypeDef(_, _, _, _) => owner.newTypeSymbol(name.toTypeName, pos, flags) + case DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => owner.newConstructor(pos, flags) + case DefDef(_, _, _, _, _, _) => owner.newMethod(name.toTermName, pos, flags) + case ClassDef(_, _, _, _) => owner.newClassSymbol(name.toTypeName, pos, flags) + case ModuleDef(_, _, _) => owner.newModule(name, pos, flags) + case ValDef(_, _, _, _) if isParameter => owner.newValueParameter(name, pos, flags) case PackageDef(pid, _) => createPackageSymbol(pos, pid) - case ValDef(_, _, _, _) => owner.newValue(pos, name) + case ValDef(_, _, _, _) => owner.newValue(name, pos, flags) } - sym setFlag (tree.mods.flags & mask) } - private def createFieldSymbol(tree: ValDef): TermSymbol = ( - owner.newValue(tree.pos, nme.getterToLocal(tree.name)) - setFlag tree.mods.flags & FieldFlags | PrivateLocal - ) + private def createFieldSymbol(tree: ValDef): TermSymbol = + owner.newValue(nme.getterToLocal(tree.name), tree.pos, tree.mods.flags & FieldFlags | PrivateLocal) private def createImportSymbol(tree: Tree) = NoSymbol.newImport(tree.pos) setInfo completerOf(tree) @@ -325,7 +324,7 @@ trait Namers extends MethodSynthesis { if (existing.isPackage && pkgOwner == existing.owner) existing else { - val pkg = pkgOwner.newPackage(pos, pid.name.toTermName) + val pkg = pkgOwner.newPackage(pid.name.toTermName, pos) val pkgClass = pkg.moduleClass val pkgClassInfo = new PackageClassInfoType(newPackageScope(pkgClass), pkgClass) @@ -579,7 +578,7 @@ trait Namers extends MethodSynthesis { // via "x$lzy" as can be seen in test #3927. val sym = ( if (owner.isClass) createFieldSymbol(tree) - else owner.newValue(tree.pos, tree.name append nme.LAZY_LOCAL) setFlag tree.mods.flags resetFlag IMPLICIT + else owner.newValue(tree.name append nme.LAZY_LOCAL, tree.pos, tree.mods.flags & ~IMPLICIT) ) enterValSymbol(tree, sym setFlag MUTABLE setLazyAccessor lazyAccessor) } diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index a8dfea02ec..07b08e52da 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -269,7 +269,7 @@ trait NamesDefaults { self: Analyzer => case _ => (seqType(arg.tpe), true) } else (arg.tpe, false) - val s = context.owner.newValue(arg.pos, unit.freshTermName("x$")) + val s = context.owner.newValue(unit.freshTermName("x$"), arg.pos) val valType = if (byName) functionType(List(), argTpe) else if (repeated) argTpe else argTpe diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index b059e023e4..4104803194 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -53,7 +53,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => import typeDebug.{ ptTree, ptBlock, ptLine } def solveContextBound(contextBoundTp: Type): (Tree, Type) = { - val solSym = NoSymbol.newTypeParameter(NoPosition, newTypeName("SolveImplicit$")) + val solSym = NoSymbol.newTypeParameter(newTypeName("SolveImplicit$")) val param = solSym.setInfo(contextBoundTp.typeSymbol.typeParams(0).info.cloneInfo(solSym)) // TypeBounds(NothingClass.typeConstructor, baseTp) val pt = appliedType(contextBoundTp, List(param.tpeHK)) val savedUndets = context.undetparams @@ -1245,7 +1245,7 @@ defined class Foo */ } t match { case Function(_, _) if t.symbol == NoSymbol => - t.symbol = currentOwner.newValue(t.pos, nme.ANON_FUN_NAME).setFlag(SYNTHETIC).setInfo(NoType) + t.symbol = currentOwner.newAnonymousFunctionValue(t.pos) // println("new symbol for "+ (t, t.symbol.ownerChain)) case Function(_, _) if (t.symbol.owner == NoSymbol) || (t.symbol.owner == origOwner) => // println("fundef: "+ (t, t.symbol.ownerChain, currentOwner.ownerChain)) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 8f9cd46611..42a60666de 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -444,6 +444,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R // check a type alias's RHS corresponds to its declaration // this overlaps somewhat with validateVariance if(member.isAliasType) { + // println("checkKindBounds" + ((List(member), List(memberTp.normalize), self, member.owner))) val kindErrors = typer.infer.checkKindBounds(List(member), List(memberTp.normalize), self, member.owner) if(!kindErrors.isEmpty) diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 92e4e257bf..1df7cd86d3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -282,7 +282,7 @@ trait SyntheticMethods extends ast.TreeDSL { def argsBody: Tree = { val otherName = context.unit.freshTermName(clazz.name + "$") - val otherSym = m.newValue(m.pos, otherName) setInfo clazz.tpe setFlag SYNTHETIC + val otherSym = m.newValue(otherName, m.pos, SYNTHETIC) setInfo clazz.tpe val pairwise = accessors map (acc => fn(Select(This(clazz), acc), acc.tpe member nme.EQ, Select(Ident(otherSym), acc))) val canEq = gen.mkMethodCall(otherSym, nme.canEqual_, Nil, List(This(clazz))) def block = Block(ValDef(otherSym, thatCast), AND(pairwise :+ canEq: _*)) diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 080a802272..02c6e86fde 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -181,10 +181,7 @@ trait TypeDiagnostics { val getter = if (member.isSetter) member.getter(member.owner) else member val flags = if (getter.setter(member.owner) != NoSymbol) DEFERRED | MUTABLE else DEFERRED - ( getter.owner.newValue(getter.pos, getter.name.toTermName) - setInfo getter.tpe.resultType - setFlag flags - ) + getter.owner.newValue(getter.name.toTermName, getter.pos, flags) setInfo getter.tpe.resultType } def treeSymTypeMsg(tree: Tree): String = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5ccf27ded9..6476244221 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1659,7 +1659,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case Some(repl) => silent(_.typedTypeConstructor(stringParser(repl).typ())) match { case tpt: Tree => - val alias = enclClass.newAliasType(useCase.pos, name.toTypeName) + val alias = enclClass.newAliasType(name.toTypeName, useCase.pos) val tparams = cloneSymbolsAtOwner(tpt.tpe.typeSymbol.typeParams, alias) alias setInfo typeFun(tparams, appliedType(tpt.tpe, tparams map (_.tpe))) context.scope.enter(alias) @@ -1793,7 +1793,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ldef @ LabelDef(_, _, _) => if (ldef.symbol == NoSymbol) ldef.symbol = namer.enterInScope( - context.owner.newLabel(ldef.pos, ldef.name) setInfo MethodType(List(), UnitClass.tpe)) + context.owner.newLabel(ldef.name, ldef.pos) setInfo MethodType(List(), UnitClass.tpe)) case _ => } } @@ -1814,7 +1814,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } else { context.scope.unlink(ldef.symbol) val sym2 = namer.enterInScope( - context.owner.newLabel(ldef.pos, ldef.name) setInfo MethodType(List(), restpe)) + context.owner.newLabel(ldef.name, ldef.pos) setInfo MethodType(List(), restpe)) val rhs2 = typed(resetAllAttrs(ldef.rhs), restpe) ldef.params foreach (param => param.tpe = param.symbol.tpe) treeCopy.LabelDef(ldef, ldef.name, ldef.params, rhs2) setSymbol sym2 setType restpe @@ -2529,7 +2529,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val unapp = unapplyMember(otpe) val unappType = otpe.memberType(unapp) - val argDummy = context.owner.newValue(fun.pos, nme.SELECTOR_DUMMY) setFlag SYNTHETIC setInfo pt + val argDummy = context.owner.newValue(nme.SELECTOR_DUMMY, fun.pos, SYNTHETIC) setInfo pt val arg = Ident(argDummy) setType pt if (!isApplicableSafe(Nil, unappType, List(pt), WildcardType)) { @@ -4098,8 +4098,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case tree @ Function(_, _) => if (tree.symbol == NoSymbol) - tree.symbol = context.owner.newValue(tree.pos, nme.ANON_FUN_NAME) - .setFlag(SYNTHETIC).setInfo(NoType) + tree.symbol = context.owner.newAnonymousFunctionValue(tree.pos) + newTyper(context.makeNewScope(tree, tree.symbol)).typedFunction(tree, mode, pt) case Assign(lhs, rhs) => diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index fd6f972ffc..a7cd89621c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -21,7 +21,7 @@ trait Unapplies extends ast.TreeDSL import CODE.{ CASE => _, _ } import treeInfo.{ isRepeatedParamType, isByNameParamType } - private val unapplyParamName = newTermName("x$0") + private val unapplyParamName = nme.x_0 /** returns type list for return type of the extraction */ def unapplyTypeList(ufn: Symbol, ufntpe: Type) = { diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala index 960b27c52f..09aa1b05f7 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala @@ -192,10 +192,10 @@ abstract class SelectiveCPSTransform extends PluginComponent with // val expr2 = if (catches.nonEmpty) { val pos = catches.head.pos - val argSym = currentOwner.newValueParameter(pos, cpsNames.ex).setInfo(ThrowableClass.tpe) + val argSym = currentOwner.newValueParameter(cpsNames.ex, pos).setInfo(ThrowableClass.tpe) val rhs = Match(Ident(argSym), catches1) val fun = Function(List(ValDef(argSym)), rhs) - val funSym = currentOwner.newValueParameter(pos, cpsNames.catches).setInfo(appliedType(PartialFunctionClass.tpe, List(ThrowableClass.tpe, targettp))) + val funSym = currentOwner.newValueParameter(cpsNames.catches, pos).setInfo(appliedType(PartialFunctionClass.tpe, List(ThrowableClass.tpe, targettp))) val funDef = localTyper.typed(atPos(pos) { ValDef(funSym, fun) }) val expr2 = localTyper.typed(atPos(pos) { Apply(Select(expr1, expr1.tpe.member(cpsNames.flatMapCatch)), List(Ident(funSym))) }) @@ -203,7 +203,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with val chown = new ChangeOwnerTraverser(currentOwner, fun.symbol) chown.traverse(rhs) - val exSym = currentOwner.newValueParameter(pos, cpsNames.ex).setInfo(ThrowableClass.tpe) + val exSym = currentOwner.newValueParameter(cpsNames.ex, pos).setInfo(ThrowableClass.tpe) val catch2 = { localTyper.typedCases(tree, List( CaseDef(Bind(exSym, Typed(Ident("_"), TypeTree(ThrowableClass.tpe))), Apply(Select(Ident(funSym), nme.isDefinedAt), List(Ident(exSym))), @@ -302,7 +302,7 @@ abstract class SelectiveCPSTransform extends PluginComponent with } def applyCombinatorFun(ctxR: Tree, body: Tree) = { - val arg = currentOwner.newValueParameter(ctxR.pos, name).setInfo(tpe) + val arg = currentOwner.newValueParameter(name, ctxR.pos).setInfo(tpe) val body1 = (new TreeSymSubstituter(List(vd.symbol), List(arg)))(body) val fun = localTyper.typed(atPos(vd.symbol.pos) { Function(List(ValDef(arg)), body1) }) // types body as well arg.owner = fun.symbol diff --git a/test/files/neg/t692.check b/test/files/neg/t692.check index 12b7d40ba5..4149366309 100644 --- a/test/files/neg/t692.check +++ b/test/files/neg/t692.check @@ -13,12 +13,7 @@ t692.scala:13: error: class Foo takes type parameters t692.scala:14: error: class Foo takes type parameters implicit def typeOfBar[T4 <: Foo](implicit elem : RefType[T4]) : RefType[Bar[T4]] = ^ -t692.scala:15: error: type mismatch; - found : test3.this.BarType[T4] - required: test3.this.RefType[test3.this.Bar[T4]] - BarType(elem); - ^ t692.scala:19: error: class Foo takes type parameters class Bar[A <: Foo](implicit tpeA : Type[A]) extends Foo; ^ -7 errors found +6 errors found -- cgit v1.2.3