Skip to content

Commit b63480a

Browse files
committed
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.
1 parent 653698e commit b63480a

19 files changed

+99
-55
lines changed

compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1024,7 +1024,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
10241024
case JavaArrayType(elem) => elem
10251025
case _ =>
10261026
ctx.error(s"JavaSeqArray with type ${field.tpe} reached backend: $field", field.pos)
1027-
ErrorType
1027+
UnspecifiedErrorType
10281028
}
10291029
def _2: List[Tree] = field.elems
10301030
}

compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import dotty.tools.dotc.ast.tpd._
1212
import dotty.tools.dotc.core.Names.TermName
1313
import dotty.tools.dotc.core.StdNames
1414
import dotty.tools.dotc.core.StdNames._
15-
import dotty.tools.dotc.core.Types.{JavaArrayType, ErrorType, Type}
15+
import dotty.tools.dotc.core.Types.{JavaArrayType, UnspecifiedErrorType, Type}
1616

1717
import scala.collection.{ mutable, immutable }
1818

@@ -73,7 +73,7 @@ class DottyPrimitives(ctx: Context) {
7373
case JavaArrayType(el) => el
7474
case _ =>
7575
ctx.error(s"expected Array $tpe")
76-
ErrorType
76+
UnspecifiedErrorType
7777
}
7878

7979
code match {

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ object Trees {
113113
* type. (Overridden by empty trees)
114114
*/
115115
def withType(tpe: Type)(implicit ctx: Context): ThisTree[Type] = {
116-
if (tpe == ErrorType) assert(ctx.reporter.errorsReported)
116+
if (tpe.isInstanceOf[ErrorType]) assert(ctx.reporter.errorsReported)
117117
withTypeUnchecked(tpe)
118118
}
119119

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,12 +1937,12 @@ object SymDenotations {
19371937
/** A completer for missing references */
19381938
class StubInfo() extends LazyType {
19391939

1940-
def initializeToDefaults(denot: SymDenotation)(implicit ctx: Context) = {
1940+
def initializeToDefaults(denot: SymDenotation, errMsg: => String)(implicit ctx: Context) = {
19411941
denot.info = denot match {
19421942
case denot: ClassDenotation =>
19431943
ClassInfo(denot.owner.thisType, denot.classSymbol, Nil, EmptyScope)
19441944
case _ =>
1945-
ErrorType
1945+
new ErrorType(errMsg)
19461946
}
19471947
denot.privateWithin = NoSymbol
19481948
}
@@ -1954,13 +1954,14 @@ object SymDenotations {
19541954
if (file != null) (s" in $file", file.toString)
19551955
else ("", "the signature")
19561956
val name = ctx.fresh.setSetting(ctx.settings.debugNames, true).nameString(denot.name)
1957-
ctx.error(
1957+
def errMsg =
19581958
i"""bad symbolic reference. A signature$location
19591959
|refers to $name in ${denot.owner.showKind} ${denot.owner.showFullName} which is not available.
19601960
|It may be completely missing from the current classpath, or the version on
1961-
|the classpath might be incompatible with the version used when compiling $src.""")
1961+
|the classpath might be incompatible with the version used when compiling $src."""
1962+
ctx.error(errMsg)
19621963
if (ctx.debug) throw new Error()
1963-
initializeToDefaults(denot)
1964+
initializeToDefaults(denot, errMsg)
19641965
}
19651966
}
19661967

compiler/src/dotty/tools/dotc/core/Symbols.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import NameOps._
2222
import ast.tpd.Tree
2323
import ast.TreeTypeMap
2424
import Constants.Constant
25+
import reporting.diagnostic.Message
2526
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
2627
import collection.mutable
2728
import io.AbstractFile
@@ -290,9 +291,11 @@ trait Symbols { this: Context =>
290291
*/
291292
def newSkolem(tp: Type) = newSymbol(defn.RootClass, nme.SKOLEM, SyntheticArtifact | Permanent, tp)
292293

293-
def newErrorSymbol(owner: Symbol, name: Name) =
294+
def newErrorSymbol(owner: Symbol, name: Name, msg: => Message) = {
295+
val errType = new ErrorType(msg)
294296
newSymbol(owner, name, SyntheticArtifact,
295-
if (name.isTypeName) TypeAlias(ErrorType) else ErrorType)
297+
if (name.isTypeName) TypeAlias(errType) else errType)
298+
}
296299

297300
/** Map given symbols, subjecting their attributes to the mappings
298301
* defined in the given TreeTypeMap `ttmap`.

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
265265
case ConstantType(v1) => v1.value == v2.value
266266
case _ => secondTry(tp1, tp2)
267267
}
268-
case ErrorType =>
268+
case _: FlexType =>
269269
true
270270
case _ =>
271271
secondTry(tp1, tp2)
@@ -341,7 +341,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
341341
false
342342
}
343343
joinOK || isSubType(tp11, tp2) && isSubType(tp12, tp2)
344-
case ErrorType =>
344+
case _: FlexType =>
345345
true
346346
case _ =>
347347
thirdTry(tp1, tp2)

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ object TypeErasure {
5555
tp.paramTypes.forall(isErasedType) && isErasedType(tp.resultType)
5656
case tp @ ClassInfo(pre, _, parents, decls, _) =>
5757
isErasedType(pre) && parents.forall(isErasedType) //&& decls.forall(sym => isErasedType(sym.info)) && isErasedType(tp.selfType)
58-
case NoType | NoPrefix | WildcardType | ErrorType | SuperType(_, _) =>
58+
case NoType | NoPrefix | WildcardType | _: ErrorType | SuperType(_, _) =>
5959
true
6060
case _ =>
6161
false
@@ -398,7 +398,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
398398
tp.derivedClassInfo(NoPrefix, parents, erasedDecls, erasedRef(tp.selfType))
399399
// can't replace selftype by NoType because this would lose the sourceModule link
400400
}
401-
case NoType | NoPrefix | ErrorType | JavaArrayType(_) =>
401+
case NoType | NoPrefix | _: ErrorType | JavaArrayType(_) =>
402402
tp
403403
case tp: WildcardType if wildcardOK =>
404404
tp
@@ -506,7 +506,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
506506
if (inst.exists) sigName(inst) else tpnme.Uninstantiated
507507
case tp: TypeProxy =>
508508
sigName(tp.underlying)
509-
case ErrorType | WildcardType =>
509+
case _: ErrorType | WildcardType =>
510510
tpnme.WILDCARD
511511
case tp: WildcardType =>
512512
sigName(tp.optBounds)

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
433433
formals = formals.updated(name, tp1.typeParamNamed(name))
434434
}
435435
normalizeToRef(tp1)
436-
case ErrorType =>
436+
case _: ErrorType =>
437437
defn.AnyType
438438
case AnnotatedType(tpe, _) =>
439439
normalizeToRef(tpe)

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ import SymDenotations._
1515
import Decorators._
1616
import Denotations._
1717
import Periods._
18-
import util.Positions.Position
18+
import util.Positions.{Position, NoPosition}
1919
import util.Stats._
2020
import util.{DotClass, SimpleMap}
21+
import reporting.diagnostic.Message
2122
import ast.tpd._
2223
import ast.TreeTypeMap
2324
import printing.Texts._
@@ -176,7 +177,7 @@ object Types {
176177

177178
/** Is this type produced as a repair for an error? */
178179
final def isError(implicit ctx: Context): Boolean = stripTypeVar match {
179-
case ErrorType => true
180+
case _: ErrorType => true
180181
case tp => (tp.typeSymbol is Erroneous) || (tp.termSymbol is Erroneous)
181182
}
182183

@@ -387,8 +388,8 @@ object Types {
387388
tp.decls.denotsNamed(name).filterExcluded(excluded).toDenot(NoPrefix)
388389
case tp: TypeProxy =>
389390
tp.underlying.findDecl(name, excluded)
390-
case ErrorType =>
391-
ctx.newErrorSymbol(classSymbol orElse defn.RootClass, name)
391+
case err: ErrorType =>
392+
ctx.newErrorSymbol(classSymbol orElse defn.RootClass, name, err.msg)
392393
case _ =>
393394
NoDenotation
394395
}
@@ -453,8 +454,8 @@ object Types {
453454
go(tp.join)
454455
case tp: JavaArrayType =>
455456
defn.ObjectType.findMember(name, pre, excluded)
456-
case ErrorType =>
457-
ctx.newErrorSymbol(pre.classSymbol orElse defn.RootClass, name)
457+
case err: ErrorType =>
458+
ctx.newErrorSymbol(pre.classSymbol orElse defn.RootClass, name, err.msg)
458459
case _ =>
459460
NoDenotation
460461
}
@@ -1497,7 +1498,7 @@ object Types {
14971498
(lastDefRunId != sym.defRunId) ||
14981499
(lastDefRunId == NoRunId)
14991500
} ||
1500-
(lastSymbol.infoOrCompleter == ErrorType ||
1501+
(lastSymbol.infoOrCompleter.isInstanceOf[ErrorType] ||
15011502
sym.owner != lastSymbol.owner &&
15021503
(sym.owner.derivesFrom(lastSymbol.owner) ||
15031504
selfTypeOf(sym).derivesFrom(lastSymbol.owner) ||
@@ -2693,7 +2694,7 @@ object Types {
26932694
protected def checkInst(implicit ctx: Context): this.type = {
26942695
def check(tycon: Type): Unit = tycon.stripTypeVar match {
26952696
case tycon: TypeRef if !tycon.symbol.isClass =>
2696-
case _: PolyParam | ErrorType | _: WildcardType =>
2697+
case _: PolyParam | _: ErrorType | _: WildcardType =>
26972698
case _: PolyType =>
26982699
assert(args.exists(_.isInstanceOf[TypeBounds]), s"unreduced type apply: $this")
26992700
case tycon: AnnotatedType =>
@@ -3251,12 +3252,16 @@ object Types {
32513252
override def computeHash = hashSeed
32523253
}
32533254

3254-
abstract class ErrorType extends UncachedGroundType with ValueType
3255+
abstract class FlexType extends UncachedGroundType with ValueType
32553256

3256-
object ErrorType extends ErrorType
3257+
class ErrorType(_msg: => Message) extends FlexType {
3258+
val msg = _msg
3259+
}
3260+
3261+
object UnspecifiedErrorType extends ErrorType("unspecified error")
32573262

32583263
/* Type used to track Select nodes that could not resolve a member and their qualifier is a scala.Dynamic. */
3259-
object TryDynamicCallType extends ErrorType
3264+
object TryDynamicCallType extends FlexType
32603265

32613266
/** Wildcard type, possibly with bounds */
32623267
abstract case class WildcardType(optBounds: Type) extends CachedGroundType with TermType {

compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ object JavaParsers {
9090
if (skipIt)
9191
skip()
9292
}
93-
def errorTypeTree = TypeTree().withType(ErrorType) withPos Position(in.offset)
93+
94+
def errorTypeTree = TypeTree().withType(UnspecifiedErrorType) withPos Position(in.offset)
9495

9596
// --------- tree building -----------------------------
9697

compiler/src/dotty/tools/dotc/printing/Formatting.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ object Formatting {
9696
case tpe: Type =>
9797
tpe.exists && !tpe.isErroneous
9898
case sym: Symbol if sym.isCompleted =>
99-
sym.info != ErrorType && sym.info != TypeAlias(ErrorType) && sym.info.exists
99+
sym.info match {
100+
case _: ErrorType | TypeAlias(_: ErrorType) | NoType => false
101+
case _ => true
102+
}
100103
case _ => true
101104
}
102105

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
154154
changePrec(AndPrec) { toText(tp1) ~ " & " ~ toText(tp2) }
155155
case OrType(tp1, tp2) =>
156156
changePrec(OrPrec) { toText(tp1) ~ " | " ~ toText(tp2) }
157-
case ErrorType =>
157+
case _: ErrorType =>
158158
"<error>"
159159
case tp: WildcardType =>
160160
if (tp.optBounds.exists) "(?" ~ toTextRHS(tp.bounds) ~ ")" else "?"

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
561561
var typedArgs = typedArgBuf.toList
562562
def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later
563563
val app1 =
564-
if (!success) app0.withType(ErrorType)
564+
if (!success) app0.withType(UnspecifiedErrorType)
565565
else {
566566
if (!sameSeq(args, orderedArgs)) {
567567
// need to lift arguments to maintain evaluation order in the
@@ -654,7 +654,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
654654
}
655655

656656
fun1.tpe match {
657-
case ErrorType => untpd.cpy.Apply(tree)(fun1, tree.args).withType(ErrorType)
657+
case err: ErrorType => untpd.cpy.Apply(tree)(fun1, tree.args).withType(err)
658658
case TryDynamicCallType => typedDynamicApply(tree, pt)
659659
case _ =>
660660
tryEither {
@@ -918,7 +918,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
918918
case tp =>
919919
val unapplyErr = if (tp.isError) unapplyFn else notAnExtractor(unapplyFn)
920920
val typedArgsErr = args mapconserve (typed(_, defn.AnyType))
921-
cpy.UnApply(tree)(unapplyErr, Nil, typedArgsErr) withType ErrorType
921+
cpy.UnApply(tree)(unapplyErr, Nil, typedArgsErr) withType unapplyErr.tpe
922922
}
923923
}
924924

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ object Checking {
5656
def checkBounds(args: List[tpd.Tree], poly: PolyType)(implicit ctx: Context): Unit =
5757
checkBounds(args, poly.paramBounds, _.substParams(poly, _))
5858

59-
/** Check applied type trees for well-formedness. This means
59+
/** Check applied type trees for well-formedness. This means
6060
* - all arguments are within their corresponding bounds
6161
* - if type is a higher-kinded application with wildcard arguments,
6262
* check that it or one of its supertypes can be reduced to a normal application.
@@ -237,8 +237,7 @@ object Checking {
237237
catch {
238238
case ex: CyclicReference =>
239239
if (reportErrors) {
240-
ctx.error(i"illegal cyclic reference: ${checker.where} ${checker.lastChecked} of $sym refers back to the type itself", sym.pos)
241-
ErrorType
240+
errorType(i"illegal cyclic reference: ${checker.where} ${checker.lastChecked} of $sym refers back to the type itself", sym.pos)
242241
}
243242
else info
244243
}

compiler/src/dotty/tools/dotc/typer/Dynamic.scala

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import dotty.tools.dotc.core.Names.Name
1111
import dotty.tools.dotc.core.StdNames._
1212
import dotty.tools.dotc.core.Types._
1313
import dotty.tools.dotc.core.Decorators._
14+
import ErrorReporting._
1415

1516
object Dynamic {
1617
def isDynamicMethod(name: Name): Boolean =
@@ -41,10 +42,9 @@ trait Dynamic { self: Typer with Applications =>
4142
def isNamedArg(arg: untpd.Tree): Boolean = arg match { case NamedArg(_, _) => true; case _ => false }
4243
val args = tree.args
4344
val dynName = if (args.exists(isNamedArg)) nme.applyDynamicNamed else nme.applyDynamic
44-
if (dynName == nme.applyDynamicNamed && untpd.isWildcardStarArgList(args)) {
45-
ctx.error("applyDynamicNamed does not support passing a vararg parameter", tree.pos)
46-
tree.withType(ErrorType)
47-
} else {
45+
if (dynName == nme.applyDynamicNamed && untpd.isWildcardStarArgList(args))
46+
errorTree(tree, "applyDynamicNamed does not support passing a vararg parameter")
47+
else {
4848
def namedArgTuple(name: String, arg: untpd.Tree) = untpd.Tuple(List(Literal(Constant(name)), arg))
4949
def namedArgs = args.map {
5050
case NamedArg(argName, arg) => namedArgTuple(argName.toString, arg)
@@ -89,8 +89,7 @@ trait Dynamic { self: Typer with Applications =>
8989
case TypeApply(Select(qual, name), targs) if !isDynamicMethod(name) =>
9090
typedDynamicAssign(qual, name, targs)
9191
case _ =>
92-
ctx.error("reassignment to val", tree.pos)
93-
tree.withType(ErrorType)
92+
errorTree(tree, "reassignment to val")
9493
}
9594
}
9695

compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ object ErrorReporting {
2323

2424
def errorType(msg: => Message, pos: Position)(implicit ctx: Context): ErrorType = {
2525
ctx.error(msg, pos)
26-
ErrorType
26+
new ErrorType(msg)
2727
}
2828

2929
def cyclicErrorMsg(ex: CyclicReference)(implicit ctx: Context) = {

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,8 @@ trait TypeAssigner {
189189
val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
190190
val whyNot = new StringBuffer
191191
alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot))
192-
if (!tpe.isError)
193-
ctx.error(ex"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
194-
ErrorType
192+
if (tpe.isError) tpe
193+
else errorType(ex"$what cannot be accessed as a member of $pre$where.$whyNot", pos)
195194
}
196195
}
197196
else if (d.symbol is TypeParamAccessor)
@@ -215,17 +214,17 @@ trait TypeAssigner {
215214
else if (site.derivesFrom(defn.DynamicClass) && !Dynamic.isDynamicMethod(name)) {
216215
TryDynamicCallType
217216
} else {
218-
if (!site.isErroneous) {
217+
if (site.isErroneous) UnspecifiedErrorType
218+
else {
219219
def kind = if (name.isTypeName) "type" else "value"
220220
def addendum =
221221
if (site.derivesFrom(defn.DynamicClass)) "\npossible cause: maybe a wrong Dynamic method signature?"
222222
else ""
223-
ctx.error(
223+
errorType(
224224
if (name == nme.CONSTRUCTOR) ex"$site does not have a constructor"
225225
else NotAMember(site, name, kind),
226226
pos)
227227
}
228-
ErrorType
229228
}
230229
}
231230

0 commit comments

Comments
 (0)