summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorHubert Plociniczak <hubert.plociniczak@epfl.ch>2011-09-07 12:17:54 +0000
committerHubert Plociniczak <hubert.plociniczak@epfl.ch>2011-09-07 12:17:54 +0000
commit620f339bbaadad57daa696007660bb887372e927 (patch)
treee9bf93cfa9d93a299f24cab28577900c36260438 /src/library
parent596be479f1e527230f92db320642f77bae7e386d (diff)
downloadscala-620f339bbaadad57daa696007660bb887372e927.tar.gz
scala-620f339bbaadad57daa696007660bb887372e927.tar.bz2
scala-620f339bbaadad57daa696007660bb887372e927.zip
First refactoring related to Error trees.
There are no more direct calls to context.error from Typers and Infer, so more work needs to be done to finish it for Implicits and Namers. I am pushing it to trunk so that all of you can share my pain (and complain). Please do not add any more context.error randomly in that code, instead deal with it appropriately (by creating specific error tree). I was trying to be as informative when it comes to error tree names as possible, but if you feel like changing names to something more appropriate then feel free to do so. When it comes to printing error messages I tried to follow test suite as closily as possible but obviously there were few changes to some tests (mostly positive, I believe). On my machine performance drawback was neglible but I am working on more aggressive caching to reduce the penalty of containsError() calls even more. Any suggestions welcome. At the moment the code supports both styles i.e. throwing type errors for the cases that are not yet handled and generating error trees. But in the future we will drop the former completely (apart from cyclic errors which can pop up almost everywhere). Review by odersky, extempore and anyone who feels like it.
Diffstat (limited to 'src/library')
-rw-r--r--src/library/scala/reflect/api/Trees.scala270
1 files changed, 236 insertions, 34 deletions
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)
}