diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-01-29 09:59:54 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2015-01-29 09:59:54 +1000 |
commit | 1db62995b52b06f5037331172b3f54739d720d62 (patch) | |
tree | 0b684c4adfcb800fa195947b37fdb5dc89731552 /src/compiler/scala/tools/nsc/typechecker | |
parent | 8b5f2b435b4b14089806406c8923f7e845d10ef6 (diff) | |
parent | eb15950e697eb77e52733f81c65e2d51951ad881 (diff) | |
download | scala-1db62995b52b06f5037331172b3f54739d720d62.tar.gz scala-1db62995b52b06f5037331172b3f54739d720d62.tar.bz2 scala-1db62995b52b06f5037331172b3f54739d720d62.zip |
Merge commit 'eb15950' into merge/2.11.x-to-2.12.x-20150129
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
5 files changed, 57 insertions, 23 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 20e462bbce..866ca37303 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -885,22 +885,31 @@ trait ContextErrors { val WrongNumber, NoParams, ArgsDoNotConform = Value } - private def issueAmbiguousTypeErrorUnlessErroneous(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): Unit = - if (!(pre.isErroneous || sym1.isErroneous || sym2.isErroneous)) { - if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) { - val methodName = nme.defaultGetterToMethod(sym1.name) - context.issueAmbiguousError(AmbiguousTypeError(sym1.enclClass.pos, - "in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName + - " define default arguments")) - } else { - context.issueAmbiguousError(AmbiguousTypeError(pos, - ("ambiguous reference to overloaded definition,\n" + - "both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) + - "\nand " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) + - "\nmatch " + rest) - )) - } - } + private def issueAmbiguousTypeErrorUnlessErroneous(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): Unit = { + // To avoid stack overflows (SI-8890), we MUST (at least) report when either `validTargets` OR `ambiguousSuppressed` + // More details: + // If `!context.ambiguousErrors`, `reporter.issueAmbiguousError` (which `context.issueAmbiguousError` forwards to) + // buffers ambiguous errors. In this case, to avoid looping, we must issue even if `!validTargets`. (TODO: why?) + // When not buffering (and thus reporting to the user), we shouldn't issue unless `validTargets`, + // otherwise we report two different errors that trace back to the same root cause, + // and unless `validTargets`, we don't know for sure the ambiguity is real anyway. + val validTargets = !(pre.isErroneous || sym1.isErroneous || sym2.isErroneous) + val ambiguousBuffered = !context.ambiguousErrors + if (validTargets || ambiguousBuffered) + context.issueAmbiguousError( + if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) { + val methodName = nme.defaultGetterToMethod(sym1.name) + AmbiguousTypeError(sym1.enclClass.pos, + s"in ${sym1.enclClass}, multiple overloaded alternatives of $methodName define default arguments") + + } else { + AmbiguousTypeError(pos, + "ambiguous reference to overloaded definition,\n" + + s"both ${sym1.fullLocationString} of type ${pre.memberType(sym1)}\n" + + s"and ${sym2.fullLocationString} of type ${pre.memberType(sym2)}\n" + + s"match $rest") + }) + } def AccessError(tree: Tree, sym: Symbol, ctx: Context, explanation: String): AbsTypeError = AccessError(tree, sym, ctx.enclClass.owner.thisType, ctx.enclClass.owner, explanation) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index c86eaffccf..da0ae4ee79 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -480,6 +480,8 @@ trait Contexts { self: Analyzer => // SI-8245 `isLazy` need to skip lazy getters to ensure `return` binds to the right place c.enclMethod = if (isDefDef && !owner.isLazy) c else enclMethod + if (tree != outer.tree) c(TypeConstructorAllowed) = false + registerContext(c.asInstanceOf[analyzer.Context]) debuglog("[context] ++ " + c.unit + " / " + tree.summaryString) c diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index e2ad578252..7ed4fe1f88 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1475,8 +1475,10 @@ trait Implicits { }) private lazy val typeParamNames: List[String] = sym.typeParams.map(_.decodedName) + private def typeArgsAtSym(paramTp: Type) = paramTp.baseType(sym).typeArgs + + def format(paramName: Name, paramTp: Type): String = format(typeArgsAtSym(paramTp) map (_.toString)) - def format(paramName: Name, paramTp: Type): String = format(paramTp.typeArgs map (_.toString)) def format(typeArgs: List[String]): String = interpolate(msg, Map((typeParamNames zip typeArgs): _*)) // TODO: give access to the name and type of the implicit argument, etc? diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index fdff2f3076..e876d4a6af 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1643,6 +1643,7 @@ trait Namers extends MethodSynthesis { def symbolAllowsDeferred = ( sym.isValueParameter || sym.isTypeParameterOrSkolem + || (sym.isAbstractType && sym.owner.isClass) || context.tree.isInstanceOf[ExistentialTypeTree] ) // Does the symbol owner require no undefined members? diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index fe6038bc00..20db85e665 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1104,7 +1104,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper adaptConstant(value) case OverloadedType(pre, alts) if !mode.inFunMode => // (1) inferExprAlternative(tree, pt) - adapt(tree, mode, pt, original) + adaptAfterOverloadResolution(tree, mode, pt, original) case NullaryMethodType(restpe) => // (2) adapt(tree setType restpe, mode, pt, original) case TypeRef(_, ByNameParamClass, arg :: Nil) if mode.inExprMode => // (2) @@ -1137,6 +1137,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } } + // This just exists to help keep track of the spots where we have to adapt a tree after + // overload resolution. These proved hard to find during the fix for SI-8267. + def adaptAfterOverloadResolution(tree: Tree, mode: Mode, pt: Type = WildcardType, original: Tree = EmptyTree): Tree = { + adapt(tree, mode, pt, original) + } + def instantiate(tree: Tree, mode: Mode, pt: Type): Tree = { inferExprInstance(tree, context.extractUndetparams(), pt) adapt(tree, mode, pt) @@ -1724,7 +1730,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if ((clazz isNonBottomSubClass ClassfileAnnotationClass) && (clazz != ClassfileAnnotationClass)) { if (!clazz.owner.isPackageClass) context.error(clazz.pos, "inner classes cannot be classfile annotations") - else restrictionWarning(cdef.pos, unit, + // Ignore @SerialVersionUID, because it is special-cased and handled completely differently. + // It only extends ClassfileAnnotationClass instead of StaticAnnotation to get the enforcement + // of constant argument values "for free". Related to SI-7041. + else if (clazz != SerialVersionUIDAttr) restrictionWarning(cdef.pos, unit, """|subclassing Classfile does not |make your annotation visible at runtime. If that is what |you want, you must write the annotation class in Java.""".stripMargin) @@ -3175,7 +3184,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (sym1 != NoSymbol) sym = sym1 } if (sym == NoSymbol) fun - else adapt(fun setSymbol sym setType pre.memberType(sym), mode.forFunMode, WildcardType) + else adaptAfterOverloadResolution(fun setSymbol sym setType pre.memberType(sym), mode.forFunMode) } else fun } @@ -3220,7 +3229,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper setError(tree) else { inferMethodAlternative(fun, undetparams, argTpes, pt) - doTypedApply(tree, adapt(fun, mode.forFunMode, WildcardType), args1, mode, pt) + doTypedApply(tree, adaptAfterOverloadResolution(fun, mode.forFunMode, WildcardType), args1, mode, pt) } } handleOverloaded @@ -3803,7 +3812,18 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper protected def typedTypeApply(tree: Tree, mode: Mode, fun: Tree, args: List[Tree]): Tree = fun.tpe match { case OverloadedType(pre, alts) => inferPolyAlternatives(fun, mapList(args)(treeTpe)) - val tparams = fun.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree) + + // SI-8267 `memberType` can introduce existentials *around* a PolyType/MethodType, see AsSeenFromMap#captureThis. + // If we had selected a non-overloaded symbol, `memberType` would have been called in `makeAccessible` + // and the resulting existential type would have been skolemized in `adapt` *before* we typechecked + // the enclosing type-/ value- application. + // + // However, if the selection is overloaded, we defer calling `memberType` until we can select a single + // alternative here. It is therefore necessary to skolemize the existential here. + // + val fun1 = adaptAfterOverloadResolution(fun, mode.forFunMode | TAPPmode) + + val tparams = fun1.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree) val args1 = if (sameLength(args, tparams)) { //@M: in case TypeApply we can't check the kind-arities of the type arguments, // as we don't know which alternative to choose... here we do @@ -3817,7 +3837,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // ...actually this was looping anyway, see bug #278. return TypedApplyWrongNumberOfTpeParametersError(fun, fun) - typedTypeApply(tree, mode, fun, args1) + typedTypeApply(tree, mode, fun1, args1) case SingleType(_, _) => typedTypeApply(tree, mode, fun setType fun.tpe.widen, args) case PolyType(tparams, restpe) if tparams.nonEmpty => |