Skip to content

Commit 7c74ea5

Browse files
committed
Make TypeErrors sticky
The purpose of this change is that we should always report a thrown TypeError and not hide it by backtracking into some other alternative. Wihthout this change test i4564.scala fails after applying the creator applications commit, since some errors about recursive methods lacking a result type are hidden by using a constructor instead. Ehere is an example: ``` object NoClashNoSig { private def apply(x: Boolean) = if (x) NoClashNoSig(1) else ??? // error: overloaded method apply needs result type } case class NoClashNoSig private(x: Int) ``` With introduction of creator applications, `NoClashSig` in `apply` would call the constructor, effectively hiding the "overloaded method apply needs result type" error. This is not what we want.
1 parent 1636a25 commit 7c74ea5

File tree

10 files changed

+35
-19
lines changed

10 files changed

+35
-19
lines changed

compiler/src/dotty/tools/dotc/reporting/Reporter.scala

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,19 @@ trait Reporting { this: Context =>
9595
def strictWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = {
9696
val fullPos = addInlineds(pos)
9797
if (this.settings.strict.value) error(msg, fullPos)
98-
else reportWarning(new ExtendMessage(() => msg)(_ + "\n(This would be an error under strict mode)").warning(fullPos))
98+
else reportWarning(
99+
new ExtendMessage(() => msg)(_ + "\n(This would be an error under strict mode)")
100+
.warning(fullPos))
99101
}
100102

101-
def error(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = {
102-
reporter.report(new Error(msg, addInlineds(pos)))
103-
}
104-
105-
def errorOrMigrationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = {
103+
def error(msg: => Message, pos: SourcePosition = NoSourcePosition, sticky: Boolean = false): Unit = {
106104
val fullPos = addInlineds(pos)
107-
if (ctx.scala2Mode) migrationWarning(msg, fullPos) else error(msg, fullPos)
105+
reporter.report(if (sticky) new StickyError(msg, fullPos) else new Error(msg, fullPos))
108106
}
109107

108+
def errorOrMigrationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
109+
if (ctx.scala2Mode) migrationWarning(msg, pos) else error(msg, pos)
110+
110111
def restrictionError(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
111112
reporter.report {
112113
new ExtendMessage(() => msg)(m => s"Implementation restriction: $m").error(addInlineds(pos))
@@ -203,6 +204,9 @@ abstract class Reporter extends interfaces.ReporterResult {
203204
/** All errors reported by this reporter (ignoring outer reporters) */
204205
def allErrors: List[Error] = errors
205206

207+
/** Were sticky errors reported? Overridden in StoreReporter. */
208+
def hasStickyErrors: Boolean = false
209+
206210
/** Have errors been reported by this reporter, or in the
207211
* case where this is a StoreReporter, by an outer reporter?
208212
*/

compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class StoreReporter(outer: Reporter) extends Reporter {
3131
override def hasUnreportedErrors: Boolean =
3232
outer != null && infos != null && infos.exists(_.isInstanceOf[Error])
3333

34+
override def hasStickyErrors: Boolean =
35+
infos != null && infos.exists(_.isInstanceOf[StickyError])
36+
3437
override def removeBufferedMessages(implicit ctx: Context): List[MessageContainer] =
3538
if (infos != null) try infos.toList finally infos = null
3639
else Nil

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ object messages {
3535
pos: SourcePosition
3636
) extends MessageContainer(msgFn, pos, ERROR)
3737

38+
/** A sticky error is an error that should not be hidden by backtracking and
39+
* trying some alternative path. Typcially, errors issued after catching
40+
* a TypeError exception are sticky.
41+
*/
42+
class StickyError(
43+
msgFn: => Message,
44+
pos: SourcePosition
45+
) extends Error(msgFn, pos)
46+
3847
class Warning(
3948
msgFn: => Message,
4049
pos: SourcePosition

compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder
249249
case ex: TypeError =>
250250
// See neg/i1750a for an example where a cyclic error can arise.
251251
// The root cause in this example is an illegal "override" of an inner trait
252-
ctx.error(ex.toMessage, csym.sourcePos)
252+
ctx.error(ex.toMessage, csym.sourcePos, sticky = true)
253253
defn.ObjectType :: Nil
254254
}
255255
if (ValueClasses.isDerivedValueClass(csym)) {

compiler/src/dotty/tools/dotc/transform/MacroTransform.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ abstract class MacroTransform extends Phase {
6464
}
6565
catch {
6666
case ex: TypeError =>
67-
ctx.error(ex.toMessage, tree.sourcePos)
67+
ctx.error(ex.toMessage, tree.sourcePos, sticky = true)
6868
tree
6969
}
7070

compiler/src/dotty/tools/dotc/transform/MegaPhase.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
205205
}
206206
catch {
207207
case ex: TypeError =>
208-
ctx.error(ex.toMessage, tree.sourcePos)
208+
ctx.error(ex.toMessage, tree.sourcePos, sticky = true)
209209
tree
210210
}
211211
if (tree.isInstanceOf[NameTree]) goNamed(tree, start) else goUnnamed(tree, start)

compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ object OverridingPairs {
134134
case ex: TypeError =>
135135
// See neg/i1750a for an example where a cyclic error can arise.
136136
// The root cause in this example is an illegal "override" of an inner trait
137-
ctx.error(ex.toMessage, base.sourcePos)
137+
ctx.error(ex.toMessage, base.sourcePos, sticky = true)
138138
}
139139
} else {
140140
curEntry = curEntry.prev

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ object ErrorReporting {
1616

1717
import tpd._
1818

19-
def errorTree(tree: untpd.Tree, msg: => Message, pos: SourcePosition)(implicit ctx: Context): tpd.Tree =
20-
tree.withType(errorType(msg, pos))
19+
def errorTree(tree: untpd.Tree, msg: => Message, pos: SourcePosition, sticky: Boolean = false)(implicit ctx: Context): tpd.Tree =
20+
tree.withType(errorType(msg, pos, sticky))
2121

2222
def errorTree(tree: untpd.Tree, msg: => Message)(implicit ctx: Context): tpd.Tree =
2323
errorTree(tree, msg, tree.sourcePos)
2424

25-
def errorType(msg: => Message, pos: SourcePosition)(implicit ctx: Context): ErrorType = {
26-
ctx.error(msg, pos)
25+
def errorType(msg: => Message, pos: SourcePosition, sticky: Boolean = false)(implicit ctx: Context): ErrorType = {
26+
ctx.error(msg, pos, sticky)
2727
ErrorType(msg)
2828
}
2929

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ class RefChecks extends MiniPhase { thisPhase =>
987987
tree
988988
} catch {
989989
case ex: TypeError =>
990-
ctx.error(ex.toMessage, tree.sourcePos)
990+
ctx.error(ex.toMessage, tree.sourcePos, sticky = true)
991991
tree
992992
}
993993

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,7 +2113,7 @@ class Typer extends Namer
21132113
try adapt(typedUnadapted(tree, pt, locked), pt, locked)
21142114
catch {
21152115
case ex: TypeError =>
2116-
errorTree(tree, ex.toMessage, tree.sourcePos.focus)
2116+
errorTree(tree, ex.toMessage, tree.sourcePos.focus, sticky = true)
21172117
// This uses tree.span.focus instead of the default tree.span, because:
21182118
// - since tree can be a top-level definition, tree.span can point to the whole definition
21192119
// - that would in turn hide all other type errors inside tree.
@@ -2203,7 +2203,7 @@ class Typer extends Namer
22032203
def tryEither[T](op: Context => T)(fallBack: (T, TyperState) => T)(implicit ctx: Context): T = {
22042204
val nestedCtx = ctx.fresh.setNewTyperState()
22052205
val result = op(nestedCtx)
2206-
if (nestedCtx.reporter.hasErrors) {
2206+
if (nestedCtx.reporter.hasErrors && !nestedCtx.reporter.hasStickyErrors)
22072207
record("tryEither.fallBack")
22082208
fallBack(result, nestedCtx.typerState)
22092209
}
@@ -2828,7 +2828,7 @@ class Typer extends Namer
28282828
}
28292829
}
28302830
catch {
2831-
case ex: TypeError => errorTree(tree, ex.toMessage, tree.sourcePos)
2831+
case ex: TypeError => errorTree(tree, ex.toMessage, tree.sourcePos, sticky = true)
28322832
}
28332833
val nestedCtx = ctx.fresh.setNewTyperState()
28342834
val app = tryExtension(nestedCtx)

0 commit comments

Comments
 (0)