diff options
Diffstat (limited to 'src/compiler')
16 files changed, 170 insertions, 104 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index e2d0a07042..56ad4738d9 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -966,10 +966,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) definitions.isDefinitionsInitialized && rootMirror.isMirrorInitialized ) - override def isPastTyper = ( + override def isPastTyper = isPast(currentRun.typerPhase) + def isPast(phase: Phase) = ( (curRun ne null) && isGlobalInitialized // defense against init order issues - && (globalPhase.id > currentRun.typerPhase.id) + && (globalPhase.id > phase.id) ) // TODO - trim these to the absolute minimum. diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala index dfd5b07a3b..c18f220d95 100644 --- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala +++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala @@ -446,9 +446,10 @@ abstract class ScalaPrimitives { inform(s"Unknown primitive method $cls.$method") else alts foreach (s => addPrimitive(s, - s.info.paramTypes match { - case tp :: _ if code == ADD && tp =:= StringTpe => CONCAT - case _ => code + if (code != ADD) code + else exitingTyper(s.info).paramTypes match { + case tp :: _ if tp =:= StringTpe => CONCAT + case _ => code } ) ) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 76d042ce3b..37dea477c6 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -1264,14 +1264,22 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { def genEqEqPrimitive(l: Tree, r: Tree, success: asm.Label, failure: asm.Label, targetIfNoJump: asm.Label, pos: Position) { /* True if the equality comparison is between values that require the use of the rich equality - * comparator (scala.runtime.Comparator.equals). This is the case when either side of the + * comparator (scala.runtime.BoxesRunTime.equals). This is the case when either side of the * comparison might have a run-time type subtype of java.lang.Number or java.lang.Character. - * When it is statically known that both sides are equal and subtypes of Number of Character, - * not using the rich equality is possible (their own equals method will do ok.) + * + * When it is statically known that both sides are equal and subtypes of Number or Character, + * not using the rich equality is possible (their own equals method will do ok), except for + * java.lang.Float and java.lang.Double: their `equals` have different behavior around `NaN` + * and `-0.0`, see Javadoc (scala-dev#329). */ val mustUseAnyComparator: Boolean = { - val areSameFinals = l.tpe.isFinalType && r.tpe.isFinalType && (l.tpe =:= r.tpe) - !areSameFinals && platform.isMaybeBoxed(l.tpe.typeSymbol) && platform.isMaybeBoxed(r.tpe.typeSymbol) + platform.isMaybeBoxed(l.tpe.typeSymbol) && platform.isMaybeBoxed(r.tpe.typeSymbol) && { + val areSameFinals = l.tpe.isFinalType && r.tpe.isFinalType && (l.tpe =:= r.tpe) && { + val sym = l.tpe.typeSymbol + sym != BoxedFloatClass && sym != BoxedDoubleClass + } + !areSameFinals + } } if (mustUseAnyComparator) { diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index f1f5f37c36..224de97734 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -77,10 +77,10 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr if (reader != null) { reader.read match { case 'a' | 'A' => - new Throwable().printStackTrace() + new Throwable().printStackTrace(writer) System.exit(1) case 's' | 'S' => - new Throwable().printStackTrace() + new Throwable().printStackTrace(writer) writer.println() writer.flush() case _ => diff --git a/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala b/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala index 0b051ef89d..c38de753c8 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala @@ -127,7 +127,7 @@ abstract class ScalaBuild extends Ordered[ScalaBuild] { def unparse: String } /** - * A development, test, nightly, snapshot or other "unofficial" build + * A development, test, integration, snapshot or other "unofficial" build */ case class Development(id: String) extends ScalaBuild { def unparse = s"-${id}" diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index d948d151a6..dd44366692 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -122,11 +122,16 @@ abstract class SymbolLoaders { * and give them `completer` as type. */ def enterClassAndModule(root: Symbol, name: String, getCompleter: (ClassSymbol, ModuleSymbol) => SymbolLoader) { - val clazz = newClass(root, name) - val module = newModule(root, name) - val completer = getCompleter(clazz, module) - enterClass(root, clazz, completer) - enterModule(root, module, completer) + val clazz0 = newClass(root, name) + val module0 = newModule(root, name) + val completer = getCompleter(clazz0, module0) + // enterClass/Module may return an existing symbol instead of the ones we created above + // this may happen when there's both sources and binaries on the classpath, but the class + // name is different from the file name, so the classpath can't match the binary and source + // representation. `companionModule/Class` prefers the source version, so we should be careful + // to reuse the symbols returned below. + val clazz = enterClass(root, clazz0, completer) + val module = enterModule(root, module0, completer) if (!clazz.isAnonymousClass) { // Diagnostic for SI-7147 def msg: String = { diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index d3e9b0bf0e..f146419a73 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -553,6 +553,7 @@ abstract class ClassfileParser { val name = readName() val sym = ownerForFlags(jflags).newMethod(name.toTermName, NoPosition, sflags) var info = pool.getType(sym, u2) + var removedOuterParameter = false if (name == nme.CONSTRUCTOR) info match { case MethodType(params, restpe) => @@ -567,6 +568,7 @@ abstract class ClassfileParser { * ClassfileParser for 1 executes, and clazz.owner is the package. */ assert(params.head.tpe.typeSymbol == clazz.owner || clazz.owner.hasPackageFlag, params.head.tpe.typeSymbol + ": " + clazz.owner) + removedOuterParameter = true params.tail case _ => params @@ -586,7 +588,7 @@ abstract class ClassfileParser { // parsed from SignatureATTR sym setInfo info propagatePackageBoundary(jflags, sym) - parseAttributes(sym, info) + parseAttributes(sym, info, removedOuterParameter) if (jflags.isVarargs) sym modifyInfo arrayToRepeated @@ -769,7 +771,7 @@ abstract class ClassfileParser { GenPolyType(ownTypeParams, tpe) } // sigToType - def parseAttributes(sym: Symbol, symtype: Type) { + def parseAttributes(sym: Symbol, symtype: Type, removedOuterParameter: Boolean = false) { def convertTo(c: Constant, pt: Type): Constant = { if (pt.typeSymbol == BooleanClass && c.tag == IntTag) Constant(c.value != 0) @@ -804,16 +806,24 @@ abstract class ClassfileParser { else devWarning(s"failure to convert $c to $symtype") case tpnme.MethodParametersATTR => def readParamNames(): Unit = { - import tools.asm.Opcodes.ACC_SYNTHETIC + import scala.tools.asm.Opcodes.ACC_SYNTHETIC val paramCount = u1 var i = 0 + if (removedOuterParameter && i < paramCount) { + in.skip(4) + i += 1 + } + var remainingParams = sym.paramss.head // Java only has exactly one parameter list while (i < paramCount) { val name = pool.getName(u2) val access = u2 - if ((access & ACC_SYNTHETIC) != ACC_SYNTHETIC) { // name not synthetic - val params = sym.paramss.head // Java only has exactly one parameter list - params(i).name = name.encode - params(i).resetFlag(SYNTHETIC) + if (remainingParams.nonEmpty) { + val param = remainingParams.head + remainingParams = remainingParams.tail + if ((access & ACC_SYNTHETIC) != ACC_SYNTHETIC) { // name not synthetic + param.name = name.encode + param.resetFlag(SYNTHETIC) + } } i += 1 } diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala deleted file mode 100644 index e69de29bb2..0000000000 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ /dev/null diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 744b9c8a8e..9e3e8ff455 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -84,7 +84,7 @@ abstract class TailCalls extends Transform { * </p> * <p> * Assumes: `Uncurry` has been run already, and no multiple - * parameter lists exit. + * parameter lists exist. * </p> */ class TailCallElimination(unit: CompilationUnit) extends Transformer { diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index dcffd7a6ab..f35dd6556f 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -342,12 +342,16 @@ abstract class UnCurry extends InfoTransform * the whole tree with it. */ private def replaceElidableTree(tree: Tree): Tree = { + def elisionOf(t: Type): Tree = t.typeSymbol match { + case StringClass => Literal(Constant("")) setType t + case _ => gen.mkZero(t) + } tree match { case DefDef(_,_,_,_,_,rhs) => - val rhs1 = if (rhs == EmptyTree) rhs else Block(Nil, gen.mkZero(rhs.tpe)) setType rhs.tpe + val rhs1 = if (rhs == EmptyTree) rhs else Block(Nil, elisionOf(rhs.tpe)) setType rhs.tpe deriveDefDef(tree)(_ => rhs1) setSymbol tree.symbol setType tree.tpe case _ => - gen.mkZero(tree.tpe) setType tree.tpe + elisionOf(tree.tpe) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala index 57de44a038..b1901c04bb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala @@ -80,7 +80,9 @@ trait Adaptations { context.deprecationWarning(t.pos, t.symbol, adaptWarningMessage(msg), "2.11.0") } } else if (settings.warnAdaptedArgs) - context.warning(t.pos, adaptWarningMessage(s"Adapting argument list by creating a ${args.size}-tuple: this may not be what you want.")) + context.warning(t.pos, adaptWarningMessage( + s"Adapting argument list by creating a ${args.size}-tuple: this may not be what you want.") + ) // return `true` if the adaptation should be kept !(settings.noAdaptedArgs || (args.isEmpty && settings.future)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index d349597b14..7a3b8d2ab6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -62,11 +62,10 @@ trait Contexts { self: Analyzer => def warnUnusedImports(unit: CompilationUnit) = if (!unit.isJava) { for (imps <- allImportInfos.remove(unit)) { - for (imp <- imps.reverse.distinct) { + for (imp <- imps.distinct.reverse) { val used = allUsedSelectors(imp) - def isMask(s: ImportSelector) = s.name != nme.WILDCARD && s.rename == nme.WILDCARD - imp.tree.selectors filterNot (s => isMask(s) || used(s)) foreach { sel => + imp.tree.selectors filterNot (s => isMaskImport(s) || used(s)) foreach { sel => reporter.warning(imp posOf sel, "Unused import") } } @@ -74,6 +73,10 @@ trait Contexts { self: Analyzer => } } + def isMaskImport(s: ImportSelector): Boolean = s.name != nme.WILDCARD && s.rename == nme.WILDCARD + def isIndividualImport(s: ImportSelector): Boolean = s.name != nme.WILDCARD && s.rename != nme.WILDCARD + def isWildcardImport(s: ImportSelector): Boolean = s.name == nme.WILDCARD + var lastAccessCheckDetails: String = "" /** List of symbols to import from in a root context. Typically that @@ -1193,27 +1196,33 @@ trait Contexts { self: Analyzer => res } - final def lookupCompanionOf(original: Symbol): Symbol = { - if (original.isModuleClass) original.sourceModule - else lookupScopeEntry(original) match { - case null => NoSymbol - case entry => entry.owner.lookupCompanion(original) + final def lookupCompanionInIncompleteOwner(original: Symbol): Symbol = { + /* Search scopes in current and enclosing contexts for the definition of `symbol` */ + def lookupScopeEntry(symbol: Symbol): ScopeEntry = { + var res: ScopeEntry = null + var ctx = this + while (res == null && ctx.outer != ctx) { + val s = ctx.scope lookupSymbolEntry symbol + if (s != null) + res = s + else + ctx = ctx.outer + } + res } - } - /** Search scopes in current and enclosing contexts for the definition of `symbol` */ - private def lookupScopeEntry(symbol: Symbol): ScopeEntry = { - var res: ScopeEntry = null - var ctx = this - while (res == null && ctx.outer != ctx) { - val s = ctx.scope lookupSymbolEntry symbol - if (s != null) - res = s - else - ctx = ctx.outer + // 1) Must be owned by the same Scope, to ensure that in + // `{ class C; { ...; object C } }`, the class is not seen as a companion of the object. + // 2) Must be a class and module symbol, so that `{ class C; def C }` or `{ type T; object T }` are not companions. + lookupScopeEntry(original) match { + case null => NoSymbol + case entry => + def isCompanion(sym: Symbol): Boolean = + (original.isModule && sym.isClass || sym.isModule && original.isClass) && sym.isCoDefinedWith(original) + entry.owner.lookupNameInSameScopeAs(original, original.name.companionName).filter(isCompanion) } - res } + } //class Context /** A `Context` focussed on an `Import` tree */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 395bda234b..28169c9da1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1955,9 +1955,12 @@ trait Namers extends MethodSynthesis { // Doing this generally would trigger cycles; that's what we also // use the lower-level scan through the current Context as a fall back. if (!currentRun.compiles(owner)) owner.initialize - original.companionSymbol orElse { - ctx.lookupCompanionOf(original) - } + + if (original.isModuleClass) original.sourceModule + else if (!owner.isTerm && owner.hasCompleteInfo) + original.companionSymbol + else + ctx.lookupCompanionInIncompleteOwner(original) } /** A version of `Symbol#linkedClassOfClass` that works with local companions, ala `companionSymbolOf`. */ diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index 990edcd86d..50743a922a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -112,7 +112,7 @@ abstract class TreeCheckers extends Analyzer { else if (prevTrees exists (t => (t eq tree) || (t.symbol == sym))) () else { - val s1 = (prevTrees map wholetreestr).sorted.distinct + val s1 = (prevTrees map wholetreestr).distinct.sorted val s2 = wholetreestr(tree) if (s1 contains s2) () else movedMsgs += ("\n** %s moved:\n** Previously:\n%s\n** Currently:\n%s".format(ownerstr(sym), s1 mkString ", ", s2)) diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index b66dbf21c0..36b9a65334 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -11,6 +11,7 @@ import scala.collection.mutable.ListBuffer import scala.util.control.Exception.ultimately import symtab.Flags._ import PartialFunction._ +import scala.annotation.tailrec /** An interface to enable higher configurability of diagnostic messages * regarding type errors. This is barely a beginning as error messages are @@ -274,19 +275,54 @@ trait TypeDiagnostics { if (AnyRefTpe <:< req) notAnyRefMessage(found) else "" } + def finalOwners(tpe: Type): Boolean = (tpe.prefix == NoPrefix) || recursivelyFinal(tpe) + + @tailrec + final def recursivelyFinal(tpe: Type): Boolean = { + val prefix = tpe.prefix + if (prefix != NoPrefix) { + if (prefix.typeSymbol.isFinal) { + recursivelyFinal(prefix) + } else { + false + } + } else { + true + } + } + // TODO - figure out how to avoid doing any work at all // when the message will never be seen. I though context.reportErrors // being false would do that, but if I return "<suppressed>" under // that condition, I see it. def foundReqMsg(found: Type, req: Type): String = { - def baseMessage = ( - ";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) + - "\n required: " + req + existentialContext(req) + explainAlias(req) - ) - ( withDisambiguation(Nil, found, req)(baseMessage) - + explainVariance(found, req) - + explainAnyVsAnyRef(found, req) - ) + val foundWiden = found.widen + val reqWiden = req.widen + val sameNamesDifferentPrefixes = + foundWiden.typeSymbol.name == reqWiden.typeSymbol.name && + foundWiden.prefix.typeSymbol != reqWiden.prefix.typeSymbol + val easilyMistakable = + sameNamesDifferentPrefixes && + !req.typeSymbol.isConstant && + finalOwners(foundWiden) && finalOwners(reqWiden) && + !found.typeSymbol.isTypeParameterOrSkolem && !req.typeSymbol.isTypeParameterOrSkolem + + if (easilyMistakable) { + val longestNameLength = foundWiden.nameAndArgsString.length max reqWiden.nameAndArgsString.length + val paddedFoundName = foundWiden.nameAndArgsString.padTo(longestNameLength, ' ') + val paddedReqName = reqWiden.nameAndArgsString.padTo(longestNameLength, ' ') + ";\n found : " + (paddedFoundName + s" (in ${found.prefix.typeSymbol.fullNameString}) ") + explainAlias(found) + + "\n required: " + (paddedReqName + s" (in ${req.prefix.typeSymbol.fullNameString}) ") + explainAlias(req) + } else { + def baseMessage = { + ";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) + + "\n required: " + req + existentialContext(req) + explainAlias(req) + } + (withDisambiguation(Nil, found, req)(baseMessage) + + explainVariance(found, req) + + explainAnyVsAnyRef(found, req) + ) + } } def typePatternAdvice(sym: Symbol, ptSym: Symbol) = { @@ -315,14 +351,6 @@ trait TypeDiagnostics { def restoreName() = sym.name = savedName def modifyName(f: String => String) = sym setName newTypeName(f(sym.name.toString)) - /** Prepend java.lang, scala., or Predef. if this type originated - * in one of those. - */ - def qualifyDefaultNamespaces() = { - val intersect = Set(trueOwner, aliasOwner) intersect UnqualifiedOwners - if (intersect.nonEmpty && tp.typeSymbolDirect.name == tp.typeSymbol.name) preQualify() - } - // functions to manipulate the name def preQualify() = modifyName(trueOwner.fullName + "." + _) def postQualify() = if (!(postQualifiedWith contains trueOwner)) { postQualifiedWith ::= trueOwner; modifyName(_ + "(in " + trueOwner + ")") } @@ -414,12 +442,6 @@ trait TypeDiagnostics { if (td1 string_== td2) tds foreach (_.nameQualify()) - // If they have the same simple name, and either of them is in the - // scala package or predef, qualify with scala so it is not confusing why - // e.g. java.util.Iterator and Iterator are different types. - if (td1 name_== td2) - tds foreach (_.qualifyDefaultNamespaces()) - // If they still print identically: // a) If they are type parameters with different owners, append (in <owner>) // b) Failing that, the best we can do is append "(some other)" to the latter. diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 837ccf7e06..2cbd9475fc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3333,15 +3333,15 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def handleOverloaded = { val undetparams = context.undetparams - def funArgTypes(tps: List[Type]) = tps.map { tp => - val relTp = tp.asSeenFrom(pre, fun.symbol.owner) + def funArgTypes(tpAlts: List[(Type, Symbol)]) = tpAlts.map { case (tp, alt) => + val relTp = tp.asSeenFrom(pre, alt.owner) val argTps = functionOrSamArgTypes(relTp) //println(s"funArgTypes $argTps from $relTp") argTps.map(approximateAbstracts) } - def functionProto(argTps: List[Type]): Type = - try functionType(funArgTypes(argTps).transpose.map(lub), WildcardType) + def functionProto(argTpWithAlt: List[(Type, Symbol)]): Type = + try functionType(funArgTypes(argTpWithAlt).transpose.map(lub), WildcardType) catch { case _: IllegalArgumentException => WildcardType } // To propagate as much information as possible to typedFunction, which uses the expected type to @@ -3355,21 +3355,21 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // do not receive special treatment: they are typed under WildcardType.) val altArgPts = if (settings.isScala212 && args.exists(treeInfo.isFunctionMissingParamType)) - try alts.map(alt => formalTypes(alt.info.paramTypes, argslen)).transpose // do least amount of work up front + try alts.map(alt => formalTypes(alt.info.paramTypes, argslen).map(ft => (ft, alt))).transpose // do least amount of work up front catch { case _: IllegalArgumentException => args.map(_ => Nil) } // fail safe in case formalTypes fails to align to argslen else args.map(_ => Nil) // will type under argPt == WildcardType val (args1, argTpes) = context.savingUndeterminedTypeParams() { val amode = forArgMode(fun, mode) - map2(args, altArgPts) { (arg, argPts) => + map2(args, altArgPts) { (arg, argPtAlts) => def typedArg0(tree: Tree) = { // if we have an overloaded HOF such as `(f: Int => Int)Int <and> (f: Char => Char)Char`, // and we're typing a function like `x => x` for the argument, try to collapse // the overloaded type into a single function type from which `typedFunction` // can derive the argument type for `x` in the function literal above val argPt = - if (argPts.nonEmpty && treeInfo.isFunctionMissingParamType(tree)) functionProto(argPts) + if (argPtAlts.nonEmpty && treeInfo.isFunctionMissingParamType(tree)) functionProto(argPtAlts) else WildcardType val argTyped = typedArg(tree, amode, BYVALmode, argPt) @@ -3426,29 +3426,29 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // repeat vararg as often as needed, remove by-name val formals = formalTypes(paramTypes, argslen) - /* Try packing all arguments into a Tuple and apply `fun` - * to that. This is the last thing which is tried (after - * default arguments) + /* Try packing all arguments into a Tuple and apply `fun` to that. + * This is the last thing which is tried (after default arguments). */ - def tryTupleApply: Tree = { - if (eligibleForTupleConversion(paramTypes, argslen) && !phase.erasedTypes) { + def tryTupleApply: Tree = + if (phase.erasedTypes || !eligibleForTupleConversion(paramTypes, argslen)) EmptyTree + else { val tupleArgs = List(atPos(tree.pos.makeTransparent)(gen.mkTuple(args))) // expected one argument, but got 0 or >1 ==> try applying to tuple // the inner "doTypedApply" does "extractUndetparams" => restore when it fails val savedUndetparams = context.undetparams - silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)) map { t => - // Depending on user options, may warn or error here if - // a Unit or tuple was inserted. - val keepTree = ( - !mode.typingExprNotFun // why? introduced in 4e488a60, doc welcome - || t.symbol == null // ditto - || checkValidAdaptation(t, args) - ) - if (keepTree) t else EmptyTree - } orElse { _ => context.undetparams = savedUndetparams ; EmptyTree } + // May warn or error if a Unit or tuple was inserted. + def validate(t: Tree): Tree = { + // regardless of typer's mode + val invalidAdaptation = t.symbol != null && !checkValidAdaptation(t, args) + // only bail if we're typing an expression (and not inside another application) + if (invalidAdaptation && mode.typingExprNotFun) EmptyTree else t + } + def reset(errors: Seq[AbsTypeError]): Tree = { + context.undetparams = savedUndetparams + EmptyTree + } + silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)).map(validate).orElse(reset) } - else EmptyTree - } /* Treats an application which uses named or default arguments. * Also works if names + a vararg used: when names are used, the vararg @@ -4666,19 +4666,20 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val qual1 = typedQualifier(qual) if (treeInfo.isVariableOrGetter(qual1)) { if (Statistics.canEnable) Statistics.stopTimer(failedOpEqNanos, opeqStart) - val erred = qual1.isErroneous || args.exists(_.isErroneous) + val erred = qual1.exists(_.isErroneous) || args.exists(_.isErroneous) if (erred) reportError(error) else { val convo = convertToAssignment(fun, qual1, name, args) silent(op = _.typed1(convo, mode, pt)) match { case SilentResultValue(t) => t - case err: SilentTypeError => reportError(SilentTypeError(advice1(convo, error.errors, err), error.warnings)) + case err: SilentTypeError => reportError( + SilentTypeError(advice1(convo, error.errors, err), error.warnings) + ) } } - } - else { + } else { if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, appStart) val Apply(Select(qual2, _), args2) = tree - val erred = qual2.isErroneous || args2.exists(_.isErroneous) + val erred = qual2.exists(_.isErroneous) || args2.exists(_.isErroneous) reportError { if (erred) error else SilentTypeError(advice2(error.errors), error.warnings) } |