aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/typer
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-12-17 15:09:27 +0100
committerMartin Odersky <odersky@gmail.com>2016-12-17 15:09:52 +0100
commitb63480a59bbdd284a5e32281fbb0037e509f4b1e (patch)
tree825824024ad6768646c3dbf630a2db9283eedcd4 /compiler/src/dotty/tools/dotc/typer
parent653698ef67a5cf8f5e0fd0fcdcd1f631f1dc96e2 (diff)
downloaddotty-b63480a59bbdd284a5e32281fbb0037e509f4b1e.tar.gz
dotty-b63480a59bbdd284a5e32281fbb0037e509f4b1e.tar.bz2
dotty-b63480a59bbdd284a5e32281fbb0037e509f4b1e.zip
Make errors are not swept under the carpet
Typer#ensureReported's comment outlines an example where errors could go unreported, resulting in error trees after typer without any reported error messages. This commit makes sure that at least one error is reported if a tree node has an error type. Fixes #1802.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/typer')
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Applications.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Checking.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Dynamic.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala23
6 files changed, 34 insertions, 24 deletions
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala
index 4203ab9b2..da0a59c7b 100644
--- a/compiler/src/dotty/tools/dotc/typer/Applications.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala
@@ -561,7 +561,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
var typedArgs = typedArgBuf.toList
def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later
val app1 =
- if (!success) app0.withType(ErrorType)
+ if (!success) app0.withType(UnspecifiedErrorType)
else {
if (!sameSeq(args, orderedArgs)) {
// need to lift arguments to maintain evaluation order in the
@@ -654,7 +654,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
}
fun1.tpe match {
- case ErrorType => untpd.cpy.Apply(tree)(fun1, tree.args).withType(ErrorType)
+ case err: ErrorType => untpd.cpy.Apply(tree)(fun1, tree.args).withType(err)
case TryDynamicCallType => typedDynamicApply(tree, pt)
case _ =>
tryEither {
@@ -918,7 +918,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
case tp =>
val unapplyErr = if (tp.isError) unapplyFn else notAnExtractor(unapplyFn)
val typedArgsErr = args mapconserve (typed(_, defn.AnyType))
- cpy.UnApply(tree)(unapplyErr, Nil, typedArgsErr) withType ErrorType
+ cpy.UnApply(tree)(unapplyErr, Nil, typedArgsErr) withType unapplyErr.tpe
}
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala
index f5f7bdbaa..41d9f9572 100644
--- a/compiler/src/dotty/tools/dotc/typer/Checking.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala
@@ -56,7 +56,7 @@ object Checking {
def checkBounds(args: List[tpd.Tree], poly: PolyType)(implicit ctx: Context): Unit =
checkBounds(args, poly.paramBounds, _.substParams(poly, _))
- /** Check applied type trees for well-formedness. This means
+ /** Check applied type trees for well-formedness. This means
* - all arguments are within their corresponding bounds
* - if type is a higher-kinded application with wildcard arguments,
* check that it or one of its supertypes can be reduced to a normal application.
@@ -237,8 +237,7 @@ object Checking {
catch {
case ex: CyclicReference =>
if (reportErrors) {
- ctx.error(i"illegal cyclic reference: ${checker.where} ${checker.lastChecked} of $sym refers back to the type itself", sym.pos)
- ErrorType
+ errorType(i"illegal cyclic reference: ${checker.where} ${checker.lastChecked} of $sym refers back to the type itself", sym.pos)
}
else info
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala
index b5ace87d3..4039c8b81 100644
--- a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala
@@ -11,6 +11,7 @@ import dotty.tools.dotc.core.Names.Name
import dotty.tools.dotc.core.StdNames._
import dotty.tools.dotc.core.Types._
import dotty.tools.dotc.core.Decorators._
+import ErrorReporting._
object Dynamic {
def isDynamicMethod(name: Name): Boolean =
@@ -41,10 +42,9 @@ trait Dynamic { self: Typer with Applications =>
def isNamedArg(arg: untpd.Tree): Boolean = arg match { case NamedArg(_, _) => true; case _ => false }
val args = tree.args
val dynName = if (args.exists(isNamedArg)) nme.applyDynamicNamed else nme.applyDynamic
- if (dynName == nme.applyDynamicNamed && untpd.isWildcardStarArgList(args)) {
- ctx.error("applyDynamicNamed does not support passing a vararg parameter", tree.pos)
- tree.withType(ErrorType)
- } else {
+ if (dynName == nme.applyDynamicNamed && untpd.isWildcardStarArgList(args))
+ errorTree(tree, "applyDynamicNamed does not support passing a vararg parameter")
+ else {
def namedArgTuple(name: String, arg: untpd.Tree) = untpd.Tuple(List(Literal(Constant(name)), arg))
def namedArgs = args.map {
case NamedArg(argName, arg) => namedArgTuple(argName.toString, arg)
@@ -89,8 +89,7 @@ trait Dynamic { self: Typer with Applications =>
case TypeApply(Select(qual, name), targs) if !isDynamicMethod(name) =>
typedDynamicAssign(qual, name, targs)
case _ =>
- ctx.error("reassignment to val", tree.pos)
- tree.withType(ErrorType)
+ errorTree(tree, "reassignment to val")
}
}
diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
index a066fc04a..270ad6c8a 100644
--- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -23,7 +23,7 @@ object ErrorReporting {
def errorType(msg: => Message, pos: Position)(implicit ctx: Context): ErrorType = {
ctx.error(msg, pos)
- ErrorType
+ new ErrorType(msg)
}
def cyclicErrorMsg(ex: CyclicReference)(implicit ctx: Context) = {
diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
index ee2d68278..ca0af0e2b 100644
--- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -189,9 +189,8 @@ trait TypeAssigner {
val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
val whyNot = new StringBuffer
alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot))
- if (!tpe.isError)
- ctx.error(ex"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
- ErrorType
+ if (tpe.isError) tpe
+ else errorType(ex"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
}
}
else if (d.symbol is TypeParamAccessor)
@@ -215,17 +214,17 @@ trait TypeAssigner {
else if (site.derivesFrom(defn.DynamicClass) && !Dynamic.isDynamicMethod(name)) {
TryDynamicCallType
} else {
- if (!site.isErroneous) {
+ if (site.isErroneous) UnspecifiedErrorType
+ else {
def kind = if (name.isTypeName) "type" else "value"
def addendum =
if (site.derivesFrom(defn.DynamicClass)) "\npossible cause: maybe a wrong Dynamic method signature?"
else ""
- ctx.error(
+ errorType(
if (name == nme.CONSTRUCTOR) ex"$site does not have a constructor"
else NotAMember(site, name, kind),
pos)
}
- ErrorType
}
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index eec3859f9..081e46841 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -351,10 +351,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val ownType =
if (rawType.exists)
ensureAccessible(rawType, superAccess = false, tree.pos)
- else {
- error(new MissingIdent(tree, kind, name.show), tree.pos)
- ErrorType
- }
+ else
+ errorType(new MissingIdent(tree, kind, name.show), tree.pos)
val tree1 = ownType match {
case ownType: NamedType if !prefixIsElidable(ownType) =>
@@ -1965,10 +1963,25 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
else err.typeMismatch(tree1, pt)
}
+ /** If tree has an error type but no errors are reported yet, issue
+ * the error message stored in the type.
+ * One way this can happen is if implicit search causes symbols and types
+ * to be completed. The types are stored by `typedAhead` so that they can be
+ * retrieved later and thus avoid duplication of typechecking work.
+ * But if the implicit search causing the `typedAhead` fails locally but
+ * another alternative succeeds we can be left with an ErrorType in the
+ * tree that went unreported. A scenario where this happens is i1802.scala.
+ */
+ def ensureReported(tp: Type) = tp match {
+ case err: ErrorType if !ctx.reporter.hasErrors => ctx.error(err.msg, tree.pos)
+ case _ =>
+ }
+
tree match {
case _: MemberDef | _: PackageDef | _: Import | _: WithoutTypeOrPos[_] => tree
case _ => tree.tpe.widen match {
- case _: ErrorType =>
+ case tp: FlexType =>
+ ensureReported(tp)
tree
case ref: TermRef =>
pt match {