summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/TreePrinters.scala3
-rw-r--r--src/compiler/scala/reflect/internal/Trees.scala5
-rw-r--r--src/compiler/scala/reflect/runtime/RuntimeTypes.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala16
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala14
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala29
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala11
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala2
-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
-rw-r--r--src/library/scala/reflect/api/Trees.scala270
-rw-r--r--test/files/neg/patternalts.check5
-rw-r--r--test/files/neg/t1878.check11
-rw-r--r--test/files/neg/t2641.check30
-rw-r--r--test/files/neg/t2918.check8
-rw-r--r--test/files/neg/t3015.check7
-rw-r--r--test/files/neg/t997.check8
-rw-r--r--test/files/neg/volatile.check7
28 files changed, 2901 insertions, 922 deletions
diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala
index e5b9fafa00..6a5cbb4035 100644
--- a/src/compiler/scala/reflect/internal/TreePrinters.scala
+++ b/src/compiler/scala/reflect/internal/TreePrinters.scala
@@ -405,7 +405,8 @@ trait TreePrinters { self: SymbolTable =>
// SelectFromArray.
// case SelectFromArray(qualifier, name, _) =>
// print(qualifier); print(".<arr>"); print(symName(tree, name))
-
+ case err: ErrorTreeWithPrettyPrinter =>
+ print(err.toString())
case tree =>
xprintRaw(this, tree)
diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala
index f9ca57fadc..dec0dcfdf9 100644
--- a/src/compiler/scala/reflect/internal/Trees.scala
+++ b/src/compiler/scala/reflect/internal/Trees.scala
@@ -117,6 +117,9 @@ trait Trees extends api.Trees { self: SymbolTable =>
def shallowDuplicate: Tree = new ShallowDuplicator(tree) transform tree
def shortClass: String = tree.getClass.getName split "[.$]" last
+
+ def containsErrorOrIsErrorTyped() = tree.containsError() || ((tree.tpe ne null) && tree.tpe.isError)
+
/** When you want to know a little more than the class, but a lot
* less than the whole tree.
*/
@@ -271,6 +274,8 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
}
+ trait ErrorTreeWithPrettyPrinter extends AbsErrorTree
+
def atPos[T <: Tree](pos: Position)(tree: T): T = {
posAssigner.pos = pos
posAssigner.traverse(tree)
diff --git a/src/compiler/scala/reflect/runtime/RuntimeTypes.scala b/src/compiler/scala/reflect/runtime/RuntimeTypes.scala
index 818596d7b3..497290dbbc 100644
--- a/src/compiler/scala/reflect/runtime/RuntimeTypes.scala
+++ b/src/compiler/scala/reflect/runtime/RuntimeTypes.scala
@@ -10,7 +10,11 @@ trait RuntimeTypes extends Universe with api.RuntimeTypes {
// to do: replace with generalized
// case class Literal(x: Any),
// once calls to the deprecated factory Literal(x: Any) has been eliminated from all code.
- case class FreeValue(any: Any) extends Tree
+ case class FreeValue(any: Any) extends Tree {
+ protected def initErrorCheck {
+ hasErrorTree = Some(false)
+ }
+ }
case class InstanceRefSymbol(value: AnyRef) extends TermSymbol(NoSymbol, NoPosition, nme.EMPTY)
object InstanceRefSymbol extends InstanceRefSymbolExtractor
diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
index 613928856d..37dea497fc 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
@@ -36,13 +36,19 @@ abstract class TreeBrowsers {
def create(): SwingBrowser = new SwingBrowser();
+ trait ValidTree extends Tree {
+ protected def initErrorCheck {
+ hasErrorTree = Some(false)
+ }
+ }
+
/** Pseudo tree class, so that all JTree nodes are treated uniformly */
- case class ProgramTree(units: List[UnitTree]) extends Tree {
+ case class ProgramTree(units: List[UnitTree]) extends ValidTree {
override def toString(): String = "Program"
}
/** Pseudo tree class, so that all JTree nodes are treated uniformly */
- case class UnitTree(unit: CompilationUnit) extends Tree {
+ case class UnitTree(unit: CompilationUnit) extends ValidTree {
override def toString(): String = unit.toString()
}
@@ -490,6 +496,9 @@ abstract class TreeBrowsers {
case Star(t) =>
("Star", EMPTY)
+
+ case _: AbsErrorTree =>
+ ("ErrorTree", EMPTY)
}
/** Return a list of children for the given tree node */
@@ -631,6 +640,9 @@ abstract class TreeBrowsers {
case Star(t) =>
List(t)
+
+ case _: AbsErrorTree =>
+ Nil
}
/** Return a textual representation of this t's symbol */
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index acca7dac7d..ee0b28b02f 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -191,15 +191,21 @@ abstract class TreeGen extends reflect.internal.TreeGen {
* symbol to its packed type, and an function for creating Idents
* which refer to it.
*/
- private def mkPackedValDef(expr: Tree, owner: Symbol, name: Name): (ValDef, () => Ident) = {
- val packedType = typer.packedType(expr, owner)
+ private def mkPackedValDef(expr: Tree, owner: Symbol, name: Name): (Tree, () => Ident) = {
+ val (packedType, errs) = typer.packedType(expr, owner)
+ // TODO ensure that they don't throw errors?
+ errs.foreach(_.emit(typer.context))
val sym = (
owner.newValue(expr.pos.makeTransparent, name)
setFlag SYNTHETIC
setInfo packedType
)
- (ValDef(sym, expr), () => Ident(sym) setPos sym.pos.focus setType expr.tpe)
+ val identFn = () => Ident(sym) setPos sym.pos.focus setType expr.tpe
+ if (errs.isEmpty)
+ (ValDef(sym, expr), identFn)
+ else
+ (analyzer.PendingErrors(errs), identFn)
}
/** Used in situations where you need to access value of an expression several times
@@ -218,7 +224,7 @@ abstract class TreeGen extends reflect.internal.TreeGen {
}
def evalOnceAll(exprs: List[Tree], owner: Symbol, unit: CompilationUnit)(within: (List[() => Tree]) => Tree): Tree = {
- val vdefs = new ListBuffer[ValDef]
+ val vdefs = new ListBuffer[Tree]
val exprs1 = new ListBuffer[() => Tree]
val used = new Array[Boolean](exprs.length)
var i = 0
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 86aca26ba6..db5848f92b 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -17,9 +17,12 @@ import scala.reflect.internal.Flags.TRAIT
trait Trees extends reflect.internal.Trees { self: Global =>
// --- additional cases --------------------------------------------------------
-
/** Only used during parsing */
- case class Parens(args: List[Tree]) extends Tree
+ case class Parens(args: List[Tree]) extends Tree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(args)
+ }
+ }
/** Documented definition, eliminated by analyzer */
case class DocDef(comment: DocComment, definition: Tree)
@@ -29,6 +32,10 @@ trait Trees extends reflect.internal.Trees { self: Global =>
override def isDef = definition.isDef
override def isTerm = definition.isTerm
override def isType = definition.isType
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(definition)
+ }
}
@@ -36,14 +43,26 @@ trait Trees extends reflect.internal.Trees { self: Global =>
* eliminated by typecheck (doTypedApply)
*/
case class AssignOrNamedArg(lhs: Tree, rhs: Tree)
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(List(lhs, rhs))
+ }
+ }
/** Array selection <qualifier> . <name> only used during erasure */
case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type)
- extends TermTree with RefTree { }
+ extends TermTree with RefTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(qualifier)
+ }
+ }
/** emitted by typer, eliminated by refchecks */
- case class TypeTreeWithDeferredRefCheck()(val check: () => TypeTree) extends TypTree
+ case class TypeTreeWithDeferredRefCheck()(val check: () => Either[AbsErrorTree, TypeTree]) extends TypTree {
+ protected def initErrorCheck {
+ hasErrorTree = Some(false)
+ }
+ }
// --- factory methods ----------------------------------------------------------
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 362ec1bae0..69cd2d1ef7 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -813,17 +813,24 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "")
private def typeMembers(pos: Position): Stream[List[TypeMember]] = {
var tree = typedTreeAt(pos)
+ val context = doLocateContext(pos)
+
// if tree consists of just x. or x.fo where fo is not yet a full member name
// ignore the selection and look in just x.
tree match {
case Select(qual, name) if tree.tpe == ErrorType => tree = qual
+ case ierr: analyzer.InteractiveErrorTree =>
+ ierr.emit(context)
+ ierr.retrieveEmitted match {
+ case Select(qual, name) => tree = qual
+ case _ =>
+ }
case _ =>
}
- val context = doLocateContext(pos)
+
if (tree.tpe == null)
- // TODO: guard with try/catch to deal with ill-typed qualifiers.
tree = analyzer.newTyper(context).typedQualifier(tree)
debugLog("typeMembers at "+tree+" "+tree.tpe)
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 56ac3e16ad..ca7ca5b41f 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -60,6 +60,7 @@ trait ScalaSettings extends AbsScalaSettings
val assemextdirs = StringSetting ("-Xassem-extdirs", "dirs", "(Requires -target:msil) List of directories containing assemblies. default:lib", Defaults.scalaLibDir.path).dependsOn(target, "msil")
val sourcedir = StringSetting ("-Xsourcedir", "directory", "(Requires -target:msil) Mirror source folder structure in output directory.", ".").dependsOn(target, "msil")
val checkInit = BooleanSetting ("-Xcheckinit", "Wrap field accessors to throw an exception on uninitialized access.")
+ val errortrees = BooleanSetting ("-Yerrortrees", "Provide more info about error trees." )
val noassertions = BooleanSetting ("-Xdisable-assertions", "Generate no assertions or assumptions.")
val elidebelow = IntSetting ("-Xelide-below", "Calls to @elidable methods are omitted if method priority is lower than argument",
elidable.MINIMUM, None, elidable.byName get _)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 12a17abe91..580014811b 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -59,7 +59,7 @@ abstract class Pickler extends SubComponent {
}
}
// If there are any erroneous types in the tree, then we will crash
- // when we pickle it: so let's report an erorr instead. We know next
+ // when we pickle it: so let's report an error instead. We know next
// to nothing about what happened, but our supposition is a lot better
// than "bad type: <error>" in terms of explanatory power.
for (t <- unit.body ; if t.isErroneous) {
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
}
diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala
index cf9d301e95..7185ea73e2 100644
--- a/src/library/scala/reflect/api/Trees.scala
+++ b/src/library/scala/reflect/api/Trees.scala
@@ -217,6 +217,25 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
override def toString: String = show(this)
override def hashCode(): Int = System.identityHashCode(this)
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
+
+ // TODO: implementation of more aggresive caching still needs
+ // more testing
+ //protected var hasErrorTree: List[ErrorTree] = null
+ protected var hasErrorTree: Option[Boolean] = None
+ protected def initErrorCheck: Unit
+
+ def containsError(): Boolean = {
+ if (hasErrorTree.isEmpty)
+ initErrorCheck
+ hasErrorTree.get
+ }
+ }
+
+ @inline def containsErrorCheck(ts: List[Tree]): Some[Boolean] = Some(ts.exists(_.containsError()))
+ @inline def containsErrorCheck(t: Tree): Some[Boolean] = Some(t.containsError())
+
+ trait AbsErrorTree extends Tree {
+ def emit(): Unit
}
/** A tree for a term. Not all terms are TermTrees; use isTerm
@@ -259,6 +278,10 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
override def tpe_=(t: Type) =
if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>")
override def isEmpty = true
+
+ protected def initErrorCheck {
+ hasErrorTree = Some(false)
+ }
}
/** Common base class for all member definitions: types, classes,
@@ -284,6 +307,10 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
extends MemberDef {
def name = pid.name
def mods = Modifiers()
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(stats)
+ }
}
/** A common base class for class and object definitions.
@@ -295,13 +322,21 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
/** A class definition.
*/
case class ClassDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], impl: Template)
- extends ImplDef
+ extends ImplDef {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(tparams ++ List(impl))
+ }
+ }
/** An object definition, e.g. `object Foo`. Internally, objects are
* quite frequently called modules to reduce ambiguity.
*/
case class ModuleDef(mods: Modifiers, name: TermName, impl: Template)
- extends ImplDef
+ extends ImplDef {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(impl)
+ }
+ }
/** A common base class for ValDefs and DefDefs.
*/
@@ -314,17 +349,29 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
/** A value definition (this includes vars as well, which differ from
* vals only in having the MUTABLE flag set in their Modifiers.)
*/
- case class ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) extends ValOrDefDef
+ case class ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) extends ValOrDefDef {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(List(tpt, rhs))
+ }
+ }
/** A method definition.
*/
case class DefDef(mods: Modifiers, name: TermName, tparams: List[TypeDef],
- vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) extends ValOrDefDef
+ vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) extends ValOrDefDef {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(tparams ++ vparamss.flatten ++ List(tpt, rhs))
+ }
+ }
/** An abstract type, a type parameter, or a type alias.
*/
case class TypeDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree)
- extends MemberDef
+ extends MemberDef {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(tparams ++ List(rhs))
+ }
+ }
/** A labelled expression. Not expressible in language syntax, but
* generated by the compiler to simulate while/do-while loops, and
@@ -341,7 +388,11 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
* Forward jumps within a block are allowed.
*/
case class LabelDef(name: TermName, params: List[Ident], rhs: Tree)
- extends DefTree with TermTree
+ extends DefTree with TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(params ++ List(rhs))
+ }
+ }
/** Import selector
*
@@ -360,7 +411,11 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
* @param selectors
*/
case class Import(expr: Tree, selectors: List[ImportSelector])
- extends SymTree
+ extends SymTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(expr)
+ }
+ }
// The symbol of an Import is an import symbol @see Symbol.newImport
// It's used primarily as a marker to check that the import has been typechecked.
@@ -382,27 +437,46 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
// def bar // owner is local dummy
// }
// System.err.println("TEMPLATE: " + parents)
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(self::parents:::body)
+ }
}
/** Block of expressions (semicolon separated expressions) */
case class Block(stats: List[Tree], expr: Tree)
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(stats ++ List(expr))
+ }
+ }
/** Case clause in a pattern match, eliminated during explicitouter
* (except for occurrences in switch statements)
*/
case class CaseDef(pat: Tree, guard: Tree, body: Tree)
- extends Tree
+ extends Tree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(List(pat, guard, body))
+ }
+ }
/** Alternatives of patterns, eliminated by explicitouter, except for
* occurrences in encoded Switch stmt (=remaining Match(CaseDef(...))
*/
case class Alternative(trees: List[Tree])
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(trees)
+ }
+ }
/** Repetition of pattern, eliminated by explicitouter */
case class Star(elem: Tree)
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(elem)
+ }
+ }
/** Bind of a variable to a rhs pattern, eliminated by explicitouter
*
@@ -410,29 +484,53 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
* @param body
*/
case class Bind(name: Name, body: Tree)
- extends DefTree
+ extends DefTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(body)
+ }
+ }
case class UnApply(fun: Tree, args: List[Tree])
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(fun::args)
+ }
+ }
/** Array of expressions, needs to be translated in backend,
*/
case class ArrayValue(elemtpt: Tree, elems: List[Tree])
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(elemtpt::elems)
+ }
+ }
/** Anonymous function, eliminated by analyzer */
case class Function(vparams: List[ValDef], body: Tree)
- extends TermTree with SymTree
+ extends TermTree with SymTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(vparams ++ List(body))
+ }
+ }
// The symbol of a Function is a synthetic value of name nme.ANON_FUN_NAME
// It is the owner of the function's parameters.
/** Assignment */
case class Assign(lhs: Tree, rhs: Tree)
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(List(lhs, rhs))
+ }
+ }
/** Conditional expression */
case class If(cond: Tree, thenp: Tree, elsep: Tree)
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(List(cond, thenp, elsep))
+ }
+ }
/** - Pattern matching expression (before explicitouter)
* - Switch statements (after explicitouter)
@@ -446,30 +544,54 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
* `Ident(nme.WILDCARD)`
*/
case class Match(selector: Tree, cases: List[CaseDef])
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(selector::cases)
+ }
+ }
/** Return expression */
case class Return(expr: Tree)
- extends TermTree with SymTree
+ extends TermTree with SymTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(expr)
+ }
+ }
// The symbol of a Return node is the enclosing method.
case class Try(block: Tree, catches: List[CaseDef], finalizer: Tree)
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(block::catches ++ List(finalizer))
+ }
+ }
/** Throw expression */
case class Throw(expr: Tree)
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(expr)
+ }
+ }
/** Object instantiation
* One should always use factory method below to build a user level new.
*
* @param tpt a class type
*/
- case class New(tpt: Tree) extends TermTree
+ case class New(tpt: Tree) extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(tpt)
+ }
+ }
/** Type annotation, eliminated by explicit outer */
case class Typed(expr: Tree, tpt: Tree)
- extends TermTree
+ extends TermTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(List(expr, tpt))
+ }
+ }
/** Common base class for Apply and TypeApply. This could in principle
* be a SymTree, but whether or not a Tree is a SymTree isn't used
@@ -488,6 +610,10 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
extends GenericApply {
override def symbol: Symbol = fun.symbol
override def symbol_=(sym: Symbol) { fun.symbol = sym }
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(fun::args)
+ }
}
/** Value application */
@@ -495,6 +621,10 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
extends GenericApply {
override def symbol: Symbol = fun.symbol
override def symbol_=(sym: Symbol) { fun.symbol = sym }
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(fun::args)
+ }
}
class ApplyToImplicitArgs(fun: Tree, args: List[Tree]) extends Apply(fun, args)
@@ -508,7 +638,11 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
* - f is stored as the node's symbol field.
*/
case class ApplyDynamic(qual: Tree, args: List[Tree])
- extends TermTree with SymTree
+ extends TermTree with SymTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(qual::args)
+ }
+ }
// The symbol of an ApplyDynamic is the function symbol of `qual`, or NoSymbol, if there is none.
/** Super reference, qual = corresponding this reference */
@@ -517,20 +651,37 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
// For instance in C.super(...), it would be C.
override def symbol: Symbol = qual.symbol
override def symbol_=(sym: Symbol) { qual.symbol = sym }
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(qual)
+ }
}
/** Self reference */
case class This(qual: TypeName)
- extends TermTree with SymTree
+ extends TermTree with SymTree {
+ protected def initErrorCheck {
+ // TODO should check qual name, symbol?
+ hasErrorTree = Some(false)
+ }
+ }
// The symbol of a This is the class to which the this refers.
// For instance in C.this, it would be C.
/** Designator <qualifier> . <name> */
case class Select(qualifier: Tree, name: Name)
- extends RefTree
+ extends RefTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(qualifier)
+ }
+ }
/** Identifier <name> */
- case class Ident(name: Name) extends RefTree { }
+ case class Ident(name: Name) extends RefTree {
+ protected def initErrorCheck {
+ hasErrorTree = Some(false)
+ }
+ }
class BackQuotedIdent(name: Name) extends Ident(name)
@@ -538,6 +689,10 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
case class Literal(value: Constant)
extends TermTree {
assert(value ne null)
+
+ protected def initErrorCheck {
+ hasErrorTree = Some(false)
+ }
}
// @deprecated("will be removed and then be re-introduced with changed semantics, use Literal(Constant(x)) instead")
@@ -548,45 +703,81 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
* Eliminated by typechecker (typedAnnotated), the annotations are then stored in
* an AnnotatedType.
*/
- case class Annotated(annot: Tree, arg: Tree) extends Tree
+ case class Annotated(annot: Tree, arg: Tree) extends Tree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(List(annot, arg))
+ }
+ }
/** Singleton type, eliminated by RefCheck */
case class SingletonTypeTree(ref: Tree)
- extends TypTree
+ extends TypTree {
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(ref)
+ }
+ }
/** Type selection <qualifier> # <name>, eliminated by RefCheck */
case class SelectFromTypeTree(qualifier: Tree, name: TypeName)
- extends TypTree with RefTree
+ extends TypTree with RefTree {
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(qualifier)
+ }
+ }
/** Intersection type <parent1> with ... with <parentN> { <decls> }, eliminated by RefCheck */
case class CompoundTypeTree(templ: Template)
- extends TypTree
+ extends TypTree {
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(templ)
+ }
+ }
/** Applied type <tpt> [ <args> ], eliminated by RefCheck */
case class AppliedTypeTree(tpt: Tree, args: List[Tree])
extends TypTree {
override def symbol: Symbol = tpt.symbol
override def symbol_=(sym: Symbol) { tpt.symbol = sym }
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(tpt::args)
+ }
}
case class TypeBoundsTree(lo: Tree, hi: Tree)
- extends TypTree
+ extends TypTree {
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(List(lo, hi))
+ }
+ }
case class ExistentialTypeTree(tpt: Tree, whereClauses: List[Tree])
- extends TypTree
+ extends TypTree {
+
+ protected def initErrorCheck {
+ hasErrorTree = containsErrorCheck(tpt::whereClauses)
+ }
+ }
/** A synthetic tree holding an arbitrary type. Not to be confused with
* with TypTree, the trait for trees that are only used for type trees.
* TypeTree's are inserted in several places, but most notably in
* `RefCheck`, where the arbitrary type trees are all replaced by
- * TypeTree's. */
+ * TypeTree's.
+ *
+ */
case class TypeTree() extends TypTree {
private var orig: Tree = null
+ private var errorCause: Tree = null
private[scala] var wasEmpty: Boolean = false
override def symbol = if (tpe == null) null else tpe.typeSymbol
override def isEmpty = (tpe eq null) || tpe == NoType
+
def original: Tree = orig
def setOriginal(tree: Tree): this.type = {
def followOriginal(t: Tree): Tree = t match {
@@ -598,10 +789,20 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
this
}
+ def setErrorCause(tree: Tree): this.type = {
+ assert(tree != null)
+ errorCause = tree
+ this
+ }
+
override def defineType(tp: Type): this.type = {
wasEmpty = isEmpty
setType(tp)
}
+
+ protected def initErrorCheck {
+ hasErrorTree = Some(errorCause != null)
+ }
}
def TypeTree(tp: Type): TypeTree = TypeTree() setType tp
@@ -715,6 +916,7 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
traverse(lo); traverse(hi)
case ExistentialTypeTree(tpt, whereClauses) =>
traverse(tpt); traverseTrees(whereClauses)
+ case _: AbsErrorTree =>
case _ => xtraverse(this, tree)
}
diff --git a/test/files/neg/patternalts.check b/test/files/neg/patternalts.check
index 9bec9a001a..63bd244345 100644
--- a/test/files/neg/patternalts.check
+++ b/test/files/neg/patternalts.check
@@ -1,4 +1,7 @@
patternalts.scala:3: error: illegal variable in pattern alternative
case List(x) | List() => Console.println(x)
^
-one error found
+patternalts.scala:3: error: not found: value x
+ case List(x) | List() => Console.println(x)
+ ^
+two errors found
diff --git a/test/files/neg/t1878.check b/test/files/neg/t1878.check
index 4b9cfebde1..de59b023ab 100644
--- a/test/files/neg/t1878.check
+++ b/test/files/neg/t1878.check
@@ -1,15 +1,18 @@
-t1878.scala:3: error: _* may only come last
- val err1 = "" match { case Seq(f @ _*, ',') => f }
- ^
t1878.scala:3: error: scrutinee is incompatible with pattern type;
found : Seq[A]
required: java.lang.String
val err1 = "" match { case Seq(f @ _*, ',') => f }
^
+t1878.scala:3: error: not found: value f
+ val err1 = "" match { case Seq(f @ _*, ',') => f }
+ ^
+t1878.scala:3: error: _* may only come last
+ val err1 = "" match { case Seq(f @ _*, ',') => f }
+ ^
t1878.scala:9: error: _* may only come last
val List(List(_*, arg2), _) = List(List(1,2,3), List(4,5,6))
^
t1878.scala:13: error: _* may only come last
case <p> { _* } </p> =>
^
-four errors found
+5 errors found
diff --git a/test/files/neg/t2641.check b/test/files/neg/t2641.check
index 2056a1b9ab..595dd46b11 100644
--- a/test/files/neg/t2641.check
+++ b/test/files/neg/t2641.check
@@ -1,24 +1,15 @@
t2641.scala:18: error: illegal cyclic reference involving trait ManagedSeq
with TraversableViewLike[A, ManagedSeqStrict[A], ManagedSeq[A]]
^
-t2641.scala:16: error: illegal inheritance;
- self-type ManagedSeq does not conform to ManagedSeqStrict[A]'s selftype ManagedSeqStrict[A]
- extends ManagedSeqStrict[A]
- ^
-t2641.scala:17: error: illegal inheritance;
- self-type ManagedSeq does not conform to scala.collection.TraversableView[A,ManagedSeqStrict[A]]'s selftype scala.collection.TraversableView[A,ManagedSeqStrict[A]]
- with TraversableView[A, ManagedSeqStrict[A]]
- ^
-t2641.scala:16: error: illegal inheritance;
- self-type ManagedSeq does not conform to ScalaObject's selftype ScalaObject
- extends ManagedSeqStrict[A]
- ^
t2641.scala:24: error: something is wrong (wrong class file?): trait ManagedSeq with type parameters [A,Coll] gets applied to arguments [], phase = typer
trait Transformed[+B] extends ManagedSeq[B, Coll] with super.Transformed[B]
^
t2641.scala:26: error: something is wrong (wrong class file?): trait ManagedSeq with type parameters [A,Coll] gets applied to arguments [], phase = namer
trait Sliced extends Transformed[A] with super.Sliced {
^
+t2641.scala:27: error: value managedIterator is not a member of ManagedSeq
+ override def managedIterator = self.managedIterator slice (from, until)
+ ^
t2641.scala:26: error: illegal inheritance; superclass Any
is not a subclass of the superclass ManagedSeqStrict
of the mixin trait Transformed
@@ -29,7 +20,16 @@ t2641.scala:26: error: illegal inheritance; superclass Any
of the mixin trait Sliced
trait Sliced extends Transformed[A] with super.Sliced {
^
-t2641.scala:27: error: value managedIterator is not a member of ManagedSeq
- override def managedIterator = self.managedIterator slice (from, until)
- ^
+t2641.scala:16: error: illegal inheritance;
+ self-type ManagedSeq does not conform to ManagedSeqStrict[A]'s selftype ManagedSeqStrict[A]
+ extends ManagedSeqStrict[A]
+ ^
+t2641.scala:17: error: illegal inheritance;
+ self-type ManagedSeq does not conform to scala.collection.TraversableView[A,ManagedSeqStrict[A]]'s selftype scala.collection.TraversableView[A,ManagedSeqStrict[A]]
+ with TraversableView[A, ManagedSeqStrict[A]]
+ ^
+t2641.scala:16: error: illegal inheritance;
+ self-type ManagedSeq does not conform to ScalaObject's selftype ScalaObject
+ extends ManagedSeqStrict[A]
+ ^
9 errors found
diff --git a/test/files/neg/t2918.check b/test/files/neg/t2918.check
index e67f24ec57..d125895463 100644
--- a/test/files/neg/t2918.check
+++ b/test/files/neg/t2918.check
@@ -1,7 +1,7 @@
-t2918.scala:2: error: cyclic aliasing or subtyping involving type A
- def g[X, A[X] <: A[X]](x: A[X]) = x
- ^
t2918.scala:2: error: A does not take type parameters
- def g[X, A[X] <: A[X]](x: A[X]) = x
+ def g[X, A[X] <: A[X]](x: A[X]) = x
^
+t2918.scala:2: error: cyclic aliasing or subtyping involving type A
+ def g[X, A[X] <: A[X]](x: A[X]) = x
+ ^
two errors found
diff --git a/test/files/neg/t3015.check b/test/files/neg/t3015.check
index 32809b0669..fec54b087b 100644
--- a/test/files/neg/t3015.check
+++ b/test/files/neg/t3015.check
@@ -3,9 +3,4 @@ t3015.scala:7: error: scrutinee is incompatible with pattern type;
required: java.lang.String
val b(foo) = "foo"
^
-t3015.scala:7: error: type mismatch;
- found : _$1(in value foo) where type _$1(in value foo) <: java.lang.String
- required: (some other)_$1(in value foo) where type (some other)_$1(in value foo)
- val b(foo) = "foo"
- ^
-two errors found
+one error found
diff --git a/test/files/neg/t997.check b/test/files/neg/t997.check
index c9fe0de756..166d465971 100644
--- a/test/files/neg/t997.check
+++ b/test/files/neg/t997.check
@@ -10,4 +10,10 @@ t997.scala:13: error: wrong number of arguments for object Foo
t997.scala:13: error: not found: value a
"x" match { case Foo(a, b, c) => Console.println((a,b,c)) }
^
-four errors found
+t997.scala:13: error: not found: value b
+"x" match { case Foo(a, b, c) => Console.println((a,b,c)) }
+ ^
+t997.scala:13: error: not found: value c
+"x" match { case Foo(a, b, c) => Console.println((a,b,c)) }
+ ^
+6 errors found
diff --git a/test/files/neg/volatile.check b/test/files/neg/volatile.check
index b904284125..da27c68e6c 100644
--- a/test/files/neg/volatile.check
+++ b/test/files/neg/volatile.check
@@ -1,7 +1,4 @@
-volatile.scala:11: error: Inferred type C.this.D with C.this.E#T contains type selection from volatile type C.this.D with C.this.E
+volatile.scala:11: error: Inferred type C.this.D with C.this.E#T contains type selection from volatile type C.this.D with C.this.E#T
var sneak = { () => y.x }
^
-volatile.scala:11: error: Inferred type () => C.this.D with C.this.E#T contains type selection from volatile type C.this.D with C.this.E
- var sneak = { () => y.x }
- ^
-two errors found
+one error found