diff options
author | Paul Phillips <paulp@improving.org> | 2012-08-17 09:14:09 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-08-17 09:14:09 -0700 |
commit | b794f4a87f5217fd381f129cd75946a2ced6eb44 (patch) | |
tree | 872c1c5b20effcc499a3b1141ab4d9c1900bf2a9 /src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | |
parent | 62d319e46ff672f523e266009025fe3723651229 (diff) | |
parent | 7fc860963a4f76cb18e44c20f2bdfb49641033f3 (diff) | |
download | scala-b794f4a87f5217fd381f129cd75946a2ced6eb44.tar.gz scala-b794f4a87f5217fd381f129cd75946a2ced6eb44.tar.bz2 scala-b794f4a87f5217fd381f129cd75946a2ced6eb44.zip |
Merge remote-tracking branch 'origin/2.10.x' into merge-210
# By Eugene Burmako (12) and others
# Via Paul Phillips (4) and others
* origin/2.10.x:
Fixes SI-6236.
Fixes SI-6189.
Hunting down eliminable :: allocations.
Absolutize tools.nsc => scala.tools.nsc.
more cleanup for typedMacroBody
shaves more than 150 lines off typedMacroBody
Optimization in SubstMap.
removes dead code
pull request feedback
more macro cleanup
further cleanup of transformTypeTagEvidenceParams
macroImplSigs => macroImplSig
Dominik's comments on api.Mirrors
phaseId(currentPeriod) >= erasurePhase.id
materializeImplicit and implicitsOfExpectedType
cleanup of reflection- and macro-related stuff
adds the `skipPackage` attribute to Scaladoc
Fixes backend crash due to incorrect consumedTypes
Fix SI-6208. mutable.Queue now returns mutable.Queue for collection methods rather than MutableList.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 164 |
1 files changed, 151 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 632f30b3a6..d0716e1a35 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -8,12 +8,15 @@ package typechecker import scala.collection.{ mutable, immutable } import scala.reflect.internal.util.StringOps.{ countElementsAsString, countAsString } -import symtab.Flags.{ PRIVATE, PROTECTED } +import symtab.Flags.{ PRIVATE, PROTECTED, IS_ERROR } +import scala.compat.Platform.EOL trait ContextErrors { self: Analyzer => import global._ + import definitions._ + import treeInfo._ object ErrorKinds extends Enumeration { type ErrorKind = Value @@ -424,8 +427,11 @@ trait ContextErrors { def AbstractionFromVolatileTypeError(vd: ValDef) = issueNormalTypeError(vd, "illegal abstraction from value with volatile type "+vd.symbol.tpe) + private[ContextErrors] def TypedApplyWrongNumberOfTpeParametersErrorMessage(fun: Tree) = + "wrong number of type parameters for "+treeSymTypeMsg(fun) + def TypedApplyWrongNumberOfTpeParametersError(tree: Tree, fun: Tree) = { - issueNormalTypeError(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun)) + issueNormalTypeError(tree, TypedApplyWrongNumberOfTpeParametersErrorMessage(fun)) setError(tree) } @@ -622,11 +628,11 @@ trait ContextErrors { } // cyclic errors - def CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) = - issueTypeError(PosAndMsgTypeError(errPos, "cyclic aliasing or subtyping involving "+sym0)) + def CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) = + issueTypeError(PosAndMsgTypeError(errPos, "cyclic aliasing or subtyping involving "+sym0)) - def CyclicReferenceError(errPos: Position, lockedSym: Symbol) = - issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym)) + def CyclicReferenceError(errPos: Position, lockedSym: Symbol) = + issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym)) } } @@ -750,21 +756,24 @@ trait ContextErrors { kindErrors.toList.mkString("\n", ", ", "")) } - def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type], - tparams: List[Symbol], kindErrors: List[String]) = { - if (settings.explaintypes.value) { + private[ContextErrors] def NotWithinBoundsErrorMessage(prefix: String, targs: List[Type], tparams: List[Symbol], explaintypes: Boolean) = { + if (explaintypes) { val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds) (targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ)) (targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi)) () } - issueNormalTypeError(tree, - prefix + "type arguments " + targs.mkString("[", ",", "]") + - " do not conform to " + tparams.head.owner + "'s type parameter bounds " + - (tparams map (_.defString)).mkString("[", ",", "]")) + prefix + "type arguments " + targs.mkString("[", ",", "]") + + " do not conform to " + tparams.head.owner + "'s type parameter bounds " + + (tparams map (_.defString)).mkString("[", ",", "]") } + def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type], + tparams: List[Symbol], kindErrors: List[String]) = + issueNormalTypeError(tree, + NotWithinBoundsErrorMessage(prefix, targs, tparams, settings.explaintypes.value)) + //substExpr def PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol], pt: Type) = issueNormalTypeError(tree, @@ -1084,4 +1093,133 @@ trait ContextErrors { setError(arg) } } + + // using an exception here is actually a good idea + // because the lifespan of this exception is extremely small and controlled + // moreover exceptions let us avoid an avalanche of "if (!hasError) do stuff" checks + case object MacroBodyTypecheckException extends Exception with scala.util.control.ControlThrowable + + trait MacroErrors { + self: MacroTyper => + + private implicit val context0 = typer.context + val context = typer.context + + // helpers + + private def lengthMsg(flavor: String, violation: String, extra: Symbol) = { + val noun = if (flavor == "value") "parameter" else "type parameter" + val message = noun + " lists have different length, " + violation + " extra " + noun + val suffix = if (extra ne NoSymbol) " " + extra.defString else "" + message + suffix + } + + private def abbreviateCoreAliases(s: String): String = List("AbsTypeTag", "Expr").foldLeft(s)((res, x) => res.replace("c.universe." + x, "c." + x)) + + private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = { + var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString + if (abbreviate) argsPart = abbreviateCoreAliases(argsPart) + var retPart = restpe.toString + if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart) + argsPart + ": " + retPart + } + + // not exactly an error generator, but very related + // and I dearly wanted to push it away from Macros.scala + private def checkSubType(slot: String, rtpe: Type, atpe: Type) = { + val ok = if (macroDebugVerbose || settings.explaintypes.value) { + if (rtpe eq atpe) println(rtpe + " <: " + atpe + "?" + EOL + "true") + withTypesExplained(rtpe <:< atpe) + } else rtpe <:< atpe + if (!ok) { + compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, abbreviateCoreAliases(rtpe.toString), abbreviateCoreAliases(atpe.toString))) + } + } + + // errors + + private def fail() = { + // need to set the IS_ERROR flag to prohibit spurious expansions + if (macroDef != null) macroDef setFlag IS_ERROR + // not setting ErrorSymbol as in `infer.setError`, because we still need to know that it's a macro + // otherwise assignTypeToTree in Namers might fail if macroDdef.tpt == EmptyTree + macroDdef setType ErrorType + throw MacroBodyTypecheckException + } + + private def genericError(tree: Tree, message: String) = { + issueNormalTypeError(tree, message) + fail() + } + + private def implRefError(message: String) = genericError(methPart(macroDdef.rhs), message) + + private def compatibilityError(message: String) = + implRefError( + "macro implementation has wrong shape:"+ + "\n required: " + showMeth(rparamss, rret, abbreviate = true) + + "\n found : " + showMeth(aparamss, aret, abbreviate = false) + + "\n" + message) + + // Phase I: sanity checks + + def MacroDefIsFastTrack() = { + macroLogVerbose("typecheck terminated unexpectedly: macro is fast track") + assert(!macroDdef.tpt.isEmpty, "fast track macros must provide result type") + throw MacroBodyTypecheckException // don't call fail, because we don't need IS_ERROR + } + + def MacroFeatureNotEnabled() = { + macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled") + fail() + } + + // Phase II: typecheck the right-hand side of the macro def + + // do nothing, just fail. relevant typecheck errors have already been reported + def MacroDefUntypeableBodyError() = fail() + + def MacroDefInvalidBodyError() = genericError(macroDdef, "macro body has wrong shape:\n required: macro [<implementation object>].<method name>[[<type args>]]") + + def MacroImplNotPublicError() = implRefError("macro implementation must be public") + + def MacroImplOverloadedError() = implRefError("macro implementation cannot be overloaded") + + def MacroImplWrongNumberOfTypeArgumentsError(macroImplRef: Tree) = implRefError(typer.TyperErrorGen.TypedApplyWrongNumberOfTpeParametersErrorMessage(macroImplRef)) + + def MacroImplNotStaticError() = implRefError("macro implementation must be in statically accessible object") + + // Phase III: check compatibility between the macro def and its macro impl + // aXXX (e.g. aparams) => characteristics of the macro impl ("a" stands for "actual") + // rXXX (e.g. rparams) => characteristics of a reference macro impl signature synthesized from the macro def ("r" stands for "reference") + + def MacroImplNonTagImplicitParameters(params: List[Symbol]) = compatibilityError("macro implementations cannot have implicit parameters other than AbsTypeTag evidences") + + def MacroImplParamssMismatchError() = compatibilityError("number of parameter sections differ") + + def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(lengthMsg("value", "found", aparams(rparams.length))) + + def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(abbreviateCoreAliases(lengthMsg("value", "required", rparams(aparams.length)))) + + def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = checkSubType("parameter " + rparam.name, rparam.tpe, atpe) + + def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = checkSubType("return type", atpe, rret) + + def MacroImplParamNameMismatchError(aparam: Symbol, rparam: Symbol) = compatibilityError("parameter names differ: " + rparam.name + " != " + aparam.name) + + def MacroImplVarargMismatchError(aparam: Symbol, rparam: Symbol) = { + if (isRepeated(rparam) && !isRepeated(aparam)) + compatibilityError("types incompatible for parameter " + rparam.name + ": corresponding is not a vararg parameter") + if (!isRepeated(rparam) && isRepeated(aparam)) + compatibilityError("types incompatible for parameter " + aparam.name + ": corresponding is not a vararg parameter") + } + + def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) = + compatibilityError(typer.infer.InferErrorGen.NotWithinBoundsErrorMessage("", atargs, atparams, macroDebugVerbose || settings.explaintypes.value)) + + def MacroImplTparamInstantiationError(atparams: List[Symbol], ex: NoInstance) = + compatibilityError( + "type parameters "+(atparams map (_.defString) mkString ", ")+" cannot be instantiated\n"+ + ex.getMessage) + } } |