From 64b0678d3344380666d62c855cab2dad8a6ef08b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Jan 2010 16:46:48 +0000 Subject: further speed improvements by eliminating most ... further speed improvements by eliminating most uses of paramTypes. Knocks off about 3% of typer time. Not overwhelming but still worth doing. Review by rytz. --- src/compiler/scala/tools/nsc/symtab/Types.scala | 112 +++++++++++++++++---- .../scala/tools/nsc/transform/Erasure.scala | 4 +- .../scala/tools/nsc/transform/LazyVals.scala | 4 +- .../scala/tools/nsc/transform/UnCurry.scala | 16 +-- .../scala/tools/nsc/typechecker/Implicits.scala | 8 +- .../scala/tools/nsc/typechecker/Infer.scala | 39 +++---- .../scala/tools/nsc/typechecker/Namers.scala | 9 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 4 +- .../tools/nsc/typechecker/SuperAccessors.scala | 22 ++-- .../scala/tools/nsc/typechecker/Typers.scala | 31 ++---- .../scala/tools/nsc/typechecker/Unapplies.scala | 4 +- 11 files changed, 161 insertions(+), 92 deletions(-) diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 0b0036fc54..be537010f6 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -795,8 +795,9 @@ trait Types { var members: Scope = null var member: Symbol = NoSymbol var excluded = excludedFlags | DEFERRED - var self: Type = null var continue = true + lazy val self: Type = this.narrow + lazy val membertpe = self.memberType(member) while (continue) { continue = false val bcs0 = baseClasses @@ -820,24 +821,22 @@ trait Types { } else if (member == NoSymbol) { member = sym } else if (members eq null) { +// val start = startTimer(timer1) if (member.name != sym.name || !(member == sym || member.owner != sym.owner && - !sym.hasFlag(PRIVATE) && { - if (self eq null) self = this.narrow; - (self.memberType(member) matches self.memberType(sym)) - })) { + !sym.hasFlag(PRIVATE) && + (membertpe matches self.memberType(sym)))) { members = new Scope(List(member, sym)) } +// stopTimer(timer1, start) } else { var prevEntry = members.lookupEntry(sym.name) while ((prevEntry ne null) && !(prevEntry.sym == sym || prevEntry.sym.owner != sym.owner && - !sym.hasFlag(PRIVATE) && { - if (self eq null) self = this.narrow; - (self.memberType(prevEntry.sym) matches self.memberType(sym)) - })) { + !sym.hasFlag(PRIVATE) && + (self.memberType(prevEntry.sym) matches self.memberType(sym)))) { prevEntry = members lookupNextEntry prevEntry } if (prevEntry eq null) { @@ -1795,7 +1794,7 @@ A type's typeSymbol should never be inspected directly. case class MethodType(override val params: List[Symbol], override val resultType: Type) extends Type { override val isTrivial: Boolean = - paramTypes.forall(_.isTrivial) && resultType.isTrivial + params.forall(_.tpe.isTrivial) && resultType.isTrivial //assert(paramTypes forall (pt => !pt.typeSymbol.isImplClass))//DEBUG override def paramSectionCount: Int = resultType.paramSectionCount + 1 @@ -1909,6 +1908,10 @@ A type's typeSymbol should never be inspected directly. override def boundSyms: List[Symbol] = quantified override def prefix = maybeRewrap(underlying.prefix) override def typeArgs = underlying.typeArgs map maybeRewrap + override def params = underlying.params mapConserve { param => + val tpe1 = rewrap(param.tpe) + if (tpe1 eq param.tpe) param else param.cloneSymbol.setInfo(tpe1) + } override def paramTypes = underlying.paramTypes map maybeRewrap override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = { // maybeRewrap(underlying.instantiateTypeParams(formals, actuals)) @@ -4151,7 +4154,7 @@ A type's typeSymbol should never be inspected directly. tp1 match { case MethodType(params1, res1) => (params1.length == params2.length && - matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && + matchingParams(params1, params2, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && (res1 <:< res2) && tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType]) case _ => @@ -4244,13 +4247,71 @@ A type's typeSymbol should never be inspected directly. } /** A function implementing `tp1' matches `tp2' */ - def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = { + final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = { + def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean = + tparams1.length == tparams2.length && + matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple) + def lastTry = + tp2 match { + case ExistentialType(_, res2) if alwaysMatchSimple => + matchesType(tp1, res2, true) + case MethodType(_, _) => + false + case PolyType(tparams2, res2) => + tparams2.isEmpty && matchesType(tp1, res2, alwaysMatchSimple) + case _ => + alwaysMatchSimple || tp1 =:= tp2 + } + tp1 match { + case MethodType(params1, res1) => + tp2 match { + case MethodType(params2, res2) => + params1.length == params2.length && // useful pre-secreening optimization + matchingParams(params1, params2, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && + matchesType(res1, res2, alwaysMatchSimple) && + tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType] + case PolyType(List(), res2) => + if (params1.isEmpty) matchesType(res1, res2, alwaysMatchSimple) + else matchesType(tp1, res2, alwaysMatchSimple) + case ExistentialType(_, res2) => + alwaysMatchSimple && matchesType(tp1, res2, true) + case _ => + false + } + case PolyType(tparams1, res1) => + tp2 match { + case PolyType(tparams2, res2) => + matchesQuantified(tparams1, tparams2, res1, res2) + case MethodType(List(), res2) if (tparams1.isEmpty) => + matchesType(res1, res2, alwaysMatchSimple) + case ExistentialType(_, res2) => + alwaysMatchSimple && matchesType(tp1, res2, true) + case _ => + tparams1.isEmpty && matchesType(res1, tp2, alwaysMatchSimple) + } + case ExistentialType(tparams1, res1) => + tp2 match { + case ExistentialType(tparams2, res2) => + matchesQuantified(tparams1, tparams2, res1, res2) + case _ => + if (alwaysMatchSimple) matchesType(res1, tp2, true) + else lastTry + } + case _ => + lastTry + } + } + +/** matchesType above is an optimized version of the following implementation: + + def matchesType2(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = { def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean = tparams1.length == tparams2.length && matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple) (tp1, tp2) match { case (MethodType(params1, res1), MethodType(params2, res2)) => - matchingParams(tp1.paramTypes, tp2.paramTypes, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && + params1.length == params2.length && // useful pre-secreening optimization + matchingParams(params1, params2, tp1.isInstanceOf[JavaMethodType], tp2.isInstanceOf[JavaMethodType]) && matchesType(res1, res2, alwaysMatchSimple) && tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType] case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => @@ -4277,14 +4338,25 @@ A type's typeSymbol should never be inspected directly. alwaysMatchSimple || tp1 =:= tp2 } } +*/ - /** Are `tps1' and `tps2' lists of pairwise equivalent types? */ - private def matchingParams(tps1: List[Type], tps2: List[Type], tps1isJava: Boolean, tps2isJava: Boolean): Boolean = - (tps1.length == tps2.length) && - ((tps1, tps2).zipped forall ((tp1, tp2) => - (tp1 =:= tp2) || - tps1isJava && tp2.typeSymbol == ObjectClass && tp1.typeSymbol == AnyClass || - tps2isJava && tp1.typeSymbol == ObjectClass && tp2.typeSymbol == AnyClass)) + /** Are `syms1' and `syms2' parameter lists with pairwise equivalent types? */ + private def matchingParams(syms1: List[Symbol], syms2: List[Symbol], syms1isJava: Boolean, syms2isJava: Boolean): Boolean = syms1 match { + case Nil => + syms2.isEmpty + case sym1 :: rest1 => + syms2 match { + case Nil => + false + case sym2 :: rest2 => + val tp1 = sym1.tpe + val tp2 = sym2.tpe + (tp1 =:= tp2 || + syms1isJava && tp2.typeSymbol == ObjectClass && tp1.typeSymbol == AnyClass || + syms2isJava && tp1.typeSymbol == ObjectClass && tp2.typeSymbol == AnyClass) && + matchingParams(rest1, rest2, syms1isJava, syms2isJava) + } + } /** like map2, but returns list `xs' itself - instead of a copy - if function * `f' maps all elements to themselves. diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 1fa81c8776..de9dadbd1f 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -497,7 +497,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. tree else if (isValueClass(tree.tpe.typeSymbol) && !isValueClass(pt.typeSymbol)) adaptToType(box(tree), pt) - else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.paramTypes.isEmpty) { + else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.params.isEmpty) { if (!tree.symbol.isStable) assert(false, "adapt "+tree+":"+tree.tpe+" to "+pt) adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt) } else if (pt <:< tree.tpe) @@ -597,7 +597,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. if (isValueClass(tree.symbol.owner) && !isValueClass(qual1.tpe.typeSymbol)) tree.symbol = NoSymbol - else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.paramTypes.isEmpty) { + else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.params.isEmpty) { assert(qual1.symbol.isStable, qual1.symbol); qual1 = Apply(qual1, List()) setPos qual1.pos setType qual1.tpe.resultType } else if (!(qual1.isInstanceOf[Super] || (qual1.tpe.typeSymbol isSubClass tree.symbol.owner))) { diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index b2f9489480..03339163a1 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -94,7 +94,9 @@ abstract class LazyVals extends Transform with ast.TreeDSL { } val bmps = bitmaps(methSym) map (ValDef(_, ZERO)) - def isMatch(params: List[Ident]) = (params.tail, methSym.tpe.paramTypes).zipped forall (_.tpe == _) + + // Martin to Iulian: Don't we need to compare lengths here? + def isMatch(params: List[Ident]) = (params.tail, methSym.tpe.params).zipped forall (_.tpe == _.tpe) if (bmps.isEmpty) rhs else rhs match { case Block(assign, l @ LabelDef(name, params, rhs1)) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 8ea0b69049..fd5dd0f9a3 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -61,7 +61,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { tp match { case MethodType(params, MethodType(params1, restpe)) => apply(MethodType(params ::: params1, restpe)) - case MethodType(formals, ExistentialType(tparams, restpe @ MethodType(_, _))) => + case MethodType(params, ExistentialType(tparams, restpe @ MethodType(_, _))) => assert(false, "unexpected curried method types with intervening exitential") tp0 case mt: ImplicitMethodType => @@ -189,8 +189,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { * additional parameter sections of a case class are skipped. */ def uncurryTreeType(tp: Type): Type = tp match { - case MethodType(formals, MethodType(formals1, restpe)) if (inPattern) => - uncurryTreeType(MethodType(formals, restpe)) + case MethodType(params, MethodType(params1, restpe)) if (inPattern) => + uncurryTreeType(MethodType(params, restpe)) case _ => uncurry(tp) } @@ -451,13 +451,15 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { if (isJava && suffix.tpe.typeSymbol == ArrayClass && isValueClass(suffix.tpe.typeArgs.head.typeSymbol) && - fun.tpe.paramTypes.last.typeSymbol == ArrayClass && - fun.tpe.paramTypes.last.typeArgs.head.typeSymbol == ObjectClass) + { val lastFormal2 = fun.tpe.params.last.tpe + lastFormal2.typeSymbol == ArrayClass && + lastFormal2.typeArgs.head.typeSymbol == ObjectClass + }) suffix = localTyper.typedPos(pos) { gen.mkRuntimeCall("toObjectArray", List(suffix)) } } - args.take(formals.length - 1) ::: List(suffix setType formals.last) + args.take(formals.length - 1) ::: List(suffix setType lastFormal) case _ => args } @@ -591,7 +593,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { transform(treeCopy.Apply(tree, fn, List(liftTree(args.head)))) } else { withNeedLift(true) { - val formals = fn.tpe.paramTypes; + val formals = fn.tpe.paramTypes treeCopy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, fn.symbol, args, formals))) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 27646363cb..9657cea101 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -642,6 +642,8 @@ self: Analyzer => * - the type itself * - the parts of its immediate components (prefix and argument) * - the parts of its base types + * - for alias types and abstract types, we take instead the parts + * - of their upper bounds. * @return For those parts that refer to classes with companion objects that * can be accessed with unambiguous stable prefixes, the implicits infos * which are members of these companion objects. @@ -675,7 +677,7 @@ self: Analyzer => args foreach getParts } } else if (sym.isAliasType) { - getParts(tp.dealias) + getParts(tp.normalize) } else if (sym.isAbstractType) { getParts(tp.bounds.hi) } @@ -687,7 +689,9 @@ self: Analyzer => for (p <- ps) getParts(p) case AnnotatedType(_, t, _) => getParts(t) - case ExistentialType(tparams, t) => + case ExistentialType(_, t) => + getParts(t) + case PolyType(_, t) => getParts(t) case _ => } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index ad2c70c9ce..5c6788f0f6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -28,7 +28,8 @@ trait Infer { private def assertNonCyclic(tvar: TypeVar) = assert(tvar.constr.inst != tvar, tvar.origin) - def isVarArgs(formals: List[Type]) = !formals.isEmpty && isRepeatedParamType(formals.last) + def isVarArgs(params: List[Symbol]) = !params.isEmpty && isRepeatedParamType(params.last.tpe) + def isVarArgTpes(formals: List[Type]) = !formals.isEmpty && isRepeatedParamType(formals.last) def isWildcard(tp: Type) = tp match { case WildcardType | BoundedWildcardType(_) => true @@ -48,11 +49,11 @@ trait Infer { /** This variant allows keeping ByName parameters. Useed in NamesDefaults. */ def formalTypes(formals: List[Type], nargs: Int, removeByName: Boolean): List[Type] = { - val formals1 = if (removeByName) formals map { + val formals1 = if (removeByName) formals mapConserve { case TypeRef(_, sym, List(arg)) if (sym == ByNameParamClass) => arg case formal => formal } else formals - if (isVarArgs(formals1)) { + if (isVarArgTpes(formals1)) { val ft = formals1.last.normalize.typeArgs.head formals1.init ::: (for (i <- List.range(formals1.length - 1, nargs)) yield ft) } else formals1 @@ -77,9 +78,11 @@ trait Infer { //todo: remove comments around following privates; right now they cause an IllegalAccess // error when built with scalac - /*private*/ class NoInstance(msg: String) extends RuntimeException(msg) with ControlException + /*private*/ + class NoInstance(msg: String) extends RuntimeException(msg) with ControlException - /*private*/ class DeferredNoInstance(getmsg: () => String) extends NoInstance("") { + /*private*/ + class DeferredNoInstance(getmsg: () => String) extends NoInstance("") { override def getMessage(): String = getmsg() } @@ -494,7 +497,7 @@ trait Infer { pt.typeSymbol == UnitClass || // can perform unit coercion isCompatible(tp, pt) || tp.isInstanceOf[MethodType] && // can perform implicit () instantiation - tp.paramTypes.length == 0 && isCompatible(tp.resultType, pt) + tp.params.isEmpty && isCompatible(tp.resultType, pt) /** Like weakly compatible but don't apply any implicit conversions yet. * Used when comparing the result type of a method with its prototype. @@ -748,8 +751,10 @@ trait Infer { case OverloadedType(pre, alts) => alts exists (alt => hasExactlyNumParams(pre.memberType(alt), n)) case _ => - formalTypes(tp.paramTypes, n).length == n + val len = tp.params.length + len == n || isVarArgs(tp.params) && len <= n + 1 } + /** * Verifies whether the named application is valid. The logic is very * similar to the one in NamesDefaults.removeNames. @@ -815,13 +820,13 @@ trait Infer { case ExistentialType(tparams, qtpe) => isApplicable(undetparams, qtpe, argtpes0, pt) case MethodType(params, _) => - def paramType(param: Symbol) = param.tpe match { - case TypeRef(_, sym, List(tpe)) if sym isNonBottomSubClass CodeClass => - tpe - case tpe => - tpe + val formals0 = params map { param => + param.tpe match { + case TypeRef(_, sym, List(tpe)) if sym isNonBottomSubClass CodeClass => tpe + case tpe => tpe + } } - val formals = formalTypes(params map paramType, argtpes0.length) + val formals = formalTypes(formals0, argtpes0.length) def tryTupleApply: Boolean = { // if 1 formal, 1 argtpe (a tuple), otherwise unmodified argtpes0 @@ -931,7 +936,7 @@ trait Infer { isAsSpecific(ftpe1.resultType, ftpe2) case MethodType(params @ (x :: xs), _) => var argtpes = params map (_.tpe) - if (isVarArgs(argtpes) && isVarArgs(ftpe2.paramTypes)) + if (isVarArgs(params) && isVarArgs(ftpe2.params)) argtpes = argtpes map (argtpe => if (isRepeatedParamType(argtpe)) argtpe.typeArgs.head else argtpe) isApplicable(List(), ftpe2, argtpes, WildcardType) @@ -1042,7 +1047,7 @@ trait Infer { def isStrictlyBetter(tpe1: Type, tpe2: Type) = { def isNullary(tpe: Type): Boolean = tpe match { case tp: RewrappingTypeProxy => isNullary(tp.underlying) - case _ => tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty + case _ => tpe.paramSectionCount == 0 || tpe.params.isEmpty } def isMethod(tpe: Type): Boolean = tpe match { case tp: RewrappingTypeProxy => isMethod(tp.underlying) @@ -1688,7 +1693,7 @@ trait Infer { isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt)) if (varArgsOnly) - allApplicable = allApplicable filter (alt => isVarArgs(alt.tpe.paramTypes)) + allApplicable = allApplicable filter (alt => isVarArgs(alt.tpe.params)) // if there are multiple, drop those that use a default // (keep those that use vararg / tupling conversion) @@ -1701,7 +1706,7 @@ trait Infer { alts map (_.tpe) case t => List(t) } - mtypes.exists(t => t.paramTypes.length < argtpes.length || // tupling (*) + mtypes.exists(t => t.params.length < argtpes.length || // tupling (*) hasExactlyNumParams(t, argtpes.length)) // same nb or vararg // (*) more arguments than parameters, but still applicable: tuplig conversion works. // todo: should not return "false" when paramTypes = (Unit) no argument is given diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 40eb72aaeb..1955348f91 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -874,14 +874,15 @@ trait Namers { self: Analyzer => } for (vparams <- vparamss) { - var pfs = resultPt.paramTypes + var pps = resultPt.params for (vparam <- vparams) { if (vparam.tpt.isEmpty) { - vparam.tpt defineType pfs.head + val paramtpe = pps.head.tpe + vparam.symbol setInfo paramtpe + vparam.tpt defineType paramtpe vparam.tpt setPos vparam.pos.focus - vparam.symbol setInfo pfs.head } - pfs = pfs.tail + pps = pps.tail } resultPt = resultPt.resultType } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 835b6f2024..7b41c7b249 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -740,7 +740,7 @@ abstract class RefChecks extends InfoTransform { sym = sym.info.bounds.hi.widen.typeSymbol sym } - val formal = underlyingClass(fn.tpe.paramTypes.head) + val formal = underlyingClass(fn.tpe.params.head.tpe) val actual = underlyingClass(args.head.tpe) val receiver = underlyingClass(qual.tpe) def nonSensibleWarning(what: String, alwaysEqual: Boolean) = @@ -948,7 +948,7 @@ abstract class RefChecks extends InfoTransform { private def isRepeatedParamArg(tree: Tree) = currentApplication match { case Apply(fn, args) => !args.isEmpty && (args.last eq tree) && - fn.tpe.paramTypes.length == args.length && isRepeatedParamType(fn.tpe.paramTypes.last) + fn.tpe.params.length == args.length && isRepeatedParamType(fn.tpe.params.last.tpe) case _ => false } diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index d09cd85137..e59b469057 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -42,22 +42,14 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT case Some((_, buf)) => buf case None => throw new AssertionError("no acc def buf for "+clazz) } -/* - private def transformArgs(args: List[Tree], formals: List[Type]) = { - if (!formals.isEmpty && formals.last.symbol == definitions.ByNameParamClass) - ((args take (formals.length - 1) map transform) ::: - withInvalidOwner { args drop (formals.length - 1) map transform }) - else - args map transform - } -*/ - private def transformArgs(args: List[Tree], formals: List[Type]) = - ((args, formals).zipped map { (arg, formal) => - if (formal.typeSymbol == definitions.ByNameParamClass) - withInvalidOwner { checkPackedConforms(transform(arg), formal.typeArgs.head) } + + private def transformArgs(args: List[Tree], params: List[Symbol]) = + ((args, params).zipped map { (arg, param) => + if (param.tpe.typeSymbol == definitions.ByNameParamClass) + withInvalidOwner { checkPackedConforms(transform(arg), param.tpe.typeArgs.head) } else transform(arg) }) ::: - (args drop formals.length map transform) + (args drop params.length map transform) private def checkPackedConforms(tree: Tree, pt: Type): Tree = { if (tree.tpe exists (_.typeSymbol.isExistentialSkolem)) { @@ -223,7 +215,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT case Apply(fn, args) => assert(fn.tpe != null, tree) - treeCopy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes)) + treeCopy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.params)) case Function(vparams, body) => withInvalidOwner { treeCopy.Function(tree, vparams, transform(body)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 3611b32ba6..f29f6fa7a3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -685,7 +685,7 @@ trait Typers { self: Analyzer => case Select(qual, _) => qual.tpe case _ => NoPrefix } - if (tree.tpe.isInstanceOf[MethodType] && pre.isStable && sym.tpe.paramTypes.isEmpty && + if (tree.tpe.isInstanceOf[MethodType] && pre.isStable && sym.tpe.params.isEmpty && (isStableContext(tree, mode, pt) || sym.isModule)) tree.setType(MethodType(List(), singleType(pre, sym))) else tree @@ -820,7 +820,7 @@ trait Typers { self: Analyzer => if (!context.undetparams.isEmpty/* && (mode & POLYmode) == 0 disabled to make implicits in new collection work; we should revisit this. */) { // (9) // println("adapt IMT: "+(context.undetparams, pt)) //@MDEBUG context.undetparams = inferExprInstance( - tree, context.extractUndetparams(), pt, mt.paramTypes exists isManifest) + tree, context.extractUndetparams(), pt, mt.params exists (p => isManifest(p.tpe))) // if we are looking for a manifest, instantiate type to Nothing anyway, // as we would get amnbiguity errors otherwise. Example // Looking for a manifest of Nil: This mas many potential types, @@ -1577,11 +1577,11 @@ trait Typers { self: Analyzer => def decompose(call: Tree): (Tree, List[Tree]) = call match { case Apply(fn, args) => val (superConstr, args1) = decompose(fn) - val formals = fn.tpe.paramTypes - val args2 = if (formals.isEmpty || !isRepeatedParamType(formals.last)) args - else args.take(formals.length - 1) ::: List(EmptyTree) - if (args2.length != formals.length) - assert(false, "mismatch " + clazz + " " + formals + " " + args2);//debug + val params = fn.tpe.params + val args2 = if (params.isEmpty || !isRepeatedParamType(params.last.tpe)) args + else args.take(params.length - 1) ::: List(EmptyTree) + if (args2.length != params.length) + assert(false, "mismatch " + clazz + " " + (params map (_.tpe)) + " " + args2);//debug (superConstr, args1 ::: args2) case Block(stats, expr) if !stats.isEmpty => decompose(stats.last) @@ -1826,8 +1826,6 @@ trait Typers { self: Analyzer => transformedOrTyped(ddef.rhs, tpt1.tpe) } - checkMethodStructuralCompatible(meth) - if (meth.isPrimaryConstructor && meth.isClassConstructor && phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) computeParamAliases(meth.owner, vparamss1, rhs1) @@ -2177,7 +2175,7 @@ trait Typers { self: Analyzer => def typedArgs(args: List[Tree], mode: Int, originalFormals: List[Type], adaptedFormals: List[Type]) = { def newmode(i: Int) = - if (isVarArgs(originalFormals) && i >= originalFormals.length - 1) STARmode else 0 + if (isVarArgTpes(originalFormals) && i >= originalFormals.length - 1) STARmode else 0 for (((arg, formal), i) <- (args zip adaptedFormals).zipWithIndex) yield typedArg(arg, mode, newmode(i), formal) @@ -2213,14 +2211,6 @@ trait Typers { self: Analyzer => def isNamedApplyBlock(tree: Tree) = context.namedApplyBlockInfo exists (_._1 == tree) - /** - * @param tree ... - * @param fun0 ... - * @param args ... - * @param mode ... - * @param pt ... - * @return ... - */ def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = { var fun = fun0 if (fun.hasSymbol && (fun.symbol hasFlag OVERLOADED)) { @@ -2281,8 +2271,9 @@ trait Typers { self: Analyzer => doTypedApply(tree, adapt(fun, funMode(mode), WildcardType), args1, mode, pt) case mt @ MethodType(params, _) => + val paramTypes = mt.paramTypes // repeat vararg as often as needed, remove by-name - val formals = formalTypes(mt.paramTypes, args.length) + val formals = formalTypes(paramTypes, args.length) /** Try packing all arguments into a Tuple and apply `fun' * to that. This is the last thing which is tried (after @@ -2383,7 +2374,7 @@ trait Typers { self: Analyzer => } else { val tparams = context.extractUndetparams() if (tparams.isEmpty) { // all type params are defined - val args1 = typedArgs(args, argMode(fun, mode), mt.paramTypes, formals) + val args1 = typedArgs(args, argMode(fun, mode), paramTypes, formals) val restpe = mt.resultType(args1 map (_.tpe)) // instantiate dependent method types def ifPatternSkipFormals(tp: Type) = tp match { case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 812276612f..3898e46c0b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -94,8 +94,8 @@ trait Unapplies extends ast.TreeDSL } /** returns unapply member's parameter type. */ def unapplyParameterType(extractor: Symbol) = { - val tps = extractor.tpe.paramTypes - if (tps.length == 1) tps.head.typeSymbol + val ps = extractor.tpe.params + if (ps.length == 1) ps.head.tpe.typeSymbol else NoSymbol } -- cgit v1.2.3