summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
authorHubert Plociniczak <hubert.plociniczak@gmail.com>2012-01-25 11:33:53 +0100
committerHubert Plociniczak <hubert.plociniczak@gmail.com>2012-01-25 11:33:53 +0100
commitc800d1fec5241ed8c29e5af30465856f9b583246 (patch)
treea37c194bb2d632adf9adeda17a107913f63864ba /src/compiler/scala/tools/nsc/typechecker/Typers.scala
parentde2b0c68785afc0f801fbe8d2750366e90c9fa70 (diff)
downloadscala-c800d1fec5241ed8c29e5af30465856f9b583246.tar.gz
scala-c800d1fec5241ed8c29e5af30465856f9b583246.tar.bz2
scala-c800d1fec5241ed8c29e5af30465856f9b583246.zip
Use context for buffering errors that cannot/shouldn't be reported in the given moment (instead of throwing type errors). This avoids previous problems where we were creating fake error trees in some incorrect places like in type completers in Namers etc. Implicits relied heavily on type errors being thrown but performance should stay the same due to some explicit checks/returns.
Some of the problems involved how ambiguous error messages were collected/reported because it was very random (similarly for divergent implicits). This should be more explicit now. Reduced the number of unnecessary cyclic references being thrown (apart from those in Symbols/Types which don't have a context and need to stay for now as is). Review by @paulp, @odersky.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala1213
1 files changed, 628 insertions, 585 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 216ad6cd4c..da7e54af5c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -12,14 +12,12 @@
package scala.tools.nsc
package typechecker
-import scala.collection.{ mutable, immutable }
+import scala.collection.mutable
import scala.tools.nsc.util.BatchSourceFile
import mutable.ListBuffer
import symtab.Flags._
import util.Statistics
import util.Statistics._
-import scala.tools.util.StringOps.{ countAsString, countElementsAsString }
-import scala.tools.util.EditDistance.similarString
// Suggestion check whether we can do without priming scopes with symbols of outer scopes,
// like the IDE does.
@@ -60,7 +58,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
super.traverse(tree)
}
}
-/* needed for experimental version where eraly types can be type arguments
+/* needed for experimental version where early types can be type arguments
class EarlyMap(clazz: Symbol) extends TypeMap {
def apply(tp: Type): Type = tp match {
case TypeRef(NoPrefix, sym, List()) if (sym hasFlag PRESUPER) =>
@@ -71,6 +69,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
*/
+ sealed abstract class SilentResult[+T]
+ case class SilentTypeError(err: AbsTypeError) extends SilentResult[Nothing] { }
+ case class SilentResultValue[+T](value: T) extends SilentResult[T] { }
+
def newTyper(context: Context): Typer = new NormalTyper(context)
private class NormalTyper(context : Context) extends Typer(context)
@@ -80,9 +82,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
private def isPastTyper = phase.id > currentRun.typerPhase.id
- abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation {
+ abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with TyperContextErrors {
import context0.unit
import typeDebug.{ ptTree, ptBlock, ptLine }
+ import TyperErrorGen._
val infer = new Inferencer(context0) {
override def isCoercible(tp: Type, pt: Type): Boolean = undoLog undo { // #3281
@@ -102,15 +105,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def mkNamedArg(argTree: Tree, paramName: Name) = atPos(argTree.pos)(new AssignOrNamedArg(Ident(paramName), (argTree)))
var mkArg: (Tree, Name) => Tree = mkPositionalArg
- def errorMessage(paramName: Name, paramTp: Type) =
- paramTp.typeSymbol match {
- case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
- case _ =>
- "could not find implicit value for "+
- (if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX) "evidence parameter of type "
- else "parameter "+paramName+": ")+paramTp
- }
-
// DEPMETTODO: instantiate type vars that depend on earlier implicit args (see adapt (4.1))
//
// apply the substitutions (undet type param -> type) that were determined
@@ -127,8 +121,19 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
argBuff += mkArg(res.tree, param.name)
} else {
mkArg = mkNamedArg // don't pass the default argument (if any) here, but start emitting named arguments for the following args
- if (!param.hasDefault)
- context.error(fun.pos, errorMessage(param.name, param.tpe))
+ if (!param.hasDefault) {
+ context.errBuffer.find(_.kind == ErrorKinds.Divergent) match {
+ case Some(divergentImplicit) =>
+ // DivergentImplicit error has higher priority than "no implicit found"
+ // no need to issue the problem again if we are still in silent mode
+ if (context.reportErrors) {
+ context.issue(divergentImplicit)
+ context.condBufferFlush(_.kind == ErrorKinds.Divergent)
+ }
+ case None =>
+ NoImplicitFoundError(fun, param)
+ }
+ }
/* else {
TODO: alternative (to expose implicit search failure more) -->
resolve argument, do type inference, keep emitting positional args, infer type params based on default value for arg
@@ -149,6 +154,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case ErrorType =>
fun
}
+
+ def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree =
+ inferView(tree, from, to, reportAmbiguous, true)
/** Infer an implicit conversion (``view'') between two types.
* @param tree The tree which needs to be converted.
@@ -157,8 +165,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* @param reportAmbiguous Should ambiguous implicit errors be reported?
* False iff we search for a view to find out
* whether one type is coercible to another.
+ * @param saveErrors Should ambiguous and divergent implicit errors that were buffered
+ * during the inference of a view be put into the original buffer.
+ * False iff we don't care about them.
*/
- def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = {
+ def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
debuglog("infer view from "+from+" to "+to)//debug
if (isPastTyper) EmptyTree
else from match {
@@ -167,7 +178,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case PolyType(_, _) => EmptyTree
case _ =>
def wrapImplicit(from: Type): Tree = {
- val result = inferImplicit(tree, functionType(List(from), to), reportAmbiguous, true, context)
+ val result = inferImplicit(tree, functionType(List(from), to), reportAmbiguous, true, context, saveErrors)
if (result.subst != EmptyTreeTypeSubstituter) result.subst traverse tree
result.tree
}
@@ -205,22 +216,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* @return ...
*/
def checkStable(tree: Tree): Tree =
- if (treeInfo.isExprSafeToInline(tree)) tree
- else errorTree(
- tree,
- "stable identifier required, but "+tree+" found."+
- (if (isStableExceptVolatile(tree)) {
- val tpe = tree.symbol.tpe match {
- case PolyType(_, rtpe) => rtpe
- case t => t
- }
- "\n Note that "+tree.symbol+" is not stable because its type, "+tree.tpe+", is volatile."
- } else ""))
+ if (treeInfo.isExprSafeToInline(tree)) tree else UnstableTreeError(tree)
/** Would tree be a stable (i.e. a pure expression) if the type
* of its symbol was not volatile?
*/
- private def isStableExceptVolatile(tree: Tree) = {
+ protected def isStableExceptVolatile(tree: Tree) = {
tree.hasSymbol && tree.symbol != NoSymbol && tree.tpe.isVolatile &&
{ val savedTpe = tree.symbol.info
val savedSTABLE = tree.symbol getFlag STABLE
@@ -234,21 +235,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
/** Check that `tpt` refers to a non-refinement class type */
- def checkClassType(tpt: Tree, existentialOK: Boolean, stablePrefix: Boolean) {
- def errorNotClass(found: AnyRef) = error(tpt.pos, "class type required but "+found+" found")
- def check(tpe: Type): Unit = tpe.normalize match {
+ def checkClassType(tpt: Tree, existentialOK: Boolean, stablePrefix: Boolean): Boolean = {
+ def errorNotClass(found: AnyRef) = { ClassTypeRequiredError(tpt, found); false }
+ def check(tpe: Type): Boolean = tpe.normalize match {
case TypeRef(pre, sym, _) if sym.isClass && !sym.isRefinementClass =>
- if (stablePrefix && !isPastTyper) {
- if (!pre.isStable)
- error(tpt.pos, "type "+pre+" is not a stable prefix")
- // A type projection like X#Y can get by the stable check if the
- // prefix is singleton-bounded, so peek at the tree too.
- else tpt match {
+ if (stablePrefix && !isPastTyper)
+ if (!pre.isStable) {
+ TypeNotAStablePrefixError(tpt, pre)
+ false
+ } else
+ // A type projection like X#Y can get by the stable check if the
+ // prefix is singleton-bounded, so peek at the tree too.
+ tpt match {
case SelectFromTypeTree(qual, _) if !isSingleType(qual.tpe) => errorNotClass(tpt)
- case _ => ;
- }
- }
- case ErrorType => ;
+ case _ => true
+ }
+ else
+ true
+ case ErrorType => true
case PolyType(_, restpe) => check(restpe)
case ExistentialType(_, restpe) if existentialOK => check(restpe)
case AnnotatedType(_, underlying, _) => check(underlying)
@@ -264,17 +268,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* @return <code>true</code> if <code>tp</code> is not a subtype of itself.
*/
def checkNonCyclic(pos: Position, tp: Type): Boolean = {
- def checkNotLocked(sym: Symbol): Boolean = {
+ def checkNotLocked(sym: Symbol) = {
sym.initialize
- sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false}
+ sym.lockOK || { CyclicAliasingOrSubtypingError(pos, sym); false }
}
tp match {
case TypeRef(pre, sym, args) =>
- (checkNotLocked(sym)) && (
- !sym.isNonClassType ||
- checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym) // @M! info for a type ref to a type parameter now returns a polytype
- // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym)
- )
+ checkNotLocked(sym) &&
+ ((!sym.isNonClassType) || checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym))
+ // @M! info for a type ref to a type parameter now returns a polytype
+ // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym)
+
case SingleType(pre, sym) =>
checkNotLocked(sym)
/*
@@ -293,10 +297,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Boolean = try {
- lockedSym.lock {
- throw new TypeError("illegal cyclic reference involving " + lockedSym)
- }
- checkNonCyclic(pos, tp)
+ if (!lockedSym.lock(CyclicReferenceError(pos, lockedSym))) false
+ else checkNonCyclic(pos, tp)
} finally {
lockedSym.unlock()
}
@@ -312,26 +314,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
- def checkParamsConvertible(pos: Position, tpe: Type) {
- tpe match {
- case MethodType(formals, restpe) =>
- /*
- if (formals.exists(_.typeSymbol == ByNameParamClass) && formals.length != 1)
- error(pos, "methods with `=>`-parameter can be converted to function values only if they take no other parameters")
- if (formals exists (isRepeatedParamType(_)))
- error(pos, "methods with `*`-parameters cannot be converted to function values");
- */
- if (restpe.isDependent)
- error(pos, "method with dependent type "+tpe+" cannot be converted to function value")
- checkParamsConvertible(pos, restpe)
- case _ =>
- }
+ def checkParamsConvertible(tree: Tree, tpe0: Type) {
+ def checkParamsConvertible0(tpe: Type) =
+ tpe match {
+ case MethodType(formals, restpe) =>
+ /*
+ if (formals.exists(_.typeSymbol == ByNameParamClass) && formals.length != 1)
+ error(pos, "methods with `=>`-parameter can be converted to function values only if they take no other parameters")
+ if (formals exists (isRepeatedParamType(_)))
+ error(pos, "methods with `*`-parameters cannot be converted to function values");
+ */
+ if (restpe.isDependent)
+ DependentMethodTpeConversionToFunctionError(tree, tpe)
+ checkParamsConvertible(tree, restpe)
+ case _ =>
+ }
+ checkParamsConvertible0(tpe0)
}
- def checkStarPatOK(pos: Position, mode: Int) =
- if ((mode & STARmode) == 0 && !isPastTyper)
- error(pos, "star patterns must correspond with varargs parameters")
-
/** Check that type of given tree does not contain local or private
* components.
*/
@@ -362,13 +362,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def locals[T <: Tree](scope: Scope, pt: Type, tree: T): T =
check(NoSymbol, scope, pt, tree)
- def check[T <: Tree](owner: Symbol, scope: Scope, pt: Type, tree: T): T = {
+ private def check[T <: Tree](owner: Symbol, scope: Scope, pt: Type, tree: T): T = {
this.owner = owner
this.scope = scope
hiddenSymbols = List()
val tp1 = apply(tree.tpe)
if (hiddenSymbols.isEmpty) tree setType tp1
- else if (hiddenSymbols exists (_.isErroneous)) setError(tree)
+ else if (hiddenSymbols exists (_.isErroneous)) HiddenSymbolWithError(tree)
else if (isFullyDefined(pt)) tree setType pt
else if (tp1.typeSymbol.isAnonymousClass)
check(owner, scope, pt, tree setType tp1.typeSymbol.classBound)
@@ -376,10 +376,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
tree setType packSymbols(hiddenSymbols.reverse, tp1)
else if (!phase.erasedTypes) { // privates
val badSymbol = hiddenSymbols.head
- error(tree.pos,
- (if (badSymbol.isPrivate) "private " else "") + badSymbol +
- " escapes its defining scope as part of type "+tree.tpe)
- setError(tree)
+ SymbolEscapesScopeError(tree, badSymbol)
} else tree
}
@@ -441,28 +438,66 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
/** The qualifying class
* of a this or super with prefix <code>qual</code>.
+ * packageOk is equal false when qualifying class symbol
*/
- def qualifyingClass(tree: Tree, qual: Name, packageOK: Boolean): Symbol =
+ def qualifyingClass(tree: Tree, qual: Name, packageOK: Boolean = false): Option[Symbol] =
context.enclClass.owner.ownerChain.find(o => qual.isEmpty || o.isClass && o.name == qual) match {
case Some(c) if packageOK || !c.isPackageClass =>
- c
+ Some(c)
case _ =>
- error(
- tree.pos,
- if (qual.isEmpty) tree+" can be used only in a class, object, or template"
- else qual+" is not an enclosing class")
- NoSymbol
+ QualifyingClassError(tree, qual)
+ None
}
/** The typer for an expression, depending on where we are. If we are before a superclass
* call, this is a typer over a constructor context; otherwise it is the current typer.
*/
- def constrTyperIf(inConstr: Boolean): Typer =
+ @inline
+ final def constrTyperIf(inConstr: Boolean): Typer =
if (inConstr) {
assert(context.undetparams.isEmpty)
newTyper(context.makeConstructorContext)
} else this
+ @inline
+ final def withCondConstrTyper[T](inConstr: Boolean)(f: Typer => T): T =
+ if (inConstr) {
+ assert(context.undetparams.isEmpty)
+ val c = context.makeConstructorContext
+ typerWithLocalContext(c)(f)
+ } else {
+ f(this)
+ }
+
+ @inline
+ final def typerWithCondLocalContext[T](c: => Context)(cond: Boolean)(f: Typer => T): T =
+ if (cond) typerWithLocalContext(c)(f) else f(this)
+
+ @inline
+ final def typerWithLocalContext[T](c: Context)(f: Typer => T): T = {
+ val res = f(newTyper(c))
+ if (c.hasErrors)
+ context.updateBuffer(c.flushAndReturnBuffer())
+ res
+ }
+
+ @inline
+ final def typerReportAnyContextErrors[T](c: Context)(f: Typer => T): T = {
+ val res = f(newTyper(c))
+ if (c.hasErrors)
+ context.issue(c.errBuffer.head)
+ res
+ }
+
+ @inline
+ final def withSavedContext[T](c: Context)(f: => T) = {
+ val savedErrors = c.flushAndReturnBuffer()
+ val res = f
+ c.updateBuffer(savedErrors)
+ res
+ }
+
+
/** The typer for a label definition. If this is part of a template we
* first have to enter the label definition.
*/
@@ -573,9 +608,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
inferExprAlternative(tree, pt)
val sym = tree.symbol
- def fail() = errorTree(tree, sym.kindString + " " + sym.fullName + " is not a value")
+ def fail() = NotAValueError(tree, sym)
- if (tree.tpe.isError) tree
+ if (tree.isErrorTyped) tree
else if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1)
if (sym.isValue) checkStable(tree)
else fail()
@@ -629,15 +664,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
def silent[T](op: Typer => T,
- reportAmbiguousErrors: Boolean = context.reportAmbiguousErrors,
- newtree: Tree = context.tree): Any /* in fact, TypeError or T */ = {
+ reportAmbiguousErrors: Boolean = context.ambiguousErrors,
+ newtree: Tree = context.tree): SilentResult[T] = {
val rawTypeStart = startCounter(rawTypeFailed)
val findMemberStart = startCounter(findMemberFailed)
val subtypeStart = startCounter(subtypeFailed)
val failedSilentStart = startTimer(failedSilentNanos)
try {
- if (context.reportGeneralErrors ||
- reportAmbiguousErrors != context.reportAmbiguousErrors ||
+ if (context.reportErrors ||
+ reportAmbiguousErrors != context.ambiguousErrors ||
newtree != context.tree) {
val context1 = context.makeSilent(reportAmbiguousErrors, newtree)
context1.undetparams = context.undetparams
@@ -648,38 +683,29 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
context.undetparams = context1.undetparams
context.savedTypeBounds = context1.savedTypeBounds
context.namedApplyBlockInfo = context1.namedApplyBlockInfo
- result
+ if (context1.hasErrors) SilentTypeError(context1.errBuffer.head)
+ else SilentResultValue(result)
} else {
- op(this)
+ assert(context.bufferErrors || isPastTyper, "silent mode is not available past typer")
+ withSavedContext(context){
+ val res = op(this)
+ val errorsToReport = context.flushAndReturnBuffer()
+ if (errorsToReport.isEmpty) SilentResultValue(res) else SilentTypeError(errorsToReport.head)
+ }
}
} catch {
case ex: CyclicReference => throw ex
case ex: TypeError =>
+ // fallback in case TypeError is still thrown
+ // @H this happens for example in cps annotation checker
stopCounter(rawTypeFailed, rawTypeStart)
stopCounter(findMemberFailed, findMemberStart)
stopCounter(subtypeFailed, subtypeStart)
stopTimer(failedSilentNanos, failedSilentStart)
- ex
+ SilentTypeError(TypeErrorWrapper(ex))
}
}
- /** Utility method: Try op1 on tree. If that gives an error try op2 instead.
- */
- def tryBoth(tree: Tree)(op1: (Typer, Tree) => Tree)(op2: (Typer, Tree) => Tree): Tree =
- silent(op1(_, tree)) match {
- case result1: Tree =>
- result1
- case ex1: TypeError =>
- silent(op2(_, resetAllAttrs(tree))) match {
- case result2: Tree =>
-// println("snd succeeded: "+result2)
- result2
- case ex2: TypeError =>
- reportTypeError(tree.pos, ex1)
- setError(tree)
- }
- }
-
def isCodeType(tpe: Type) = tpe.typeSymbol isNonBottomSubClass CodeClass
/** Perform the following adaptations of expression, pattern or type `tree` wrt to
@@ -724,8 +750,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (context.undetparams nonEmpty) { // (9) -- should revisit dropped condition `(mode & POLYmode) == 0`
// dropped so that type args of implicit method are inferred even if polymorphic expressions are allowed
// needed for implicits in 2.8 collection library -- maybe once #3346 is fixed, we can reinstate the condition?
- context.undetparams =
- inferExprInstance(tree, context.extractUndetparams(), pt,
+ context.undetparams = inferExprInstance(tree, context.extractUndetparams(), pt,
// approximate types that depend on arguments since dependency on implicit argument is like dependency on type parameter
mt.approximate,
// if we are looking for a manifest, instantiate type to Nothing anyway,
@@ -736,18 +761,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
useWeaklyCompatible = true) // #3808
}
- val typer1 = constrTyperIf(treeInfo.isSelfOrSuperConstrCall(tree))
- if (original != EmptyTree && pt != WildcardType)
- typer1.silent(tpr => tpr.typed(tpr.applyImplicitArgs(tree), mode, pt)) match {
- case result: Tree => result
- case ex: TypeError =>
- debuglog("fallback on implicits: " + tree + "/" + resetAllAttrs(original))
- val tree1 = typed(resetAllAttrs(original), mode, WildcardType)
- tree1.tpe = addAnnotations(tree1, tree1.tpe)
- if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree)
- }
- else
- typer1.typed(typer1.applyImplicitArgs(tree), mode, pt)
+ // avoid throwing spurious DivergentImplicit errors
+ if (context.hasErrors)
+ return setError(tree)
+
+ withCondConstrTyper(treeInfo.isSelfOrSuperConstrCall(tree)){ typer1 =>
+ if (original != EmptyTree && pt != WildcardType)
+ typer1.silent(tpr => tpr.typed(tpr.applyImplicitArgs(tree), mode, pt)) match {
+ case SilentResultValue(result) =>
+ result
+ case _ =>
+ debuglog("fallback on implicits: " + tree + "/" + resetAllAttrs(original))
+ val tree1 = typed(resetAllAttrs(original), mode, WildcardType)
+ tree1.tpe = addAnnotations(tree1, tree1.tpe)
+ if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, EmptyTree)
+ }
+ else
+ typer1.typed(typer1.applyImplicitArgs(tree), mode, pt)
+ }
}
def instantiateToMethodType(mt: MethodType): Tree = {
@@ -758,7 +789,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
if (!meth.isConstructor && !meth.isMacro && isFunctionType(pt)) { // (4.2)
debuglog("eta-expanding " + tree + ":" + tree.tpe + " to " + pt)
- checkParamsConvertible(tree.pos, tree.tpe)
+ checkParamsConvertible(tree, tree.tpe)
val tree0 = etaExpand(context.unit, tree)
// println("eta "+tree+" ---> "+tree0+":"+tree0.tpe+" undet: "+context.undetparams+ " mode: "+Integer.toHexString(mode))
@@ -775,9 +806,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
} else if (!meth.isConstructor && mt.params.isEmpty) { // (4.3)
adapt(typed(Apply(tree, List()) setPos tree.pos), mode, pt, original)
} else if (context.implicitsEnabled) {
- errorTree(tree, "missing arguments for " + meth + meth.locationString +
- (if (meth.isConstructor) ""
- else ";\nfollow this method with `_' if you want to treat it as a partially applied function"))
+ MissingArgsForMethodTpeError(tree, meth)
} else {
setError(tree)
}
@@ -792,8 +821,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// or raw type (tree.symbol.isJavaDefined && context.unit.isJava), types must be of kind *,
// and thus parameterized types must be applied to their type arguments
// @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't?
- errorTree(tree, tree.symbol + " takes type parameters")
- tree setType tree.tpe
+ MissingTypeParametersError(tree)
} else if ( // (7.1) @M: check kind-arity
// @M: removed check for tree.hasSymbol and replace tree.symbol by tree.tpe.symbol (TypeTree's must also be checked here, and they don't directly have a symbol)
(inHKMode(mode)) &&
@@ -808,9 +836,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// Note that we treat Any and Nothing as kind-polymorphic.
// We can't perform this check when typing type arguments to an overloaded method before the overload is resolved
// (or in the case of an error type) -- this is indicated by pt == WildcardType (see case TypeApply in typed1).
- errorTree(tree, tree.tpe + " takes " + countElementsAsString(tree.tpe.typeParams.length, "type parameter") +
- ", expected: " + countAsString(pt.typeParams.length))
- tree setType tree.tpe
+ KindArityMismatchError(tree, pt)
} else tree match { // (6)
case TypeTree() => tree
case _ => TypeTree(tree.tpe) setOriginal (tree) setPos (tree.pos)
@@ -836,7 +862,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
tree
}
} else {
- errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method")
+ CaseClassConstructorError(tree)
}
}
@@ -960,7 +986,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (!context.undetparams.isEmpty) {
return instantiate(tree, mode, pt)
}
- if (context.implicitsEnabled && !tree.tpe.isError && !pt.isError) {
+ if (context.implicitsEnabled && !pt.isError && !tree.isErrorTyped) {
// (14); the condition prevents chains of views
debuglog("inferring view from " + tree.tpe + " to " + pt)
val coercion = inferView(tree, tree.tpe, pt, true)
@@ -977,8 +1003,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
unit.echo(tree.pos, msg)
debuglog(msg)
- return newTyper(context.makeImplicit(context.reportAmbiguousErrors)).typed(
+ val silentContext = context.makeImplicit(context.ambiguousErrors)
+ val res = newTyper(silentContext).typed(
new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
+ if (silentContext.hasErrors) context.issue(silentContext.errBuffer.head) else return res
}
}
}
@@ -986,31 +1014,34 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
log("error tree = " + tree)
if (settings.explaintypes.value) explainTypes(tree.tpe, pt)
}
- try {
- typeErrorTree(tree, tree.tpe, pt)
- } catch {
- case ex: TypeError =>
- if (isPastTyper && pt.existentialSkolems.nonEmpty) {
- // Ignore type errors raised in later phases that are due to mismatching types with existential skolems
- // We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
- // Here's my hypothsis why this happens. The pattern matcher defines a variable of type
- //
- // val x: T = expr
- //
- // where T is the type of expr, but T contains existential skolems ts.
- // In that case, this value definition does not typecheck.
- // The value definition
- //
- // val x: T forSome { ts } = expr
- //
- // would typecheck. Or one can simply leave out the type of the `val`:
- //
- // val x = expr
- context.unit.warning(tree.pos, "recovering from existential Skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree)
- adapt(tree, mode, deriveTypeWithWildcards(pt.existentialSkolems)(pt))
- } else
- throw ex
+
+ val found = tree.tpe
+ val req = pt
+ if (!found.isErroneous && !req.isErroneous) {
+ if (!context.reportErrors && isPastTyper && req.existentialSkolems.nonEmpty) {
+ // Ignore type errors raised in later phases that are due to mismatching types with existential skolems
+ // We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
+ // Here's my hypothsis why this happens. The pattern matcher defines a variable of type
+ //
+ // val x: T = expr
+ //
+ // where T is the type of expr, but T contains existential skolems ts.
+ // In that case, this value definition does not typecheck.
+ // The value definition
+ //
+ // val x: T forSome { ts } = expr
+ //
+ // would typecheck. Or one can simply leave out the type of the `val`:
+ //
+ // val x = expr
+ context.unit.warning(tree.pos, "recovering from existential Skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree)
+ adapt(tree, mode, deriveTypeWithWildcards(pt.existentialSkolems)(pt))
+ } else {
+ // create an actual error
+ AdaptTypeError(tree, found, req)
+ }
}
+ setError(tree)
}
}
}
@@ -1027,7 +1058,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def instantiateExpectingUnit(tree: Tree, mode: Int): Tree = {
val savedUndetparams = context.undetparams
silent(_.instantiate(tree, mode, UnitClass.tpe)) match {
- case t: Tree => t
+ case SilentResultValue(t) => t
case _ =>
context.undetparams = savedUndetparams
val valueDiscard = atPos(tree.pos)(Block(List(instantiate(tree, mode, WildcardType)), Literal(Constant())))
@@ -1053,15 +1084,20 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// Note: implicit arguments are still inferred (this kind of "chaining" is allowed)
)
}
+
+ def adaptToMember(qual: Tree, searchTemplate: Type): Tree =
+ adaptToMember(qual, searchTemplate, true, true)
+ def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean): Tree =
+ adaptToMember(qual, searchTemplate, reportAmbiguous, true)
- def adaptToMember(qual: Tree, searchTemplate: Type): Tree = {
+ def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
if (isAdaptableWithView(qual)) {
qual.tpe.widen.normalize match {
case et: ExistentialType =>
qual setType et.skolemizeExistential(context.owner, qual) // open the existential
case _ =>
}
- inferView(qual, qual.tpe, searchTemplate, true) match {
+ inferView(qual, qual.tpe, searchTemplate, reportAmbiguous, saveErrors) match {
case EmptyTree => qual
case coercion =>
if (settings.logImplicitConv.value)
@@ -1083,13 +1119,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* If no conversion is found, return `qual` unchanged.
*
*/
- def adaptToArguments(qual: Tree, name: Name, args: List[Tree], pt: Type): Tree = {
+ def adaptToArguments(qual: Tree, name: Name, args: List[Tree], pt: Type, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
def doAdapt(restpe: Type) =
//util.trace("adaptToArgs "+qual+", name = "+name+", argtpes = "+(args map (_.tpe))+", pt = "+pt+" = ")
- adaptToMember(qual, HasMethodMatching(name, args map (_.tpe), restpe))
+ adaptToMember(qual, HasMethodMatching(name, args map (_.tpe), restpe), reportAmbiguous, saveErrors)
if (pt != WildcardType) {
silent(_ => doAdapt(pt)) match {
- case result: Tree if result != qual =>
+ case SilentResultValue(result) if result != qual =>
result
case _ =>
debuglog("fallback on implicits in adaptToArguments: "+qual+" . "+name)
@@ -1099,30 +1135,32 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
doAdapt(pt)
}
- /** Try o apply an implicit conversion to `qual` to that it contains
- * a method `name`. If that's ambiguous try taking arguments into account using `adaptToArguments`.
+ /** Try to apply an implicit conversion to `qual` so that it contains
+ * a method `name`. If that's ambiguous try taking arguments into
+ * account using `adaptToArguments`.
*/
- def adaptToMemberWithArgs(tree: Tree, qual: Tree, name: Name, mode: Int): Tree = {
- try {
- adaptToMember(qual, HasMember(name))
- } catch {
- case ex: TypeError =>
- // this happens if implicits are ambiguous; try again with more context info.
- // println("last ditch effort: "+qual+" . "+name)
+ def adaptToMemberWithArgs(tree: Tree, qual: Tree, name: Name, mode: Int, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
+ def onError(reportError: => Tree): Tree = {
context.tree match {
- case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty => // try handling the arguments
- // println("typing args: "+args)
+ case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty =>
silent(_.typedArgs(args, mode)) match {
- case args: List[_] =>
- adaptToArguments(qual, name, args.asInstanceOf[List[Tree]], WildcardType)
- case _ =>
- throw ex
+ case SilentResultValue(xs) =>
+ val args = xs.asInstanceOf[List[Tree]]
+ if (args exists (_.isErrorTyped))
+ reportError
+ else
+ adaptToArguments(qual, name, args, WildcardType, reportAmbiguous, saveErrors)
+ case _ =>
+ reportError
}
case _ =>
- // println("not in an apply: "+context.tree+"/"+tree)
- throw ex
+ reportError
}
}
+ silent(_.adaptToMember(qual, HasMember(name), false)) match {
+ case SilentResultValue(res) => res
+ case SilentTypeError(err) => onError({if (reportAmbiguous) { context.issue(err) }; setError(tree)})
+ }
}
/** Try to apply an implicit conversion to `qual` to that it contains a
@@ -1162,7 +1200,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// If first parent is a trait, make it first mixin and add its superclass as first parent
while ((supertpt.tpe.typeSymbol ne null) && supertpt.tpe.typeSymbol.initialize.isTrait) {
val supertpt1 = typedType(supertpt)
- if (!supertpt1.tpe.isError) {
+ if (!supertpt1.isErrorTyped) {
mixins = supertpt1 :: mixins
supertpt = TypeTree(supertpt1.tpe.parents.head) setPos supertpt.pos.focus
}
@@ -1206,14 +1244,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val cbody2 = newTyper(cscope) // called both during completion AND typing.
.typePrimaryConstrBody(clazz,
cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate)))
+
superCall match {
case Apply(_, _) =>
val sarg = treeInfo.firstArgument(superCall)
if (sarg != EmptyTree && supertpe.typeSymbol != firstParent)
- error(sarg.pos, firstParent+" is a trait; does not take constructor arguments")
- if (!supertparams.isEmpty) supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos.focus
+ ConstrArgsInTraitParentTpeError(sarg, firstParent)
+ if (!supertparams.isEmpty)
+ supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos.focus
case _ =>
- if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")
+ if (!supertparams.isEmpty)
+ MissingTypeArgumentsParentTpeError(supertpt)
}
val preSuperVals = treeInfo.preSuperFields(templ.body)
@@ -1223,7 +1264,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe)
case _ =>
- if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")
+ if (!supertparams.isEmpty)
+ MissingTypeArgumentsParentTpeError(supertpt)
}
/* experimental: early types as type arguments
val hasEarlyTypes = templ.body exists (treeInfo.isEarlyTypeDef)
@@ -1256,8 +1298,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
catch {
case ex: TypeError =>
- templ.tpe = null
- reportTypeError(templ.pos, ex)
+ // fallback in case of cyclic errors
+ // @H none of the tests enter here but I couldn't rule it out
+ ParentTypesError(templ, ex)
List(TypeTree(AnyRefClass.tpe))
}
@@ -1276,30 +1319,29 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* </ul>
*/
def validateParentClasses(parents: List[Tree], selfType: Type) {
+ val pending = ListBuffer[AbsTypeError]()
def validateParentClass(parent: Tree, superclazz: Symbol) {
- if (!parent.tpe.isError) {
+ if (!parent.isErrorTyped) {
val psym = parent.tpe.typeSymbol.initialize
checkClassType(parent, false, true)
if (psym != superclazz) {
if (psym.isTrait) {
val ps = psym.info.parents
if (!ps.isEmpty && !superclazz.isSubClass(ps.head.typeSymbol))
- error(parent.pos, "illegal inheritance; super"+superclazz+
- "\n is not a subclass of the super"+ps.head.typeSymbol+
- "\n of the mixin " + psym)
+ pending += ParentSuperSubclassError(parent, superclazz, ps.head.typeSymbol, psym)
} else {
- error(parent.pos, psym+" needs to be a trait to be mixed in")
+ pending += ParentNotATraitMixinError(parent, psym)
}
}
- if (psym.isFinal) {
- error(parent.pos, "illegal inheritance from final "+psym)
- }
+ if (psym.isFinal)
+ pending += ParentFinalInheritanceError(parent, psym)
+
if (psym.isSealed && !phase.erasedTypes) {
// AnyVal is sealed, but we have to let the value classes through manually
if (context.unit.source.file == psym.sourceFile || isValueClass(context.owner))
psym addChild context.owner
else
- error(parent.pos, "illegal inheritance from sealed "+psym+": " + context.unit.source.file.canonicalPath + " != " + psym.sourceFile.canonicalPath)
+ pending += ParentSealedInheritanceError(parent, psym)
}
if (!(selfType <:< parent.tpe.typeOfThis) &&
!phase.erasedTypes &&
@@ -1311,17 +1353,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
//Console.println(context.owner);//DEBUG
//Console.println(context.owner.unsafeTypeParams);//DEBUG
//Console.println(List.fromArray(context.owner.info.closure));//DEBUG
- error(parent.pos, "illegal inheritance;\n self-type "+
- selfType+" does not conform to "+parent +
- "'s selftype "+parent.tpe.typeOfThis)
+ pending += ParentSelfTypeConformanceError(parent, selfType)
if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis)
}
if (parents exists (p => p != parent && p.tpe.typeSymbol == psym && !psym.isError))
- error(parent.pos, psym+" is inherited twice")
+ pending += ParentInheritedTwiceError(parent, psym)
}
}
-
- if (!parents.isEmpty && !parents.head.tpe.isError)
+ if (!parents.isEmpty && parents.forall(!_.isErrorTyped))
for (p <- parents) validateParentClass(p, parents.head.tpe.typeSymbol)
/*
@@ -1331,13 +1370,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
", baseclasses = "+(context.owner.info.baseClasses map (_.fullName))+
", lin = "+(context.owner.info.baseClasses map (context.owner.thisType.baseType)))
*/
+ pending.foreach(ErrorUtils.issueTypeError)
}
def checkFinitary(classinfo: ClassInfoType) {
val clazz = classinfo.typeSymbol
+
for (tparam <- clazz.typeParams) {
if (classinfo.expansiveRefs(tparam) contains tparam) {
- error(tparam.pos, "class graph is not finitary because type parameter "+tparam.name+" is expansively recursive")
val newinfo = ClassInfoType(
classinfo.parents map (_.instantiateTypeParams(List(tparam), List(AnyRefClass.tpe))),
classinfo.decls,
@@ -1348,6 +1388,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case _ => newinfo
}
}
+ FinitaryError(tparam)
}
}
}
@@ -1363,8 +1404,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
assert(clazz != NoSymbol)
reenterTypeParams(cdef.tparams)
val tparams1 = cdef.tparams mapConserve (typedTypeDef)
- val impl1 = newTyper(context.make(cdef.impl, clazz, new Scope))
- .typedTemplate(cdef.impl, parentTypes(cdef.impl))
+ val impl1 = typerReportAnyContextErrors(context.make(cdef.impl, clazz, new Scope)){
+ _.typedTemplate(cdef.impl, parentTypes(cdef.impl))
+ }
val impl2 = finishMethodSynthesis(impl1, clazz, context)
if ((clazz != ClassfileAnnotationClass) &&
(clazz isNonBottomSubClass ClassfileAnnotationClass))
@@ -1397,17 +1439,16 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val clazz = mdef.symbol.moduleClass
val typedMods = removeAnnotations(mdef.mods)
assert(clazz != NoSymbol, mdef)
-
- val typer0 = newTyper(context.make(mdef.impl, clazz, new Scope))
- val impl1 = typer0.typedTemplate(mdef.impl, {
- parentTypes(mdef.impl) ++ (
- if (linkedClass == NoSymbol || !linkedClass.isSerializable || clazz.isSerializable) Nil
- else {
- clazz.makeSerializable()
- List(TypeTree(SerializableClass.tpe) setPos clazz.pos.focus)
- }
- )
- })
+ val impl1 = typerReportAnyContextErrors(context.make(mdef.impl, clazz, new Scope)){
+ _.typedTemplate(mdef.impl, {
+ parentTypes(mdef.impl) ++ (
+ if (linkedClass == NoSymbol || !linkedClass.isSerializable || clazz.isSerializable) Nil
+ else {
+ clazz.makeSerializable()
+ List(TypeTree(SerializableClass.tpe) setPos clazz.pos.focus)
+ }
+ )
+ })}
val impl2 = finishMethodSynthesis(impl1, clazz, context)
treeCopy.ModuleDef(mdef, typedMods, mdef.name, impl2) setType NoType
@@ -1516,14 +1557,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (sym.hasAnnotation(definitions.VolatileAttr)) {
if (!sym.isMutable)
- error(vdef.pos, "values cannot be volatile")
+ VolatileValueError(vdef)
else if (sym.isFinal)
- error(vdef.pos, "final vars cannot be volatile")
+ FinalVolatileVarError(vdef)
}
val rhs1 =
if (vdef.rhs.isEmpty) {
if (sym.isVariable && sym.owner.isTerm && !isPastTyper)
- error(vdef.pos, "local variables must be initialized")
+ LocalVarUninitializedError(vdef)
vdef.rhs
} else {
val tpt2 = if (sym.hasDefault) {
@@ -1571,16 +1612,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val (superConstr, superArgs) = decompose(rhs)
assert(superConstr.symbol ne null)//debug
+ val pending = ListBuffer[AbsTypeError]()
// an object cannot be allowed to pass a reference to itself to a superconstructor
// because of initialization issues; bug #473
for (arg <- superArgs ; tree <- arg) {
val sym = tree.symbol
if (sym != null && (sym.info.baseClasses contains clazz)) {
if (sym.isModule)
- error(tree.pos, "super constructor cannot be passed a self reference unless parameter is declared by-name")
+ pending += SuperConstrReferenceError(tree)
tree match {
case This(qual) =>
- error(tree.pos, "super constructor arguments cannot reference unconstructed `this`")
+ pending += SuperConstrArgsThisReferenceError(tree)
case _ => ()
}
}
@@ -1613,6 +1655,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
}
+ pending.foreach(ErrorUtils.issueTypeError)
}
/** Check if a structurally defined method violates implementation restrictions.
@@ -1661,7 +1704,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
lookupVariable(name.toString.substring(1), enclClass) match {
case Some(repl) =>
silent(_.typedTypeConstructor(stringParser(repl).typ())) match {
- case tpt: Tree =>
+ case SilentResultValue(tpt) =>
val alias = enclClass.newAliasType(name.toTypeName, useCase.pos)
val tparams = cloneSymbolsAtOwner(tpt.tpe.typeSymbol.typeParams, alias)
alias setInfo typeFun(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
@@ -1711,7 +1754,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
for (vparams1 <- vparamss1; vparam1 <- vparams1 dropRight 1)
if (isRepeatedParamType(vparam1.symbol.tpe))
- error(vparam1.pos, "*-parameter must come last")
+ StarParamNotLastError(vparam1)
var tpt1 = checkNoEscaping.privates(meth, typedType(ddef.tpt))
checkNonCyclic(ddef, tpt1)
@@ -1723,7 +1766,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
(!meth.owner.isClass ||
meth.owner.isModuleClass ||
meth.owner.isAnonOrRefinementClass))
- error(ddef.pos, "constructor definition not allowed here")
+ InvalidConstructorDefError(ddef)
typed(ddef.rhs)
} else if (meth.isMacro) {
EmptyTree
@@ -1738,30 +1781,26 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (!isPastTyper && meth.owner.isClass &&
meth.paramss.exists(ps => ps.exists(_.hasDefaultFlag) && isRepeatedParamType(ps.last.tpe)))
- error(meth.pos, "a parameter section with a `*'-parameter is not allowed to have default arguments")
+ StarWithDefaultError(meth)
if (!isPastTyper) {
val allParams = meth.paramss.flatten
for (p <- allParams) {
for (n <- p.deprecatedParamName) {
if (allParams.exists(p1 => p1.name == n || (p != p1 && p1.deprecatedParamName.exists(_ == n))))
- error(p.pos, "deprecated parameter name "+ n +" has to be distinct from any other parameter name (deprecated or not).")
+ DeprecatedParamNameError(p, n)
}
}
}
if (meth.isStructuralRefinementMember)
checkMethodStructuralCompatible(meth)
-
treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
}
- def typedTypeDef(tdef: TypeDef): TypeDef = {
- def typeDefTyper = {
- if(tdef.tparams isEmpty) Typer.this
- else newTyper(context.makeNewScope(tdef, tdef.symbol))
+ def typedTypeDef(tdef: TypeDef): TypeDef =
+ typerWithCondLocalContext(context.makeNewScope(tdef, tdef.symbol))(tdef.tparams.nonEmpty){
+ _.typedTypeDef0(tdef)
}
- typeDefTyper.typedTypeDef0(tdef)
- }
// call typedTypeDef instead
// a TypeDef with type parameters must always be type checked in a new scope
@@ -1783,10 +1822,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
checkNonCyclic(tdef.symbol)
if (tdef.symbol.owner.isType)
rhs1.tpe match {
- case TypeBounds(lo1, hi1) =>
- if (!(lo1 <:< hi1))
- error(tdef.pos, "lower bound "+lo1+" does not conform to upper bound "+hi1)
- case _ =>
+ case TypeBounds(lo1, hi1) if (!(lo1 <:< hi1)) => LowerBoundError(tdef, lo1, hi1)
+ case _ => ()
}
treeCopy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType
}
@@ -1906,9 +1943,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedCase(cdef: CaseDef, pattpe: Type, pt: Type): CaseDef = {
// verify no _* except in last position
for (Apply(_, xs) <- cdef.pat ; x <- xs dropRight 1 ; if treeInfo isStar x)
- error(x.pos, "_* may only come last")
+ StarPositionInPatternError(x)
- val pat1: Tree = typedPattern(cdef.pat, pattpe)
+ val pat1 = typedPattern(cdef.pat, pattpe)
// When case classes have more than two parameter lists, the pattern ends
// up typed as a method. We only pattern match on the first parameter
// list, so substitute the final result type of the method, i.e. the type
@@ -1952,7 +1989,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val codeExpected = !forMSIL && (pt.typeSymbol isNonBottomSubClass CodeClass)
if (numVparams > definitions.MaxFunctionArity)
- return errorTree(fun, "implementation restricts functions to " + definitions.MaxFunctionArity + " parameters")
+ return MaxFunctionArityError(fun)
def decompose(pt: Type): (Symbol, List[Type], Type) =
if ((isFunctionType(pt)
@@ -1968,9 +2005,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
(FunctionClass(numVparams), fun.vparams map (x => NoType), WildcardType)
val (clazz, argpts, respt) = decompose(if (codeExpected) pt.normalize.typeArgs.head else pt)
-
if (argpts.lengthCompare(numVparams) != 0)
- errorTree(fun, "wrong number of parameters; expected = " + argpts.length)
+ WrongNumberOfParametersError(fun, argpts)
else {
val vparamSyms = map2(fun.vparams, argpts) { (vparam, argpt) =>
if (vparam.tpt.isEmpty) {
@@ -1980,7 +2016,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
fun match {
case etaExpansion(vparams, fn, args) if !codeExpected =>
silent(_.typed(fn, forFunMode(mode), pt)) match {
- case fn1: Tree if context.undetparams.isEmpty =>
+ case SilentResultValue(fn1) if context.undetparams.isEmpty =>
// if context,undetparams is not empty, the function was polymorphic,
// so we need the missing arguments to infer its type. See #871
//println("typing eta "+fun+":"+fn1.tpe+"/"+context.undetparams)
@@ -1991,7 +2027,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
case _ =>
}
- error(vparam.pos, missingParameterTypeMsg(fun, vparam, pt))
+ MissingParameterTypeError(fun, vparam, pt)
ErrorType
}
if (!vparam.tpt.pos.isDefined) vparam.tpt setPos vparam.pos.focus
@@ -2005,12 +2041,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// for (vparam <- vparams) {
// checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
// }
- var body = typed(fun.body, respt)
+ val body1 = typed(fun.body, respt)
val formals = vparamSyms map (_.tpe)
- val restpe = packedType(body, fun.symbol).deconst.resultType
+ val restpe = packedType(body1, fun.symbol).deconst.resultType
val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe)
// body = checkNoEscaping.locals(context.scope, restpe, body)
- val fun1 = treeCopy.Function(fun, vparams, body).setType(funtpe)
+ val fun1 = treeCopy.Function(fun, vparams, body1).setType(funtpe)
if (codeExpected) lifted(fun1) else fun1
}
}
@@ -2025,7 +2061,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
unit.toCheck += { () =>
// go to next outer context which is not silent, see #3614
var c = context
- while (!c.reportGeneralErrors) c = c.outer
+ while (c.bufferErrors) c = c.outer
val stats1 = newTyper(c).typedStats(stats, NoSymbol)
for (stat <- stats1 if stat.isDef) {
val member = stat.symbol
@@ -2041,11 +2077,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Some(imp1: Import) => imp1
case None => log("unhandled import: "+imp+" in "+unit); imp
}
-
private def isWarnablePureExpression(tree: Tree) = tree match {
case EmptyTree | Literal(Constant(())) => false
case _ =>
- (treeInfo isExprSafeToInline tree) && {
+ !tree.isErrorTyped && (treeInfo isExprSafeToInline tree) && {
val sym = tree.symbol
(sym == null) || !(sym.isModule || sym.isLazy) || {
debuglog("'Pure' but side-effecting expression in statement position: " + tree)
@@ -2059,9 +2094,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def includesTargetPos(tree: Tree) =
tree.pos.isRange && context.unit.exists && (tree.pos includes context.unit.targetPos)
val localTarget = stats exists includesTargetPos
+ val statsErrors = scala.collection.mutable.LinkedHashSet[AbsTypeError]()
def typedStat(stat: Tree): Tree = {
if (context.owner.isRefinementClass && !treeInfo.isDeclarationOrTypeDef(stat))
- errorTree(stat, "only declarations allowed here")
+ OnlyDeclarationsError(stat)
else
stat match {
case imp @ Import(_, _) =>
@@ -2074,20 +2110,25 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// the targetposition
stat
} else {
- val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) this
- else newTyper(context.make(stat, exprOwner))
+ val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) {
+ context.flushBuffer()
+ this
+ } else newTyper(context.make(stat, exprOwner))
// XXX this creates a spurious dead code warning if an exception is thrown
// in a constructor, even if it is the only thing in the constructor.
val result = checkDead(localTyper.typed(stat, EXPRmode | BYVALmode, WildcardType))
+
if (treeInfo.isSelfOrSuperConstrCall(result)) {
context.inConstructorSuffix = true
if (treeInfo.isSelfConstrCall(result) && result.symbol.pos.pointOrElse(0) >= exprOwner.enclMethod.pos.pointOrElse(0))
- error(stat.pos, "called constructor's definition must precede calling constructor's definition")
+ ConstructorsOrderError(stat)
}
+
if (isWarnablePureExpression(result)) context.warning(stat.pos,
"a pure expression does nothing in statement position; " +
"you may be omitting necessary parentheses"
)
+ statsErrors ++= localTyper.context.errBuffer
result
}
}
@@ -2121,9 +2162,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// error for this is issued in RefChecks.checkDefaultsInOverloaded
if (!e.sym.isErroneous && !e1.sym.isErroneous && !e.sym.hasDefaultFlag &&
!e.sym.hasAnnotation(BridgeClass) && !e1.sym.hasAnnotation(BridgeClass)) {
- error(e.sym.pos, e1.sym+" is defined twice"+
- {if(!settings.debug.value) "" else " in "+unit.toString}+
- {if (e.sym.isMacro && e1.sym.isMacro) " \n(note that macros cannot be overloaded)" else ""})
+ DefDefinedTwiceError(e.sym, e1.sym)
scope.unlink(e1) // need to unlink to avoid later problems with lub; see #2779
}
e1 = scope.lookupNextEntry(e1)
@@ -2168,14 +2207,20 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}) ::: newStats.toList
}
}
- val result = stats mapConserve typedStat
- if (phase.erasedTypes) result
- else checkNoDoubleDefsAndAddSynthetics(result)
+
+ val stats1 = withSavedContext(context) {
+ val result = stats mapConserve typedStat
+ context.flushBuffer()
+ result
+ }
+ context.updateBuffer(statsErrors)
+ if (phase.erasedTypes) stats1
+ else checkNoDoubleDefsAndAddSynthetics(stats1)
}
def typedArg(arg: Tree, mode: Int, newmode: Int, pt: Type): Tree = {
val typedMode = onlyStickyModes(mode) | newmode
- val t = constrTyperIf((mode & SCCmode) != 0).typed(arg, typedMode, pt)
+ val t = withCondConstrTyper((mode & SCCmode) != 0)(_.typed(arg, typedMode, pt))
checkDead.inMode(typedMode, t)
}
@@ -2244,8 +2289,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = {
// TODO_NMT: check the assumption that args nonEmpty
- def errTree = setError(treeCopy.Apply(tree, fun0, args))
- def errorTree(msg: String) = { error(tree.pos, msg); errTree }
+ def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
+ def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
var fun = fun0
if (fun.hasSymbol && fun.symbol.isOverloaded) {
@@ -2308,8 +2353,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
arg1
}
context.undetparams = undetparams
- inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args))
- doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt)
+ if (context.hasErrors)
+ setError(tree)
+ else {
+ inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args))
+ doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt)
+ }
case mt @ MethodType(params, _) =>
val paramTypes = mt.paramTypes
@@ -2329,7 +2378,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// the inner "doTypedApply" does "extractUndetparams" => restore when it fails
val savedUndetparams = context.undetparams
silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)) match {
- case t: Tree =>
+ case SilentResultValue(t) =>
// Depending on user options, may warn or error here if
// a Unit or tuple was inserted.
Some(t) filter (tupledTree =>
@@ -2337,7 +2386,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
|| tupledTree.symbol == null
|| checkValidAdaptation(tupledTree, args)
)
- case ex =>
+ case _ =>
context.undetparams = savedUndetparams
None
}
@@ -2352,21 +2401,21 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def tryNamesDefaults: Tree = {
val lencmp = compareLengths(args, formals)
- if (mt.isErroneous) errTree
- else if (inPatternMode(mode))
+ if (mt.isErroneous) duplErrTree
+ else if (inPatternMode(mode)) {
// #2064
- errorTree("wrong number of arguments for "+ treeSymTypeMsg(fun))
- else if (lencmp > 0) {
- tryTupleApply getOrElse errorTree("too many arguments for "+treeSymTypeMsg(fun))
+ duplErrorTree(WrongNumberOfArgsError(tree, fun))
+ } else if (lencmp > 0) {
+ tryTupleApply getOrElse duplErrorTree(TooManyArgsNamesDefaultsError(tree, fun))
} else if (lencmp == 0) {
// we don't need defaults. names were used, so this application is transformed
// into a block (@see transformNamedApplication in NamesDefaults)
val (namelessArgs, argPos) = removeNames(Typer.this)(args, params)
if (namelessArgs exists (_.isErroneous)) {
- errTree
+ duplErrTree
} else if (!isIdentity(argPos) && !sameLength(formals, params))
// !isIdentity indicates that named arguments are used to re-order arguments
- errorTree("when using named arguments, the vararg parameter has to be specified exactly once")
+ duplErrorTree(MultipleVarargError(tree))
else if (isIdentity(argPos) && !isNamedApplyBlock(fun)) {
// if there's no re-ordering, and fun is not transformed, no need to transform
// more than an optimization, e.g. important in "synchronized { x = update-x }"
@@ -2380,7 +2429,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// calls to the default getters. Example:
// foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a))
val fun1 = transformNamedApplication(Typer.this, mode, pt)(fun, x => x)
- if (fun1.isErroneous) errTree
+ if (fun1.isErroneous) duplErrTree
else {
assert(isNamedApplyBlock(fun1), fun1)
val NamedApplyInfo(qual, targs, previousArgss, _) = context.namedApplyBlockInfo.get._2
@@ -2397,17 +2446,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val lencmp2 = compareLengths(allArgs, formals)
if (!sameLength(allArgs, args) && callToCompanionConstr(context, funSym)) {
- errorTree("module extending its companion class cannot use default constructor arguments")
+ duplErrorTree(ModuleUsingCompanionClassDefaultArgsErrror(tree))
} else if (lencmp2 > 0) {
removeNames(Typer.this)(allArgs, params) // #3818
- errTree
+ duplErrTree
} else if (lencmp2 == 0) {
// useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]()
val note = "Error occurred in an application involving default arguments."
if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic
doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
} else {
- tryTupleApply getOrElse errorTree(notEnoughArgumentsMsg(fun, missing))
+ tryTupleApply getOrElse duplErrorTree(NotEnoughArgsError(tree, fun, missing))
}
}
}
@@ -2466,7 +2515,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
atPos(tree.pos)(gen.mkNil setType restpe)
else
constfold(treeCopy.Apply(tree, fun, args1) setType ifPatternSkipFormals(restpe))
-
} else if (needsInstantiation(tparams, formals, args)) {
//println("needs inst "+fun+" "+tparams+"/"+(tparams map (_.info)))
inferExprInstance(fun, tparams)
@@ -2488,11 +2536,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (!argtparams.isEmpty) {
val strictPt = formal.instantiateTypeParams(tparams, strictTargs)
inferArgumentInstance(arg1, argtparams, strictPt, lenientPt)
- }
- arg1
+ arg1
+ } else arg1
}
val args1 = map2(args, formals)(typedArgToPoly)
- if (args1 exists (_.tpe.isError)) errTree
+ if (args1 exists {_.isErrorTyped}) duplErrTree
else {
debuglog("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info)) //debug
// define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun"
@@ -2509,12 +2557,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
doTypedApply(tree, fun setType fun.tpe.widen, args, mode, pt)
case ErrorType =>
- setError(treeCopy.Apply(tree, fun, args))
+ if (!tree.isErrorTyped) setError(tree) else tree
+ // @H change to setError(treeCopy.Apply(tree, fun, args))
/* --- begin unapply --- */
case otpe if inPatternMode(mode) && unapplyMember(otpe).exists =>
if (args.length > MaxTupleArity)
- error(fun.pos, "too many arguments for unapply pattern, maximum = "+MaxTupleArity)
+ return duplErrorTree(TooManyArgsPatternError(fun))
//
def freshArgType(tp: Type): (List[Symbol], Type) = tp match {
@@ -2522,11 +2571,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
(Nil, param.tpe)
case PolyType(tparams, restpe) =>
createFromClonedSymbols(tparams, freshArgType(restpe)._2)((ps, t) => ((ps, t)))
+ // No longer used, see test case neg/t960.scala (#960 has nothing to do with it)
case OverloadedType(_, _) =>
- error(fun.pos, "cannot resolve overloaded unapply")
+ OverloadedUnapplyError(fun)
(Nil, ErrorType)
case _ =>
- error(fun.pos, "an unapply method must accept a single argument.")
+ UnapplyWithSingleArgError(fun)
(Nil, ErrorType)
}
@@ -2542,7 +2592,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
freeVars foreach unapplyContext.scope.enter
val typer1 = newTyper(unapplyContext)
- val pattp = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe)
+ val pattp = typer1.infer.inferTypedPattern(tree, unappFormal, arg.tpe)
// turn any unresolved type variables in freevars into existential skolems
val skolems = freeVars map (fv => unapplyContext.owner.newExistentialSkolem(fv, fv))
@@ -2553,8 +2603,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// setType null is necessary so that ref will be stabilized; see bug 881
val fun1 = typedPos(fun.pos)(Apply(Select(fun setType null, unapp), List(arg)))
- if (fun1.tpe.isErroneous) errTree
- else {
+ if (fun1.tpe.isErroneous) {
+ duplErrTree
+ } else {
val formals0 = unapplyTypeList(fun1.symbol, fun1.tpe)
val formals1 = formalTypes(formals0, args.length)
if (sameLength(formals1, args)) {
@@ -2567,15 +2618,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val itype = glb(List(pt1, arg.tpe))
arg.tpe = pt1 // restore type (arg is a dummy tree, just needs to pass typechecking)
UnApply(fun1, args1) setPos tree.pos setType itype
- }
- else {
- errorTree("wrong number of arguments for "+treeSymTypeMsg(fun))
- }
+ } else
+ duplErrorTree(WrongNumberArgsPatternError(tree, fun))
}
/* --- end unapply --- */
case _ =>
- errorTree(fun.tpe+" does not take parameters")
+ duplErrorTree(ApplyWithoutArgsError(tree, fun))
}
}
@@ -2587,8 +2636,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedAnnotation(ann: Tree, mode: Int = EXPRmode, selfsym: Symbol = NoSymbol, annClass: Symbol = AnnotationClass, requireJava: Boolean = false): AnnotationInfo = {
lazy val annotationError = AnnotationInfo(ErrorType, Nil, Nil)
var hasError: Boolean = false
- def error(pos: Position, msg: String) = {
- context.error(pos, msg)
+ val pending = ListBuffer[AbsTypeError]()
+
+ def reportAnnotationError(err: AbsTypeError) = {
+ pending += err
hasError = true
annotationError
}
@@ -2604,13 +2655,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case tpe => null
}
}
- def fail(msg: String) = { error(tr.pos, msg) ; None }
- if (const == null)
- fail("annotation argument needs to be a constant; found: " + tr)
- else if (const.value == null)
- fail("annotation argument cannot be null")
- else
+ if (const == null) {
+ reportAnnotationError(AnnotationNotAConstantError(tr)); None
+ } else if (const.value == null) {
+ reportAnnotationError(AnnotationArgNullError(tr)); None
+ } else
Some(LiteralAnnotArg(const))
}
@@ -2619,16 +2669,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
*/
def tree2ConstArg(tree: Tree, pt: Type): Option[ClassfileAnnotArg] = tree match {
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) if (pt.typeSymbol == ArrayClass) =>
- error(tree.pos, "Array constants have to be specified using the `Array(...)' factory method")
- None
+ reportAnnotationError(ArrayConstantsError(tree)); None
case ann @ Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
val annInfo = typedAnnotation(ann, mode, NoSymbol, pt.typeSymbol, true)
- if (annInfo.atp.isErroneous) {
- // recursive typedAnnotation call already printed an error, so don't call "error"
- hasError = true
- None
- } else Some(NestedAnnotArg(annInfo))
+ if (annInfo.atp.isErroneous) { hasError = true; None }
+ else Some(NestedAnnotArg(annInfo))
// use of Array.apply[T: ClassManifest](xs: T*): Array[T]
// and Array.apply(x: Int, xs: Int*): Array[Int] (and similar)
@@ -2643,13 +2689,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// BT = Int, .., String, Class[_], JavaAnnotClass
// T = BT | Array[BT]
// So an array literal as argument can only be valid if pt is Array[_]
- error(tree.pos, "found array constant, expected argument of type "+ pt)
+ reportAnnotationError(ArrayConstantsTypeMismatchError(tree, pt))
None
}
- else
- tryConst(tree, pt)
+ else tryConst(tree, pt)
- case Typed(t, _) => tree2ConstArg(t, pt)
+ case Typed(t, _) =>
+ tree2ConstArg(t, pt)
case tree =>
tryConst(tree, pt)
@@ -2669,13 +2715,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Select(New(tpt), nme.CONSTRUCTOR) =>
(fun, outerArgss)
case _ =>
- error(fun.pos, "unexpected tree in annotation: "+ fun)
+ reportAnnotationError(UnexpectedTreeAnnotation(fun))
(setError(fun), outerArgss)
}
extract(ann, List())
}
- if (fun.isErroneous) annotationError
+ val res = if (fun.isErroneous) annotationError
else {
val typedFun @ Select(New(tpt), _) = typed(fun, forFunMode(mode), WildcardType)
val annType = tpt.tpe
@@ -2685,9 +2731,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// annotation to be saved as java classfile annotation
val isJava = typedFun.symbol.owner.isJavaDefined
if (!annType.typeSymbol.isNonBottomSubClass(annClass)) {
- error(tpt.pos, "expected annotation of type "+ annClass.tpe +", found "+ annType)
+ reportAnnotationError(AnnotationTypeMismatchError(tpt, annClass.tpe, annType))
} else if (argss.length > 1) {
- error(ann.pos, "multiple argument lists on classfile annotation")
+ reportAnnotationError(MultipleArgumentListForAnnotationError(ann))
} else {
val args =
if (argss.head.length == 1 && !isNamed(argss.head.head))
@@ -2703,10 +2749,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val sym = if (isJava) annScope.lookup(name)
else typedFun.tpe.params.find(p => p.name == name).getOrElse(NoSymbol)
if (sym == NoSymbol) {
- error(arg.pos, "unknown annotation argument name: " + name)
+ reportAnnotationError(UnknownAnnotationNameError(arg, name))
(nme.ERROR, None)
} else if (!names.contains(sym)) {
- error(arg.pos, "duplicate value for annotation argument " + name)
+ reportAnnotationError(DuplicateValueAnnotationError(arg, name))
(nme.ERROR, None)
} else {
names -= sym
@@ -2715,21 +2761,21 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
(sym.name, annArg)
}
case arg =>
- error(arg.pos, "classfile annotation arguments have to be supplied as named arguments")
+ reportAnnotationError(ClassfileAnnotationsAsNamedArgsError(arg))
(nme.ERROR, None)
}
for (sym <- names) {
// make sure the flags are up to date before erroring (jvm/t3415 fails otherwise)
sym.initialize
if (!sym.hasAnnotation(AnnotationDefaultAttr) && !sym.hasDefaultFlag)
- error(ann.pos, "annotation " + annType.typeSymbol.fullName + " is missing argument " + sym.name)
+ reportAnnotationError(AnnotationMissingArgError(ann, annType, sym))
}
if (hasError) annotationError
else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}).setPos(ann.pos)
}
} else if (requireJava) {
- error(ann.pos, "nested classfile annotations must be defined in java; found: "+ annType)
+ reportAnnotationError(NestedAnnotationError(ann, annType))
} else {
val typedAnn = if (selfsym == NoSymbol) {
typed(ann, mode, annClass.tpe)
@@ -2781,7 +2827,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
annInfo(fun)
case _ =>
- error(t.pos, "unexpected tree after typing annotation: "+ typedAnn)
+ reportAnnotationError(UnexpectedTreeAnnotationError(t, typedAnn))
}
if (annType.typeSymbol == DeprecatedAttr && argss.flatten.size < 2)
@@ -2791,6 +2837,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else annInfo(typedAnn)
}
}
+
+ if (hasError) {
+ pending.foreach(ErrorUtils.issueTypeError)
+ annotationError
+ } else res
}
def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type?
@@ -2890,7 +2941,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (sym.isAliasType && containsLocal(tp)) apply(tp.normalize)
else {
if (pre.isVolatile)
- context.error(tree.pos, "Inferred type "+tree.tpe+" contains type selection from volatile type "+pre)
+ InferTypeWithVolatileTypeSelectionError(tree, pre)
mapOver(tp)
}
case _ =>
@@ -2907,8 +2958,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
localSyms += sym
remainingSyms += sym
} else {
- unit.error(tree.pos,
- "can't existentially abstract over parameterized type " + tp)
+ AbstractExistentiallyOverParamerizedTpeError(tree, tp)
}
}
}
@@ -2977,10 +3027,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
new DeSkolemizeMap mapOver tp
}
- def typedClassOf(tree: Tree, tpt: Tree) = {
- checkClassType(tpt, true, false)
- atPos(tree.pos)(gen.mkClassOf(tpt.tpe))
- }
+ def typedClassOf(tree: Tree, tpt: Tree, noGen: Boolean = false) =
+ if (!checkClassType(tpt, true, false) && noGen) tpt
+ else atPos(tree.pos)(gen.mkClassOf(tpt.tpe))
protected def typedExistentialTypeTree(tree: ExistentialTypeTree, mode: Int): Tree = {
for (wc <- tree.whereClauses)
@@ -2989,7 +3038,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val whereClauses1 = typedStats(tree.whereClauses, context.owner)
for (vd @ ValDef(_, _, _, _) <- tree.whereClauses)
if (vd.symbol.tpe.isVolatile)
- error(vd.pos, "illegal abstraction from value with volatile type "+vd.symbol.tpe)
+ AbstractionFromVolatileTypeError(vd)
val tpt1 = typedType(tree.tpt, mode)
existentialTransform(tree.whereClauses map (_.symbol), tpt1.tpe)((tparams, tp) =>
TypeTree(newExistentialType(tparams, tp)) setOriginal tree
@@ -3012,7 +3061,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// Martin, I'm using fake trees, because, if you use args or arg.map(typedType),
// inferPolyAlternatives loops... -- I have no idea why :-(
// ...actually this was looping anyway, see bug #278.
- return errorTree(fun, "wrong number of type parameters for "+treeSymTypeMsg(fun))
+ return TypedApplyWrongNumberOfTpeParametersError(fun, fun)
typedTypeApply(tree, mode, fun, args1)
case SingleType(_, _) =>
@@ -3020,12 +3069,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case PolyType(tparams, restpe) if tparams.nonEmpty =>
if (sameLength(tparams, args)) {
val targs = args map (_.tpe)
- checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "")
+ checkBounds(tree, NoPrefix, NoSymbol, tparams, targs, "")
if (fun.symbol == Predef_classOf)
- typedClassOf(tree, args.head)
+ typedClassOf(tree, args.head, true)
else {
if (!isPastTyper && fun.symbol == Any_isInstanceOf && !targs.isEmpty)
- checkCheckable(tree.pos, targs.head, "")
+ checkCheckable(tree, targs.head, "")
val resultpe = restpe.instantiateTypeParams(tparams, targs)
//@M substitution in instantiateParams needs to be careful!
//@M example: class Foo[a] { def foo[m[x]]: m[a] = error("") } (new Foo[Int]).foo[List] : List[Int]
@@ -3036,12 +3085,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
treeCopy.TypeApply(tree, fun, args) setType resultpe
}
} else {
- errorTree(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun))
+ TypedApplyWrongNumberOfTpeParametersError(tree, fun)
}
case ErrorType =>
setError(treeCopy.TypeApply(tree, fun, args))
case _ =>
- errorTree(tree, treeSymTypeMsg(fun)+" does not take type parameters.")
+ TypedApplyDoesNotTakeTpeParametersError(tree, fun)
}
@inline final def deindentTyping() = context.typingIndentLevel -= 2
@@ -3110,6 +3159,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// this annotation did not need it
if (ainfo.isErroneous)
+ // Erroneous annotations were already reported in typedAnnotation
arg1 // simply drop erroneous annotations
else {
ann.tpe = atype
@@ -3149,7 +3199,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
vble = context.owner.newValue(name, tree.pos)
if (vble.name.toTermName != nme.WILDCARD) {
if ((mode & ALTmode) != 0)
- error(tree.pos, "illegal variable in pattern alternative")
+ VariableInPatternAlternativeError(tree)
vble = namer.enterInScope(vble)
}
val body1 = typed(body, mode, pt)
@@ -3176,18 +3226,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedAssign(lhs: Tree, rhs: Tree): Tree = {
val lhs1 = typed(lhs, EXPRmode | LHSmode, WildcardType)
val varsym = lhs1.symbol
- def failMsg =
- if (varsym != null && varsym.isValue) "reassignment to val"
- else "assignment to non variable"
- def fail = {
- if (!lhs1.tpe.isError)
- error(tree.pos, failMsg)
+ // see #2494 for double error message example
+ def fail() =
+ if (lhs1.isErrorTyped) lhs1
+ else AssignmentError(tree, varsym)
- setError(tree)
- }
if (varsym == null)
- return fail
+ return fail()
if (treeInfo.mayBeVarGetter(varsym)) {
treeInfo.methPart(lhs1) match {
@@ -3203,7 +3249,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val rhs1 = typed(rhs, EXPRmode | BYVALmode, lhs1.tpe)
treeCopy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe
}
- else fail
+ else fail()
}
def typedIf(cond: Tree, thenp: Tree, elsep: Tree) = {
@@ -3273,12 +3319,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
enclMethod.owner.isConstructor ||
context.enclClass.enclMethod == enclMethod // i.e., we are in a constructor of a local class
) {
- errorTree(tree, "return outside method definition")
+ ReturnOutsideOfDefError(tree)
} else {
val DefDef(_, name, _, _, restpt, _) = enclMethod.tree
- if (restpt.tpe eq null)
- errorTree(tree, enclMethod.owner + " has return statement; needs result type")
- else {
+ if (restpt.tpe eq null) {
+ ReturnWithoutTypeError(tree, enclMethod.owner)
+ } else {
context.enclMethod.returnsSeen = true
val expr1: Tree = typed(expr, EXPRmode | BYVALmode, restpt.tpe)
// Warn about returning a value if no value can be returned.
@@ -3297,12 +3343,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedNew(tpt: Tree) = {
val tpt1 = {
val tpt0 = typedTypeConstructor(tpt)
- checkClassType(tpt0, false, true)
- if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) {
- context.undetparams = cloneSymbols(tpt0.symbol.typeParams)
- TypeTree().setOriginal(tpt0)
- .setType(appliedType(tpt0.tpe, context.undetparams map (_.tpeHK))) // @PP: tpeHK! #3343, #4018, #4347.
- } else tpt0
+ if (checkClassType(tpt0, false, true))
+ if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) {
+ context.undetparams = cloneSymbols(tpt0.symbol.typeParams)
+ TypeTree().setOriginal(tpt0)
+ .setType(appliedType(tpt0.tpe, context.undetparams map (_.tpeHK))) // @PP: tpeHK! #3343, #4018, #4347.
+ } else tpt0
+ else tpt0
}
/** If current tree <tree> appears in <val x(: T)? = <tree>>
@@ -3321,17 +3368,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val tp = tpt1.tpe
val sym = tp.typeSymbol.initialize
if (sym.isAbstractType || sym.hasAbstractFlag)
- error(tree.pos, sym + " is abstract; cannot be instantiated")
+ IsAbstractError(tree, sym)
else if (!( tp == sym.thisSym.tpe // when there's no explicit self type -- with (#3612) or without self variable
// sym.thisSym.tpe == tp.typeOfThis (except for objects)
|| narrowRhs(tp) <:< tp.typeOfThis
|| phase.erasedTypes
)) {
- error(tree.pos, sym +
- " cannot be instantiated because it does not conform to its self-type "+
- tp.typeOfThis)
- }
- treeCopy.New(tree, tpt1).setType(tp)
+ DoesNotConformToSelfTypeError(tree, sym, tp.typeOfThis)
+ } else
+ treeCopy.New(tree, tpt1).setType(tp)
}
def typedEta(expr1: Tree): Tree = expr1.tpe match {
@@ -3369,22 +3414,28 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case ErrorType =>
expr1
case _ =>
- errorTree(expr1, "_ must follow method; cannot follow " + expr1.tpe)
+ UnderscoreEtaError(expr1)
}
/**
* @param args ...
* @return ...
*/
- def tryTypedArgs(args: List[Tree], mode: Int, other: TypeError): List[Tree] = {
+ def tryTypedArgs(args: List[Tree], mode: Int): Option[List[Tree]] = {
val c = context.makeSilent(false)
c.retyping = true
try {
- newTyper(c).typedArgs(args, mode)
+ val res = newTyper(c).typedArgs(args, mode)
+ if (c.hasErrors) None else Some(res)
} catch {
- case ex: CyclicReference => throw ex
- case ex: TypeError =>
- null
+ case ex: CyclicReference =>
+ throw ex
+ case te: TypeError =>
+ // @H some of typer erros can still leak,
+ // for instance in continuations
+ None
+ } finally {
+ c.flushBuffer()
}
}
@@ -3393,10 +3444,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
*/
def tryTypedApply(fun: Tree, args: List[Tree]): Tree = {
val start = startTimer(failedApplyNanos)
- silent(_.doTypedApply(tree, fun, args, mode, pt)) match {
- case t: Tree =>
- t
- case ex: TypeError =>
+
+ def onError(typeError: AbsTypeError): Tree = {
stopTimer(failedApplyNanos, start)
// If the problem is with raw types, copnvert to existentials and try again.
@@ -3419,27 +3468,39 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Typed(r, Function(Nil, EmptyTree)) => treesInResult(r)
case _ => Nil
})
- def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == ex.pos)
- val retry = fun :: tree :: args exists errorInResult
+ def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == typeError.errPos)
+
+ val retry = (typeError.errPos != null) && (fun :: tree :: args exists errorInResult)
printTyping {
val funStr = ptTree(fun) + " and " + (args map ptTree mkString ", ")
if (retry) "second try: " + funStr
- else "no second try: " + funStr + " because error not in result: " + ex.pos+"!="+tree.pos
+ else "no second try: " + funStr + " because error not in result: " + typeError.errPos+"!="+tree.pos
}
if (retry) {
val Select(qual, name) = fun
- val args1 = tryTypedArgs(args, forArgMode(fun, mode), ex)
- val qual1 =
- if ((args1 ne null) && !pt.isError) adaptToArguments(qual, name, args1, pt)
- else qual
- if (qual1 ne qual) {
- val tree1 = Apply(Select(qual1, name) setPos fun.pos, args1) setPos tree.pos
- return typed1(tree1, mode | SNDTRYmode, pt)
+ tryTypedArgs(args, forArgMode(fun, mode)) match {
+ case Some(args1) =>
+ assert((args1.length == 0) || !args1.head.tpe.isErroneous, "try typed args is ok")
+ val qual1 =
+ if (!pt.isError) adaptToArguments(qual, name, args1, pt, true, true)
+ else qual
+ if (qual1 ne qual) {
+ val tree1 = Apply(Select(qual1, name) setPos fun.pos, args1) setPos tree.pos
+ return typed1(tree1, mode | SNDTRYmode, pt)
+ }
+ case _ => ()
}
}
- reportTypeError(tree.pos, ex)
+ issue(typeError)
setError(treeCopy.Apply(tree, fun, args))
}
+
+ silent(_.doTypedApply(tree, fun, args, mode, pt)) match {
+ case SilentResultValue(t) =>
+ t
+ case SilentTypeError(err) =>
+ onError(err)
+ }
}
def typedApply(fun: Tree, args: List[Tree]) = {
@@ -3451,10 +3512,28 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val funpt = if (isPatternMode) pt else WildcardType
val appStart = startTimer(failedApplyNanos)
val opeqStart = startTimer(failedOpEqNanos)
+
+ def onError(reportError: => Tree): Tree = {
+ fun match {
+ case Select(qual, name)
+ if !isPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) =>
+ val qual1 = typedQualifier(qual)
+ if (treeInfo.isVariableOrGetter(qual1)) {
+ stopTimer(failedOpEqNanos, opeqStart)
+ convertToAssignment(fun, qual1, name, args)
+ } else {
+ stopTimer(failedApplyNanos, appStart)
+ reportError
+ }
+ case _ =>
+ stopTimer(failedApplyNanos, appStart)
+ reportError
+ }
+ }
silent(_.typed(fun, forFunMode(mode), funpt),
- if ((mode & EXPRmode) != 0) false else context.reportAmbiguousErrors,
+ if ((mode & EXPRmode) != 0) false else context.ambiguousErrors,
if ((mode & EXPRmode) != 0) tree else context.tree) match {
- case fun1: Tree =>
+ case SilentResultValue(fun1) =>
val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1
incCounter(typedApplyCount)
def isImplicitMethod(tpe: Type) = tpe match {
@@ -3481,7 +3560,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
//if (fun2.hasSymbol && fun2.symbol.name == nme.apply && fun2.symbol.owner == ArrayClass) {
// But this causes cyclic reference for Array class in Cleanup. It is easy to overcome this
// by calling ArrayClass.info here (or some other place before specialize).
- if (fun2.symbol == Array_apply) {
+ if (fun2.symbol == Array_apply && !res.isErrorTyped) {
val checked = gen.mkCheckInit(res)
// this check is needed to avoid infinite recursion in Duplicators
// (calling typed1 more than once for the same tree)
@@ -3489,30 +3568,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
else res
} else
res
- case ex: TypeError =>
- fun match {
- case Select(qual, name)
- if !isPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) =>
- val qual1 = typedQualifier(qual)
- if (treeInfo.isVariableOrGetter(qual1)) {
- stopTimer(failedOpEqNanos, opeqStart)
- convertToAssignment(fun, qual1, name, args, ex)
- }
- else {
- stopTimer(failedApplyNanos, appStart)
- reportTypeError(fun.pos, ex)
- setError(tree)
- }
- case _ =>
- stopTimer(failedApplyNanos, appStart)
- reportTypeError(fun.pos, ex)
- setError(tree)
- }
+ case SilentTypeError(err) =>
+ onError({issue(err); setError(tree)})
}
}
}
- def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree], ex: TypeError): Tree = {
+ def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree]): Tree = {
val prefix = name.subName(0, name.length - nme.EQL.length)
def mkAssign(vble: Tree): Tree =
Assign(
@@ -3553,25 +3615,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Apply(fn, indices) =>
treeInfo.methPart(fn) match {
case Select(table, nme.apply) => mkUpdate(table, indices)
- case _ => errorTree(qual, "Unexpected tree during assignment conversion.")
+ case _ => UnexpectedTreeAssignmentConversionError(qual)
}
}
typed1(tree1, mode, pt)
-/*
- debuglog("retry assign: "+tree1)
- silent(_.typed1(tree1, mode, pt)) match {
- case t: Tree =>
- t
- case _ =>
- reportTypeError(tree.pos, ex)
- setError(tree)
- }
-*/
}
- def qualifyingClassSym(qual: Name): Symbol =
- if (tree.symbol != NoSymbol) tree.symbol else qualifyingClass(tree, qual, false)
-
def typedSuper(qual: Tree, mix: TypeName) = {
val qual1 = typed(qual)
@@ -3596,12 +3645,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// println(mix)
// the reference to super class got lost during erasure
restrictionError(tree.pos, unit, "traits may not select fields or methods from super[C] where C is a class")
+ ErrorType
} else {
- error(tree.pos, mix+" does not name a parent class of "+clazz)
+ MixinMissingParentClassNameError(tree, mix, clazz)
+ ErrorType
}
- ErrorType
} else if (!ps.tail.isEmpty) {
- error(tree.pos, "ambiguous parent class qualifier")
+ AmbiguousParentClassError(tree)
ErrorType
} else {
ps.head
@@ -3618,16 +3668,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
findMixinSuper(clazz.tpe)
}
- treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype)
- }
+ treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype)
+ }
def typedThis(qual: Name) = {
- val clazz = qualifyingClassSym(qual)
- if (clazz == NoSymbol) setError(tree)
- else {
- tree setSymbol clazz setType clazz.thisType.underlying
- if (isStableContext(tree, mode, pt)) tree setType clazz.thisType
- tree
+ val qualifyingClassSym = if (tree.symbol != NoSymbol) Some(tree.symbol) else qualifyingClass(tree, qual)
+ qualifyingClassSym match {
+ case Some(clazz) =>
+ tree setSymbol clazz setType clazz.thisType.underlying
+ if (isStableContext(tree, mode, pt)) tree setType clazz.thisType
+ tree
+ case None => tree
}
}
@@ -3659,10 +3710,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & EXPRmode) != 0) {
val qual1 =
if (member(qual, name) != NoSymbol) qual
- else adaptToMemberWithArgs(tree, qual, name, mode)
- if (qual1 ne qual) return typed(treeCopy.Select(tree, qual1, name), mode, pt)
- }
+ else adaptToMemberWithArgs(tree, qual, name, mode, true, true)
+ if (qual1 ne qual)
+ return typed(treeCopy.Select(tree, qual1, name), mode, pt)
+ }
if (!reallyExists(sym)) {
if (context.owner.toplevelClass.isJavaDefined && name.isTypeName) {
val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) }
@@ -3691,7 +3743,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
)
}
- def makeErrorTree = {
+ def makeInteractiveErrorTree = {
val tree1 = tree match {
case Select(_, _) => treeCopy.Select(tree, qual, name)
case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
@@ -3700,24 +3752,31 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
if (name == nme.ERROR && forInteractive)
- return makeErrorTree
+ return makeInteractiveErrorTree
if (!qual.tpe.widen.isErroneous) {
if ((mode & QUALmode) != 0) {
val lastTry = missingHook(qual.tpe.typeSymbol, name)
if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
}
- notAMemberError(tree.pos, qual, name)
+ NotAMemberError(tree, qual, name)
}
- if (forInteractive) makeErrorTree else setError(tree)
+ if (forInteractive) makeInteractiveErrorTree else setError(tree)
} else {
val tree1 = tree match {
case Select(_, _) => treeCopy.Select(tree, qual, name)
case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
}
- val (tree2, pre2) = makeAccessible(tree1, sym, qual.tpe, qual)
- val result = stabilize(tree2, pre2, mode, pt)
+ val (result, accessibleError) = silent(_.makeAccessible(tree1, sym, qual.tpe, qual)) match {
+ case SilentTypeError(err) =>
+ if (err.kind != ErrorKinds.Access) {
+ context issue err
+ return setError(tree)
+ } else (tree1, Some(err))
+ case SilentResultValue(treeAndPre) =>
+ (stabilize(treeAndPre._1, treeAndPre._2, mode, pt), None)
+ }
def isPotentialNullDeference() = {
!isPastTyper &&
@@ -3736,16 +3795,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
result,
(TypeTreeWithDeferredRefCheck(){ () => val tp = qual.tpe; val sym = tp.typeSymbolDirect
// will execute during refchecks -- TODO: make private checkTypeRef in refchecks public and call that one?
- checkBounds(qual.pos, tp.prefix, sym.owner, sym.typeParams, tp.typeArgs, "")
+ checkBounds(qual, tp.prefix, sym.owner, sym.typeParams, tp.typeArgs, "")
qual // you only get to see the wrapped tree after running this check :-p
}) setType qual.tpe setPos qual.pos,
name)
- case accErr: Inferencer#AccessError =>
- val qual1 =
- try adaptToMemberWithArgs(tree, qual, name, mode)
- catch { case _: TypeError => qual }
- if (qual1 ne qual) typed(Select(qual1, name) setPos tree.pos, mode, pt)
- else accErr.emit()
+ case _ if accessibleError.isDefined =>
+ val qual1 = adaptToMemberWithArgs(tree, qual, name, mode, false, false)
+ if (!qual1.isErrorTyped && (qual1 ne qual))
+ typed(Select(qual1, name) setPos tree.pos, mode, pt)
+ else {
+ issue(accessibleError.get)
+ setError(tree)
+ }
case _ =>
result
}
@@ -3753,7 +3814,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// getClass, we have to catch it immediately so expressions
// like x.getClass().newInstance() are typed with the type of x.
val isRefinableGetClass = (
- selection.symbol.name == nme.getClass_
+ !selection.isErrorTyped
+ && selection.symbol.name == nme.getClass_
&& selection.tpe.params.isEmpty
// TODO: If the type of the qualifier is inaccessible, we can cause private types
// to escape scope here, e.g. pos/t1107. I'm not sure how to properly handle this
@@ -3761,7 +3823,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
&& qual.tpe.typeSymbol.isPublic
)
if (isRefinableGetClass)
- selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe))
+ selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe))
else
selection
}
@@ -3775,8 +3837,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* (2) Change imported symbols to selections
*/
def typedIdent(name: Name): Tree = {
- def ambiguousError(msg: String) =
- error(tree.pos, "reference to " + name + " is ambiguous;\n" + msg)
+ var errorContainer: AbsTypeError = null
+ @inline
+ def ambiguousError(msg: String) = {
+ assert(errorContainer == null, "Cannot set ambiguous error twice for identifier")
+ errorContainer = AmbiguousIdentError(tree, name, msg)
+ }
+ @inline
+ def identError(tree: AbsTypeError) = {
+ assert(errorContainer == null, "Cannot set ambiguous error twice for identifier")
+ errorContainer = tree
+ }
var defSym: Symbol = tree.symbol // the directly found symbol
var pre: Type = NoPrefix // the prefix type of defSym, if a class member
@@ -3896,7 +3967,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
ambiguousError(
"it is imported twice in the same scope by\n"+imports.head + "\nand "+imports1.head)
}
- while (!imports1.isEmpty &&
+ while (errorContainer == null && !imports1.isEmpty &&
(!imports.head.isExplicitImport(name) ||
imports1.head.depth == imports.head.depth)) {
var impSym1 = imports1.head.importedSymbol(name)
@@ -3930,72 +4001,47 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (inaccessibleSym eq NoSymbol) {
// Avoiding some spurious error messages: see SI-2388.
if (reporter.hasErrors && (name startsWith tpnme.ANON_CLASS_NAME)) ()
- else {
- // This laborious determination arrived at to keep the tests working.
- val calcSimilar = (
- name.length > 2 && (
- startingIdentContext.reportGeneralErrors
- || startingIdentContext.enclClassOrMethod.reportGeneralErrors
- )
- )
- // avoid calculating if we're in "silent" mode.
- // name length check to limit unhelpful suggestions for e.g. "x" and "b1"
- val similar = {
- if (!calcSimilar) ""
- else {
- val allowed = (
- startingIdentContext.enclosingContextChain
- flatMap (ctx => ctx.scope.toList ++ ctx.imports.flatMap(_.allImportedSymbols))
- filter (sym => sym.isTerm == name.isTermName)
- filterNot (sym => sym.isPackage || sym.isSynthetic || sym.hasMeaninglessName)
- )
- val allowedStrings = (
- allowed.map("" + _.name).distinct.sorted
- filterNot (s => (s contains '$') || (s contains ' '))
- )
- similarString("" + name, allowedStrings)
- }
- }
- error(tree.pos, "not found: "+decodeWithKind(name, context.owner) + similar)
- }
- }
- else new AccessError(
- tree, inaccessibleSym, context.enclClass.owner.thisType,
- inaccessibleExplanation
- ).emit()
+ else identError(SymbolNotFoundError(tree, name, context.owner, startingIdentContext))
+ } else
+ identError(InferErrorGen.AccessError(
+ tree, inaccessibleSym, context.enclClass.owner.thisType, context.enclClass.owner,
+ inaccessibleExplanation
+ ))
defSym = context.owner.newErrorSymbol(name)
}
}
}
- if (defSym.owner.isPackageClass)
- pre = defSym.owner.thisType
+ if (errorContainer != null) {
+ ErrorUtils.issueTypeError(errorContainer)
+ setError(tree)
+ } else {
+ if (defSym.owner.isPackageClass)
+ pre = defSym.owner.thisType
- // Inferring classOf type parameter from expected type.
- if (defSym.isThisSym) {
- typed1(This(defSym.owner) setPos tree.pos, mode, pt)
- }
- // Inferring classOf type parameter from expected type. Otherwise an
- // actual call to the stubbed classOf method is generated, returning null.
- else if (isPredefMemberNamed(defSym, nme.classOf) && pt.typeSymbol == ClassClass && pt.typeArgs.nonEmpty)
- typedClassOf(tree, TypeTree(pt.typeArgs.head))
- else {
- val tree1 = (
- if (qual == EmptyTree) tree
- // atPos necessary because qualifier might come from startContext
- else atPos(tree.pos)(Select(qual, name))
- )
- val (tree2, pre2) = makeAccessible(tree1, defSym, pre, qual)
- // assert(pre.typeArgs isEmpty) // no need to add #2416-style check here, right?
- stabilize(tree2, pre2, mode, pt) match {
- case accErr: Inferencer#AccessError => accErr.emit()
- case result => result
+ // Inferring classOf type parameter from expected type.
+ if (defSym.isThisSym) {
+ typed1(This(defSym.owner) setPos tree.pos, mode, pt)
+ }
+ // Inferring classOf type parameter from expected type. Otherwise an
+ // actual call to the stubbed classOf method is generated, returning null.
+ else if (isPredefMemberNamed(defSym, nme.classOf) && pt.typeSymbol == ClassClass && pt.typeArgs.nonEmpty)
+ typedClassOf(tree, TypeTree(pt.typeArgs.head))
+ else {
+ val tree1 = (
+ if (qual == EmptyTree) tree
+ // atPos necessary because qualifier might come from startContext
+ else atPos(tree.pos)(Select(qual, name))
+ )
+ val (tree2, pre2) = makeAccessible(tree1, defSym, pre, qual)
+ // assert(pre.typeArgs isEmpty) // no need to add #2416-style check here, right?
+ stabilize(tree2, pre2, mode, pt)
}
}
}
def typedCompoundTypeTree(templ: Template) = {
val parents1 = templ.parents mapConserve (typedType(_, mode))
- if (parents1 exists (_.tpe.isError)) tree setType ErrorType
+ if (parents1 exists (_.isErrorTyped)) tree setType ErrorType
else {
val decls = new Scope
//Console.println("Owner: " + context.enclClass.owner + " " + context.enclClass.owner.id)
@@ -4007,10 +4053,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def typedAppliedTypeTree(tpt: Tree, args: List[Tree]) = {
val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType)
- if (tpt1.tpe.isError) {
- setError(tree)
+ if (tpt1.isErrorTyped) {
+ tpt1
} else if (!tpt1.hasSymbol) {
- errorTree(tree, tpt1.tpe+" does not take type parameters")
+ AppliedTypeNoParametersError(tree, tpt1.tpe)
} else {
val tparams = tpt1.symbol.typeParams
if (sameLength(tparams, args)) {
@@ -4042,16 +4088,16 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// wrap the tree and include the bounds check -- refchecks will perform this check (that the beta reduction was indeed allowed) and unwrap
// we can't simply use original in refchecks because it does not contains types
// (and the only typed trees we have have been mangled so they're not quite the original tree anymore)
- checkBounds(result.pos, tpt1.tpe.prefix, tpt1.symbol.owner, tpt1.symbol.typeParams, argtypes, "")
+ checkBounds(result, tpt1.tpe.prefix, tpt1.symbol.owner, tpt1.symbol.typeParams, argtypes, "")
result // you only get to see the wrapped tree after running this check :-p
} setType (result.tpe) setPos(result.pos)
else result
} else if (tparams.isEmpty) {
- errorTree(tree, tpt1.tpe+" does not take type parameters")
+ AppliedTypeNoParametersError(tree, tpt1.tpe)
} else {
//Console.println("\{tpt1}:\{tpt1.symbol}:\{tpt1.symbol.info}")
if (settings.debug.value) Console.println(tpt1+":"+tpt1.symbol+":"+tpt1.symbol.info)//debug
- errorTree(tree, "wrong number of type arguments for "+tpt1.tpe+", should be "+tparams.length)
+ AppliedTypeWrongNumberOfArgsError(tree, tpt1, tparams)
}
}
}
@@ -4098,8 +4144,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val typer1 = newTyper(context.makeNewScope(tree, context.owner))
for (useCase <- comment.useCases) {
typer1.silent(_.typedUseCase(useCase)) match {
- case ex: TypeError =>
- unit.warning(useCase.pos, ex.msg)
+ case SilentTypeError(err) =>
+ unit.warning(useCase.pos, err.errMsg)
case _ =>
}
for (useCaseSym <- useCase.defined) {
@@ -4114,17 +4160,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
typedAnnotated(constr, typed(arg, mode, pt))
case tree @ Block(_, _) =>
- newTyper(context.makeNewScope(tree, context.owner))
- .typedBlock(tree, mode, pt)
+ typerWithLocalContext(context.makeNewScope(tree, context.owner)){
+ _.typedBlock(tree, mode, pt)
+ }
case Alternative(alts) =>
val alts1 = alts mapConserve (alt => typed(alt, mode | ALTmode, pt))
treeCopy.Alternative(tree, alts1) setType pt
case Star(elem) =>
- checkStarPatOK(tree.pos, mode)
- val elem1 = typed(elem, mode, pt)
- treeCopy.Star(tree, elem1) setType makeFullyDefined(pt)
+ if ((mode & STARmode) == 0 && !isPastTyper)
+ StarPatternWithVarargParametersError(tree)
+ treeCopy.Star(tree, typed(elem, mode, pt)) setType makeFullyDefined(pt)
case Bind(name, body) =>
typedBind(name, body)
@@ -4141,8 +4188,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case tree @ Function(_, _) =>
if (tree.symbol == NoSymbol)
tree.symbol = context.owner.newAnonymousFunctionValue(tree.pos)
-
- newTyper(context.makeNewScope(tree, tree.symbol)).typedFunction(tree, mode, pt)
+ typerWithLocalContext(context.makeNewScope(tree, tree.symbol))(_.typedFunction(tree, mode, pt))
case Assign(lhs, rhs) =>
typedAssign(lhs, rhs)
@@ -4181,17 +4227,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Typed(expr, Function(List(), EmptyTree)) =>
typedEta(checkDead(typed1(expr, mode, pt)))
- case Typed(expr, tpt @ Ident(tpnme.WILDCARD_STAR)) =>
- val expr0 = typed(expr, onlyStickyModes(mode), WildcardType)
+ case Typed(expr0, tpt @ Ident(tpnme.WILDCARD_STAR)) =>
+ val expr = typed(expr0, onlyStickyModes(mode), WildcardType)
def subArrayType(pt: Type) =
if (isValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt)
else {
val tparam = context.owner freshExistential "" setInfo TypeBounds.upper(pt)
newExistentialType(List(tparam), arrayType(tparam.tpe))
}
- val (expr1, baseClass) = expr0.tpe.typeSymbol match {
- case ArrayClass => (adapt(expr0, onlyStickyModes(mode), subArrayType(pt)), ArrayClass)
- case _ => (adapt(expr0, onlyStickyModes(mode), seqType(pt)), SeqClass)
+
+ val (expr1, baseClass) = expr.tpe.typeSymbol match {
+ case ArrayClass => (adapt(expr, onlyStickyModes(mode), subArrayType(pt)), ArrayClass)
+ case _ => (adapt(expr, onlyStickyModes(mode), seqType(pt)), SeqClass)
}
expr1.tpe.baseType(baseClass) match {
case TypeRef(_, _, List(elemtp)) =>
@@ -4203,11 +4250,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case Typed(expr, tpt) =>
val tpt1 = typedType(tpt, mode)
val expr1 = typed(expr, onlyStickyModes(mode), tpt1.tpe.deconst)
- val owntype =
- if (isPatternMode) inferTypedPattern(tpt1.pos, tpt1.tpe, pt)
- else tpt1.tpe
- //Console.println(typed pattern: "+tree+":"+", tp = "+tpt1.tpe+", pt = "+pt+" ==> "+owntype)//DEBUG
- treeCopy.Typed(tree, expr1, tpt1) setType owntype
+ val ownType = if (isPatternMode) inferTypedPattern(tpt1, tpt1.tpe, pt) else tpt1.tpe
+ treeCopy.Typed(tree, expr1, tpt1) setType ownType
case TypeApply(fun, args) =>
// @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
@@ -4259,12 +4303,14 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// convert new Array^N[T](len) for N > 1 to evidence[ClassManifest[T]].newArrayN(len)
val Some((level, manifType)) = erasure.GenericArray.unapply(tpt.tpe)
if (level > MaxArrayDims)
- error(tree.pos, "cannot create a generic multi-dimensional array of more than "+MaxArrayDims+" dimensions")
- val newArrayApp = atPos(tree.pos) {
- val manif = getManifestTree(tree.pos, manifType, false)
- new ApplyToImplicitArgs(Select(manif, if (level == 1) "newArray" else "newArray"+level), args)
+ MultiDimensionalArrayError(tree)
+ else {
+ val newArrayApp = atPos(tree.pos) {
+ val manif = getManifestTree(tree, manifType, false)
+ new ApplyToImplicitArgs(Select(manif, if (level == 1) "newArray" else "newArray"+level), args)
+ }
+ typed(newArrayApp, mode, pt)
}
- typed(newArrayApp, mode, pt)
case tree1 =>
tree1
}
@@ -4295,18 +4341,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
val tree1 = // temporarily use `filter` and an alternative for `withFilter`
if (name == nme.withFilter)
silent(_ => typedSelect(qual1, name)) match {
- case result1: Tree =>
- result1
- case ex1: TypeError =>
+ case SilentResultValue(result) =>
+ result
+ case _ =>
silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match {
- case result2: Tree =>
+ case SilentResultValue(result2) =>
unit.deprecationWarning(
tree.pos, "`withFilter' method does not yet exist on "+qual1.tpe.widen+
", using `filter' method instead")
result2
- case ex2: TypeError =>
- reportTypeError(tree.pos, ex1)
- setError(tree)
+ case SilentTypeError(err) =>
+ WithFilterError(tree, err)
}
}
else
@@ -4339,8 +4384,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
case SelectFromTypeTree(qual, selector) =>
val qual1 = typedType(qual, mode)
- if (qual1.tpe.isVolatile) error(tree.pos, "illegal type selection from volatile type "+qual.tpe)
- typedSelect(qual1, selector)
+ if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual)
+ else typedSelect(qual1, selector)
case CompoundTypeTree(templ) =>
typedCompoundTypeTree(templ)
@@ -4354,7 +4399,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
treeCopy.TypeBoundsTree(tree, lo1, hi1) setType TypeBounds(lo1.tpe, hi1.tpe)
case etpt @ ExistentialTypeTree(_, _) =>
- newTyper(context.makeNewScope(tree, context.owner)).typedExistentialTypeTree(etpt, mode)
+ typerWithLocalContext(context.makeNewScope(tree, context.owner)){
+ _.typedExistentialTypeTree(etpt, mode)
+ }
case dc@TypeTreeWithDeferredRefCheck() => dc // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure)
case tpt @ TypeTree() =>
@@ -4404,7 +4451,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
ptLine("typing %s: pt = %s".format(ptTree(tree), pt),
"undetparams" -> context.undetparams,
"implicitsEnabled" -> context.implicitsEnabled,
- "silent" -> !context.reportGeneralErrors,
+ "silent" -> context.bufferErrors,
"context.owner" -> context.owner
)
)
@@ -4424,16 +4471,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
tree1, tree1.tpe.widen, pt, context.undetparamsString)
) //DEBUG
}
-
-// for (t <- tree1.tpe) assert(t != WildcardType)
-// if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe)
if (!isPastTyper) signalDone(context.asInstanceOf[analyzer.Context], tree, result)
result
} catch {
case ex: TypeError =>
tree.tpe = null
+ // The only problematic case are (recoverable) cyclic reference errors which can pop up almost anywhere.
printTyping("caught %s: while typing %s".format(ex, tree)) //DEBUG
- reportTypeError(tree.pos, ex)
+
+ reportTypeError(context, tree.pos, ex)
setError(tree)
case ex: Exception =>
if (settings.debug.value) // @M causes cyclic reference error
@@ -4455,14 +4501,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
- def expandMacro(tree: Tree): Tree = try {
- macroExpand(tree) match {
- case t: Tree => t
- case t => errorTree(tree, "macros must return a compiler-specific tree; returned class is: " + t.getClass)
+ def expandMacro(tree: Tree): Tree =
+ macroExpand(tree, context) match {
+ case Some(t: Tree) => t
+ case Some(t) => MacroExpandError(tree, t)
+ case None => setError(tree) // error already reported
}
- } catch {
- case ex: MacroExpandError => errorTree(tree, ex.msg)
- }
def atOwner(owner: Symbol): Typer =
newTyper(context.make(context.tree, owner))
@@ -4547,22 +4591,22 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
// to see are those in the signatures. These do not need a unique object as a prefix.
// The situation is different for new's and super's, but scalac does not look deep
// enough to see those. See #3938
- error(tree.pos, restpe.prefix+" is not a legal prefix for a constructor")
- }
-
- //@M fix for #2208
- // if there are no type arguments, normalization does not bypass any checks, so perform it to get rid of AnyRef
- if(result.tpe.typeArgs.isEmpty) {
- // minimal check: if(result.tpe.typeSymbolDirect eq AnyRefClass) {
- // must expand the fake AnyRef type alias, because bootstrapping (init in Definitions) is not
- // designed to deal with the cycles in the scala package (ScalaObject extends
- // AnyRef, but the AnyRef type alias is entered after the scala package is
- // loaded and completed, so that ScalaObject is unpickled while AnyRef is not
- // yet defined )
- result setType(restpe)
- } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
- // during uncurry (after refchecks), all types are normalized
- result
+ ConstructorPrefixError(tree, restpe)
+ } else {
+ //@M fix for #2208
+ // if there are no type arguments, normalization does not bypass any checks, so perform it to get rid of AnyRef
+ if (result.tpe.typeArgs.isEmpty) {
+ // minimal check: if(result.tpe.typeSymbolDirect eq AnyRefClass) {
+ // must expand the fake AnyRef type alias, because bootstrapping (init in Definitions) is not
+ // designed to deal with the cycles in the scala package (ScalaObject extends
+ // AnyRef, but the AnyRef type alias is entered after the scala package is
+ // loaded and completed, so that ScalaObject is unpickled while AnyRef is not
+ // yet defined )
+ result setType(restpe)
+ } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
+ // during uncurry (after refchecks), all types are normalized
+ result
+ }
}
}
@@ -4586,11 +4630,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
true, false, context)
}
- def getManifestTree(pos: Position, tp: Type, full: Boolean): Tree = {
+ def getManifestTree(tree: Tree, tp: Type, full: Boolean): Tree = {
val manifestOpt = findManifest(tp, full)
if (manifestOpt.tree.isEmpty) {
- error(pos, "cannot find "+(if (full) "" else "class ")+"manifest for element type "+tp)
- Literal(Constant(null))
+ MissingManifestError(tree, full, tp)
} else {
manifestOpt.tree
}