summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker
diff options
context:
space:
mode:
authorHubert Plociniczak <hubert.plociniczak@epfl.ch>2011-09-07 12:17:54 +0000
committerHubert Plociniczak <hubert.plociniczak@epfl.ch>2011-09-07 12:17:54 +0000
commit620f339bbaadad57daa696007660bb887372e927 (patch)
treee9bf93cfa9d93a299f24cab28577900c36260438 /src/compiler/scala/tools/nsc/typechecker
parent596be479f1e527230f92db320642f77bae7e386d (diff)
downloadscala-620f339bbaadad57daa696007660bb887372e927.tar.gz
scala-620f339bbaadad57daa696007660bb887372e927.tar.bz2
scala-620f339bbaadad57daa696007660bb887372e927.zip
First refactoring related to Error trees.
There are no more direct calls to context.error from Typers and Infer, so more work needs to be done to finish it for Implicits and Namers. I am pushing it to trunk so that all of you can share my pain (and complain). Please do not add any more context.error randomly in that code, instead deal with it appropriately (by creating specific error tree). I was trying to be as informative when it comes to error tree names as possible, but if you feel like changing names to something more appropriate then feel free to do so. When it comes to printing error messages I tried to follow test suite as closily as possible but obviously there were few changes to some tests (mostly positive, I believe). On my machine performance drawback was neglible but I am working on more aggressive caching to reduce the penalty of containsError() calls even more. Any suggestions welcome. At the moment the code supports both styles i.e. throwing type errors for the cases that are not yet handled and generating error trees. But in the future we will drop the former completely (apart from cyclic errors which can pop up almost everywhere). Review by odersky, extempore and anyone who feels like it.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ErrorTrees.scala1346
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala26
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala303
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala55
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala72
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala26
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala73
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala1481
11 files changed, 2554 insertions, 836 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index e3786c154f..60e1a6c747 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -22,6 +22,7 @@ trait Analyzer extends AnyRef
with Unapplies
with NamesDefaults
with TypeDiagnostics
+ with ErrorTrees
{
val global : Global
import global._
diff --git a/src/compiler/scala/tools/nsc/typechecker/ErrorTrees.scala b/src/compiler/scala/tools/nsc/typechecker/ErrorTrees.scala
new file mode 100644
index 0000000000..714c4384ce
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/ErrorTrees.scala
@@ -0,0 +1,1346 @@
+package scala.tools.nsc
+package typechecker
+
+trait ErrorTrees {
+ self: Analyzer =>
+
+ import global._
+
+ trait ErrorTree extends AbsErrorTree {
+
+ def emit(context: Context): Unit
+ def emit(): Unit = emit(typer.context.asInstanceOf[Context])
+ protected def initErrorCheck {
+ hasErrorTree = Some(true)
+ }
+ def exception: TypeError = null // Once we get rid of all thrown type errors (apart from cyclic), remove
+ var reported = false
+ override def tpe = ErrorType
+ printName(this)
+ }
+
+ trait InteractiveErrorTree extends ErrorTree {
+ def retrieveEmitted: Tree
+ }
+
+ trait ContextError {
+ def errMsg: String
+ def errPos: Position
+ def emit(context: Context) = context.error(errPos, errMsg)
+ }
+
+ // Debugging option
+ @inline private def printName(t: ErrorTree) {
+ if (settings.errortrees.value)
+ println("[ErrorTree instance] " + t.getClass)
+ }
+
+ object errorTreesFinder extends Traverser {
+ import scala.collection.mutable
+ var trees: mutable.ListBuffer[ErrorTree] = _
+ override def traverse(t: Tree) {
+ t match {
+ case e: ErrorTree if !e.reported =>
+ trees += e
+ case e: ErrorTree =>
+ case _ =>
+ super.traverse(t)
+ }
+ }
+ def apply(t: Tree) = {
+ trees = new mutable.ListBuffer()
+ traverse(t)
+ trees
+ }
+ }
+
+ object quickErrorTreeFinder extends Traverser {
+ import scala.collection.mutable
+ var found: Option[ErrorTree] = None
+ override def traverse(t: Tree) {
+ if (!found.isDefined)
+ t match {
+ case e: ErrorTree =>
+ found = Some(e)
+ case _ =>
+ super.traverse(t)
+ }
+ }
+ def apply(t: Tree) = {
+ found = None
+ traverse(t)
+ found.get
+ }
+ }
+
+ abstract class TreeForwarder(forwardTo: Tree) extends Tree {
+ override def pos = forwardTo.pos
+ override def hasSymbol = forwardTo.hasSymbol
+ override def symbol = forwardTo.symbol
+ override def symbol_=(x: Symbol) = forwardTo.symbol = x
+ }
+
+ // create trees for specific error trees
+
+ trait TyperErrorTrees {
+ self: Typer =>
+
+ import infer.setError
+
+ case class UnstableTreeError(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ val msg = "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 (!tree.isErroneous)
+ context.error(tree.pos, msg)
+ }
+ }
+
+ case class NoImplicitFoundError(fun: Tree, param: Symbol)
+ extends TreeForwarder(fun) with ErrorTree with ContextError {
+
+ def errMsg = {
+ val paramName = param.name
+ val paramTp = param.tpe
+ 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
+ }
+ }
+ def errPos = fun.pos
+ }
+
+ case class TypeErrorTree(tree: Tree, pt: Type, override val exception: TypeError)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ reportTypeError(context, tree.pos, exception)
+ }
+ }
+
+ case class AdaptToMemberWithArgsError(tree: Tree, override val exception: TypeError)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ reportTypeError(context, tree.pos, exception)
+ }
+ }
+
+ case class WithFilterError(tree0: Tree, override val exception: TypeError)
+ extends TreeForwarder(tree0) with ErrorTree {
+
+ def emit(context: Context) {
+ reportTypeError(context, tree0.pos, exception)
+ setError(tree0)
+ }
+ }
+
+ case class ParentTypesError(templ: Template, override val exception: TypeError)
+ extends ErrorTree {
+
+ def emit(context: Context) {
+ templ.tpe = null
+ reportTypeError(context, templ.pos, exception)
+ }
+ }
+
+ // additional parentTypes errors
+
+ case class ConstrArgsInTraitParentTpeError(arg: Tree, parent: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = parent + " is a trait; does not take constructor arguments"
+ def errPos = arg.pos
+ }
+
+ case class MissingTypeArgumentsParentTpeError(supertpt: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "missing type arguments"
+ def errPos = supertpt.pos
+ }
+
+ case class SilentTypeError(tree: Tree, override val exception: TypeError)
+ extends ErrorTree {
+
+ def emit(context: Context) {
+ reportTypeError(context, tree.pos, exception)
+ }
+ }
+
+ case class TypedApplyError(tree: Tree, override val exception: TypeError)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ reportTypeError(context, tree.pos, exception)
+ }
+
+ override def pos = exception.pos
+ }
+
+ case class AssignmentTypedApplyError(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg = "reassignment to val"
+ def errPos = tree.pos
+ }
+
+
+ // typedIdent
+ case class AmbiguousIdentError(tree: Tree, name: Name, msg: String)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg = "reference to " + name + " is ambiguous;\n" + msg
+ def errPos = tree.pos
+ }
+
+ case class SymbolNotFound(tree: Tree, name: Name, owner: Symbol)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg = "not found: "+decodeWithKind(name, owner)
+ def errPos = tree.pos
+ }
+
+ // typedAppliedTypeTree
+ case class AppliedTypeNoParametersError(tree: Tree, errTpe: Type)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, errTpe + " does not take type parameters")
+ }
+ }
+
+ case class AppliedTypeWrongNumberOfArgsError(tree: Tree, msg: String)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, msg)
+ }
+ }
+
+ // packagedef
+ case class RefTreeError(tree: Tree, name: Name)
+ extends ErrorTree with RefTree {
+
+ def emit(context: Context) {
+ // Error was already reported
+ }
+ }
+
+ // typedTypeDef
+ case class LowerBoundError(tree: TypeDef, lowB: Type, highB: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "lower bound "+lowB+" does not conform to upper bound "+highB
+ def errPos = tree.pos
+ }
+
+ // check privates
+ case class HiddenSymbolWithError(tree: Tree)
+ extends ErrorTree {
+
+ def emit(context: Context) {}
+ }
+
+ case class SymbolEscapesScopeError(tree: Tree, badSymbol: Symbol)
+ extends ErrorTree with ContextError {
+
+ val treeTpe = tree.tpe
+ def errMsg = (if (badSymbol.isPrivate) "private " else "") + badSymbol +
+ " escapes its defining scope as part of type "+treeTpe
+ def errPos = tree.pos
+ }
+
+ // typedDefDef
+ case class StarParamNotLastError(param: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "*-parameter must come last"
+ def errPos = param.pos
+ }
+
+ case class StarWithDefaultError(meth: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "a parameter section with a `*'-parameter is not allowed to have default arguments"
+ def errPos = meth.pos
+ }
+
+ case class InvalidConstructorDefError(ddef: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "constructor definition not allowed here"
+ def errPos = ddef.pos
+ }
+
+ case class DeprecatedParamNameError(param: Symbol, name: Name)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "deprecated parameter name "+ name +" has to be distinct from any other parameter name (deprecated or not)."
+ def errPos = param.pos
+ }
+
+ // computeParamAliases
+ case class SuperConstrReferenceError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "super constructor cannot be passed a self reference unless parameter is declared by-name"
+ def errPos = tree.pos
+ }
+
+ case class SuperConstrArgsThisReferenceError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "super constructor arguments cannot reference unconstructed `this`"
+ def errPos = tree.pos
+ }
+
+ // typedValDef
+ case class VolatileValueError(vdef: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "values cannot be volatile"
+ def errPos = vdef.pos
+ }
+
+ case class FinalVolatileVarError(vdef: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "final vars cannot be volatile"
+ def errPos = vdef.pos
+ }
+
+ case class LocalVarUninitializedError(vdef: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "local variables must be initialized"
+ def errPos = vdef.pos
+ }
+
+ //typedAssign
+ case class AssignmentError(tree: Tree, varSym: Symbol)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg =
+ if (varSym != null && varSym.isValue) "reassignment to val"
+ else "assignment to non variable"
+ def errPos = tree.pos
+ }
+
+ case class UnexpectedTreeAssignmentConversionError(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg = "Unexpected tree during assignment conversion."
+ def errPos = tree.pos
+ }
+
+ case class MultiDimensionalArrayError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "cannot create a generic multi-dimensional array of more than "+ definitions.MaxArrayDims+" dimensions"
+ def errPos = tree.pos
+ }
+
+ //typedSuper
+ case class MixinMissingParentClassNameError(tree: Tree, mix: Name, clazz: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = mix+" does not name a parent class of "+clazz
+ def errPos = tree.pos
+ }
+
+ case class AmbiguousParentClassError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "ambiguous parent class qualifier"
+ def errPos = tree.pos
+ }
+
+ //typedSelect
+ case class NotAMemberErroneous(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) { }
+ }
+
+ case class NotAMemberInteractive(originalTree: Tree)
+ extends TreeForwarder(originalTree) with InteractiveErrorTree {
+
+ private[this] var newTree = originalTree
+
+ def emit(context: Context) {
+ def copyTree = {
+ val tree1 = originalTree match {
+ case Select(qual, name) => treeCopy.Select(originalTree, qual, name)
+ case SelectFromTypeTree(qual, name) => treeCopy.SelectFromTypeTree(originalTree, qual, name)
+ }
+ tree1
+ }
+ newTree = copyTree
+ }
+
+ def retrieveEmitted = newTree
+ }
+
+ case class NotAMemberError(sel: Tree, qual: Tree, name: Name)
+ extends TreeForwarder(sel) with ErrorTree with ContextError {
+
+ def errMsg = {
+ val owner = qual.tpe.typeSymbol
+ val target = qual.tpe.widen
+ def targetKindString = if (owner.isTypeParameterOrSkolem) "type parameter " else ""
+ def nameString = decodeWithKind(name, owner)
+ /** Illuminating some common situations and errors a bit further. */
+ def addendum = {
+ val companion = {
+ if (name.isTermName && owner.isPackageClass) {
+ target.member(name.toTypeName) match {
+ case NoSymbol => ""
+ case sym => "\nNote: %s exists, but it has no companion object.".format(sym)
+ }
+ }
+ else ""
+ }
+ val semicolon = (
+ if (linePrecedes(qual, sel))
+ "\npossible cause: maybe a semicolon is missing before `"+nameString+"'?"
+ else
+ ""
+ )
+ companion + semicolon
+ }
+ withAddendum(qual.pos)(
+ if (name == nme.CONSTRUCTOR) target + " does not have a constructor"
+ else nameString + " is not a member of " + targetKindString + target + addendum
+ )
+ }
+
+ def errPos = sel.pos
+ }
+
+ //typedNew
+ case class IsAbstractError(tree: Tree, sym: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = sym + " is abstract; cannot be instantiated"
+ def errPos = tree.pos
+ }
+
+ case class DoesNotConformToSelfTypeError(tree: Tree, sym: Symbol, tpe0: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = sym +
+ " cannot be instantiated because it does not conform to its self-type "+
+ tpe0
+ def errPos = tree.pos
+ }
+
+ //typedEta
+ case class UnderscoreEtaError(tree: Tree)
+ extends ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "_ must follow method; cannot follow " + tree.tpe)
+ }
+ }
+
+ //typedReturn
+ case class ReturnOutsideOfDefError(tree: Tree)
+ extends ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "return outside method definition")
+ }
+ }
+
+ case class ReturnWithoutTypeError(tree: Tree, owner: Symbol)
+ extends ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, owner + " has return statement; needs result type")
+ }
+ }
+
+ //typedBind
+ case class VariableInPatternAlternativeError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "illegal variable in pattern alternative"
+ def errPos = tree.pos
+ }
+
+ //typedCase
+ case class StarPositionInPatternError(pos0: Position)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "_* may only come last"
+ def errPos = pos0
+ }
+
+ //typedFunction
+ case class MaxFunctionArityError(fun: Tree)
+ extends TreeForwarder(fun) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!fun.isErroneous)
+ context.error(fun.pos,"implementation restricts functions to " + definitions.MaxFunctionArity + " parameters")
+ }
+ }
+
+ case class WrongNumberOfParametersError(tree: Tree, argpts: List[Type])
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos,"wrong number of parameters; expected = " + argpts.length)
+ }
+ }
+
+ case class MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type)
+ extends ErrorTree with ContextError {
+
+ def anonMessage = (
+ "\nThe argument types of an anonymous function must be fully known. (SLS 8.5)" +
+ "\nExpected type was: " + pt.toLongString
+ )
+
+ private val suffix =
+ if (!vparam.mods.isSynthetic) ""
+ else " for expanded function" + (fun match {
+ case Function(_, Match(_, _)) => anonMessage
+ case _ => " " + fun
+ })
+
+ def errMsg = "missing parameter type" + suffix
+ def errPos = vparam.pos
+ }
+
+ case class ConstructorsOrderError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "called constructor's definition must precede calling constructor's definition"
+ def errPos = tree.pos
+ }
+
+ case class OnlyDeclarationsError(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "only declarations allowed here")
+ }
+ }
+
+ // typedAnnotation
+ case class AnnotationNotAConstantError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "annotation argument needs to be a constant; found: " + tree
+ def errPos = tree.pos
+ }
+
+ case class AnnotationArgNulError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "annotation argument cannot be null"
+ def errPos = tree.pos
+ }
+
+ case class ArrayConstantsError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "Array constants have to be specified using the `Array(...)' factory method"
+ def errPos = tree.pos
+ }
+
+ case class ArrayConstantsTypeMismatchError(tree: Tree, pt: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "found array constant, expected argument of type " + pt
+ def errPos = tree.pos
+ }
+
+ case class UnexpectedTreeAnnotation(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "unexpected tree in annotation: "+ tree
+ def errPos = tree.pos
+ }
+
+ case class AnnotationTypeMismatchError(tree: Tree, expected: Type, found: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "expected annotation of type "+ expected +", found "+ found
+ def errPos = tree.pos
+ }
+
+ case class MultipleArgumentListForAnnotationError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "multiple argument lists on classfile annotation"
+ def errPos = tree.pos
+ }
+
+ case class UnknownAnnotationNameError(tree: Tree, name: Name)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "unknown annotation argument name: " + name
+ def errPos = tree.pos
+ }
+
+ case class DuplicateValueAnnotationError(tree: Tree, name: Name)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "duplicate value for annotation argument " + name
+ def errPos = tree.pos
+ }
+
+ case class ClassfileAnnotationsAsNamedArgsError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "classfile annotation arguments have to be supplied as named arguments"
+ def errPos = tree.pos
+ }
+
+ case class AnnotationMissingArgError(tree: Tree, annType: Type, name: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "annotation " + annType.typeSymbol.fullName + " is missing argument " + name.name
+ def errPos = tree.pos
+ }
+
+ case class NestedAnnotationError(tree: Tree, annType: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "nested classfile annotations must be defined in java; found: "+ annType
+ def errPos = tree.pos
+ }
+
+ case class UnexpectedTreeAnnotationError(tree: Tree, unexpected: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "unexpected tree after typing annotation: "+ unexpected
+ def errPos = tree.pos
+ }
+
+ // TODO no test case
+ //typedExistentialTypeTree
+ case class AbstractionFromVolatileTypeError(vd: ValDef)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "illegal abstraction from value with volatile type "+vd.symbol.tpe
+ def errPos = vd.pos
+ }
+
+ case class TypedApplyWrongNumberOfTpeParametersError(tree: Tree, fun: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "wrong number of type parameters for "+treeSymTypeMsg(fun))
+ }
+ }
+
+ case class TypedApplyDoesNotTakeTpeParametersError(tree: Tree, fun: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, treeSymTypeMsg(fun)+" does not take type parameters.")
+ }
+ }
+
+ // doTypeApply
+ //tryNamesDefaults
+ case class WrongNumberOfArgsError(tree: Tree, fun: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "wrong number of arguments for "+ treeSymTypeMsg(fun))
+ }
+ }
+
+ case class TooManyArgsNamesDefaultsError(tree: Tree, fun: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "too many arguments for "+treeSymTypeMsg(fun))
+ }
+ }
+
+ case class MultipleVarargError(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "when using named arguments, the vararg parameter "+
+ "has to be specified exactly once")
+ }
+ }
+
+ case class ModuleUsingCompanionClassDefaultArgsErrror(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "module extending its companion class cannot use default constructor arguments")
+ }
+ }
+
+ case class NotEnoughArgsError(tree: Tree, fun0: Tree, missing0: List[Symbol])
+ extends TreeForwarder(tree) with ErrorTree {
+ def notEnoughArgumentsMsg(fun: Tree, missing: List[Symbol]): String = {
+ val suffix = {
+ if (missing.isEmpty) ""
+ else {
+ val keep = missing take 3 map (_.name)
+ ".\nUnspecified value parameter%s %s".format(
+ if (missing.tail.isEmpty) "" else "s",
+ if (missing drop 3 nonEmpty) (keep :+ "...").mkString(", ")
+ else keep.mkString("", ", ", ".")
+ )
+ }
+ }
+
+ "not enough arguments for " + treeSymTypeMsg(fun) + suffix
+ }
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, notEnoughArgumentsMsg(fun0, missing0))
+ }
+ }
+
+ //doTypedApply - ErrorType
+ case class ErroneousFunInTypeApplyError(fun: Tree, args: List[Tree])
+ extends TreeForwarder(fun) with ErrorTree {
+
+ def emit(context: Context) {
+ val all = errorTreesFinder(fun) ++ args.map(arg => errorTreesFinder(arg)).flatten
+ all.foreach(_.emit(context))
+ }
+ }
+
+ //doTypedApply - patternMode
+ // TODO: missing test case
+ case class TooManyArgsPatternError(fun: Tree)
+ extends TreeForwarder(fun) with ErrorTree with ContextError {
+
+ def errMsg = "too many arguments for unapply pattern, maximum = "+definitions.MaxTupleArity
+ def errPos = fun.pos
+ }
+
+ case class WrongNumberArgsPatternError(tree: Tree, fun: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "wrong number of arguments for "+treeSymTypeMsg(fun))
+ }
+ }
+
+
+ // Extends ErrorTreeWithPrettyPrinter to pass presentation/ping-pong test case
+ case class ApplyWithoutArgsError(tree: Tree, fun: Tree)
+ extends TreeForwarder(tree) with ErrorTreeWithPrettyPrinter with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, fun.tpe+" does not take parameters")
+ }
+
+ override def toString() = tree.toString()
+ }
+
+ //checkClassType
+ // When validating parents we sometimes should continue to
+ // type the body of the template and sometimes not.
+ // trait BlockingError allows us to distinguish it
+ trait BlockingError
+
+ case class TypeNotAStablePrefixError(pre: Type, pos0: Position)
+ extends ErrorTree with BlockingError with ContextError {
+
+ def errMsg = "type "+pre+" is not a stable prefix"
+ def errPos = pos0
+ }
+
+ case class ClassTypeRequiredError(tree: Tree, found: AnyRef)
+ extends ErrorTree with BlockingError with ContextError {
+
+ def errMsg = "class type required but "+found+" found"
+ def errPos = tree.pos
+ }
+
+ // validateParentClasses
+ case class ParentSuperSubclassError(pos0: Position, superclazz: Symbol,
+ parentSym: Symbol, mixin: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "illegal inheritance; super"+superclazz+
+ "\n is not a subclass of the super"+parentSym+
+ "\n of the mixin " + mixin
+ def errPos = pos0
+ }
+
+ case class ParentNotATraitMixinError(pos0: Position, mixin: Symbol)
+ extends ErrorTree with BlockingError with ContextError {
+
+ def errMsg = mixin+" needs to be a trait to be mixed in"
+ def errPos = pos0
+ }
+
+ case class ParentFinalInheritanceError(pos0: Position, mixin: Symbol)
+ extends ErrorTree with BlockingError with ContextError {
+
+ def errMsg = "illegal inheritance from final "+mixin
+ def errPos = pos0
+ }
+
+ case class ParentSealedInheritanceError(pos0: Position, mixin: Symbol)
+ extends ErrorTree with BlockingError with ContextError {
+
+ def errMsg = "illegal inheritance from sealed "+mixin
+ def errPos = pos0
+ }
+
+ case class ParentSelfTypeConformanceError(
+ pos0: Position, selfType: Type, parent: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "illegal inheritance;\n self-type "+
+ selfType+" does not conform to "+parent +
+ "'s selftype "+parent.tpe.typeOfThis
+ def errPos = pos0
+ }
+
+ case class ParentInheritedTwiceError(pos0: Position, parent: Symbol)
+ extends ErrorTree with BlockingError with ContextError {
+
+ def errMsg = parent+" is inherited twice"
+ def errPos = pos0
+ }
+
+ //adapt
+ case class MissingArgsForMethodTpeError(tree: Tree, meth: Symbol)
+ extends ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "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"))
+ }
+ }
+
+ // This is really a workaround for a compiler bug
+ case class Bug4425Error(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg = "erroneous or inaccessible type"
+ def errPos = tree.pos
+ }
+
+ case class MissingTypeParametersError(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, tree.symbol+" takes type parameters")
+ setError(tree)
+ }
+ }
+
+ case class KindArityMismatchError(tree: Tree, pt: Type)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ import scala.tools.util.StringOps.{countElementsAsString, countAsString}
+ if (!tree.isErroneous)
+ context.error(tree.pos,
+ tree.tpe+" takes "+countElementsAsString(tree.tpe.typeParams.length, "type parameter")+
+ ", expected: "+countAsString(pt.typeParams.length))
+ }
+ }
+ //case class ParamsNotConvertible
+
+ case class CaseClassConstructorError(tree: Tree)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ import scala.tools.util.StringOps.{countElementsAsString, countAsString}
+ if (!tree.isErroneous)
+ context.error(tree.pos,
+ tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method")
+ }
+ }
+
+ //TODO Needs test case
+ case class ConstructorPrefixError(tree: Tree, restpe: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = restpe.prefix+" is not a legal prefix for a constructor"
+ def errPos = tree.pos
+ }
+
+ // SelectFromTypeTree
+ case class TypeSelectionFromVolatileTypeError(tree: Tree, qual: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "illegal type selection from volatile type "+qual.tpe
+ def errPos = tree.pos
+ }
+
+ // packedType
+ case class InferTypeWithVolatileTypeSelectionError(tree: Tree, pre: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "Inferred type "+tree.tpe+" contains type selection from volatile type "+pre
+ def errPos = tree.pos
+ }
+
+ case class AbstractExistentiallyOverParamerizedTpeError(tree: Tree, tp: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "can't existentially abstract over parameterized type " + tp
+ def errPos = tree.pos
+ }
+
+ //manifestTreee
+ case class MissingManifestError(pos0: Position, full: Boolean, tp: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "cannot find "+(if (full) "" else "class ")+"manifest for element type "+tp
+ def errPos = pos0
+ }
+
+
+ // TODO needs test case
+ // cases where we do not necessairly return trees
+ case class DependentMethodTpeConversionToFunctionError(pos0: Position, tp: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "method with dependent type "+tpe+" cannot be converted to function value"
+ def errPos = pos0
+
+ override def pos = pos0
+ }
+
+ //checkStarPatOK
+ case class StarPatternWithVarargParametersError(pos0: Position)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "star patterns must correspond with varargs parameters"
+ def errPos = pos0
+ }
+
+ case class GetterDefinedTwiceError(getter: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = getter+" is defined twice"
+ def errPos = getter.pos
+ }
+
+ case class BeanPropertyAnnotationLimitationError(tree: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "implementation limitation: the BeanProperty annotation cannot be used in a type alias or renamed import"
+ def errPos = tree.pos
+ }
+
+ // TODO missing test case
+ case class FinitiaryError(tparam: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "class graph is not finitary because type parameter "+tparam.name+" is expansively recursive"
+ def errPos = tparam.pos
+ }
+
+ // TODO missing test case for a second case
+ case class QualifyingClassError(tree: Tree, qual: Name)
+ extends ErrorTree with ContextError {
+
+ def errMsg =
+ if (qual.isEmpty) tree + " can be used only in a class, object, or template"
+ else qual + " is not an enclosing class"
+ def errPos = tree.pos
+ }
+
+ // def stabilize
+ case class NotAValueError(tree: Tree, sym: Symbol)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, sym.kindString + " " + sym.fullName + " is not a value")
+ }
+ }
+
+ // checkNoDoubleDefs...
+ case class DefDefinedTwiceError(sym0: Symbol, sym1: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = sym1+" is defined twice"+{if(!settings.debug.value) "" else " in "+context.unit.toString}
+ def errPos = sym0.pos
+ override def pos = sym0.pos
+
+ }
+
+ // cyclic errors
+ case class CyclicAliasingOrSubtypingError(pos0: Position, sym0: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "cyclic aliasing or subtyping involving "+sym0
+ def errPos = pos0
+
+ override def pos = pos0
+ }
+
+ case class CyclicReferenceError(pos0: Position, lockedSym: Symbol)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "illegal cyclic reference involving " + lockedSym
+ def errPos = pos0
+ override def pos = pos0
+ }
+
+ }
+
+ trait InferencerErrorTrees {
+ self: Inferencer =>
+
+ private def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = {
+ def asParams(xs: List[Any]) = xs.mkString("(", ", ", ")")
+
+ def resType = if (pt isWildcard) "" else " with expected result type " + pt
+ def allTypes = (alternatives(tree) flatMap (_.paramTypes)) ++ argtpes :+ pt
+ def locals = alternatives(tree) flatMap (_.typeParams)
+
+ withDisambiguation(locals, allTypes: _*) {
+ treeSymTypeMsg(tree) + msg + asParams(argtpes) + resType
+ }
+ }
+
+ case class AccessError(tree: Tree, sym: Symbol, pre: Type,
+ owner0: Symbol, explanation: String)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg = {
+ val realsym = underlying(sym)
+ val location = if (sym.isClassConstructor) owner0 else pre.widen
+
+ realsym.fullLocationString + " cannot be accessed in " +
+ location + explanation
+ }
+ def errPos = tree.pos
+ }
+
+ case class NoMethodInstanceError(fn: Tree, args: List[Tree],
+ msg: String)
+ extends TreeForwarder(fn) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!fn.isErroneous)
+ context.error(fn.pos, "no type parameters for " +
+ applyErrorMsg(fn, " exist so that it can be applied to arguments ", args map (_.tpe.widen), WildcardType) +
+ "\n --- because ---\n" + msg)
+ }
+ }
+
+ // TODO: no test case
+ case class NoConstructorInstanceError(tree: Tree, restpe: Type,
+ pt: Type, msg: String)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "constructor of type " + restpe +
+ " cannot be uniquely instantiated to expected type " + pt +
+ "\n --- because ---\n" + msg)
+ }
+ }
+
+ case class ConstrInstantiationError(tree: Tree, restpe: Type,
+ pt: Type)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, "constructor cannot be instantiated to expected type" +
+ foundReqMsg(restpe, pt))
+ }
+
+ }
+
+ case class NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type],
+ pt: Type)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!tree.isErroneous)
+ context.error(tree.pos, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt))
+ }
+
+ }
+
+ case class AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol,
+ firstCompeting: Symbol, argtpes: List[Type], pt: Type)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ context.ambiguousError(tree.pos, pre, best, firstCompeting,
+ "argument types " + argtpes.mkString("(", ",", ")") +
+ (if (pt == WildcardType) "" else " and expected result type " + pt))
+ }
+ }
+
+ case class NoBestExprAlternativeError(tree: Tree, pt: Type)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg = withAddendum(tree.pos)(typeErrorMsg(tree.symbol.tpe, pt))
+ def errPos = tree.pos
+ }
+
+ case class AmbiguousExprAlternativeError(tree: Tree, pre: Type, best: Symbol,
+ firstCompeting: Symbol, pt: Type)
+ extends TreeForwarder(tree) with ErrorTree {
+
+ def emit(context: Context) {
+ context.ambiguousError(tree.pos, pre, best, firstCompeting,
+ "expected type " + pt)
+ }
+ }
+
+ // checkBounds
+ case class KindBoundErrors(pos0: Position, prefix: String, targs: List[Type],
+ tparams: List[Symbol], kindErrors: List[String])
+ extends ErrorTree with ContextError {
+
+ def errMsg =
+ prefix + "kinds of the type arguments " + targs.mkString("(", ",", ")") +
+ " do not conform to the expected kinds of the type parameters "+ tparams.mkString("(", ",", ")") + tparams.head.locationString+ "." +
+ kindErrors.toList.mkString("\n", ", ", "")
+ def errPos = pos0
+
+ override def pos = pos0
+ }
+
+ case class NotWithinBounds(pos0: Position, prefix: String, targs: List[Type],
+ tparams: List[Symbol], kindErrors: List[String])
+ extends ErrorTree {
+
+ val savedContext = getContext
+ def emit(context: Context) {
+ val validContext = if (context.unit == NoCompilationUnit) savedContext else context
+ validContext.error(pos0,
+ prefix + "type arguments " + targs.mkString("[", ",", "]") +
+ " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
+ (tparams map (_.defString)).mkString("[", ",", "]"))
+ if (settings.explaintypes.value) {
+ val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds)
+ (targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ))
+ (targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi))
+ ()
+ }
+ }
+
+ override def pos = pos0
+ }
+
+ //substExpr
+ case class PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol],
+ pt: Type)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg =
+ "polymorphic expression cannot be instantiated to expected type" +
+ foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt)
+ def errPos = tree.pos
+ }
+
+
+ //checkCheckable
+ case class TypePatternOrIsInstanceTestError(pos0: Position, tp: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "type "+tp+" cannot be used in a type pattern or isInstanceOf test"
+ def errPos = pos0
+ override def pos = pos0
+ }
+
+ case class IncompletePatternTypeError(pos0: Position, pattp: Type, pt: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "pattern type is incompatible with expected type" + foundReqMsg(pattp, pt)
+ def errPos = pos0
+ override def pos = pos0
+ }
+
+ case class IncompatibleScrutineeTypeError(pos0: Position, pattp: Type, pt: Type)
+ extends ErrorTree with ContextError {
+
+ def errMsg = "scrutinee is incompatible with pattern type" + foundReqMsg(pattp, pt)
+ def errPos = pos0
+ override def pos = pos0
+ }
+
+ case class PatternTypeIncompatibleWithPtError(pat: Tree, pt1: Type, pt: Type)
+ extends TreeForwarder(pat) with ErrorTree with ContextError {
+
+ def errMsg = {
+ val sym = pat.tpe.typeSymbol
+ val clazz = sym.companionClass
+ val addendum = (
+ if (sym.isModuleClass && clazz.isCaseClass && (clazz isSubClass pt1.typeSymbol)) {
+ // TODO: move these somewhere reusable.
+ val typeString = clazz.typeParams match {
+ case Nil => "" + clazz.name
+ case xs => xs map (_ => "_") mkString (clazz.name + "[", ",", "]")
+ }
+ val caseString = (
+ clazz.caseFieldAccessors
+ map (_ => "_") // could use the actual param names here
+ mkString (clazz.name + "(", ",", ")")
+ )
+ (
+ "\nNote: if you intended to match against the class, try `case _: " +
+ typeString + "` or `case " + caseString + "`"
+ )
+ }
+ else ""
+ )
+ "pattern type is incompatible with expected type"+foundReqMsg(pat.tpe, pt) + addendum
+ }
+ def errPos = pat.pos
+ }
+
+ case class PolyAlternativeError(tree: Tree, msg: String)
+ extends TreeForwarder(tree) with ErrorTree with ContextError {
+
+ def errMsg = msg
+ def errPos = tree.pos
+ }
+ }
+
+ trait NamerErrorTrees {
+ self: Namer =>
+
+ // Currently too general
+ case class TypeSigError(tree: Tree, override val exception: TypeError)
+ extends ErrorTree {
+
+ def emit(context: Context) {
+ typer.reportTypeError(context, tree.pos, exception)
+ }
+ }
+ }
+
+ // General errors
+ case class PendingErrors(pending0: List[ErrorTree])
+ extends ErrorTree {
+ assert(pending0.length != 0, "pending exceptions cannot be empty")
+
+
+ def emit(context: Context) {
+ // Try to report each, here we dont' care
+ // if any of those throws TypeError
+ // this is handled in the actual application code
+ pending0.foreach(_.emit(context))
+ }
+
+ override def pos = pending0.head.pos
+ override def exception: TypeError = pending0.head.exception
+ }
+
+ case object NullErrorTree extends ErrorTree {
+
+ def emit(context: Context) {}
+ }
+
+ case class SetErrorTree(tree: Tree) extends ErrorTree {
+
+ def emit(context: Context) {
+ typer.infer.setError(tree)
+ }
+ }
+
+ //NamesDefaults errors, refactor to their own trait
+ case class NameClashError(sym: Symbol, arg: Tree)
+ extends ErrorTree with ContextError {
+
+ def errMsg =
+ "%s definition needs %s because '%s' is used as a named argument in its body.".format(
+ "variable", // "method"
+ "type", // "result type"
+ sym.name)
+ def errPos = sym.pos
+
+ override def emit(context: Context) = {
+ super.emit(context)
+ // This is ugly hack to avoid reporting double errors
+ // when dealing with AmbiguousReferences problem (error tree below) in names defaults.
+ typer.infer.setError(arg)
+ }
+
+ override def pos = sym.pos
+ }
+
+ case class AmbiguousReferenceInNamesDefaultError(arg: Tree, name: Name)
+ extends TreeForwarder(arg) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!arg.isErroneous) {
+ context.error(
+ arg.pos,
+ "reference to "+ name +" is ambiguous; it is both, a parameter\n"+
+ "name of the method and the name of a variable currently in scope.")
+ }
+ }
+ }
+
+ case class UnknwonParameterNameNamesDefaultError(arg: Tree, name: Name)
+ extends TreeForwarder(arg) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!arg.isErroneous)
+ context.error(arg.pos, "unknown parameter name: " + name)
+ }
+ }
+
+ case class DoubleParamNamesDefaultError(arg: Tree, name: Name)
+ extends TreeForwarder(arg) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!arg.isErroneous)
+ context.error(arg.pos, "parameter specified twice: "+ name)
+ }
+ }
+
+ case class PositionalAfterNamedNamesDefaultError(arg: Tree)
+ extends TreeForwarder(arg) with ErrorTree {
+
+ def emit(context: Context) {
+ if (!arg.isErroneous)
+ context.error(arg.pos, "positional after named argument.")
+ }
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 169295e5c9..7ceff8d1d4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -522,6 +522,9 @@ trait Implicits {
else
typed1(itree, EXPRmode, wildPt)
+ if (itree1.containsError())
+ return SearchFailure
+
incCounter(typedImplicits)
printTyping("typed implicit %s:%s, pt=%s".format(itree1, itree1.tpe, wildPt))
@@ -541,7 +544,7 @@ trait Implicits {
}
}
- if (itree2.tpe.isError)
+ if (itree2.containsErrorOrIsErrorTyped())
SearchFailure
else if (!hasMatchingSymbol(itree1))
fail("candidate implicit %s is shadowed by other implicit %s".format(
@@ -565,7 +568,11 @@ trait Implicits {
false, lubDepth(List(itree2.tpe, pt)))
// #2421: check that we correctly instantiated type parameters outside of the implicit tree:
- checkBounds(itree2.pos, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
+ // TODO: refactoring needed, shouldn't emit it here
+ checkBounds(itree2.pos, NoPrefix, NoSymbol, undetParams, targs, "inferred ") match {
+ case Some(err) => err.emit(context)
+ case _ =>
+ }
// filter out failures from type inference, don't want to remove them from undetParams!
// we must be conservative in leaving type params in undetparams
@@ -590,12 +597,21 @@ trait Implicits {
// re-typecheck)
// TODO: the return tree is ignored. This seems to make
// no difference, but it's bad practice regardless.
- itree2 match {
+
+ // we call typedTypeApply which can return an error tree,
+ // so we cannot ignore the tree
+ // TODO check if that is enough
+ val checked = itree2 match {
case TypeApply(fun, args) => typedTypeApply(itree2, EXPRmode, fun, args)
case Apply(TypeApply(fun, args), _) => typedTypeApply(itree2, EXPRmode, fun, args) // t2421c
case t => t
}
- val result = new SearchResult(itree2, subst)
+ if (checked.containsError()) {
+ // TODO: for the moment workaround for situations where we get errortrees
+ val res = errorTreesFinder(checked)
+ res.foreach(t => t.emit(context))
+ }
+ val result = new SearchResult(checked, subst)
incCounter(foundImplicits)
printInference("[typedImplicit1] SearchResult: " + result)
result
@@ -605,6 +621,8 @@ trait Implicits {
}
}
catch {
+ // TODO: once refactoring of type errors is done we should only
+ // catch here cyclic references.
case ex: TypeError => fail(ex.getMessage())
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 354eb52913..26e4da5d79 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -189,7 +189,7 @@ trait Infer {
private val stdErrorValue = stdErrorClass.newErrorValue(nme.ERROR)
/** The context-dependent inferencer part */
- class Inferencer(context: Context) {
+ class Inferencer(context: Context) extends InferencerErrorTrees {
/* -- Error Messages --------------------------------------------------- */
def setError[T <: Tree](tree: T): T = {
def name = newTermName("<error: " + tree.symbol + ">")
@@ -203,19 +203,20 @@ trait Infer {
tree setType ErrorType
}
+ protected def getContext = context
+
def error(pos: Position, msg: String) {
context.error(pos, msg)
}
- def errorTree(tree: Tree, msg: String): Tree = {
+/* def makeErrorTree(tree: Tree, msg: String): Tree = {
if (!tree.isErroneous) error(tree.pos, msg)
setError(tree)
- }
+ }*/
def typeError(pos: Position, found: Type, req: Type) {
if (!found.isErroneous && !req.isErroneous) {
error(pos, withAddendum(pos)(typeErrorMsg(found, req)))
-
if (settings.explaintypes.value)
explainTypes(found, req)
}
@@ -228,6 +229,8 @@ trait Infer {
"type mismatch" + foundReqMsg(found, req) + missingArgsMsg
}
+ // TODO: replace with standard Error tree
+ // currently only used in adapt in Typers
def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = {
// If the expected type is a refinement type, and the found type is a refinement or an anon
// class, we can greatly improve the error message by retyping the tree to recover the actual
@@ -287,7 +290,7 @@ trait Infer {
Console.println(tree)
Console.println("" + pre + " " + sym.owner + " " + context.owner + " " + context.outer.enclClass.owner + " " + sym.owner.thisType + (pre =:= sym.owner.thisType))
}
- new AccessError(tree, sym, pre,
+ AccessError(tree, sym, pre, context.enclClass.owner,
if (settings.check.isDefault)
analyzer.lastAccessCheckDetails
else
@@ -314,11 +317,17 @@ trait Infer {
if (settings.debug.value) ex.printStackTrace
val sym2 = underlying(sym1)
val itype = pre.memberType(sym2)
- new AccessError(tree, sym, pre,
+ return AccessError(tree, sym, pre, context.enclClass.owner,
"\n because its instance type "+itype+
(if ("malformed type: "+itype.toString==ex.msg) " is malformed"
- else " contains a "+ex.msg)).emit()
- ErrorType
+ else " contains a "+ex.msg))
+
+// enabling the following TypeError case
+// crashes a few examples because there are situations (like in NamesDefaults)
+// where CyclicReference is expected
+// case ex: TypeError =>
+// return TypeErrorTree(tree, ex)(context)
+
}
if (pre.isInstanceOf[SuperType])
owntype = owntype.substSuper(pre, site.symbol.thisType)
@@ -911,7 +920,9 @@ trait Infer {
false
}
- /** Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors).
+ /**
+ * Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors).
+ * The chance of TypeErrors should be reduced through error trees
*/
private[typechecker] def isApplicableSafe(undetparams: List[Symbol], ftpe: Type,
argtpes0: List[Type], pt: Type): Boolean = {
@@ -1092,37 +1103,20 @@ trait Infer {
*/
/** error if arguments not within bounds. */
def checkBounds(pos: Position, pre: Type, owner: Symbol,
- tparams: List[Symbol], targs: List[Type], prefix: String) = {
+ tparams: List[Symbol], targs: List[Type], prefix: String): Option[ErrorTree] = {
//@M validate variances & bounds of targs wrt variances & bounds of tparams
//@M TODO: better place to check this?
//@M TODO: errors for getters & setters are reported separately
val kindErrors = checkKindBounds(tparams, targs, pre, owner)
- if (!kindErrors.isEmpty) {
- if (targs contains WildcardType) ()
- else error(pos,
- prefix + "kinds of the type arguments " + targs.mkString("(", ",", ")") +
- " do not conform to the expected kinds of the type parameters "+
- tparams.mkString("(", ",", ")") + tparams.head.locationString+ "." +
- kindErrors.toList.mkString("\n", ", ", ""))
- }
- else if (!isWithinBounds(pre, owner, tparams, targs)) {
- if (!(targs exists (_.isErroneous)) && !(tparams exists (_.isErroneous))) {
- //val bounds = instantiatedBounds(pre, owner, tparams, targs)//DEBUG
- //println("bounds = "+bounds+", targs = "+targs+", targclasses = "+(targs map (_.getClass))+", parents = "+(targs map (_.parents)))
- //println(List.map2(bounds, targs)((bound, targ) => bound containsType targ))
- error(pos,
- prefix + "type arguments " + targs.mkString("[", ",", "]") +
- " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
- (tparams map (_.defString)).mkString("[", ",", "]"))
- if (settings.explaintypes.value) {
- val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds)
- (targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ))
- (targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi))
- ()
- }
- }
- }
+ if(!kindErrors.isEmpty) {
+ if (targs contains WildcardType) None
+ else Some(KindBoundErrors(pos, prefix, targs, tparams, kindErrors))
+ } else if (!isWithinBounds(pre, owner, tparams, targs)) {
+ if (!(targs exists (_.isErroneous)) && !(tparams exists (_.isErroneous)))
+ Some(NotWithinBounds(pos, prefix, targs, tparams, kindErrors))
+ else None
+ } else None
}
@@ -1166,7 +1160,7 @@ trait Infer {
* first to `strictPt` and then, if this fails, to `lenientPt`. If both
* attempts fail, an error is produced.
*/
- def inferArgumentInstance(tree: Tree, undetparams: List[Symbol], strictPt: Type, lenientPt: Type) {
+ def inferArgumentInstance(tree: Tree, undetparams: List[Symbol], strictPt: Type, lenientPt: Type) = {
printInference(
ptBlock("inferArgumentInstance",
"tree" -> tree,
@@ -1180,8 +1174,8 @@ trait Infer {
if ((targs eq null) || !(tree.tpe.subst(undetparams, targs) <:< strictPt)) {
targs = exprTypeArgs(undetparams, tree.tpe, lenientPt)
}
- substExpr(tree, undetparams, targs, lenientPt)
printInference("[inferArgumentInstance] finished, targs = " + targs)
+ substExpr(tree, undetparams, targs, lenientPt)
}
/** Infer type arguments `targs` for `tparams` of polymorphic expression in `tree`, given prototype `pt`.
@@ -1189,7 +1183,7 @@ trait Infer {
* Substitute `tparams` to `targs` in `tree`, after adjustment by `adjustTypeArgs`, returning the type parameters that were not determined
* If passed, infers against specified type `treeTp` instead of `tree.tp`.
*/
- def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type = WildcardType, treeTp0: Type = null, keepNothings: Boolean = true, useWeaklyCompatible: Boolean = false): List[Symbol] = {
+ def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type = WildcardType, treeTp0: Type = null, keepNothings: Boolean = true, useWeaklyCompatible: Boolean = false): (Option[ErrorTree], List[Symbol]) = {
val treeTp = if(treeTp0 eq null) tree.tpe else treeTp0 // can't refer to tree in default for treeTp0
printInference(
ptBlock("inferExprInstance",
@@ -1202,8 +1196,7 @@ trait Infer {
val targs = exprTypeArgs(tparams, treeTp, pt, useWeaklyCompatible)
if (keepNothings || (targs eq null)) { //@M: adjustTypeArgs fails if targs==null, neg/t0226
- substExpr(tree, tparams, targs, pt)
- List()
+ (substExpr(tree, tparams, targs, pt), List())
} else {
val AdjustedTypeArgs.Undets(okParams, okArgs, leftUndet) = adjustTypeArgs(tparams, targs)
printInference(
@@ -1213,8 +1206,7 @@ trait Infer {
"leftUndet" -> leftUndet
)
)
- substExpr(tree, okParams, okArgs, pt)
- leftUndet
+ (substExpr(tree, okParams, okArgs, pt), leftUndet)
}
}
@@ -1227,13 +1219,15 @@ trait Infer {
* @param pt ...
*/
private def substExpr(tree: Tree, undetparams: List[Symbol],
- targs: List[Type], pt: Type) {
+ targs: List[Type], pt: Type): Option[ErrorTree] = {
if (targs eq null) {
if (!tree.tpe.isErroneous && !pt.isErroneous)
- error(tree.pos, "polymorphic expression cannot be instantiated to expected type" +
- foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt))
+ Some(PolymorphicExpressionInstantiationError(tree, undetparams, pt))
+ else
+ None
} else {
new TreeTypeSubstituter(undetparams, targs).traverse(tree)
+ None
}
}
@@ -1248,7 +1242,7 @@ trait Infer {
* and that thus have not been substituted.
*/
def inferMethodInstance(fn: Tree, undetparams: List[Symbol],
- args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match {
+ args: List[Tree], pt0: Type): Either[ErrorTree, List[Symbol]] = fn.tpe match {
case MethodType(params0, _) =>
printInference(
ptBlock("inferMethodInstance",
@@ -1268,31 +1262,32 @@ trait Infer {
val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) =
methTypeArgs(undetparams, formals, restpe, argtpes, pt)
- checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ")
- val treeSubst = new TreeTypeSubstituter(okparams, okargs)
- treeSubst traverseTrees fn :: args
-
- val result = leftUndet match {
- case Nil => Nil
- case xs =>
- // #3890
- val xs1 = treeSubst.typeSubst mapOver xs
- if (xs ne xs1)
- new TreeSymSubstTraverser(xs, xs1) traverseTrees fn :: args
+ checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ") match {
+ case Some(err) =>
+ Left(err)
+ case _ =>
+ // bounds are ok
+ val treeSubst = new TreeTypeSubstituter(okparams, okargs)
+ treeSubst traverseTrees fn :: args
+
+ val result = leftUndet match {
+ case Nil => Nil
+ case xs =>
+ // #3890
+ val xs1 = treeSubst.typeSubst mapOver xs
+ if (xs ne xs1)
+ new TreeSymSubstTraverser(xs, xs1) traverseTrees fn :: args
+
+ xs1
+ }
+ if (result.nonEmpty)
+ printInference("inferMethodInstance, still undetermined: " + result)
- xs1
+ Right(result)
}
- if (result.nonEmpty)
- printInference("inferMethodInstance, still undetermined: " + result)
-
- result
}
catch ifNoInstance { msg =>
- errorTree(fn, "no type parameters for " +
- applyErrorMsg(fn, " exist so that it can be applied to arguments ", args map (_.tpe.widen), WildcardType) +
- "\n --- because ---\n" + msg
- )
- Nil
+ Left(NoMethodInstanceError(fn, args, msg))
}
}
@@ -1317,7 +1312,7 @@ trait Infer {
* @param undetparams the undetermined type parameters
* @param pt the expected result type of the instance
*/
- def inferConstructorInstance(tree: Tree, undetparams: List[Symbol], pt0: Type) {
+ def inferConstructorInstance(tree: Tree, undetparams: List[Symbol], pt0: Type): Option[ErrorTree] = {
val pt = widen(pt0)
//println("infer constr inst "+tree+"/"+undetparams+"/"+pt0)
var restpe = tree.tpe.finalResultType
@@ -1332,17 +1327,14 @@ trait Infer {
// checkBounds(tree.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ")
// no checkBounds here. If we enable it, test bug602 fails.
new TreeTypeSubstituter(undetparams, targs).traverse(tree)
- } catch {
- case ex: NoInstance =>
- errorTree(tree, "constructor of type " + restpe +
- " cannot be uniquely instantiated to expected type " + pt +
- "\n --- because ---\n" + ex.getMessage())
+ None
+ } catch ifNoInstance{ msg =>
+ Some(NoConstructorInstanceError(tree, restpe, pt, msg))
}
def instError = {
if (settings.debug.value) Console.println("ici " + tree + " " + undetparams + " " + pt)
if (settings.explaintypes.value) explainTypes(restpe.instantiateTypeParams(undetparams, tvars), pt)
- errorTree(tree, "constructor cannot be instantiated to expected type" +
- foundReqMsg(restpe, pt))
+ Some(ConstrInstantiationError(tree, restpe, pt))
}
if (restpe.instantiateTypeParams(undetparams, tvars) <:< pt) {
computeArgs
@@ -1360,6 +1352,7 @@ trait Infer {
val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
if (isPopulated(restpe, pt1)) {
ptvars foreach instantiateTypeVar
+ None
} else { if (settings.debug.value) Console.println("no instance: "); instError }
} else { if (settings.debug.value) Console.println("not a subtype " + restpe.instantiateTypeParams(undetparams, tvars) + " of " + ptWithWildcards); instError }
} else { if (settings.debug.value) Console.println("not fully defined: " + pt); instError }
@@ -1412,11 +1405,12 @@ trait Infer {
}
}
- def checkCheckable(pos: Position, tp: Type, kind: String) {
+ def checkCheckable(pos: Position, tp: Type, kind: String): Option[ErrorTree] = {
def patternWarning(tp0: Type, prefix: String) = {
context.unit.uncheckedWarning(pos, prefix+tp0+" in type "+kind+tp+" is unchecked since it is eliminated by erasure")
}
- def check(tp: Type, bound: List[Symbol]) {
+ def check(tp: Type, bound: List[Symbol]): Option[ErrorTree] = {
+ implicit def listErrorsToPending(l: List[ErrorTree]): Option[ErrorTree] = if (l.isEmpty) None else Some(PendingErrors(l))
def isLocalBinding(sym: Symbol) =
sym.isAbstractType &&
((bound contains sym) ||
@@ -1428,36 +1422,38 @@ trait Infer {
case SingleType(pre, _) =>
check(pre, bound)
case TypeRef(pre, sym, args) =>
- if (sym.isAbstractType) {
+ val checkForSymAndArgs: Option[ErrorTree] = if (sym.isAbstractType) {
if (!isLocalBinding(sym)) patternWarning(tp, "abstract type ")
+ None
} else if (sym.isAliasType) {
check(tp.normalize, bound)
} else if (sym == NothingClass || sym == NullClass || sym == AnyValClass) {
- error(pos, "type "+tp+" cannot be used in a type pattern or isInstanceOf test")
+ Some(TypePatternOrIsInstanceTestError(pos, tp))
} else {
- for (arg <- args) {
+ args.map( arg => {
if (sym == ArrayClass) check(arg, bound)
- else if (arg.typeArgs.nonEmpty) () // avoid spurious warnings with higher-kinded types
- else arg match {
+ else if (arg.typeArgs.nonEmpty) None // avoid spurious warnings with higher-kinded types
+ else {arg match {
case TypeRef(_, sym, _) if isLocalBinding(sym) =>
- ;
+
case _ =>
patternWarning(arg, "non variable type-argument ")
- }
- }
+ }; None}
+ }).flatten
}
- check(pre, bound)
+ List(checkForSymAndArgs, check(pre, bound)).flatten
case RefinedType(parents, decls) =>
- if (decls.isEmpty) for (p <- parents) check(p, bound)
- else patternWarning(tp, "refinement ")
+ if (decls.isEmpty) parents.map(p => check(p, bound)).flatten
+ else { patternWarning(tp, "refinement "); None }
case ExistentialType(quantified, tp1) =>
check(tp1, bound ::: quantified)
case ThisType(_) =>
- ;
+ None
case NoPrefix =>
- ;
+ None
case _ =>
patternWarning(tp, "type ")
+ None
}
}
check(tp, List())
@@ -1480,7 +1476,7 @@ trait Infer {
}
}
- def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Type = {
+ def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Either[ErrorTree, Type] = {
val pt = widen(pt0)
val ptparams = freeTypeParamsOfTerms.collect(pt)
val tpparams = freeTypeParamsOfTerms.collect(pattp)
@@ -1493,9 +1489,13 @@ trait Infer {
* and is a "final type", meaning final + invariant in all type parameters.
*/
if (pt.isFinalType && ptparams.isEmpty && !ptMatchesPattp)
- error(pos, "scrutinee is incompatible with pattern type" + foundReqMsg(pattp, pt))
+ return Left(IncompatibleScrutineeTypeError(pos, pattp, pt))
- checkCheckable(pos, pattp, "pattern ")
+ checkCheckable(pos, pattp, "pattern ") match {
+ case Some(err) =>
+ return Left(err)
+ case _ => ()
+ }
if (pattp <:< pt) ()
else {
debuglog("free type params (1) = " + tpparams)
@@ -1517,10 +1517,8 @@ trait Infer {
// fail if we didn't allow for pattpMatchesPt.
if (isPopulated(tp, pt1) && isInstantiatable(tvars ++ ptvars) || pattpMatchesPt)
ptvars foreach instantiateTypeVar
- else {
- error(pos, "pattern type is incompatible with expected type" + foundReqMsg(pattp, pt))
- return pattp
- }
+ else
+ return Left(IncompletePatternTypeError(pos, pattp, pt))
}
tvars foreach instantiateTypeVar
}
@@ -1528,43 +1526,22 @@ trait Infer {
* we have to flip the arguments so the expected type is treated as more
* general when calculating the intersection. See run/bug2755.scala.
*/
- if (tpparams.isEmpty && ptparams.nonEmpty) intersect(pattp, pt)
- else intersect(pt, pattp)
+ if (tpparams.isEmpty && ptparams.nonEmpty) Right(intersect(pattp, pt))
+ else Right(intersect(pt, pattp))
}
- def inferModulePattern(pat: Tree, pt: Type) =
+ def inferModulePattern(pat: Tree, pt: Type): Option[ErrorTree] =
if (!(pat.tpe <:< pt)) {
val ptparams = freeTypeParamsOfTerms.collect(pt)
debuglog("free type params (2) = " + ptparams)
val ptvars = ptparams map freshVar
val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
- if (pat.tpe <:< pt1)
+ if (pat.tpe <:< pt1) {
ptvars foreach instantiateTypeVar
- else {
- val sym = pat.tpe.typeSymbol
- val clazz = sym.companionClass
- val addendum = (
- if (sym.isModuleClass && clazz.isCaseClass && (clazz isSubClass pt1.typeSymbol)) {
- // TODO: move these somewhere reusable.
- val typeString = clazz.typeParams match {
- case Nil => "" + clazz.name
- case xs => xs map (_ => "_") mkString (clazz.name + "[", ",", "]")
- }
- val caseString = (
- clazz.caseFieldAccessors
- map (_ => "_") // could use the actual param names here
- mkString (clazz.name + "(", ",", ")")
- )
- (
- "\nNote: if you intended to match against the class, try `case _: " +
- typeString + "` or `case " + caseString + "`"
- )
- }
- else ""
- )
- error(pat.pos, "pattern type is incompatible with expected type"+foundReqMsg(pat.tpe, pt) + addendum)
- }
- }
+ None
+ } else
+ Some(PatternTypeIncompatibleWithPtError(pat, pt1, pt))
+ } else None
object toOrigin extends TypeMap {
def apply(tp: Type): Type = tp match {
@@ -1631,7 +1608,7 @@ trait Infer {
* If several alternatives match `pt`, take parameterless one.
* If no alternative matches `pt`, take the parameterless one anyway.
*/
- def inferExprAlternative(tree: Tree, pt: Type): Unit = tree.tpe match {
+ def inferExprAlternative(tree: Tree, pt: Type): Option[ErrorTree] = tree.tpe match {
case OverloadedType(pre, alts) => tryTwice {
val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt))
val secondTry = alts0.isEmpty
@@ -1662,24 +1639,27 @@ trait Infer {
case _ =>
}
}
- typeErrorTree(tree, tree.symbol.tpe, pt)
+ Some(NoBestExprAlternativeError(tree, pt))
} else if (!competing.isEmpty) {
if (secondTry) {
- typeErrorTree(tree, tree.symbol.tpe, pt)
+ Some(NoBestExprAlternativeError(tree, pt))
} else {
if (!pt.isErroneous)
- context.ambiguousError(tree.pos, pre, best, competing.head, "expected type " + pt)
- setError(tree)
+ Some(AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt))
+ else
+ Some(NullErrorTree) // already reported
}
} else {
// val applicable = alts1 filter (alt =>
// global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt))
// checkNotShadowed(tree.pos, pre, best, applicable)
tree.setSymbol(best).setType(pre.memberType(best))
+ None
}
}
}
+ // TODO: remove once error tree refactoring is done
@inline private def wrapTypeError(expr: => Boolean): Boolean =
try expr
catch { case _: TypeError => false }
@@ -1743,7 +1723,7 @@ trait Infer {
* assignment expression.
*/
def inferMethodAlternative(tree: Tree, undetparams: List[Symbol],
- argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Unit = tree.tpe match {
+ argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Option[ErrorTree] = tree.tpe match {
case OverloadedType(pre, alts) =>
val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
tryTwice {
@@ -1770,24 +1750,22 @@ trait Infer {
if (improves(alt, best)) alt else best)
val competing = applicable.dropWhile(alt => best == alt || improves(best, alt))
if (best == NoSymbol) {
- if (pt == WildcardType) {
- errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt))
- } else {
+ if (pt == WildcardType)
+ Some(NoBestMethodAlternativeError(tree, argtpes, pt))
+ else
inferMethodAlternative(tree, undetparams, argtpes, WildcardType)
- }
} else if (!competing.isEmpty) {
if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous)
- context.ambiguousError(tree.pos, pre, best, competing.head,
- "argument types " + argtpes.mkString("(", ",", ")") +
- (if (pt == WildcardType) "" else " and expected result type " + pt))
- setError(tree)
- ()
+ Some(AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt))
+ else
+ Some(NullErrorTree)
} else {
// checkNotShadowed(tree.pos, pre, best, applicable)
tree.setSymbol(best).setType(pre.memberType(best))
+ None
}
}
- case _ =>
+ case _ => None
}
/** Try inference twice, once without views and once with views,
@@ -1795,18 +1773,25 @@ trait Infer {
*
* @param infer ...
*/
- def tryTwice(infer: => Unit) {
+ def tryTwice(infer: => Option[ErrorTree]): Option[ErrorTree] = {
if (context.implicitsEnabled) {
val reportGeneralErrors = context.reportGeneralErrors
context.reportGeneralErrors = false
- try context.withImplicitsDisabled(infer)
- catch {
+ val res = try {
+ context.withImplicitsDisabled(infer) match {
+ case Some(err) =>
+ context.reportGeneralErrors = reportGeneralErrors
+ infer
+ case ok => ok
+ }
+ } catch {
case ex: CyclicReference => throw ex
case ex: TypeError =>
context.reportGeneralErrors = reportGeneralErrors
infer
}
context.reportGeneralErrors = reportGeneralErrors
+ res
}
else infer
}
@@ -1818,10 +1803,10 @@ trait Infer {
* @param tree ...
* @param nparams ...
*/
- def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Unit = {
+ def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Option[ErrorTree] = {
val OverloadedType(pre, alts) = tree.tpe
val sym0 = tree.symbol filter (alt => sameLength(alt.typeParams, argtypes))
- def fail(msg: String): Unit = error(tree.pos, msg)
+ def fail(msg: String) = Some(PolyAlternativeError(tree, msg))
if (sym0 == NoSymbol) return fail(
if (alts exists (_.typeParams.nonEmpty))
@@ -1835,12 +1820,13 @@ trait Infer {
else {
val sym = sym0 filter (alt => isWithinBounds(pre, alt.owner, alt.typeParams, argtypes))
if (sym == NoSymbol) {
- if (argtypes forall (x => !x.isErroneous)) fail(
+ if (argtypes forall (x => !x.isErroneous))
+ return fail(
"type arguments " + argtypes.mkString("[", ",", "]") +
" conform to the bounds of none of the overloaded alternatives of\n "+sym0+
": "+sym0.info
)
- return
+ return None
}
else if (sym.isOverloaded) {
val xs = sym.alternatives
@@ -1855,24 +1841,7 @@ trait Infer {
}
// Side effects tree with symbol and type
tree setSymbol resSym setType resTpe
- }
-
- abstract class TreeForwarder(forwardTo: Tree) extends Tree {
- override def pos = forwardTo.pos
- override def hasSymbol = forwardTo.hasSymbol
- override def symbol = forwardTo.symbol
- override def symbol_=(x: Symbol) = forwardTo.symbol = x
- }
-
- case class AccessError(tree: Tree, sym: Symbol, pre: Type, explanation: String) extends TreeForwarder(tree) {
- setError(this)
-
- // @PP: It is improbable this logic shouldn't be in use elsewhere as well.
- private def location = if (sym.isClassConstructor) context.enclClass.owner else pre.widen
- def emit(): Tree = {
- val realsym = underlying(sym)
- errorTree(tree, realsym.fullLocationString + " cannot be accessed in " + location + explanation)
- }
+ None
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 56651f9af9..5a336d9027 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -65,13 +65,26 @@ trait Namers { self: Analyzer =>
classAndNamerOfModule.clear
}
- abstract class Namer(val context: Context) {
+ abstract class Namer(val context: Context) extends NamerErrorTrees {
val typer = newTyper(context)
def setPrivateWithin[Sym <: Symbol](tree: Tree, sym: Sym, mods: Modifiers): Sym = {
- if (mods.hasAccessBoundary)
- sym.privateWithin = typer.qualifyingClass(tree, mods.privateWithin, true)
+ if (mods.hasAccessBoundary) {
+ val symOrError = typer.qualifyingClass(tree, mods.privateWithin, true) match {
+ case Left(err) =>
+ try {
+ err.emit(context)
+ } catch {
+ case _: TypeError =>
+ assert(false, "qualifying class info can fail but cannot throw type errors")
+ }
+ NoSymbol
+ case Right(sym) =>
+ sym
+ }
+ sym.privateWithin = symOrError
+ }
sym
}
@@ -151,6 +164,7 @@ trait Namers { self: Analyzer =>
private def setInfo[Sym <: Symbol](sym : Sym)(tpe : LazyType) : Sym = sym.setInfo(tpe)
+ // TODO: make it into error trees
private def doubleDefError(pos: Position, sym: Symbol) {
val s1 = if (sym.isModule) "case class companion " else ""
val s2 = if (sym.isSynthetic) "(compiler-generated) " + s1 else ""
@@ -634,10 +648,18 @@ trait Namers { self: Analyzer =>
case _ =>
}
sym.setInfo(if (sym.isJavaDefined) RestrictJavaArraysMap(tp) else tp)
- if ((sym.isAliasType || sym.isAbstractType) && !sym.isParameter &&
- !typer.checkNonCyclic(tree.pos, tp))
- sym.setInfo(ErrorType) // this early test is there to avoid infinite baseTypes when
- // adding setters and getters --> bug798
+ if ((sym.isAliasType || sym.isAbstractType) && !sym.isParameter) {
+ val check = typer.checkNonCyclic(tree.pos, tp)
+ if (check.isDefined) {
+ sym.setInfo(ErrorType) // this early test is there to avoid infinite baseTypes when
+ // adding setters and getters --> bug798
+ try {
+ check.get.emit(context)
+ } catch {
+ case _: TypeError => assert(false, "Type errors cannot be thrown in type completers")
+ }
+ }
+ }
debuglog("defined " + sym);
validate(sym)
}
@@ -803,7 +825,14 @@ trait Namers { self: Analyzer =>
}
*/
- var parents = typer.parentTypes(templ) map checkParent
+ var parents0 = typer.parentTypes(templ)
+ try {
+ parents0.foreach(p => if (p.containsError()) typer.emitAllErrorTrees(p, context))
+ } catch {
+ case _: TypeError =>
+ assert(false, "parent types cannot throw type errors")
+ }
+ val parents = parents0 map checkParent
enterSelf(templ.self)
val decls = new Scope
// for (etdef <- earlyTypes) decls enter etdef.symbol
@@ -1287,7 +1316,10 @@ trait Namers { self: Analyzer =>
case Import(expr, selectors) =>
val expr1 = typer.typedQualifier(expr)
- typer checkStable expr1
+ val stable = typer.checkStable(expr1)
+ if (stable.containsError())
+ typer.emitAllErrorTrees(stable, context)
+
if (expr1.symbol != null && expr1.symbol.isRootPackage)
context.error(tree.pos, "_root_ cannot be imported")
@@ -1303,7 +1335,10 @@ trait Namers { self: Analyzer =>
} catch {
case ex: TypeError =>
//Console.println("caught " + ex + " in typeSig")
- typer.reportTypeError(tree.pos, ex)
+ // TODO: once ErrorTrees are implemented we should be able
+ // to get rid of this catch and simply report the error
+ // (maybe apart from cyclic errors)
+ TypeSigError(tree, ex).emit(context)
ErrorType
}
result match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index bf7cc72fab..cef099e371 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -304,7 +304,9 @@ trait NamesDefaults { self: Analyzer =>
// `fun` is typed. `namelessArgs` might be typed or not, if they are types are kept.
case Apply(fun, namelessArgs) =>
val transformedFun = transformNamedApplication(typer, mode, pt)(fun, x => x)
- if (transformedFun.isErroneous) setError(tree)
+ // Is it safe to replace containsError() with containsErrorOrIsErrorTyped()?
+ if (transformedFun.containsError()) transformedFun
+ else if (transformedFun.isErroneous) NullErrorTree
else {
assert(isNamedApplyBlock(transformedFun), transformedFun)
val NamedApplyInfo(qual, targs, vargss, blockTyper) =
@@ -313,8 +315,7 @@ trait NamesDefaults { self: Analyzer =>
// type the application without names; put the arguments in definition-site order
val typedApp = doTypedApply(tree, funOnly, reorderArgs(namelessArgs, argPos), mode, pt)
-
- if (typedApp.tpe.isError) setError(tree)
+ if (typedApp.containsErrorOrIsErrorTyped()) typedApp
else typedApp match {
// Extract the typed arguments, restore the call-site evaluation order (using
// ValDef's in the block), change the arguments to these local values.
@@ -439,7 +440,6 @@ trait NamesDefaults { self: Analyzer =>
* after named ones.
*/
def removeNames(typer: Typer)(args: List[Tree], params: List[Symbol]): (List[Tree], Array[Int]) = {
- import typer.infer.errorTree
// maps indicies from (order written by user) to (order of definition)
val argPos = (new Array[Int](args.length)) map (x => -1)
@@ -457,10 +457,10 @@ trait NamesDefaults { self: Analyzer =>
// treat the arg as an assignment of type Unit
Assign(a.lhs, rhs).setPos(arg.pos)
} else {
- errorTree(arg, "unknown parameter name: "+ name)
+ UnknwonParameterNameNamesDefaultError(arg, name)
}
} else if (argPos contains pos) {
- errorTree(arg, "parameter specified twice: "+ name)
+ DoubleParamNamesDefaultError(arg, name)
} else {
// for named arguments, check whether the assignment expression would
// typecheck. if it does, report an ambiguous error.
@@ -481,26 +481,20 @@ trait NamesDefaults { self: Analyzer =>
val reportAmbiguousErrors = typer.context.reportAmbiguousErrors
typer.context.reportAmbiguousErrors = false
- var variableNameClash = false
val typedAssign = try {
typer.silent(_.typed(arg, subst(paramtpe)))
} catch {
// `silent` only catches and returns TypeErrors which are not
// CyclicReferences. Fix for #3685
+
+ // Returning CyclicReference error trees is problematic
+ // so we stay with throwing exceptions
case cr @ CyclicReference(sym, info) if sym.name == param.name =>
if (sym.isVariable || sym.isGetter && sym.accessed.isVariable) {
// named arg not allowed
- variableNameClash = true
- typer.context.error(sym.pos,
- "%s definition needs %s because '%s' is used as a named argument in its body.".format(
- "variable", // "method"
- "type", // "result type"
- sym.name
- )
- )
- typer.infer.setError(arg)
+ NameClashError(sym, arg)
}
- else cr
+ else NullErrorTree
}
def applyNamedArg = {
@@ -513,28 +507,27 @@ trait NamesDefaults { self: Analyzer =>
}
val res = typedAssign match {
- case _: TypeError => applyNamedArg
-
+ case err: NameClashError =>
+ err
+ case _: TypeError =>
+ // TODO: is should be safe to remove this case after error trees are fully implemented
+ applyNamedArg
+ case t: Tree if t.containsErrorOrIsErrorTyped() =>
+ // containsErrorOrIsErrorTyped() needed because of for instance #4041
+ applyNamedArg
case t: Tree =>
- if (t.isErroneous && !variableNameClash) {
- applyNamedArg
- } else if (t.isErroneous) {
- t // name clash with variable. error was already reported above.
- } else {
- // This throws an exception which is caught in `tryTypedApply` (as it
- // uses `silent`) - unfortunately, tryTypedApply recovers from the
- // exception if you use errorTree(arg, ...) and conforms is allowed as
- // a view (see tryImplicit in Implicits) because it tries to produce a
- // new qualifier (if the old one was P, the new one will be
- // conforms.apply(P)), and if that works, it pretends nothing happened.
- //
- // To make sure tryTypedApply fails, we would like to pass EmptyTree
- // instead of arg, but can't do that because eventually setType(ErrorType)
- // is called, and EmptyTree can only be typed NoType. Thus we need to
- // disable conforms as a view...
- errorTree(arg, "reference to "+ name +" is ambiguous; it is both, a parameter\n"+
- "name of the method and the name of a variable currently in scope.")
- }
+ // This throws an exception which is caught in `tryTypedApply` (as it
+ // uses `silent`) - unfortunately, tryTypedApply recovers from the
+ // exception if you use errorTree(arg, ...) and conforms is allowed as
+ // a view (see tryImplicit in Implicits) because it tries to produce a
+ // new qualifier (if the old one was P, the new one will be
+ // conforms.apply(P)), and if that works, it pretends nothing happened.
+ //
+ // To make sure tryTypedApply fails, we would like to pass EmptyTree
+ // instead of arg, but can't do that because eventually setType(ErrorType)
+ // is called, and EmptyTree can only be typed NoType. Thus we need to
+ // disable conforms as a view...
+ AmbiguousReferenceInNamesDefaultError(arg, name)
}
typer.context.reportAmbiguousErrors = reportAmbiguousErrors
@@ -546,8 +539,9 @@ trait NamesDefaults { self: Analyzer =>
case _ =>
argPos(index) = index
if (positionalAllowed) arg
- else errorTree(arg, "positional after named argument.")
+ else PositionalAfterNamedNamesDefaultError(arg)
}
+
(namelessArgs, argPos)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 10918ecffa..c05a5e721e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1150,10 +1150,15 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
/* Check whether argument types conform to bounds of type parameters */
private def checkBounds(pre: Type, owner: Symbol, tparams: List[Symbol], argtps: List[Type], pos: Position): Unit =
- try typer.infer.checkBounds(pos, pre, owner, tparams, argtps, "")
+ try typer.infer.checkBounds(pos, pre, owner, tparams, argtps, "") match {
+ case Some(err) => err.emit(typer.context)
+ case _ => ()
+ }
catch {
case ex: TypeError =>
- unit.error(pos, ex.getMessage());
+ // checkBounds no longer throws errors (apart from Cyclic ones)
+ // so maybe it is safe to remove/simplify this catch?
+ unit.error(pos, ex.getMessage())
if (settings.explaintypes.value) {
val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, argtps).bounds)
(argtps, bounds).zipped map ((targ, bound) => explainTypes(bound.lo, targ))
@@ -1310,7 +1315,13 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
case tpt@TypeTree() =>
if(tpt.original != null) {
tpt.original foreach {
- case dc@TypeTreeWithDeferredRefCheck() => applyRefchecksToAnnotations(dc.check()) // #2416
+ case dc@TypeTreeWithDeferredRefCheck() =>
+ dc.check() match {
+ case Left(err) =>
+ err.emit()
+ case Right(t) =>
+ applyRefchecksToAnnotations(t) // #2416
+ }
case _ =>
}
}
@@ -1474,8 +1485,11 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
if(tpt.original != null) {
tpt.original foreach {
case dc@TypeTreeWithDeferredRefCheck() =>
- transform(dc.check()) // #2416 -- only call transform to do refchecks, but discard results
- // tpt has the right type if the deferred checks are ok
+ dc.check() match {
+ case Left(err) => err.emit()
+ case Right(tree) => transform(tree) // #2416 -- only call transform to do refchecks, but discard results
+ // tpt has the right type if the deferred checks are ok
+ }
case _ =>
}
}
@@ -1551,7 +1565,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
result
} catch {
case ex: TypeError =>
- if (settings.debug.value) ex.printStackTrace();
+ if (settings.debug.value) ex.printStackTrace()
unit.error(tree.pos, ex.getMessage())
tree
} finally {
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 03d1c66a36..35709ac40c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -52,10 +52,11 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
private def checkPackedConforms(tree: Tree, pt: Type): Tree = {
if (tree.tpe exists (_.typeSymbol.isExistentialSkolem)) {
val packed = localTyper.packedType(tree, NoSymbol)
- if (!(packed <:< pt)) {
+ packed._2.foreach(_.emit())
+ if (!(packed._1 <:< pt)) {
val errorContext = localTyper.context.make(localTyper.context.tree)
errorContext.reportGeneralErrors = true
- analyzer.newTyper(errorContext).infer.typeError(tree.pos, packed, pt)
+ analyzer.newTyper(errorContext).infer.typeError(tree.pos, packed._1, pt)
}
}
tree
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 9a8bcca2ba..6eaa65ce9b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -41,7 +41,7 @@ trait SyntheticMethods extends ast.TreeDSL {
import CODE._
val localTyper = newTyper(
- if (reporter.hasErrors) context makeSilent false else context
+ if (reporter.hasErrors || templ.containsError()) context makeSilent false else context
)
def accessorTypes = clazz.caseFieldAccessors map (_.tpe.finalResultType)
def accessorLub = global.weakLub(accessorTypes)._1
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 6e0e78e8e2..0b84e67447 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -135,21 +135,6 @@ trait TypeDiagnostics {
def alternativesString(tree: Tree) =
alternatives(tree) map (x => " " + methodTypeErrorString(x)) mkString ("", " <and>\n", "\n")
- def missingParameterTypeMsg(fun: Tree, vparam: ValDef, pt: Type) = {
- def anonMessage = (
- "\nThe argument types of an anonymous function must be fully known. (SLS 8.5)" +
- "\nExpected type was: " + pt.toLongString
- )
- val suffix =
- if (!vparam.mods.isSynthetic) ""
- else " for expanded function" + (fun match {
- case Function(_, Match(_, _)) => anonMessage
- case _ => " " + fun
- })
-
- "missing parameter type" + suffix
- }
-
def treeSymTypeMsg(tree: Tree): String = {
val sym = tree.symbol
def hasParams = tree.tpe.paramSectionCount > 0
@@ -168,34 +153,6 @@ trait TypeDiagnostics {
else defaultMessage
}
- def notEnoughArgumentsMsg(fun: Tree, missing: List[Symbol]): String = {
- val suffix = {
- if (missing.isEmpty) ""
- else {
- val keep = missing take 3 map (_.name)
- ".\nUnspecified value parameter%s %s".format(
- if (missing.tail.isEmpty) "" else "s",
- if (missing drop 3 nonEmpty) (keep :+ "...").mkString(", ")
- else keep.mkString("", ", ", ".")
- )
- }
- }
-
- "not enough arguments for " + treeSymTypeMsg(fun) + suffix
- }
-
- def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = {
- def asParams(xs: List[Any]) = xs.mkString("(", ", ", ")")
-
- def resType = if (pt isWildcard) "" else " with expected result type " + pt
- def allTypes = (alternatives(tree) flatMap (_.paramTypes)) ++ argtpes :+ pt
- def locals = alternatives(tree) flatMap (_.typeParams)
-
- withDisambiguation(locals, allTypes: _*) {
- treeSymTypeMsg(tree) + msg + asParams(argtpes) + resType
- }
- }
-
def disambiguate(ss: List[String]) = ss match {
case Nil => Nil
case s :: ss => s :: (ss map { case `s` => "(some other)"+s ; case x => x })
@@ -405,8 +362,10 @@ trait TypeDiagnostics {
trait TyperDiagnostics {
self: Typer =>
- private def contextError(pos: Position, msg: String) = context.error(pos, msg)
- private def contextError(pos: Position, err: Throwable) = context.error(pos, err)
+ private def contextError(pos: Position, msg: String) { contextError(context, pos, msg) }
+ private def contextError(context0: Analyzer#Context, pos: Position, msg: String) { context0.error(pos, msg) }
+ private def contextError(pos: Position, err: Throwable) { contextError(context, pos, err) }
+ private def contextError(context0: Analyzer#Context, pos: Position, err: Throwable) { context0.error(pos, err) }
object checkDead {
private var expr: Symbol = NoSymbol
@@ -440,36 +399,46 @@ trait TypeDiagnostics {
}
}
- def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded
- def cyclicAdjective(sym: Symbol) = if (symWasOverloaded(sym)) "overloaded" else "recursive"
+ private def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded
+ private def cyclicAdjective(sym: Symbol) = if (symWasOverloaded(sym)) "overloaded" else "recursive"
/** Returns Some(msg) if the given tree is untyped apparently due
* to a cyclic reference, and None otherwise.
*/
- def cyclicReferenceMessage(sym: Symbol, tree: Tree) = condOpt(tree) {
+ private def cyclicReferenceMessage(sym: Symbol, tree: Tree) = condOpt(tree) {
case ValDef(_, _, tpt, _) if tpt.tpe == null => "recursive "+sym+" needs type"
case DefDef(_, _, _, _, tpt, _) if tpt.tpe == null => List(cyclicAdjective(sym), sym, "needs result type") mkString " "
}
+ def reportTypeError(pos: Position, ex: TypeError) {
+ reportTypeError(context, pos, ex)
+ }
+
/** Report a type error.
*
* @param pos0 The position where to report the error
* @param ex The exception that caused the error
*/
- def reportTypeError(pos: Position, ex: TypeError) {
+ def reportTypeError(context0: Analyzer#Context, pos: Position, ex: TypeError) {
if (ex.pos == NoPosition) ex.pos = pos
- if (!context.reportGeneralErrors) throw ex
+ if (!context0.reportGeneralErrors) throw ex
if (settings.debug.value) ex.printStackTrace()
ex match {
case CyclicReference(sym, info: TypeCompleter) =>
- contextError(ex.pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
+ contextError(context0, ex.pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage())
if (sym == ObjectClass)
throw new FatalError("cannot redefine root "+sym)
case _ =>
- contextError(ex.pos, ex)
+ contextError(context0, ex.pos, ex)
}
}
+
+ def emitAllErrorTrees(tree: Tree, context: Context) =
+ errorTreesFinder(tree).foreach(_.emit(context))
+
+ def findAllNestedErrors(trees: List[Tree]): List[ErrorTree] =
+ trees.map(errorTreesFinder(_)).flatten
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index eb5a575596..e6b23d6097 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -12,13 +12,13 @@
package scala.tools.nsc
package typechecker
-import scala.collection.{ mutable, immutable }
-import scala.tools.nsc.util.BatchSourceFile
+import scala.collection.mutable
import mutable.ListBuffer
+
+import scala.tools.nsc.util.BatchSourceFile
import symtab.Flags._
-import util.Statistics
import util.Statistics._
-import scala.tools.util.StringOps.{ countAsString, countElementsAsString }
+import util.Statistics
// Suggestion check whether we can do without priming scopes with symbols of outer scopes,
// like the IDE does.
@@ -59,7 +59,7 @@ trait Typers extends Modes with Adaptations {
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) =>
@@ -77,7 +77,7 @@ trait Typers extends Modes with Adaptations {
// that are turned private by typedBlock
private final val SYNTHETIC_PRIVATE = TRANS_FLAG
- abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation {
+ abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with TyperErrorTrees {
import context0.unit
import typeDebug.{ ptTree, ptBlock, ptLine }
@@ -99,15 +99,6 @@ trait Typers extends Modes with Adaptations {
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
@@ -124,8 +115,9 @@ trait Typers extends Modes with Adaptations {
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) {
+ argBuff += 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
@@ -186,6 +178,20 @@ trait Typers extends Modes with Adaptations {
var context = context0
def context1 = context
+ @inline
+ private def logErrorTree(t: Tree, buffer: List[ErrorTree]) = {
+ t match {
+ case et: ErrorTree =>
+ et::buffer
+ case _ =>
+ buffer
+ }
+ }
+
+ @inline
+ private def wrapInBlock(errTree: Tree, original: Tree): Tree = Block(errTree, original) setType ErrorType
+
+
def dropExistential(tp: Type): Type = tp match {
case ExistentialType(tparams, tpe) =>
new SubstWildcardMap(tparams).apply(tp)
@@ -202,22 +208,12 @@ trait Typers extends Modes with Adaptations {
* @return ...
*/
def checkStable(tree: Tree): Tree =
- if (treeInfo.isPureExpr(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.isPureExpr(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
@@ -231,21 +227,21 @@ trait Typers extends Modes with Adaptations {
}
/** 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) = {
+ def errorNotClass(found: AnyRef) = Some(ClassTypeRequiredError(tpt, found))
+ def check(tpe: Type): Option[ErrorTree] = tpe.normalize match {
case TypeRef(pre, sym, _) if sym.isClass && !sym.isRefinementClass =>
- if (stablePrefix && phase.id <= currentRun.typerPhase.id) {
+ if (stablePrefix && phase.id <= currentRun.typerPhase.id)
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 {
+ Some(TypeNotAStablePrefixError(pre, tpt.pos))
+ else
+ tpt match {
case SelectFromTypeTree(qual, _) if !isSingleType(qual.tpe) => errorNotClass(tpt)
- case _ => ;
- }
- }
- case ErrorType => ;
+ case _ => None
+ }
+ else
+ None
+ case ErrorType => None
case PolyType(_, restpe) => check(restpe)
case ExistentialType(_, restpe) if existentialOK => check(restpe)
case AnnotatedType(_, underlying, _) => check(underlying)
@@ -260,18 +256,19 @@ trait Typers extends Modes with Adaptations {
* @param tp ...
* @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 checkNonCyclic(pos: Position, tp: Type): Option[ErrorTree] = {
+ def checkNotLocked(sym: Symbol): Option[ErrorTree] = {
sym.initialize
- sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false}
+ if (sym.lockOK) None
+ else Some(CyclicAliasingOrSubtypingError(pos, sym))
}
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)
- )
+ val check = checkNotLocked(sym)
+ if (check.isDefined) check
+ else if (!sym.isNonClassType) None
+ else checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym)
+
case SingleType(pre, sym) =>
checkNotLocked(sym)
/*
@@ -283,51 +280,70 @@ trait Typers extends Modes with Adaptations {
case st: SubType =>
checkNonCyclic(pos, st.supertype)
case ct: CompoundType =>
- ct.parents forall (x => checkNonCyclic(pos, x))
+ val checkRes = ct.parents map (x => checkNonCyclic(pos, x)) flatten
+
+ if (checkRes.isEmpty) None
+ else Some(PendingErrors(checkRes))
case _ =>
- true
+ None
}
}
- def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Boolean = try {
+ // TODO in order to return CyclicReferenceError we need to change the signature of lock
+ // let's leave it for now
+ def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Option[ErrorTree] = try {
lockedSym.lock {
throw new TypeError("illegal cyclic reference involving " + lockedSym)
}
checkNonCyclic(pos, tp)
+ } catch {
+ case _ :TypeError =>
+ Some(CyclicReferenceError(pos, lockedSym))
} finally {
lockedSym.unlock()
}
- def checkNonCyclic(sym: Symbol) {
- if (!checkNonCyclic(sym.pos, sym.tpe)) sym.setInfo(ErrorType)
+ def checkNonCyclic(sym: Symbol): Option[ErrorTree] = {
+ val check = checkNonCyclic(sym.pos, sym.tpe)
+ if (check.isDefined)
+ sym.setInfo(ErrorType)
+ check
}
- def checkNonCyclic(defn: Tree, tpt: Tree) {
- if (!checkNonCyclic(defn.pos, tpt.tpe, defn.symbol)) {
+ def checkNonCyclic(defn: Tree, tpt: Tree): Option[ErrorTree] = {
+ val check = checkNonCyclic(defn.pos, tpt.tpe, defn.symbol)
+ if (check.isDefined) {
tpt.tpe = ErrorType
defn.symbol.setInfo(ErrorType)
}
+ check
}
- 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(pos: Position, tpe0: Type): List[ErrorTree] = {
+ var pending: List[ErrorTree] = List()
+ 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)
+ pending = logErrorTree(DependentMethodTpeConversionToFunctionError(pos, tpe), pending)
+ checkParamsConvertible(pos, restpe)
+ case _ =>
+ }
+ checkParamsConvertible0(tpe0)
+ pending
}
- def checkStarPatOK(pos: Position, mode: Int) =
+ @inline
+ private def checkStarPatOK(pos: Position, mode: Int):Option[ErrorTree] =
if ((mode & STARmode) == 0 && phase.id <= currentRun.typerPhase.id)
- error(pos, "star patterns must correspond with varargs parameters")
+ Some(StarPatternWithVarargParametersError(pos))
+ else None
/** Check that type of given tree does not contain local or private
* components.
@@ -345,7 +361,7 @@ trait Typers extends Modes with Adaptations {
* @param tree ...
* @return ...
*/
- def privates[T <: Tree](owner: Symbol, tree: T): T =
+ def privates(owner: Symbol, tree: Tree): Tree =
check(owner, EmptyScope, WildcardType, tree)
/** Check that type <code>tree</code> does not refer to entities
@@ -356,16 +372,16 @@ trait Typers extends Modes with Adaptations {
* @param tree ...
* @return ...
*/
- def locals[T <: Tree](scope: Scope, pt: Type, tree: T): T =
+ def locals(scope: Scope, pt: Type, tree: Tree): Tree =
check(NoSymbol, scope, pt, tree)
- def check[T <: Tree](owner: Symbol, scope: Scope, pt: Type, tree: T): T = {
+ private def check(owner: Symbol, scope: Scope, pt: Type, tree: Tree): Tree = {
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) //setError(tree)
else if (isFullyDefined(pt)) tree setType pt //todo: eliminate
else if (tp1.typeSymbol.isAnonymousClass) // todo: eliminate
check(owner, scope, pt, tree setType tp1.typeSymbol.classBound)
@@ -373,10 +389,7 @@ trait Typers extends Modes with Adaptations {
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
}
@@ -439,16 +452,12 @@ trait Typers extends Modes with Adaptations {
/** The qualifying class
* of a this or super with prefix <code>qual</code>.
*/
- def qualifyingClass(tree: Tree, qual: Name, packageOK: Boolean): Symbol =
+ def qualifyingClass(tree: Tree, qual: Name, packageOK: Boolean): Either[ErrorTree, Symbol] =
context.enclClass.owner.ownerChain.find(o => qual.isEmpty || o.isClass && o.name == qual) match {
case Some(c) if packageOK || !c.isPackageClass =>
- c
+ Right(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
+ Left(QualifyingClassError(tree, qual))
}
/** The typer for an expression, depending on where we are. If we are before a superclass
@@ -565,14 +574,19 @@ trait Typers extends Modes with Adaptations {
* 2. Check that packages and static modules are not used as values
* 3. Turn tree type into stable type if possible and required by context.
*/
- private def stabilize(tree: Tree, pre: Type, mode: Int, pt: Type): Tree = {
- if (tree.symbol.isOverloaded && !inFunMode(mode))
- inferExprAlternative(tree, pt)
+ private def stabilize(tree0: Tree, pre: Type, mode: Int, pt: Type): Tree = {
+ val tree =
+ if (tree0.symbol.isOverloaded && !inFunMode(mode))
+ inferExprAlternative(tree0, pt) match {
+ case Some(err) => err
+ case _ => tree0
+ }
+ else tree0
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.containsErrorOrIsErrorTyped()) tree
else if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1)
if (sym.isValue) checkStable(tree)
else fail()
@@ -652,6 +666,12 @@ trait Typers extends Modes with Adaptations {
} catch {
case ex: CyclicReference => throw ex
case ex: TypeError =>
+ // TODO: when move to error trees is complete we should
+ // be able to just drop this case
+
+ // probably not, since we use it for Unit/List[Tree] as well.
+ // This method in theory will be eliminated/simplified once we are done
+ // with the transformation
stopCounter(rawTypeFailed, rawTypeStart)
stopCounter(findMemberFailed, findMemberStart)
stopCounter(subtypeFailed, subtypeStart)
@@ -660,23 +680,6 @@ trait Typers extends Modes with Adaptations {
}
}
- /** 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
@@ -722,7 +725,6 @@ trait Typers extends Modes with Adaptations {
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,
// approximate types that depend on arguments since dependency on implicit argument is like dependency on type parameter
if (settings.YdepMethTpes.value) mt.approximate else mt,
@@ -731,14 +733,21 @@ trait Typers extends Modes with Adaptations {
// Looking for a manifest of Nil: This has many potential types,
// so we need to instantiate to minimal type List[Nothing].
keepNothings = false, // retract Nothing's that indicate failure, ambiguities in manifests are dealt with in manifestOfType
- useWeaklyCompatible = true) // #3808
+ useWeaklyCompatible = true) match {// #3808
+ case (Some(err), undetparams1) =>
+ context.undetparams = undetparams1
+ return err
+ case (_, undetparams1) =>
+ context.undetparams = undetparams1
+ }
}
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 =>
+ case result: Tree if !result.containsError() =>
+ result
+ case _ =>
debuglog("fallback on implicits: " + tree + "/" + resetAllAttrs(original))
val tree1 = typed(resetAllAttrs(original), mode, WildcardType)
tree1.tpe = addAnnotations(tree1, tree1.tpe)
@@ -756,7 +765,10 @@ trait Typers extends Modes with Adaptations {
}
if (!meth.isConstructor && isFunctionType(pt)) { // (4.2)
debuglog("eta-expanding " + tree + ":" + tree.tpe + " to " + pt)
- checkParamsConvertible(tree.pos, tree.tpe)
+ val errs = checkParamsConvertible(tree.pos, tree.tpe)
+ if (!errs.isEmpty) {
+ return PendingErrors(errs.reverse)
+ }
val tree0 = etaExpand(context.unit, tree)
// println("eta "+tree+" ---> "+tree0+":"+tree0.tpe+" undet: "+context.undetparams+ " mode: "+Integer.toHexString(mode))
@@ -773,11 +785,10 @@ trait Typers extends Modes with Adaptations {
} 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)
+ // Relevant only for #4425 ?
+ Bug4425Error(tree)
}
}
@@ -790,8 +801,7 @@ trait Typers extends Modes with Adaptations {
// 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)) &&
@@ -806,9 +816,7 @@ trait Typers extends Modes with Adaptations {
// 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)
@@ -828,13 +836,18 @@ trait Typers extends Modes with Adaptations {
val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner))
.setOriginal(tree)
- inferConstructorInstance(tree1, clazz.typeParams, pt)
- tree1
+ inferConstructorInstance(tree1, clazz.typeParams, pt) match {
+ case Some(err) =>
+ if (tree1.containsError())
+ Block(List(err), tree1)
+ else err
+ case _ => tree1
+ }
} else {
tree
}
} else {
- errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method")
+ CaseClassConstructorError(tree)
}
}
@@ -852,7 +865,8 @@ trait Typers extends Modes with Adaptations {
case other =>
other
}
- typed(atPos(tree.pos)(Select(qual, nme.apply)), mode, pt)
+ if (qual.containsError()) qual // Fail quickly
+ else typed(atPos(tree.pos)(Select(qual, nme.apply)), mode, pt)
}
// begin adapt
@@ -867,8 +881,10 @@ trait Typers extends Modes with Adaptations {
}
treeCopy.Literal(tree, value)
case OverloadedType(pre, alts) if !inFunMode(mode) => // (1)
- inferExprAlternative(tree, pt)
- adapt(tree, mode, pt, original)
+ inferExprAlternative(tree, pt) match {
+ case Some(err) => err
+ case _ => adapt(tree, mode, pt, original)
+ }
case NullaryMethodType(restpe) => // (2)
adapt(tree setType restpe, mode, pt, original)
case TypeRef(_, ByNameParamClass, List(arg)) if ((mode & EXPRmode) != 0) => // (2)
@@ -927,7 +943,10 @@ trait Typers extends Modes with Adaptations {
} else {
if (inPatternMode(mode)) {
if ((tree.symbol ne null) && tree.symbol.isModule)
- inferModulePattern(tree, pt)
+ inferModulePattern(tree, pt) match {
+ case Some(err) => return err
+ case _ =>
+ }
if (isPopulated(tree.tpe, approximateAbstracts(pt)))
return tree
}
@@ -955,7 +974,8 @@ trait Typers extends Modes with Adaptations {
if (!context.undetparams.isEmpty) {
return instantiate(tree, mode, pt)
}
- if (context.implicitsEnabled && !tree.tpe.isError && !pt.isError) {
+ val validTree = !tree.containsErrorOrIsErrorTyped()
+ if (context.implicitsEnabled && !pt.isError && validTree) {
// (14); the condition prevents chains of views
debuglog("inferring view from " + tree.tpe + " to " + pt)
val coercion = inferView(tree, tree.tpe, pt, true)
@@ -972,7 +992,7 @@ trait Typers extends Modes with Adaptations {
new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
}
}
- if (isCodeType(pt) && !isCodeType(tree.tpe) && !tree.tpe.isError)
+ if (isCodeType(pt) && !isCodeType(tree.tpe) && validTree)
return adapt(lifted(tree), mode, pt, original)
}
if (settings.debug.value) {
@@ -1003,7 +1023,7 @@ trait Typers extends Modes with Adaptations {
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, pt.subst(pt.existentialSkolems, pt.existentialSkolems map (_ => WildcardType)))
} else
- throw ex
+ TypeErrorTree(tree, pt, ex)
}
}
}
@@ -1011,8 +1031,10 @@ trait Typers extends Modes with Adaptations {
}
def instantiate(tree: Tree, mode: Int, pt: Type): Tree = {
- inferExprInstance(tree, context.extractUndetparams(), pt)
- adapt(tree, mode, pt)
+ inferExprInstance(tree, context.extractUndetparams(), pt) match {
+ case (Some(err), _) => err
+ case _ => adapt(tree, mode, pt)
+ }
}
/** If the expected type is Unit: try instantiating type arguments
* with expected type Unit, but if that fails, try again with pt = WildcardType
@@ -1020,8 +1042,8 @@ trait Typers extends Modes with Adaptations {
*/
def instantiateExpectingUnit(tree: Tree, mode: Int): Tree = {
val savedUndetparams = context.undetparams
- silent(_.instantiate(tree, mode, UnitClass.tpe)) match {
- case t: Tree => t
+ instantiate(tree, mode, UnitClass.tpe) match {
+ case t: Tree if !t.containsError() => t
case _ =>
context.undetparams = savedUndetparams
val valueDiscard = atPos(tree.pos)(Block(List(instantiate(tree, mode, WildcardType)), Literal(Constant())))
@@ -1069,40 +1091,44 @@ trait Typers extends Modes with Adaptations {
adaptToMember(qual, HasMethodMatching(name, args map (_.tpe), restpe))
if (pt != WildcardType) {
silent(_ => doAdapt(pt)) match {
- case result: Tree if result != qual =>
+ case result: Tree if result != qual && !result.containsError() =>
result
case _ =>
debuglog("fallback on implicits in adaptToArguments: "+qual+" . "+name)
doAdapt(WildcardType)
}
- } else
+ } else {
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 onError(reportError: => Tree): Tree = {
+ // last change effort
context.tree match {
case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty => // try handling the arguments
// println("typing args: "+args)
silent(_.typedArgs(args, mode)) match {
- case args: List[_] =>
+ case args: List[Tree] if args.forall(!_.containsError()) =>
adaptToArguments(qual, name, args.asInstanceOf[List[Tree]], WildcardType)
case _ =>
- throw ex
+ reportError
}
case _ =>
- // println("not in an apply: "+context.tree+"/"+tree)
- throw ex
+ reportError
}
}
+ try {
+ val res = adaptToMember(qual, HasMember(name))
+ if (res.containsError()) onError(res) else res
+ } catch {
+ case ex: TypeError =>
+ onError(AdaptToMemberWithArgsError(tree, ex))
+ }
}
/** Try to apply an implicit conversion to `qual` to that it contains a
@@ -1135,6 +1161,7 @@ trait Typers extends Modes with Adaptations {
if (templ.parents.isEmpty) List()
else try {
val clazz = context.owner
+ var pending: List[ErrorTree] = List()
// Normalize supertype and mixins so that supertype is always a class, not a trait.
var supertpt = typedTypeConstructor(templ.parents.head)
@@ -1143,7 +1170,13 @@ trait Typers extends Modes with Adaptations {
// 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.containsError()) {
+ // we assume here that all errors in supertpt1 have already been reported
+ supertpt setType ErrorType
+ } else if (supertpt1.tpe.isError) {
+ // Should not happen with ErrorTree
+ assert(false, "Erroneous SuperType contains Error tree")
+ } else {
mixins = supertpt1 :: mixins
supertpt = TypeTree(supertpt1.tpe.parents.head) setPos supertpt.pos.focus
}
@@ -1192,21 +1225,28 @@ trait Typers extends Modes with Adaptations {
.typePrimaryConstrBody(clazz,
cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate)))
+ if (cbody2.containsError()) {
+ val allErrors = errorTreesFinder(cbody2)
+ pending = allErrors.toList:::pending
+ }
+
scall match {
case Apply(_, _) =>
val sarg = treeInfo.firstArgument(scall)
if (sarg != EmptyTree && supertpe.typeSymbol != firstParent)
- error(sarg.pos, firstParent+" is a trait; does not take constructor arguments")
+ pending = logErrorTree(ConstrArgsInTraitParentTpeError(sarg, firstParent), pending)
if (!supertparams.isEmpty) supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos.focus
case _ =>
- if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")
+ if (!supertparams.isEmpty)
+ pending = logErrorTree(MissingTypeArgumentsParentTpeError(supertpt), pending)
}
(cstats1, treeInfo.preSuperFields(templ.body)).zipped map {
(ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe
}
case _ =>
- if (!supertparams.isEmpty) error(supertpt.pos, "missing type arguments")
+ if (!supertparams.isEmpty)
+ pending = logErrorTree(MissingTypeArgumentsParentTpeError(supertpt), pending)
}
/* experimental: early types as type arguments
val hasEarlyTypes = templ.body exists (treeInfo.isEarlyTypeDef)
@@ -1218,12 +1258,11 @@ trait Typers extends Modes with Adaptations {
*/
//Console.println("parents("+clazz") = "+supertpt :: mixins);//DEBUG
- supertpt :: mixins mapConserve (tpt => checkNoEscaping.privates(clazz, tpt))
+ supertpt :: pending ::: mixins mapConserve (tpt => checkNoEscaping.privates(clazz, tpt))
} catch {
case ex: TypeError =>
- templ.tpe = null
- reportTypeError(templ.pos, ex)
- List(TypeTree(AnyRefClass.tpe))
+ // TODO: remove once error trees refactoring is done
+ List(ParentTypesError(templ, ex))
}
/** <p>Check that</p>
@@ -1240,32 +1279,35 @@ trait Typers extends Modes with Adaptations {
* <li>no two parents define same symbol.</li>
* </ul>
*/
- def validateParentClasses(parents: List[Tree], selfType: Type) {
+ def validateParentClasses(parents: List[Tree], selfType: Type): Option[PendingErrors] = {
+ var pending: List[ErrorTree] = List()
def validateParentClass(parent: Tree, superclazz: Symbol) {
- if (!parent.tpe.isError) {
+ if (!parent.containsErrorOrIsErrorTyped()) {
val psym = parent.tpe.typeSymbol.initialize
- checkClassType(parent, false, true)
+ checkClassType(parent, false, true) match {
+ case t@Some(err) =>
+ pending = logErrorTree(err, pending)
+ case _ =>
+ }
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 = logErrorTree(ParentSuperSubclassError(parent.pos, superclazz, ps.head.typeSymbol, psym), pending)
} else {
- error(parent.pos, psym+" needs to be a trait to be mixed in")
+ pending = logErrorTree(ParentNotATraitMixinError(parent.pos, psym), pending)
}
}
- if (psym.isFinal) {
- error(parent.pos, "illegal inheritance from final "+psym)
- }
+ if (psym.isFinal)
+ pending = logErrorTree(ParentFinalInheritanceError(parent.pos, psym), pending)
+
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)
+ pending = logErrorTree(ParentSealedInheritanceError(parent.pos, psym), pending)
}
if (!(selfType <:< parent.tpe.typeOfThis) &&
!phase.erasedTypes &&
@@ -1277,18 +1319,19 @@ trait Typers extends Modes with Adaptations {
//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 = logErrorTree(ParentSelfTypeConformanceError(parent.pos, selfType, parent), pending)
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 = logErrorTree(ParentInheritedTwiceError(parent.pos, psym), pending)
}
}
-
- if (!parents.isEmpty && !parents.head.tpe.isError)
- for (p <- parents) validateParentClass(p, parents.head.tpe.typeSymbol)
+ if (parents.forall(!_.containsError())) {
+ // proceed as normal, we know that head.tpe is not error?
+ if (!parents.isEmpty && !parents.head.tpe.isError)
+ for (p <- parents) validateParentClass(p, parents.head.tpe.typeSymbol)
+ }
+ if (pending.isEmpty) None else Some(PendingErrors(pending.reverse))
/*
if (settings.Xshowcls.value != "" &&
@@ -1299,11 +1342,11 @@ trait Typers extends Modes with Adaptations {
*/
}
- def checkFinitary(classinfo: ClassInfoType) {
+ def checkFinitary(classinfo: ClassInfoType): List[ErrorTree] = {
val clazz = classinfo.typeSymbol
- for (tparam <- clazz.typeParams) {
+
+ clazz.typeParams.map(tparam =>
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,
@@ -1314,8 +1357,9 @@ trait Typers extends Modes with Adaptations {
case _ => newinfo
}
}
- }
- }
+ Some(FinitiaryError(tparam))
+ } else None
+ ).flatten
}
/**
@@ -1402,15 +1446,16 @@ trait Typers extends Modes with Adaptations {
val getter = if (isDeferred) value else value.getter(value.owner)
assert(getter != NoSymbol, stat)
+ val gs = new ListBuffer[Tree]
if (getter.isOverloaded)
- error(getter.pos, getter+" is defined twice")
+ gs.append(GetterDefinedTwiceError(getter))
getter.setAnnotations(memberAnnots(allAnnots, GetterTargetClass))
if (value.isLazy) List(stat)
else {
val vdef = treeCopy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs)
- val getterDef: DefDef = atPos(vdef.pos.focus) {
+ val getterDef = atPos(vdef.pos.focus) {
if (isDeferred) {
val r = DefDef(getter, EmptyTree)
r.tpt.asInstanceOf[TypeTree].setOriginal(tpt) // keep type tree of original abstract field
@@ -1426,18 +1471,21 @@ trait Typers extends Modes with Adaptations {
r
}
}
- checkNoEscaping.privates(getter, getterDef.tpt)
- def setterDef(setter: Symbol, isBean: Boolean = false): DefDef = {
+
+ def setterDef(setter: Symbol, isBean: Boolean = false): Tree = {
setter setAnnotations memberAnnots(allAnnots, if (isBean) BeanSetterTargetClass else SetterTargetClass)
val defTree =
if ((mods hasFlag DEFERRED) || (setter hasFlag OVERLOADED)) EmptyTree
else Assign(Select(This(value.owner), value), Ident(setter.paramss.head.head))
- typedPos(vdef.pos.focus)(DefDef(setter, defTree)).asInstanceOf[DefDef]
+ typedPos(vdef.pos.focus)(DefDef(setter, defTree))
}
- val gs = new ListBuffer[DefDef]
+ val privateErrors = checkNoEscaping.privates(getter, getterDef.tpt)
+ if (privateErrors.containsError())
+ privateErrors.foreach(err => gs.append(err))
+
gs.append(getterDef)
if (mods.isMutable) {
val setter = getter.setter(value.owner)
@@ -1453,7 +1501,7 @@ trait Typers extends Modes with Adaptations {
if (beanGetter == NoSymbol) {
// the namer decides wether to generate these symbols or not. at that point, we don't
// have symbolic information yet, so we only look for annotations named "BeanProperty".
- unit.error(stat.pos, "implementation limitation: the BeanProperty annotation cannot be used in a type alias or renamed import")
+ gs.append(BeanPropertyAnnotationLimitationError(stat))
}
beanGetter.setAnnotations(memberAnnots(allAnnots, BeanGetterTargetClass))
if (mods.isMutable && beanGetter != NoSymbol) {
@@ -1552,20 +1600,32 @@ trait Typers extends Modes with Adaptations {
// the following is necessary for templates generated later
assert(clazz.info.decls != EmptyScope)
enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templ.body)
- validateParentClasses(parents1, selfType)
+
+ var doNotTypeBody = false
+ val parents2 = validateParentClasses(parents1, selfType) match {
+ case Some(err) =>
+ doNotTypeBody = err.pending0.exists(_.isInstanceOf[BlockingError])
+ List(err)
+ case _ => parents1
+ }
if (clazz.isCase)
validateNoCaseAncestor(clazz)
if ((clazz isSubClass ClassfileAnnotationClass) && !clazz.owner.isPackageClass)
unit.error(clazz.pos, "inner classes cannot be classfile annotations")
- if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members
- checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType])
+
+ val finitiaryErrs =
+ if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members
+ checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType])
+ else List()
val body =
- if (phase.id <= currentRun.typerPhase.id && !reporter.hasErrors)
+ if (phase.id <= currentRun.typerPhase.id && !reporter.hasErrors && !doNotTypeBody)
templ.body flatMap addGetterSetter
else templ.body
- val body1 = typedStats(body, templ.symbol)
- treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe
+
+ val body1 = if (doNotTypeBody) body else typedStats(body, templ.symbol)
+ val body2 = finitiaryErrs ++ body1
+ treeCopy.Template(templ, parents2, self1, body2) setType clazz.tpe
}
/** Remove definition annotations from modifiers (they have been saved
@@ -1583,22 +1643,29 @@ trait Typers extends Modes with Adaptations {
val sym = vdef.symbol
val typer1 = constrTyperIf(sym.isParameter && sym.owner.isConstructor)
val typedMods = removeAnnotations(vdef.mods)
+ var pending: List[ErrorTree] = List()
// complete lazy annotations
val annots = sym.annotations
var tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt))
- checkNonCyclic(vdef, tpt1)
+ checkNonCyclic(vdef, tpt1) match {
+ case Some(cyclic) =>
+ pending = logErrorTree(cyclic, pending)
+ case _ =>
+ }
if (sym.hasAnnotation(definitions.VolatileAttr)) {
if (!sym.isMutable)
- error(vdef.pos, "values cannot be volatile")
+ pending = logErrorTree(VolatileValueError(vdef), pending)
else if (sym.isFinal)
- error(vdef.pos, "final vars cannot be volatile")
+ pending = logErrorTree(FinalVolatileVarError(vdef), pending)
}
val rhs1 =
- if (vdef.rhs.isEmpty) {
+ if (tpt1.containsError()) {
+ vdef.rhs
+ } else if (vdef.rhs.isEmpty) {
if (sym.isVariable && sym.owner.isTerm && phase.id <= currentRun.typerPhase.id)
- error(vdef.pos, "local variables must be initialized")
+ pending = logErrorTree(LocalVarUninitializedError(vdef), pending)
vdef.rhs
} else {
val tpt2 = if (sym.hasDefault) {
@@ -1621,7 +1688,11 @@ trait Typers extends Modes with Adaptations {
} else tpt1.tpe
newTyper(typer1.context.make(vdef, sym)).transformedOrTyped(vdef.rhs, EXPRmode | BYVALmode, tpt2)
}
- treeCopy.ValDef(vdef, typedMods, vdef.name, tpt1, checkDead(rhs1)) setType NoType
+ // flush all pending erros
+ val rhs2 = if (pending.nonEmpty) {
+ PendingErrors(pending.reverse)
+ } else rhs1
+ treeCopy.ValDef(vdef, typedMods, vdef.name, tpt1, checkDead(rhs2)) setType NoType
}
/** Enter all aliases of local parameter accessors.
@@ -1630,7 +1701,7 @@ trait Typers extends Modes with Adaptations {
* @param vparamss ...
* @param rhs ...
*/
- def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree) {
+ def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree): List[ErrorTree] = {
debuglog("computing param aliases for "+clazz+":"+clazz.primaryConstructor.tpe+":"+rhs)//debug
def decompose(call: Tree): (Tree, List[Tree]) = call match {
case Apply(fn, args) =>
@@ -1648,16 +1719,17 @@ trait Typers extends Modes with Adaptations {
val (superConstr, superArgs) = decompose(rhs)
assert(superConstr.symbol ne null)//debug
+ var pending: List[ErrorTree] = List()
// 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)::pending
tree match {
case This(qual) =>
- error(tree.pos, "super constructor arguments cannot reference unconstructed `this`")
+ pending = SuperConstrArgsThisReferenceError(tree)::pending
case _ => ()
}
}
@@ -1695,6 +1767,8 @@ trait Typers extends Modes with Adaptations {
}
}
}
+
+ pending
}
/** Check if a structurally defined method violates implementation restrictions.
@@ -1743,7 +1817,7 @@ trait Typers extends Modes with Adaptations {
lookupVariable(name.toString.substring(1), enclClass) match {
case Some(repl) =>
silent(_.typedTypeConstructor(stringParser(repl).typ())) match {
- case tpt: Tree =>
+ case tpt: Tree if !tpt.containsError()=>
val alias = enclClass.newAliasType(useCase.pos, name.toTypeName)
val tparams = cloneSymbols(tpt.tpe.typeSymbol.typeParams, alias)
alias setInfo typeFun(tparams, appliedType(tpt.tpe, tparams map (_.tpe)))
@@ -1772,6 +1846,7 @@ trait Typers extends Modes with Adaptations {
*/
def typedDefDef(ddef: DefDef): DefDef = {
val meth = ddef.symbol
+ var pending: List[ErrorTree] = List()
reenterTypeParams(ddef.tparams)
reenterValueParams(ddef.vparamss)
@@ -1793,17 +1868,22 @@ trait Typers extends Modes with Adaptations {
val annots = meth.annotations
for (vparams1 <- vparamss1; vparam1 <- vparams1 dropRight 1)
- if (isRepeatedParamType(vparam1.symbol.tpe))
- error(vparam1.pos, "*-parameter must come last")
+ if (isRepeatedParamType(vparam1.symbol.tpe)) {
+ pending = logErrorTree(StarParamNotLastError(vparam1), pending)
+ }
var tpt1 = checkNoEscaping.privates(meth, typedType(ddef.tpt))
if (!settings.YdepMethTpes.value) {
for (vparams <- vparamss1; vparam <- vparams) {
- checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
+ pending = logErrorTree(checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt), pending)
}
- checkNoEscaping.locals(context.scope, WildcardType, tpt1)
+ pending = logErrorTree(checkNoEscaping.locals(context.scope, WildcardType, tpt1), pending)
+ }
+ checkNonCyclic(ddef, tpt1) match {
+ case Some(cylic) =>
+ pending = logErrorTree(cylic, pending)
+ case _ =>
}
- checkNonCyclic(ddef, tpt1)
ddef.tpt.setType(tpt1.tpe)
val typedMods = removeAnnotations(ddef.mods)
var rhs1 =
@@ -1812,35 +1892,42 @@ trait Typers extends Modes with Adaptations {
(!meth.owner.isClass ||
meth.owner.isModuleClass ||
meth.owner.isAnonOrRefinementClass))
- error(ddef.pos, "constructor definition not allowed here")
+ pending = logErrorTree(InvalidConstructorDefError(ddef), pending)
typed(ddef.rhs)
} else {
transformedOrTyped(ddef.rhs, EXPRmode, tpt1.tpe)
}
if (meth.isPrimaryConstructor && meth.isClassConstructor &&
- phase.id <= currentRun.typerPhase.id && !reporter.hasErrors)
- computeParamAliases(meth.owner, vparamss1, rhs1)
+ phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) {
+ // Handle new error trees
+ val pending0 = computeParamAliases(meth.owner, vparamss1, rhs1)
+
+ if (pending0.nonEmpty) {
+ pending = pending0 ::: pending
+ }
+ }
if (tpt1.tpe.typeSymbol != NothingClass && !context.returnsSeen && rhs1.tpe.typeSymbol != NothingClass)
rhs1 = checkDead(rhs1)
if (phase.id <= currentRun.typerPhase.id && 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")
+ pending = logErrorTree(StarWithDefaultError(meth), pending)
if (phase.id <= currentRun.typerPhase.id) {
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).")
+ pending = logErrorTree(DeprecatedParamNameError(p, n), pending)
}
}
}
if (meth.isStructuralRefinementMember)
checkMethodStructuralCompatible(meth)
-
+ if (pending.nonEmpty)
+ rhs1 = wrapInBlock(PendingErrors(pending.reverse), rhs1)
treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
}
@@ -1869,15 +1956,22 @@ trait Typers extends Modes with Adaptations {
}
val rhs1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.rhs))
- 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 _ =>
- }
- treeCopy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType
+ val rhs2 = checkNonCyclic(tdef.symbol) match {
+ case Some(cyclic) =>
+ wrapInBlock(cyclic, rhs1)
+ case None =>
+ if (tdef.symbol.owner.isType)
+ rhs1.tpe match {
+ case TypeBounds(lo1, hi1) if (!(lo1 <:< hi1)) =>
+ wrapInBlock(
+ LowerBoundError(tdef, lo1, hi1),
+ rhs1)
+ case _ =>
+ rhs1
+ }
+ else rhs1
+ }
+ treeCopy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs2) setType NoType
}
private def enterLabelDef(stat: Tree) {
@@ -1994,10 +2088,17 @@ trait Typers extends Modes with Adaptations {
*/
def typedCase(cdef: CaseDef, pattpe: Type, pt: Type): CaseDef = {
// verify no _* except in last position
+ var pending: List[ErrorTree] = List()
for (Apply(_, xs) <- cdef.pat ; x <- xs dropRight 1 ; if treeInfo isStar x)
- error(x.pos, "_* may only come last")
+ pending = logErrorTree(StarPositionInPatternError(x.pos), pending)
- val pat1: Tree = typedPattern(cdef.pat, pattpe)
+ val pat0 = typedPattern(cdef.pat, pattpe)
+ val pat1: Tree = pending match {
+ case List() =>
+ pat0
+ case _ =>
+ wrapInBlock(PendingErrors(pending.reverse), pat0)
+ }
// 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
@@ -2013,16 +2114,17 @@ trait Typers extends Modes with Adaptations {
val guard1: Tree = if (cdef.guard == EmptyTree) EmptyTree
else typed(cdef.guard, BooleanClass.tpe)
+
var body1: Tree = typed(cdef.body, pt)
if (!context.savedTypeBounds.isEmpty) {
body1.tpe = context.restoreTypeBounds(body1.tpe)
if (isFullyDefined(pt) && !(body1.tpe <:< pt)) {
- body1 =
- typed {
- atPos(body1.pos) {
- TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt))) // @M no need for pt.normalize here, is done in erasure
- }
+ body1 = typed {
+ atPos(body1.pos) {
+ // @M no need for pt.normalize here, is done in erasure
+ TypeApply(Select(body1, Any_asInstanceOf), List(TypeTree(pt)))
}
+ }
}
}
// body1 = checkNoEscaping.locals(context.scope, pt, body1)
@@ -2045,7 +2147,7 @@ trait Typers extends Modes with Adaptations {
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)
@@ -2061,9 +2163,10 @@ trait Typers extends Modes with Adaptations {
(FunctionClass(numVparams), fun.vparams map (x => NoType), WildcardType)
val (clazz, argpts, respt) = decompose(if (codeExpected) pt.normalize.typeArgs.head else pt)
+ val vparamErrors = new mutable.HashMap[ValDef, ErrorTree]()
if (argpts.lengthCompare(numVparams) != 0)
- errorTree(fun, "wrong number of parameters; expected = " + argpts.length)
+ WrongNumberOfParametersError(fun, argpts)
else {
val vparamSyms = (fun.vparams, argpts).zipped map { (vparam, argpt) =>
if (vparam.tpt.isEmpty) {
@@ -2073,7 +2176,7 @@ trait Typers extends Modes with Adaptations {
fun match {
case etaExpansion(vparams, fn, args) if !codeExpected =>
silent(_.typed(fn, forFunMode(mode), pt)) match {
- case fn1: Tree if context.undetparams.isEmpty =>
+ case fn1: Tree if context.undetparams.isEmpty && !fn1.containsError() =>
// 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)
@@ -2084,7 +2187,7 @@ trait Typers extends Modes with Adaptations {
}
case _ =>
}
- error(vparam.pos, missingParameterTypeMsg(fun, vparam, pt))
+ vparamErrors += ((vparam, MissingParameterTypeError(fun, vparam, pt)))
ErrorType
}
if (!vparam.tpt.pos.isDefined) vparam.tpt setPos vparam.pos.focus
@@ -2094,14 +2197,21 @@ trait Typers extends Modes with Adaptations {
vparam.symbol
}
- val vparams = fun.vparams mapConserve (typedValDef)
+ val vparams = fun.vparams mapConserve (p =>
+ { val p0 = typedValDef(p)
+ if (vparamErrors.contains(p)) {
+ treeCopy.ValDef(p0, p0.mods, p0.name, vparamErrors(p), p0.rhs)
+ }
+ else p0
+ })
// for (vparam <- vparams) {
// checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
// }
- var body = typed(fun.body, respt)
+ val body0 = typed(fun.body, respt)
val formals = vparamSyms map (_.tpe)
- val restpe = packedType(body, fun.symbol).deconst
- val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe)
+ val (restpe0, errs) = packedType(body0, fun.symbol)//.deconst
+ val body = if (errs.isEmpty) body0 else Block(errs, body0)
+ val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe0.deconst)
// body = checkNoEscaping.locals(context.scope, restpe, body)
val fun1 = treeCopy.Function(fun, vparams, body).setType(funtpe)
if (codeExpected) lifted(fun1) else fun1
@@ -2142,7 +2252,7 @@ trait Typers extends Modes with Adaptations {
val localTarget = stats exists includesTargetPos
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(_, _) =>
@@ -2160,26 +2270,30 @@ trait Typers extends Modes with Adaptations {
// 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")
- }
- result match {
- case EmptyTree | Literal(Constant(())) => ()
- case _ =>
- if (treeInfo isPureExpr result) {
- val sym = result.symbol
+
+ val result1 = if (treeInfo.isSelfOrSuperConstrCall(result)) {
+ context.inConstructorSuffix = true
+ if (treeInfo.isSelfConstrCall(result) && result.symbol.pos.pointOrElse(0) >= exprOwner.enclMethod.pos.pointOrElse(0))
+ wrapInBlock(ConstructorsOrderError(stat), result)
+ else result
+ } else result
+
+ result1 match {
+ case EmptyTree | Literal(Constant(())) => result1
+ case tree if tree.containsError() => result1
+ case tree =>
+ if (treeInfo isPureExpr result1) {
+ val sym = result1.symbol
if (sym != null && (sym.isModule || sym.isLazy)) {
- debuglog("'Pure' but side-effecting expression in statement position: " + result)
+ debuglog("'Pure' but side-effecting expression in statement position: " + result1)
}
else context.warning(stat.pos,
"a pure expression does nothing in statement position; " +
"you may be omitting necessary parentheses"
)
}
+ result1
}
- result
}
}
}
@@ -2211,8 +2325,7 @@ trait Typers extends Modes with Adaptations {
// 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})
+ newStats += DefDefinedTwiceError(e.sym, e1.sym)
scope.unlink(e1) // need to unlink to avoid later problems with lub; see #2779
}
e1 = scope.lookupNextEntry(e1)
@@ -2379,8 +2492,15 @@ trait Typers extends Modes with Adaptations {
arg1
}
context.undetparams = undetparams
- inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args))
- doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt)
+
+ inferMethodAlternative(fun, undetparams, argtpes.toList, pt,
+ varArgsOnly = treeInfo.isWildcardStarArgList(args)) match {
+ case Some(err) =>
+ err
+ case _ =>
+ doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt)
+ }
+
case mt @ MethodType(params, _) =>
val paramTypes = mt.paramTypes
@@ -2400,7 +2520,7 @@ trait Typers extends Modes with Adaptations {
// 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 t: Tree if !t.containsError() =>
// Depending on user options, may warn or error here if
// a Unit or tuple was inserted.
Some(t) filter (tupledTree =>
@@ -2408,7 +2528,7 @@ trait Typers extends Modes with Adaptations {
|| tupledTree.symbol == null
|| checkValidAdaptation(tupledTree, args)
)
- case ex =>
+ case _ =>
context.undetparams = savedUndetparams
None
}
@@ -2426,19 +2546,24 @@ trait Typers extends Modes with Adaptations {
if (mt.isErroneous) setError(tree)
else if (inPatternMode(mode))
// #2064
- errorTree(tree, "wrong number of arguments for "+ treeSymTypeMsg(fun))
+ WrongNumberOfArgsError(tree, fun)
else if (lencmp > 0) {
- tryTupleApply getOrElse errorTree(tree, "too many arguments for "+treeSymTypeMsg(fun))
+ tryTupleApply getOrElse 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)) {
+ if (namelessArgs exists (_.containsError())) {
+ // This should maybe be special handled
+ val tree1 = treeCopy.Apply(tree, fun, namelessArgs)
+ setError(tree1)
+ } else if (namelessArgs exists (_.isErroneous)) {
+ assert(false, "removeNames for NamesDefaults returns only ErrorTrees in case of error. We got " + namelessArgs)
setError(tree)
} else if (!isIdentity(argPos) && !sameLength(formals, params))
// !isIdentity indicates that named arguments are used to re-order arguments
- errorTree(tree, "when using named arguments, the vararg parameter "+
- "has to be specified exactly once")
+ 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 }"
@@ -2452,7 +2577,8 @@ trait Typers extends Modes with Adaptations {
// 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) setError(tree)
+ if (fun1.containsError()) fun1
+ else if (fun1.isErroneous) setError(tree)
else {
assert(isNamedApplyBlock(fun1), fun1)
val NamedApplyInfo(qual, targs, previousArgss, _) = context.namedApplyBlockInfo.get._2
@@ -2469,17 +2595,20 @@ trait Typers extends Modes with Adaptations {
val lencmp2 = compareLengths(allArgs, formals)
if (!sameLength(allArgs, args) && callToCompanionConstr(context, funSym)) {
- errorTree(tree, "module extending its companion class cannot use default constructor arguments")
+ ModuleUsingCompanionClassDefaultArgsErrror(tree)
} else if (lencmp2 > 0) {
- removeNames(Typer.this)(allArgs, params) // #3818
- setError(tree)
+ val errors = removeNames(Typer.this)(allArgs, params)._1.filter(_.containsError()) // #3818
+ if (!errors.isEmpty)
+ wrapInBlock(PendingErrors(findAllNestedErrors(errors)), tree)
+ else
+ setError(tree)
} 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(tree, notEnoughArgumentsMsg(fun, missing))
+ tryTupleApply getOrElse NotEnoughArgsError(tree, fun, missing)
}
}
}
@@ -2503,6 +2632,7 @@ trait Typers extends Modes with Adaptations {
// instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case:
// val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo)
// precise(foo) : foo.type => foo.type
+
val restpe = mt.resultType(args1 map (arg => gen.stableTypeFor(arg) getOrElse arg.tpe))
def ifPatternSkipFormals(tp: Type) = tp match {
case MethodType(_, rtp) if (inPatternMode(mode)) => rtp
@@ -2538,11 +2668,12 @@ trait Typers extends Modes with Adaptations {
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)
- doTypedApply(tree, fun, args, mode, pt)
+ inferExprInstance(fun, tparams) match {
+ case (Some(err), _) => err
+ case _ => doTypedApply(tree, fun, args, mode, pt)
+ }
} else {
assert(!inPatternMode(mode)) // this case cannot arise for patterns
val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
@@ -2559,20 +2690,31 @@ trait Typers extends Modes with Adaptations {
val argtparams = context.extractUndetparams()
if (!argtparams.isEmpty) {
val strictPt = formal.instantiateTypeParams(tparams, strictTargs)
- inferArgumentInstance(arg1, argtparams, strictPt, lenientPt)
- }
- arg1
+ inferArgumentInstance(arg1, argtparams, strictPt, lenientPt) match {
+ case Some(err) =>
+ err
+ case _ =>
+ arg1
+ }
+ } else arg1
}
val args1 = (args, formals).zipped map typedArgToPoly
- if (args1 exists (_.tpe.isError)) setError(tree)
- else {
+ if (args1 exists {_.containsErrorOrIsErrorTyped()}) {
+ val allNestedErrors = findAllNestedErrors(args1.filter(_.containsError()))
+ if (allNestedErrors.isEmpty) SetErrorTree(tree) else PendingErrors(allNestedErrors)
+ } 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"
// returns those undetparams which have not been instantiated.
- val undetparams = inferMethodInstance(fun, tparams, args1, pt)
- val result = doTypedApply(tree, fun, args1, mode, pt)
- context.undetparams = undetparams
- result
+ val undetparamsOrError = inferMethodInstance(fun, tparams, args1, pt)
+ if (undetparamsOrError.isLeft) {
+ context.undetparams = Nil
+ undetparamsOrError.left.get
+ } else {
+ val result = doTypedApply(tree, fun, args1, mode, pt)
+ context.undetparams = undetparamsOrError.right.get
+ result
+ }
}
}
}
@@ -2581,12 +2723,15 @@ trait Typers extends Modes with Adaptations {
doTypedApply(tree, fun setType fun.tpe.widen, args, mode, pt)
case ErrorType =>
- setError(treeCopy.Apply(tree, fun, args))
+ if (tree.containsError())
+ tree
+ else
+ ErroneousFunInTypeApplyError(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 TooManyArgsPatternError(fun)
def freshArgType(tp: Type): (Type, List[Symbol]) = (tp: @unchecked) match {
case MethodType(param :: _, _) =>
@@ -2594,9 +2739,10 @@ trait Typers extends Modes with Adaptations {
case PolyType(tparams, restype) =>
val tparams1 = cloneSymbols(tparams)
(freshArgType(restype)._1.substSym(tparams, tparams1), tparams1)
- case OverloadedType(_, _) =>
- error(fun.pos, "cannot resolve overloaded unapply")
- (ErrorType, Nil)
+ // 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")
+// (ErrorType, Nil)
}
val unapp = unapplyMember(otpe)
@@ -2611,7 +2757,11 @@ trait Typers extends Modes with Adaptations {
freeVars foreach context1.scope.enter
val typer1 = newTyper(context1)
- val pattp = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe)
+ val pattp0 = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe)
+ val pattp = pattp0 match {
+ case Left(err) => return err // Fail quickly
+ case Right(tp) => tp
+ }
// turn any unresolved type variables in freevars into existential skolems
val skolems = freeVars map { fv =>
@@ -2627,7 +2777,14 @@ trait Typers extends Modes with Adaptations {
// 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) setError(tree)
+ // Set error tree
+ if (fun1.containsError())
+ ErroneousFunInTypeApplyError(fun1, args)
+ else if (fun1.tpe.isErroneous) {
+ assert(false, "Bug #4425 workaround is invalid")
+ //Bug4425Error(tree)
+ setError(tree)
+ }
else {
val formals0 = unapplyTypeList(fun1.symbol, fun1.tpe)
val formals1 = formalTypes(formals0, args.length)
@@ -2642,14 +2799,13 @@ trait Typers extends Modes with Adaptations {
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(tree, "wrong number of arguments for "+treeSymTypeMsg(fun))
- }
+ else
+ WrongNumberArgsPatternError(tree, fun)
}
/* --- end unapply --- */
case _ =>
- errorTree(tree, fun.tpe+" does not take parameters")
+ ApplyWithoutArgsError(tree, fun)
}
}
@@ -2661,8 +2817,11 @@ trait Typers extends Modes with Adaptations {
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)
+ var pending: List[ErrorTree] = List()
+
+ @inline
+ def reportAnnotationError(errTree: ErrorTree) = {
+ pending = logErrorTree(errTree, pending)
hasError = true
annotationError
}
@@ -2670,7 +2829,7 @@ trait Typers extends Modes with Adaptations {
/** Calling constfold right here is necessary because some trees (negated
* floats and literals in particular) are not yet folded.
*/
- def tryConst(tr: Tree, pt: Type): Option[LiteralAnnotArg] = {
+ def tryConst(tr: Tree, pt: Type): Either[ErrorTree, LiteralAnnotArg] = {
val const: Constant = typed(constfold(tr), EXPRmode, pt) match {
case l @ Literal(c) if !l.isErroneous => c
case tree => tree.tpe match {
@@ -2678,37 +2837,37 @@ trait Typers extends Modes with Adaptations {
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")
+ if (const == null) {
+ Left(AnnotationNotAConstantError(tr))
+ } else if (const.value == null)
+ Left(AnnotationArgNulError(tr))
else
- Some(LiteralAnnotArg(const))
+ Right(LiteralAnnotArg(const))
}
/** Converts an untyped tree to a ClassfileAnnotArg. If the conversion fails,
* an error message is reported and None is returned.
*/
- def tree2ConstArg(tree: Tree, pt: Type): Option[ClassfileAnnotArg] = tree match {
+ def tree2ConstArg(tree: Tree, pt: Type): Either[Tree, 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
+ Left(ArrayConstantsError(tree))
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))
+ Left(NullErrorTree)
+ } else
+ Right(NestedAnnotArg(annInfo))
// use of Array.apply[T: ClassManifest](xs: T*): Array[T]
// and Array.apply(x: Int, xs: Int*): Array[Int] (and similar)
case Apply(fun, args) =>
val typedFun = typed(fun, forFunMode(mode), WildcardType)
- if (typedFun.symbol.owner == ArrayModule.moduleClass && typedFun.symbol.name == nme.apply)
+ if (typedFun.containsError()) {
+ Left(typedFun)
+ } else if (typedFun.symbol.owner == ArrayModule.moduleClass && typedFun.symbol.name == nme.apply)
pt match {
case TypeRef(_, ArrayClass, targ :: _) =>
trees2ConstArg(args, targ)
@@ -2717,21 +2876,24 @@ trait Typers extends Modes with Adaptations {
// 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)
- None
+ Left(ArrayConstantsTypeMismatchError(tree, pt))
}
- 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)
}
- def trees2ConstArg(trees: List[Tree], pt: Type): Option[ArrayAnnotArg] = {
+
+ def trees2ConstArg(trees: List[Tree], pt: Type): Either[ErrorTree, ArrayAnnotArg] = {
val args = trees.map(tree2ConstArg(_, pt))
- if (args.exists(_.isEmpty)) None
- else Some(ArrayAnnotArg(args.flatten.toArray))
+ val par = args.filter(_.isLeft)
+ if (!par.isEmpty)
+ Left(PendingErrors(findAllNestedErrors(par.map(_.left.get))))
+ else
+ Right(ArrayAnnotArg(args.map(_.right.get).toArray))
}
// begin typedAnnotation
@@ -2743,14 +2905,18 @@ trait Typers extends Modes with Adaptations {
case Select(New(tpt), nme.CONSTRUCTOR) =>
(fun, outerArgss)
case _ =>
- error(fun.pos, "unexpected tree in annotation: "+ fun)
- (setError(fun), outerArgss)
+ (UnexpectedTreeAnnotation(fun), outerArgss)
}
extract(ann, List())
}
- if (fun.isErroneous) annotationError
- else {
+
+ // It seems that fun.isErroneous was used due to check for deep error within fun?
+ // We don't need it now because deep error within fun
+ // is now detected by containsError()
+ val res = if (fun.containsErrorOrIsErrorTyped()) {
+ annotationError
+ } else {
val typedFun @ Select(New(tpt), _) = typed(fun, forFunMode(mode), WildcardType)
val annType = tpt.tpe
@@ -2759,9 +2925,9 @@ trait Typers extends Modes with Adaptations {
// 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))
@@ -2777,33 +2943,37 @@ trait Typers extends Modes with Adaptations {
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
if (isJava) sym.cookJavaRawInfo() // #3429
val annArg = tree2ConstArg(rhs, sym.tpe.resultType)
- (sym.name, annArg)
+ if (annArg.isLeft) {
+ errorTreesFinder(annArg.left.get).foreach(reportAnnotationError)
+ (nme.ERROR, None)
+ } else
+ (sym.name, Some(annArg.right.get))
}
case arg =>
- error(arg.pos, "classfile annotation arguments have to be supplied as named arguments")
+ reportAnnotationError(ClassfileAnnotationsAsNamedArgsError(arg))
(nme.ERROR, None)
}
for (name <- names) {
if (!name.annotations.contains(AnnotationInfo(AnnotationDefaultAttr.tpe, List(), List())) &&
!name.hasDefaultFlag)
- error(ann.pos, "annotation " + annType.typeSymbol.fullName + " is missing argument " + name.name)
+ reportAnnotationError(AnnotationMissingArgError(ann, annType, name))
}
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)
@@ -2831,6 +3001,9 @@ trait Typers extends Modes with Adaptations {
List(selfsym.info, annClass.tpe))
(typed(func, mode, funcType): @unchecked) match {
+ case t if t.containsError() =>
+ reportAnnotationError(NullErrorTree)
+ t
case t @ Function(List(arg), rhs) =>
val subs =
new TreeSymSubstituter(List(arg.symbol),List(selfsym))
@@ -2855,16 +3028,27 @@ trait Typers extends Modes with Adaptations {
annInfo(fun)
case _ =>
- error(t.pos, "unexpected tree after typing annotation: "+ typedAnn)
+ reportAnnotationError(UnexpectedTreeAnnotationError(t, typedAnn))
}
if (annType.typeSymbol == DeprecatedAttr && argss.flatten.size < 2)
unit.deprecationWarning(ann.pos, "@deprecated now takes two arguments; see the scaladoc.")
- if ((typedAnn.tpe == null) || typedAnn.tpe.isErroneous) annotationError
+ if (typedAnn.containsError() || (typedAnn.tpe == null) || typedAnn.tpe.isErroneous) annotationError
else annInfo(typedAnn)
}
}
+
+ if (hasError) {
+ // We got errors, so now is the last chance to report them
+ try {
+ pending.foreach(_.emit(context))
+ } catch {
+ case _: TypeError =>
+ assert(false, "Cannot throw type errors when creating AnnotationInfo")
+ }
+ annotationError
+ } else res
}
def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type?
@@ -2923,7 +3107,8 @@ trait Typers extends Modes with Adaptations {
}
/** convert skolems to existentials */
- def packedType(tree: Tree, owner: Symbol): Type = {
+ def packedType(tree: Tree, owner: Symbol): (Type, List[ErrorTree]) = {
+ var pending: List[ErrorTree] = List()
def defines(tree: Tree, sym: Symbol) =
sym.isExistentialSkolem && sym.unpackLocation == tree ||
tree.isDef && tree.symbol == sym
@@ -2949,7 +3134,7 @@ trait Typers extends Modes with Adaptations {
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)
+ pending = logErrorTree(InferTypeWithVolatileTypeSelectionError(tree, tp), pending)
mapOver(tp)
}
case _ =>
@@ -2966,8 +3151,7 @@ trait Typers extends Modes with Adaptations {
localSyms += sym
remainingSyms += sym
} else {
- unit.error(tree.pos,
- "can't existentially abstract over parameterized type " + tp)
+ pending = logErrorTree(AbstractExistentiallyOverParamerizedTpeError(tree, tp), pending)
}
}
}
@@ -2996,10 +3180,10 @@ trait Typers extends Modes with Adaptations {
}
for (sym <- remainingSyms) addLocals(sym.existentialBound)
}
-
val normalizedTpe = normalizeLocals(tree.tpe)
addLocals(normalizedTpe)
- packSymbols(localSyms.toList, normalizedTpe)
+ val res = packSymbols(localSyms.toList, normalizedTpe)
+ (res, pending.reverse)
}
protected def typedExistentialTypeTree(tree: ExistentialTypeTree, mode: Int): Tree = {
@@ -3007,19 +3191,23 @@ trait Typers extends Modes with Adaptations {
if (wc.symbol == NoSymbol) { namer.enterSym(wc); wc.symbol setFlag EXISTENTIAL }
else context.scope enter wc.symbol
val whereClauses1 = typedStats(tree.whereClauses, context.owner)
+ var pending: List[ErrorTree] = List()
for (vd @ ValDef(_, _, _, _) <- tree.whereClauses)
if (vd.symbol.tpe.isVolatile)
- error(vd.pos, "illegal abstraction from value with volatile type "+vd.symbol.tpe)
+ pending = logErrorTree(AbstractionFromVolatileTypeError(vd), pending)
val tpt1 = typedType(tree.tpt, mode)
val (typeParams, tpe) = existentialTransform(tree.whereClauses map (_.symbol), tpt1.tpe)
- //println(tpe + ": " + tpe.getClass )
- TypeTree(ExistentialType(typeParams, tpe)) setOriginal tree
+ val tt = TypeTree(ExistentialType(typeParams, tpe)) setOriginal tree
+ if (pending.isEmpty) tt else tt.setErrorCause(PendingErrors(pending.reverse))
}
// lifted out of typed1 because it's needed in typedImplicit0
protected def typedTypeApply(tree: Tree, mode: Int, fun: Tree, args: List[Tree]): Tree = fun.tpe match {
case OverloadedType(pre, alts) =>
- inferPolyAlternatives(fun, args map (_.tpe))
+ inferPolyAlternatives(fun, args map (_.tpe)) match {
+ case Some(err) => return err
+ case _ =>
+ }
val tparams = fun.symbol.typeParams //@M TODO: fun.symbol.info.typeParams ? (as in typedAppliedTypeTree)
val args1 = if (sameLength(args, tparams)) {
//@M: in case TypeApply we can't check the kind-arities of the type arguments,
@@ -3032,7 +3220,7 @@ trait Typers extends Modes with Adaptations {
// 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(_, _) =>
@@ -3040,30 +3228,36 @@ trait Typers extends Modes with Adaptations {
case PolyType(tparams, restpe) if tparams.nonEmpty =>
if (sameLength(tparams, args)) {
val targs = args map (_.tpe)
- checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "")
- if (fun.symbol == Predef_classOf) {
- checkClassType(args.head, true, false)
- atPos(tree.pos) { gen.mkClassOf(targs.head) }
- } else {
- if (phase.id <= currentRun.typerPhase.id &&
- fun.symbol == Any_isInstanceOf && !targs.isEmpty)
- checkCheckable(tree.pos, 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]
- //@M --> first, m[a] gets changed to m[Int], then m gets substituted for List,
- // this must preserve m's type argument, so that we end up with List[Int], and not List[a]
- //@M related bug: #1438
- //println("instantiating type params "+restpe+" "+tparams+" "+targs+" = "+resultpe)
- treeCopy.TypeApply(tree, fun, args) setType resultpe
+ checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "") match {
+ case Some(err) =>
+ err
+ case None =>
+ if (fun.symbol == Predef_classOf) {
+ checkClassType(args.head, true, false) match {
+ case Some(err) => err
+ case _ => atPos(tree.pos) { gen.mkClassOf(targs.head) }
+ }
+ } else {
+ if (phase.id <= currentRun.typerPhase.id &&
+ fun.symbol == Any_isInstanceOf && !targs.isEmpty)
+ checkCheckable(tree.pos, 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]
+ //@M --> first, m[a] gets changed to m[Int], then m gets substituted for List,
+ // this must preserve m's type argument, so that we end up with List[Int], and not List[a]
+ //@M related bug: #1438
+ //println("instantiating type params "+restpe+" "+tparams+" "+targs+" = "+resultpe)
+ treeCopy.TypeApply(tree, fun, args) setType resultpe
+ }
}
} else {
- errorTree(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun))
+ TypedApplyWrongNumberOfTpeParametersError(tree, fun)
}
case ErrorType =>
setError(tree)
case _ =>
- errorTree(tree, treeSymTypeMsg(fun)+" does not take type parameters.")
+ TypedApplyDoesNotTakeTpeParametersError(tree, fun)
}
@inline final def deindentTyping() = context.typingIndentLevel -= 2
@@ -3133,9 +3327,10 @@ trait Typers extends Modes with Adaptations {
atype0 // do not record selfsym if
// this annotation did not need it
- if (ainfo.isErroneous)
+ if (ainfo.isErroneous) {
+ // Erroneous annotations were already reported in typedAnnotation
arg1 // simply drop erroneous annotations
- else {
+ } else {
ann.tpe = atype
TypeTree(atype) setOriginal tree
}
@@ -3169,18 +3364,24 @@ trait Typers extends Modes with Adaptations {
tree setSymbol vble setType vble.tpe
}
def typedBindTerm(name: TermName) = {
+ def typedBindTerm0() = {
+ val body1 = typed(body, mode, pt)
+ vble.setInfo(
+ if (treeInfo.isSequenceValued(body)) seqType(body1.tpe)
+ else body1.tpe)
+ treeCopy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // burak, was: pt
+ }
if (vble == NoSymbol)
vble = context.owner.newValue(tree.pos, name)
if (vble.name.toTermName != nme.WILDCARD) {
- if ((mode & ALTmode) != 0)
- error(tree.pos, "illegal variable in pattern alternative")
vble = namer.enterInScope(vble)
- }
- val body1 = typed(body, mode, pt)
- vble.setInfo(
- if (treeInfo.isSequenceValued(body)) seqType(body1.tpe)
- else body1.tpe)
- treeCopy.Bind(tree, name, body1) setSymbol vble setType body1.tpe // burak, was: pt
+
+ if ((mode & ALTmode) != 0)
+ VariableInPatternAlternativeError(tree)
+ else {
+ typedBindTerm0()
+ }
+ } else typedBindTerm0()
}
name match {
case x: TypeName => typedBindType(x)
@@ -3200,15 +3401,12 @@ trait Typers extends Modes with Adaptations {
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)
-
- setError(tree)
+ if (lhs1.containsErrorOrIsErrorTyped())
+ lhs1
+ else // see #2494 for double error message example
+ AssignmentError(tree, varsym)
}
if (varsym == null)
return fail
@@ -3253,12 +3451,12 @@ trait Typers extends Modes with Adaptations {
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.
@@ -3277,12 +3475,15 @@ trait Typers extends Modes with Adaptations {
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
+ checkClassType(tpt0, false, true) match {
+ case Some(err) => err
+ case _ =>
+ 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 current tree <tree> appears in <val x(: T)? = <tree>>
@@ -3301,17 +3502,15 @@ trait Typers extends Modes with Adaptations {
val tp = tpt1.tpe
val sym = tp.typeSymbol
if (sym.isAbstractType || sym.hasAbstractFlag)
- error(tree.pos, sym + " is abstract; cannot be instantiated")
+ IsAbstractError(tree, sym)
else if (!( tp == sym.initialize.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 {
@@ -3349,22 +3548,23 @@ trait Typers extends Modes with Adaptations {
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): List[Tree] = {
val c = context.makeSilent(false)
c.retyping = true
try {
newTyper(c).typedArgs(args, mode)
} catch {
- case ex: CyclicReference => throw ex
- case ex: TypeError =>
- null
+ case ex: CyclicReference =>
+ throw ex
+ case _: TypeError =>
+ List(NullErrorTree)
}
}
@@ -3373,10 +3573,8 @@ trait Typers extends Modes with Adaptations {
*/
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(treeWithError: Tree): Tree = {
stopTimer(failedApplyNanos, start)
// If the problem is with raw types, copnvert to existentials and try again.
@@ -3399,26 +3597,44 @@ trait Typers extends Modes with Adaptations {
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
+ // Get correct posiition for the error
+ val (ePos, firstToReport) = {
+ val firstError = quickErrorTreeFinder(treeWithError)
+ (firstError.pos, firstError)
+ }
+
+ def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == ePos)
+ val retry = (ePos != null) && (fun :: tree :: args exists errorInResult)
+ if (settings.errortrees.value)
+ println("[ErrorTree retry] " + retry + " with " + treeWithError + " " + firstToReport.exception)
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: " + ePos+"!="+tree.pos
}
if (retry) {
val Select(qual, name) = fun
- val args1 = tryTypedArgs(args, forArgMode(fun, mode), ex)
+ val args1 = tryTypedArgs(args, forArgMode(fun, mode))
+ val invalidArgs = args1.length == 1 && (args1.head.containsError() || args1.head.tpe.isErroneous)
val qual1 =
- if ((args1 ne null) && !pt.isError) adaptToArguments(qual, name, args1, pt)
+ if (!invalidArgs && !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)
}
}
- reportTypeError(tree.pos, ex)
- setError(tree)
+
+ firstToReport
+ }
+
+ silent(_.doTypedApply(tree, fun, args, mode, pt)) match {
+ case t: Tree if !t.containsError() =>
+ t
+ case t: Tree =>
+ onError(t)
+ case ex: TypeError =>
+ onError(TypedApplyError(fun, ex))
}
}
@@ -3431,10 +3647,32 @@ trait Typers extends Modes with Adaptations {
val funpt = if (isPatternMode) pt else WildcardType
val appStart = startTimer(failedApplyNanos)
val opeqStart = startTimer(failedOpEqNanos)
+
+ def onError(reportError: => ErrorTree): Tree = {
+ fun match {
+ case Select(qual, name)
+ if !isPatternMode && nme.isOpAssignmentName(name.decode) =>
+ val qual1 = typedQualifier(qual)
+ if (treeInfo.isVariableOrGetter(qual1)) {
+ stopTimer(failedOpEqNanos, opeqStart)
+ convertToAssignment(fun, qual1, name, args)
+ } else {
+ stopTimer(failedApplyNanos, appStart)
+ if ((qual1.symbol ne null) && qual1.symbol.isValue)
+ AssignmentTypedApplyError(tree)
+ else
+ reportError
+ }
+ case _ =>
+ stopTimer(failedApplyNanos, appStart)
+ reportError
+ }
+ }
+
silent(_.typed(fun, forFunMode(mode), funpt),
if ((mode & EXPRmode) != 0) false else context.reportAmbiguousErrors,
if ((mode & EXPRmode) != 0) tree else context.tree) match {
- case fun1: Tree =>
+ case fun1: Tree if !fun1.containsError() =>
val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1
incCounter(typedApplyCount)
def isImplicitMethod(tpe: Type) = tpe match {
@@ -3460,39 +3698,30 @@ trait Typers extends Modes with Adaptations {
//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.containsError()) {
val checked = gen.mkCheckInit(res)
// this check is needed to avoid infinite recursion in Duplicators
// (calling typed1 more than once for the same tree)
if (checked ne res) typed { atPos(tree.pos)(checked) }
else res
} else res
+
+ case eTree: Tree =>
+ if (settings.errortrees.value)
+ println("[ErrorTree silent] Encounter error in silent typing of apply")
+
+ val ex = quickErrorTreeFinder(eTree)
+ onError(if (ex.exception == null) ex else TypedApplyError(fun, ex.exception))
+
case ex: TypeError =>
- fun match {
- case Select(qual, name)
- if !isPatternMode && nme.isOpAssignmentName(name.decode) =>
- val qual1 = typedQualifier(qual)
- if (treeInfo.isVariableOrGetter(qual1)) {
- stopTimer(failedOpEqNanos, opeqStart)
- convertToAssignment(fun, qual1, name, args, ex)
- } else {
- stopTimer(failedApplyNanos, appStart)
- if ((qual1.symbol ne null) && qual1.symbol.isValue)
- error(tree.pos, "reassignment to val")
- else
- reportTypeError(fun.pos, ex)
- setError(tree)
- }
- case _ =>
- stopTimer(failedApplyNanos, appStart)
- reportTypeError(fun.pos, ex)
- setError(tree)
- }
+ onError(TypedApplyError(fun, ex))
+
+
}
}
}
- 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(
@@ -3533,10 +3762,11 @@ trait Typers extends Modes with Adaptations {
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 {
@@ -3549,8 +3779,8 @@ trait Typers extends Modes with Adaptations {
*/
}
- def qualifyingClassSym(qual: Name): Symbol =
- if (tree.symbol != NoSymbol) tree.symbol else qualifyingClass(tree, qual, false)
+ def qualifyingClassSym(qual: Name): Either[ErrorTree, Symbol] =
+ if (tree.symbol != NoSymbol) Right(tree.symbol) else qualifyingClass(tree, qual, false)
def typedSuper(qual: Tree, mix: TypeName) = {
val qual1 = typed(qual)
@@ -3561,7 +3791,7 @@ trait Typers extends Modes with Adaptations {
}
//println(clazz+"/"+qual1.tpe.typeSymbol+"/"+qual1)
- def findMixinSuper(site: Type): Type = {
+ def findMixinSuper(site: Type): Either[ErrorTree, Type] = {
var ps = site.parents filter (_.typeSymbol.name == mix)
if (ps.isEmpty)
ps = site.parents filter (_.typeSymbol.toInterface.name == mix)
@@ -3576,35 +3806,48 @@ trait Typers extends Modes with Adaptations {
// 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")
+ Left(NullErrorTree)
} else {
- error(tree.pos, mix+" does not name a parent class of "+clazz)
+ Left(MixinMissingParentClassNameError(tree, mix, clazz))
}
- ErrorType
} else if (!ps.tail.isEmpty) {
- error(tree.pos, "ambiguous parent class qualifier")
- ErrorType
+ Left(AmbiguousParentClassError(tree))
} else {
- ps.head
+ Right(ps.head)
}
}
val owntype =
if (mix.isEmpty) {
if ((mode & SUPERCONSTRmode) != 0)
- if (clazz.info.parents.isEmpty) AnyRefClass.tpe // can happen due to cyclic references ==> #1036
- else clazz.info.parents.head
- else intersectionType(clazz.info.parents)
+ if (clazz.info.parents.isEmpty) Right(AnyRefClass.tpe) // can happen due to cyclic references ==> #1036
+ else Right(clazz.info.parents.head)
+ else Right(intersectionType(clazz.info.parents))
} else {
findMixinSuper(clazz.tpe)
}
- treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype)
+ val owntype1 = if (owntype.isLeft) {
+ // Is there any way we can push the error tree into super?
+ // Report here for the moment
+ try {
+ owntype.left.get.emit(context)
+ } catch {
+ case _: TypeError =>
+ assert(false, "Invalid type error when typing Super")
+ }
+ ErrorType
+ } else owntype.right.get
+
+ treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype1)
}
def typedThis(qual: Name) = {
- val clazz = qualifyingClassSym(qual)
- if (clazz == NoSymbol) setError(tree)
+ val clazzOrError = qualifyingClassSym(qual)
+ if (clazzOrError.isLeft) clazzOrError.left.get
+ else if (clazzOrError.right.get == NoSymbol) setError(tree)
else {
+ val clazz = clazzOrError.right.get
tree setSymbol clazz setType clazz.thisType.underlying
if (isStableContext(tree, mode, pt)) tree setType clazz.thisType
tree
@@ -3638,9 +3881,14 @@ trait Typers extends Modes with Adaptations {
}
if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & EXPRmode) != 0) {
val qual1 =
- if (member(qual, name) != NoSymbol) qual
+ if (member(qual, name) != NoSymbol) NullErrorTree
else adaptToMemberWithArgs(tree, qual, name, mode)
- if (qual1 ne qual) return typed(treeCopy.Select(tree, qual1, name), mode, pt)
+ if (!qual1.containsError()) {
+ if (qual1 ne qual)
+ return typed(treeCopy.Select(tree, qual1, name), mode, pt)
+ } else {
+ return qual1
+ }
}
if (!reallyExists(sym)) {
@@ -3671,24 +3919,14 @@ trait Typers extends Modes with Adaptations {
)
}
- def makeErrorTree = {
- val tree1 = tree match {
- case Select(_, _) => treeCopy.Select(tree, qual, name)
- case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
- }
- setError(tree1)
- }
-
- if (name == nme.ERROR && forInteractive)
- return makeErrorTree
-
- if (!qual.tpe.widen.isErroneous) {
+ if (forInteractive)
+ NotAMemberInteractive(tree)
+ else if (!qual.tpe.widen.isErroneous) {
val lastTry = missingHook(qual.tpe.typeSymbol, name)
if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
- notAMemberError(tree.pos, qual, name)
- }
-
- if (forInteractive) makeErrorTree else setError(tree)
+ NotAMemberError(tree, qual, name)
+ } else
+ NotAMemberErroneous(tree)
} else {
val tree1 = tree match {
case Select(_, _) => treeCopy.Select(tree, qual, name)
@@ -3714,16 +3952,32 @@ trait Typers extends Modes with Adaptations {
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, "")
- qual // you only get to see the wrapped tree after running this check :-p
+ checkBounds(qual.pos, tp.prefix, sym.owner, sym.typeParams, tp.typeArgs, "") match {
+ case Some(err) => Left(err)
+ case _ => Right(qual) // you only get to see the wrapped tree after running this check :-p
+ }
}) setType qual.tpe,
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 tt if tt.containsError() =>
+ val errTree = quickErrorTreeFinder(tt)
+ errTree match {
+ case accError: AccessError =>
+ val qual1 =
+ try adaptToMemberWithArgs(tree, qual, name, mode)
+ catch {
+ case _: TypeError =>
+ // Ambigues implicits throw TypeError
+ // and then they are reported here.
+ NullErrorTree
+ }
+ if (!qual1.containsError() && (qual1 ne qual)) {
+ typed(Select(qual1, name) setPos tree.pos, mode, pt)
+ } else {
+ accError
+ }
+ case _ =>
+ tt
+ }
case _ =>
result
}
@@ -3731,7 +3985,8 @@ trait Typers extends Modes with Adaptations {
// 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.containsError()
+ && 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
@@ -3739,7 +3994,7 @@ trait Typers extends Modes with Adaptations {
&& qual.tpe.typeSymbol.isPublic
)
if (isRefinableGetClass)
- selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe))
+ selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe))
else
selection
}
@@ -3753,8 +4008,17 @@ trait Typers extends Modes with Adaptations {
* (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: Tree = 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: ErrorTree) = {
+ 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
@@ -3856,7 +4120,7 @@ trait Typers extends Modes with Adaptations {
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)
@@ -3871,11 +4135,17 @@ trait Typers extends Modes with Adaptations {
}
imports1 = imports1.tail
}
- defSym = impSym
- val qual0 = imports.head.qual
- if (!(shortenImports && qual0.symbol.isPackage)) // optimization: don't write out package prefixes
- qual = atPos(tree.pos.focusStart)(resetPos(qual0.duplicate))
- pre = qual.tpe
+ if (errorContainer == null) {
+ if (imports.head.qual.containsError()) {
+ defSym = context.owner.newErrorSymbol(name)
+ } else {
+ defSym = impSym
+ val qual0 = imports.head.qual
+ if (!(shortenImports && qual0.symbol.isPackage)) // optimization: don't write out package prefixes
+ qual = atPos(tree.pos.focusStart)(resetPos(qual0.duplicate))
+ pre = qual.tpe
+ }
+ }
}
else if (settings.exposeEmptyPackage.value && checkEmptyPackage())
log("Allowing empty package member " + name + " due to settings.")
@@ -3889,50 +4159,53 @@ trait Typers extends Modes with Adaptations {
if (inaccessibleSym eq NoSymbol) {
// Avoiding some spurious error messages: see SI-2388.
if (reporter.hasErrors && (name startsWith tpnme.ANON_CLASS_NAME)) ()
- else error(tree.pos, "not found: "+decodeWithKind(name, context.owner))
+ else identError(SymbolNotFound(tree, name, context.owner))
+ } else {
+ identError(AccessError(
+ tree, inaccessibleSym, context.enclClass.owner.thisType, context.enclClass.owner,
+ inaccessibleExplanation
+ ))
}
- else new AccessError(
- tree, inaccessibleSym, context.enclClass.owner.thisType,
- inaccessibleExplanation
- ).emit()
defSym = context.owner.newErrorSymbol(name)
}
}
}
- if (defSym.owner.isPackageClass) pre = defSym.owner.thisType
- if (defSym.isThisSym) {
- typed1(This(defSym.owner) setPos tree.pos, mode, pt)
+
+ if (errorContainer != null) {
+ errorContainer
} else {
- val tree1 = if (qual == EmptyTree) tree
- else atPos(tree.pos)(Select(qual, name))
- // atPos necessary because qualifier might come from startContext
- 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
+ if (defSym.owner.isPackageClass) pre = defSym.owner.thisType
+ if (defSym.isThisSym) {
+ typed1(This(defSym.owner) setPos tree.pos, mode, pt)
+ } else {
+ val tree1 = if (qual == EmptyTree) tree
+ else atPos(tree.pos)(Select(qual, name))
+ // atPos necessary because qualifier might come from startContext
+ 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 (_.containsErrorOrIsErrorTyped())) tree setType ErrorType
else {
val decls = new Scope
//Console.println("Owner: " + context.enclClass.owner + " " + context.enclClass.owner.id)
val self = refinedType(parents1 map (_.tpe), context.enclClass.owner, decls, templ.pos)
newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ.body)
- tree setType self
+ tree.setType(self)
}
}
def typedAppliedTypeTree(tpt: Tree, args: List[Tree]) = {
val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType)
- if (tpt1.tpe.isError) {
- setError(tree)
+ if (tpt1.containsErrorOrIsErrorTyped()) {
+ setError(treeCopy.AppliedTypeTree(tree, tpt1, args))
} 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)) {
@@ -3965,16 +4238,18 @@ trait Typers extends Modes with Adaptations {
// 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, "")
- result // you only get to see the wrapped tree after running this check :-p
+ checkBounds(result.pos, tpt1.tpe.prefix, tpt1.symbol.owner, tpt1.symbol.typeParams, argtypes, "") match {
+ case Some(err) => Left(err)
+ case _ => Right(result) // you only get to see the wrapped tree after running this check :-p
+ }
}).setType(result.tpe)
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, "wrong number of type arguments for "+tpt1.tpe+", should be "+tparams.length)
}
}
}
@@ -3988,7 +4263,12 @@ trait Typers extends Modes with Adaptations {
//if (settings.debug.value && tree.isDef) log("typing definition of "+sym);//DEBUG
tree match {
case PackageDef(pid, stats) =>
- val pid1 = typedQualifier(pid).asInstanceOf[RefTree]
+ val pid1 = typedQualifier(pid) match {
+ case e: ErrorTree =>
+ RefTreeError(e, pid.name)
+ case t: RefTree =>
+ t
+ }
assert(sym.moduleClass ne NoSymbol, sym)
// complete lazy annotations
val annots = sym.annotations
@@ -4023,6 +4303,9 @@ trait Typers extends Modes with Adaptations {
typer1.silent(_.typedUseCase(useCase)) match {
case ex: TypeError =>
unit.warning(useCase.pos, ex.msg)
+ case tree: Tree if tree.containsError() =>
+ val ex = quickErrorTreeFinder(tree)
+ unit.warning(useCase.pos, ex.exception.msg)
case _ =>
}
for (useCaseSym <- useCase.defined) {
@@ -4045,9 +4328,14 @@ trait Typers extends Modes with Adaptations {
treeCopy.Alternative(tree, alts1) setType pt
case Star(elem) =>
- checkStarPatOK(tree.pos, mode)
+ val err0 = checkStarPatOK(tree.pos, mode)
val elem1 = typed(elem, mode, pt)
- treeCopy.Star(tree, elem1) setType makeFullyDefined(pt)
+ val elem2 = err0 match {
+ case Some(err) =>
+ wrapInBlock(err, elem1)
+ case _ => elem1
+ }
+ treeCopy.Star(tree, elem2) setType makeFullyDefined(pt)
case Bind(name, body) =>
typedBind(name, body)
@@ -4131,25 +4419,32 @@ trait Typers extends Modes with Adaptations {
val tparam = context.owner freshExistential "" setInfo TypeBounds.upper(pt)
ExistentialType(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)
- }
- expr1.tpe.baseType(baseClass) match {
- case TypeRef(_, _, List(elemtp)) =>
- treeCopy.Typed(tree, expr1, tpt setType elemtp) setType elemtp
- case _ =>
- setError(tree)
+
+ if (expr0.containsError())
+ treeCopy.Typed(tree, expr0, tpt setType ErrorType) setType ErrorType
+ else {
+ val (expr1, baseClass) = expr0.tpe.typeSymbol match {
+ case ArrayClass => (adapt(expr0, onlyStickyModes(mode), subArrayType(pt)), ArrayClass)
+ case _ => (adapt(expr0, onlyStickyModes(mode), seqType(pt)), SeqClass)
+ }
+ expr1.tpe.baseType(baseClass) match {
+ case TypeRef(_, _, List(elemtp)) =>
+ treeCopy.Typed(tree, expr1, tpt setType elemtp) setType elemtp
+ case _ =>
+ setError(tree)
+ }
}
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 (expr2, ownType) = if (isPatternMode)
+ inferTypedPattern(tpt1.pos, tpt1.tpe, pt) match {
+ case Left(err) =>
+ (wrapInBlock(expr1, err), ErrorType)
+ case Right(tp) => (expr1, tp)
+ } else (expr1, 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)
@@ -4192,6 +4487,8 @@ trait Typers extends Modes with Adaptations {
case Apply(fun, args) =>
typedApply(fun, args) match {
+ case tree1 if tree1.containsError() =>
+ tree1
case Apply(Select(New(tpt), name), args)
if (tpt.tpe != null &&
tpt.tpe.typeSymbol == ArrayClass &&
@@ -4201,12 +4498,14 @@ trait Typers extends Modes with Adaptations {
// 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.pos, 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
}
@@ -4235,20 +4534,26 @@ trait Typers extends Modes with Adaptations {
if (name.isTypeName) qual1 = checkStable(qual1)
val tree1 = // temporarily use `filter` and an alternative for `withFilter`
- if (name == nme.withFilter)
+ if (qual1.containsError())
+ treeCopy.Select(tree, qual1, name) setType ErrorType
+ else if (name == nme.withFilter)
silent(_ => typedSelect(qual1, name)) match {
- case result1: Tree =>
+ case result1: Tree if !result1.containsError() =>
result1
- case ex1: TypeError =>
+ case ex1 =>
silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match {
case result2: Tree =>
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 _: TypeError =>
+ val ex2 = ex1 match {
+ case te: TypeError => te
+ case t: Tree =>
+ quickErrorTreeFinder(t).exception
+ }
+ WithFilterError(tree, ex2)
}
}
else
@@ -4273,12 +4578,17 @@ trait Typers extends Modes with Adaptations {
case SingletonTypeTree(ref) =>
val ref1 = checkStable(
typed(ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe))
- tree setType ref1.tpe.resultType
+ if (ref1.containsError())
+ treeCopy.SingletonTypeTree(tree, ref1) setType ErrorType
+ else
+ tree setType ref1.tpe.resultType
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)
@@ -4311,6 +4621,39 @@ trait Typers extends Modes with Adaptations {
}
}
+ def handleErrorTree(t: Tree) {
+ val allErrors = errorTreesFinder(t)
+
+ // Report any errors if possible in the current context
+ // If an error tree throws type error (we are in silent mode), then we will not mark
+ // tree as visited and it will be reported later if necessary
+ allErrors.foreach { t0 =>
+ try {
+ if (settings.errortrees.value) {
+ println("[ErrorTree emit] " + t0)
+ if (t0.exception != null) {
+ println(t0.exception.getClass)
+ }
+ }
+ t0.emit(context)
+ t0.reported = true
+ } catch {
+ case te: TypeError =>
+ // Catch all type errors if we are in typer phase.
+ // All typer errors will be reported at some point anyway.
+ if (settings.errortrees.value)
+ println("[ErrorTree TypeError] Throws " + te)
+
+ // After typer all bets are off
+ // and we do not try to hide TypeError within error tree
+ if (phase.id > currentRun.typerPhase.id) {
+ t0.reported = true
+ throw te
+ }
+ }
+ }
+ }
+
/**
* @param tree ...
* @param mode ...
@@ -4354,22 +4697,36 @@ trait Typers extends Modes with Adaptations {
tree1
}
- tree1.tpe = addAnnotations(tree1, tree1.tpe)
- val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, tree)
+ if (tree1.containsError()) {
+ handleErrorTree(tree1)
+ if (phase.id <= currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, tree1)
+ tree1
+ } else {
+ tree1.tpe = addAnnotations(tree1, tree1.tpe)
+ val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt, tree)
- if (!alreadyTyped) {
- printTyping("adapted %s: %s to %s, %s".format(
- tree1, tree1.tpe.widen, pt, context.undetparamsString)
- ) //DEBUG
+ if (!alreadyTyped) {
+ printTyping("adapted %s: %s to %s, %s".format(
+ tree1, tree1.tpe.widen, pt, context.undetparamsString)
+ ) //DEBUG
+ }
+ if (phase.id <= currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, result)
+ if (result.containsError()) handleErrorTree(result)
+ result
}
-
-// for (t <- tree1.tpe) assert(t != WildcardType)
-// if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe)
- if (phase.id <= currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, result)
- result
} catch {
case ex: TypeError =>
tree.tpe = null
+ // At some point we might want to get rid of the code below
+ // because everything will be handled by error trees.
+ // The only problematic case are Cyclic errors which can pop up almost anywhere
+ if (settings.errortrees.value) {
+ println("[ErrorTree CAUGHT] %s: while typing %s".format(ex, tree))
+ println("TODO with error trees shouldn't throw non-cyclic errors")
+ ex.printStackTrace()
+ println("----------")
+ }
+
printTyping("caught %s: while typing %s".format(ex, tree)) //DEBUG
reportTypeError(tree.pos, ex)
setError(tree)
@@ -4473,12 +4830,12 @@ trait Typers extends Modes with Adaptations {
// 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")
+ return ConstructorPrefixError(tree, restpe)
}
//@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) {
+ if (result.tpe.typeArgs.isEmpty && !result.containsError()) {
// 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
@@ -4494,10 +4851,25 @@ trait Typers extends Modes with Adaptations {
def typedTypeConstructor(tree: Tree): Tree = typedTypeConstructor(tree, NOmode)
+ // Because this is called from Namers and pattern matcher, we
+ // have to report missing errors (if any)
def computeType(tree: Tree, pt: Type): Type = {
val tree1 = typed(tree, pt)
- transformed(tree) = tree1
- packedType(tree1, context.owner)
+ if (tree1.containsError()) {
+ assert(errorTreesFinder(tree1).isEmpty, "All type errors have been reported during computation of type")
+ ErrorType
+ } else {
+ transformed(tree) = tree1
+ val (tpe, errs) = packedType(tree1, context.owner)
+ try {
+ errs.foreach(_.emit(context))
+ tpe
+ } catch {
+ case _: TypeError =>
+ assert(false, "No type errors can be thrown after type was computed")
+ ErrorType
+ }
+ }
}
def transformedOrTyped(tree: Tree, mode: Int, pt: Type): Tree = transformed.get(tree) match {
@@ -4515,8 +4887,7 @@ trait Typers extends Modes with Adaptations {
def getManifestTree(pos: Position, 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(pos, full, tp)
} else {
manifestOpt.tree
}