aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala2
-rw-r--r--compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Trees.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/SymDenotations.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/core/Symbols.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeComparer.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeErasure.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeOps.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala27
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/printing/Formatting.scala5
-rw-r--r--compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala2
-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
-rw-r--r--tests/neg/i1802.scala21
19 files changed, 99 insertions, 55 deletions
diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
index ed32d2df9..123dc3450 100644
--- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
+++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -1024,7 +1024,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
case JavaArrayType(elem) => elem
case _ =>
ctx.error(s"JavaSeqArray with type ${field.tpe} reached backend: $field", field.pos)
- ErrorType
+ UnspecifiedErrorType
}
def _2: List[Tree] = field.elems
}
diff --git a/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala b/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala
index eb4da5400..89831e56b 100644
--- a/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala
+++ b/compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala
@@ -12,7 +12,7 @@ import dotty.tools.dotc.ast.tpd._
import dotty.tools.dotc.core.Names.TermName
import dotty.tools.dotc.core.StdNames
import dotty.tools.dotc.core.StdNames._
-import dotty.tools.dotc.core.Types.{JavaArrayType, ErrorType, Type}
+import dotty.tools.dotc.core.Types.{JavaArrayType, UnspecifiedErrorType, Type}
import scala.collection.{ mutable, immutable }
@@ -73,7 +73,7 @@ class DottyPrimitives(ctx: Context) {
case JavaArrayType(el) => el
case _ =>
ctx.error(s"expected Array $tpe")
- ErrorType
+ UnspecifiedErrorType
}
code match {
diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala
index 20273eb85..28ae89c4a 100644
--- a/compiler/src/dotty/tools/dotc/ast/Trees.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala
@@ -113,7 +113,7 @@ object Trees {
* type. (Overridden by empty trees)
*/
def withType(tpe: Type)(implicit ctx: Context): ThisTree[Type] = {
- if (tpe == ErrorType) assert(ctx.reporter.errorsReported)
+ if (tpe.isInstanceOf[ErrorType]) assert(ctx.reporter.errorsReported)
withTypeUnchecked(tpe)
}
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index e2bb0ac1a..aaae78c57 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -1937,12 +1937,12 @@ object SymDenotations {
/** A completer for missing references */
class StubInfo() extends LazyType {
- def initializeToDefaults(denot: SymDenotation)(implicit ctx: Context) = {
+ def initializeToDefaults(denot: SymDenotation, errMsg: => String)(implicit ctx: Context) = {
denot.info = denot match {
case denot: ClassDenotation =>
ClassInfo(denot.owner.thisType, denot.classSymbol, Nil, EmptyScope)
case _ =>
- ErrorType
+ new ErrorType(errMsg)
}
denot.privateWithin = NoSymbol
}
@@ -1954,13 +1954,14 @@ object SymDenotations {
if (file != null) (s" in $file", file.toString)
else ("", "the signature")
val name = ctx.fresh.setSetting(ctx.settings.debugNames, true).nameString(denot.name)
- ctx.error(
+ def errMsg =
i"""bad symbolic reference. A signature$location
|refers to $name in ${denot.owner.showKind} ${denot.owner.showFullName} which is not available.
|It may be completely missing from the current classpath, or the version on
- |the classpath might be incompatible with the version used when compiling $src.""")
+ |the classpath might be incompatible with the version used when compiling $src."""
+ ctx.error(errMsg)
if (ctx.debug) throw new Error()
- initializeToDefaults(denot)
+ initializeToDefaults(denot, errMsg)
}
}
diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala
index cfd85c49c..b10b94ad8 100644
--- a/compiler/src/dotty/tools/dotc/core/Symbols.scala
+++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala
@@ -22,6 +22,7 @@ import NameOps._
import ast.tpd.Tree
import ast.TreeTypeMap
import Constants.Constant
+import reporting.diagnostic.Message
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
import collection.mutable
import io.AbstractFile
@@ -290,9 +291,11 @@ trait Symbols { this: Context =>
*/
def newSkolem(tp: Type) = newSymbol(defn.RootClass, nme.SKOLEM, SyntheticArtifact | Permanent, tp)
- def newErrorSymbol(owner: Symbol, name: Name) =
+ def newErrorSymbol(owner: Symbol, name: Name, msg: => Message) = {
+ val errType = new ErrorType(msg)
newSymbol(owner, name, SyntheticArtifact,
- if (name.isTypeName) TypeAlias(ErrorType) else ErrorType)
+ if (name.isTypeName) TypeAlias(errType) else errType)
+ }
/** Map given symbols, subjecting their attributes to the mappings
* defined in the given TreeTypeMap `ttmap`.
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index 743220f55..e8905320b 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -265,7 +265,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
case ConstantType(v1) => v1.value == v2.value
case _ => secondTry(tp1, tp2)
}
- case ErrorType =>
+ case _: FlexType =>
true
case _ =>
secondTry(tp1, tp2)
@@ -341,7 +341,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
false
}
joinOK || isSubType(tp11, tp2) && isSubType(tp12, tp2)
- case ErrorType =>
+ case _: FlexType =>
true
case _ =>
thirdTry(tp1, tp2)
diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
index 82943377a..2e7c1db04 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -55,7 +55,7 @@ object TypeErasure {
tp.paramTypes.forall(isErasedType) && isErasedType(tp.resultType)
case tp @ ClassInfo(pre, _, parents, decls, _) =>
isErasedType(pre) && parents.forall(isErasedType) //&& decls.forall(sym => isErasedType(sym.info)) && isErasedType(tp.selfType)
- case NoType | NoPrefix | WildcardType | ErrorType | SuperType(_, _) =>
+ case NoType | NoPrefix | WildcardType | _: ErrorType | SuperType(_, _) =>
true
case _ =>
false
@@ -398,7 +398,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
tp.derivedClassInfo(NoPrefix, parents, erasedDecls, erasedRef(tp.selfType))
// can't replace selftype by NoType because this would lose the sourceModule link
}
- case NoType | NoPrefix | ErrorType | JavaArrayType(_) =>
+ case NoType | NoPrefix | _: ErrorType | JavaArrayType(_) =>
tp
case tp: WildcardType if wildcardOK =>
tp
@@ -506,7 +506,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
if (inst.exists) sigName(inst) else tpnme.Uninstantiated
case tp: TypeProxy =>
sigName(tp.underlying)
- case ErrorType | WildcardType =>
+ case _: ErrorType | WildcardType =>
tpnme.WILDCARD
case tp: WildcardType =>
sigName(tp.optBounds)
diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
index 39214dd0c..f134412a7 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala
@@ -433,7 +433,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
formals = formals.updated(name, tp1.typeParamNamed(name))
}
normalizeToRef(tp1)
- case ErrorType =>
+ case _: ErrorType =>
defn.AnyType
case AnnotatedType(tpe, _) =>
normalizeToRef(tpe)
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 4dffc4542..8f43ed9bb 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -15,9 +15,10 @@ import SymDenotations._
import Decorators._
import Denotations._
import Periods._
-import util.Positions.Position
+import util.Positions.{Position, NoPosition}
import util.Stats._
import util.{DotClass, SimpleMap}
+import reporting.diagnostic.Message
import ast.tpd._
import ast.TreeTypeMap
import printing.Texts._
@@ -176,7 +177,7 @@ object Types {
/** Is this type produced as a repair for an error? */
final def isError(implicit ctx: Context): Boolean = stripTypeVar match {
- case ErrorType => true
+ case _: ErrorType => true
case tp => (tp.typeSymbol is Erroneous) || (tp.termSymbol is Erroneous)
}
@@ -387,8 +388,8 @@ object Types {
tp.decls.denotsNamed(name).filterExcluded(excluded).toDenot(NoPrefix)
case tp: TypeProxy =>
tp.underlying.findDecl(name, excluded)
- case ErrorType =>
- ctx.newErrorSymbol(classSymbol orElse defn.RootClass, name)
+ case err: ErrorType =>
+ ctx.newErrorSymbol(classSymbol orElse defn.RootClass, name, err.msg)
case _ =>
NoDenotation
}
@@ -453,8 +454,8 @@ object Types {
go(tp.join)
case tp: JavaArrayType =>
defn.ObjectType.findMember(name, pre, excluded)
- case ErrorType =>
- ctx.newErrorSymbol(pre.classSymbol orElse defn.RootClass, name)
+ case err: ErrorType =>
+ ctx.newErrorSymbol(pre.classSymbol orElse defn.RootClass, name, err.msg)
case _ =>
NoDenotation
}
@@ -1497,7 +1498,7 @@ object Types {
(lastDefRunId != sym.defRunId) ||
(lastDefRunId == NoRunId)
} ||
- (lastSymbol.infoOrCompleter == ErrorType ||
+ (lastSymbol.infoOrCompleter.isInstanceOf[ErrorType] ||
sym.owner != lastSymbol.owner &&
(sym.owner.derivesFrom(lastSymbol.owner) ||
selfTypeOf(sym).derivesFrom(lastSymbol.owner) ||
@@ -2693,7 +2694,7 @@ object Types {
protected def checkInst(implicit ctx: Context): this.type = {
def check(tycon: Type): Unit = tycon.stripTypeVar match {
case tycon: TypeRef if !tycon.symbol.isClass =>
- case _: PolyParam | ErrorType | _: WildcardType =>
+ case _: PolyParam | _: ErrorType | _: WildcardType =>
case _: PolyType =>
assert(args.exists(_.isInstanceOf[TypeBounds]), s"unreduced type apply: $this")
case tycon: AnnotatedType =>
@@ -3251,12 +3252,16 @@ object Types {
override def computeHash = hashSeed
}
- abstract class ErrorType extends UncachedGroundType with ValueType
+ abstract class FlexType extends UncachedGroundType with ValueType
- object ErrorType extends ErrorType
+ class ErrorType(_msg: => Message) extends FlexType {
+ val msg = _msg
+ }
+
+ object UnspecifiedErrorType extends ErrorType("unspecified error")
/* Type used to track Select nodes that could not resolve a member and their qualifier is a scala.Dynamic. */
- object TryDynamicCallType extends ErrorType
+ object TryDynamicCallType extends FlexType
/** Wildcard type, possibly with bounds */
abstract case class WildcardType(optBounds: Type) extends CachedGroundType with TermType {
diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala
index 0f63b25bb..92ab10db9 100644
--- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala
@@ -90,7 +90,8 @@ object JavaParsers {
if (skipIt)
skip()
}
- def errorTypeTree = TypeTree().withType(ErrorType) withPos Position(in.offset)
+
+ def errorTypeTree = TypeTree().withType(UnspecifiedErrorType) withPos Position(in.offset)
// --------- tree building -----------------------------
diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala
index b321d3736..05f1af9d7 100644
--- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala
+++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala
@@ -96,7 +96,10 @@ object Formatting {
case tpe: Type =>
tpe.exists && !tpe.isErroneous
case sym: Symbol if sym.isCompleted =>
- sym.info != ErrorType && sym.info != TypeAlias(ErrorType) && sym.info.exists
+ sym.info match {
+ case _: ErrorType | TypeAlias(_: ErrorType) | NoType => false
+ case _ => true
+ }
case _ => true
}
diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 15c382bb0..61f23c214 100644
--- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -154,7 +154,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
changePrec(AndPrec) { toText(tp1) ~ " & " ~ toText(tp2) }
case OrType(tp1, tp2) =>
changePrec(OrPrec) { toText(tp1) ~ " | " ~ toText(tp2) }
- case ErrorType =>
+ case _: ErrorType =>
"<error>"
case tp: WildcardType =>
if (tp.optBounds.exists) "(?" ~ toTextRHS(tp.bounds) ~ ")" else "?"
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 {
diff --git a/tests/neg/i1802.scala b/tests/neg/i1802.scala
new file mode 100644
index 000000000..56da672a8
--- /dev/null
+++ b/tests/neg/i1802.scala
@@ -0,0 +1,21 @@
+import scala.collection.immutable.List
+import scala.reflect.{ ClassTag, classTag }
+import scala.language.implicitConversions
+
+object Exception {
+ type Catcher[+T] = PartialFunction[Throwable, T]
+
+ def mkCatcher[Ex <: Throwable: ClassTag, T](isDef: Ex => Boolean, f: Ex => T) = new Catcher[T] {
+ private def downcast(x: Throwable): Option[Ex] =
+ if (classTag[Ex].runtimeClass.isAssignableFrom(x.getClass)) Some(x.asInstanceOf[Ex])
+ else None
+
+ def isDefinedAt(x: Throwable) = downcast(x) exists isDef
+ def apply(x: Throwable): T = f(downcast(x).get)
+ }
+
+ def mkThrowableCatcher[T](isDef: Throwable => Boolean, f: Throwable => T) = mkCatcher(isDef, f)
+
+ implicit def throwableSubtypeToCatcher[Ex <: Throwable: ClassTag, T](pf: PartialFunction[Ex, T]) = // error: cyclic reference
+ mkCatcher(pf.isDefinedAt _, pf.apply _)
+}