diff options
author | Josh Suereth <Joshua.Suereth@gmail.com> | 2012-08-10 09:05:29 -0700 |
---|---|---|
committer | Josh Suereth <Joshua.Suereth@gmail.com> | 2012-08-10 09:05:29 -0700 |
commit | 7dd0ead39ceb7cd6f445d86f37c68b78218eef57 (patch) | |
tree | 61a10ec88c12546ccf44dbe653fec42a8429d203 /src/compiler/scala/tools | |
parent | c0d5f0aaddc7bc309f84afd5d4f4b5c136c65816 (diff) | |
parent | eb2375cc5327293c708226e78f80a97cc780a12f (diff) | |
download | scala-7dd0ead39ceb7cd6f445d86f37c68b78218eef57.tar.gz scala-7dd0ead39ceb7cd6f445d86f37c68b78218eef57.tar.bz2 scala-7dd0ead39ceb7cd6f445d86f37c68b78218eef57.zip |
Merge pull request #1109 from paulp/topic/warn-inferred-any
Warn when Any or AnyVal is inferred.
Diffstat (limited to 'src/compiler/scala/tools')
6 files changed, 46 insertions, 26 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala index 0d688d51f2..aa3f4dcb7e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala @@ -381,10 +381,9 @@ abstract class ICodeCheckers { for (instr <- b) { this.instruction = instr - def checkLocal(local: Local): Unit = { - method lookupLocal local.sym.name getOrElse { - icodeError(" " + local + " is not defined in method " + method) - } + def checkLocal(local: Local) { + if ((method lookupLocal local.sym.name).isEmpty) + icodeError(s" $local is not defined in method $method") } def checkField(obj: TypeKind, field: Symbol): Unit = obj match { case REFERENCE(sym) => diff --git a/src/compiler/scala/tools/nsc/interpreter/ISettings.scala b/src/compiler/scala/tools/nsc/interpreter/ISettings.scala index b65a1ac889..762092c08a 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ISettings.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ISettings.scala @@ -44,7 +44,7 @@ class ISettings(intp: IMain) { } def deprecation: Boolean = intp.settings.deprecation.value - def allSettings = Map( + def allSettings = Map[String, Any]( "maxPrintString" -> maxPrintString, "maxAutoprintCompletion" -> maxAutoprintCompletion, "unwrapStrings" -> unwrapStrings, diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala index 16f8685a87..bfa1714894 100644 --- a/src/compiler/scala/tools/nsc/settings/Warnings.scala +++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala @@ -29,7 +29,8 @@ trait Warnings { warnInaccessible, warnNullaryOverride, warnNullaryUnit, - warnAdaptedArgs + warnAdaptedArgs, + warnInferAny ) // Warning groups. @@ -52,6 +53,7 @@ trait Warnings { val warnInaccessible = BooleanSetting ("-Ywarn-inaccessible", "Warn about inaccessible types in method signatures.") val warnNullaryOverride = BooleanSetting ("-Ywarn-nullary-override", "Warn when non-nullary overrides nullary, e.g. `def foo()` over `def foo`.") + val warnInferAny = BooleanSetting ("-Ywarn-infer-any", "Warn when a type argument is inferred to be `Any`.") // Backward compatibility. def Xwarnfatal = fatalWarnings diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index de04b1cb68..032212e3c0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -149,14 +149,13 @@ trait Infer { case tv @ TypeVar(origin, constr) if !tv.untouchable => if (constr.inst == NoType) { throw new DeferredNoInstance(() => - "no unique instantiation of type variable " + origin + " could be found") + s"no unique instantiation of type variable $origin could be found") } else if (excludedVars(tv)) { throw new NoInstance("cyclic instantiation") } else { excludedVars += tv - val res = apply(constr.inst) - excludedVars -= tv - res + try apply(constr.inst) + finally excludedVars -= tv } case _ => mapOver(tp) @@ -643,6 +642,25 @@ trait Infer { tvars, tparams, tparams map inferVariance(formals, restpe), false, lubDepth(formals) max lubDepth(argtpes) ) + // Can warn about inferring Any/AnyVal as long as they don't appear + // explicitly anywhere amongst the formal, argument, result, or expected type. + def canWarnAboutAny = !(pt :: restpe :: formals ::: argtpes exists (t => (t contains AnyClass) || (t contains AnyValClass))) + def argumentPosition(idx: Int): Position = context.tree match { + case x: ValOrDefDef => x.rhs match { + case Apply(fn, args) if idx < args.size => args(idx).pos + case _ => context.tree.pos + } + case _ => context.tree.pos + } + if (settings.warnInferAny.value && context.reportErrors && canWarnAboutAny) { + foreachWithIndex(targs) ((targ, idx) => + targ.typeSymbol match { + case sym @ (AnyClass | AnyValClass) => + context.unit.warning(argumentPosition(idx), s"a type was inferred to be `${sym.name}`; this may indicate a programming error.") + case _ => + } + ) + } adjustTypeArgs(tparams, tvars, targs, restpe) } @@ -1088,12 +1106,12 @@ trait Infer { * @param targs ... * @param pt ... */ - private def substExpr(tree: Tree, undetparams: List[Symbol], - targs: List[Type], pt: Type) { + private def substExpr(tree: Tree, undetparams: List[Symbol], targs: List[Type], pt: Type) { if (targs eq null) { if (!tree.tpe.isErroneous && !pt.isErroneous) PolymorphicExpressionInstantiationError(tree, undetparams, pt) - } else { + } + else { new TreeTypeSubstituter(undetparams, targs).traverse(tree) notifyUndetparamsInferred(undetparams, targs) } @@ -1221,17 +1239,19 @@ trait Infer { } } else None - (inferFor(pt) orElse inferForApproxPt) map { targs => - new TreeTypeSubstituter(undetparams, targs).traverse(tree) - notifyUndetparamsInferred(undetparams, targs) - } getOrElse { - debugwarn("failed inferConstructorInstance for "+ tree +" : "+ tree.tpe +" under "+ undetparams +" pt = "+ pt +(if(isFullyDefined(pt)) " (fully defined)" else " (not fully defined)")) - // if (settings.explaintypes.value) explainTypes(resTp.instantiateTypeParams(undetparams, tvars), pt) - ConstrInstantiationError(tree, resTp, pt) + val inferred = inferFor(pt) orElse inferForApproxPt + + inferred match { + case Some(targs) => + new TreeTypeSubstituter(undetparams, targs).traverse(tree) + notifyUndetparamsInferred(undetparams, targs) + case _ => + debugwarn("failed inferConstructorInstance for "+ tree +" : "+ tree.tpe +" under "+ undetparams +" pt = "+ pt +(if(isFullyDefined(pt)) " (fully defined)" else " (not fully defined)")) + // if (settings.explaintypes.value) explainTypes(resTp.instantiateTypeParams(undetparams, tvars), pt) + ConstrInstantiationError(tree, resTp, pt) } } - def instBounds(tvar: TypeVar): (Type, Type) = { val tparam = tvar.origin.typeSymbol val instType = toOrigin(tvar.constr.inst) diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index 07d457b17b..9d5b52808d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -278,7 +278,7 @@ abstract class TreeCheckers extends Analyzer { def cond(s: Symbol) = !s.isTerm || s.isMethod || s == sym.owner if (sym.owner != currentOwner) { - val expected = currentOwner.ownerChain find (x => cond(x)) getOrElse fail("DefTree can't find owner: ") + val expected = currentOwner.ownerChain find (x => cond(x)) getOrElse { fail("DefTree can't find owner: ") ; NoSymbol } if (sym.owner != expected) fail("""| | currentOwner chain: %s diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e3bcff7d84..7eb53ca7de 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3111,9 +3111,8 @@ trait Typers extends Modes with Adaptations with Tags { // define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun" // returns those undetparams which have not been instantiated. val undetparams = inferMethodInstance(fun, tparams, args1, pt) - val result = doTypedApply(tree, fun, args1, mode, pt) - context.undetparams = undetparams - result + try doTypedApply(tree, fun, args1, mode, pt) + finally context.undetparams = undetparams } } } @@ -4555,7 +4554,7 @@ trait Typers extends Modes with Adaptations with Tags { assert(errorContainer == null, "Cannot set ambiguous error twice for identifier") errorContainer = tree } - + val fingerPrint: Long = name.fingerPrint var defSym: Symbol = tree.symbol // the directly found symbol |