Skip to content

Commit 7c84a3e

Browse files
committed
make parser warnings and @nowarn work in the repl
1 parent 312b8c0 commit 7c84a3e

File tree

4 files changed

+69
-27
lines changed

4 files changed

+69
-27
lines changed

compiler/src/dotty/tools/dotc/Run.scala

+7
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
106106
private val mySuspendedMessages: mutable.LinkedHashMap[SourceFile, mutable.LinkedHashSet[Warning]] = mutable.LinkedHashMap.empty
107107

108108
object suppressions:
109+
// When the REPL creates a new run (ReplDriver.compile), parsing is already done in the old context, with the
110+
// previous Run. Parser warnings were suspended in the old run and need to be copied over so they are not lost.
111+
// Same as scala/scala/commit/79ca1408c7.
112+
def initSuspendedMessages(oldRun: Run) = if oldRun != null then
113+
mySuspendedMessages.clear()
114+
mySuspendedMessages ++= oldRun.mySuspendedMessages
115+
109116
def suppressionsComplete(source: SourceFile) = source == NoSource || mySuppressionsComplete(source)
110117

111118
def addSuspendedMessage(warning: Warning) =

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

+10-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ abstract class Reporter extends interfaces.ReporterResult {
9090
finally incompleteHandler = saved
9191
}
9292

93+
private def isIncompleteChecking = incompleteHandler ne defaultIncompleteHandler
94+
9395
private var _errorCount = 0
9496
private var _warningCount = 0
9597

@@ -172,6 +174,9 @@ abstract class Reporter extends interfaces.ReporterResult {
172174
}
173175
end go
174176

177+
// `ctx.run` can be null in test, also in the repl when parsing the first line. The parser runs early, the Run is
178+
// only created in ReplDriver.compile when a line is submitted. This means that `@nowarn` doesnt work on parser
179+
// warnings in the first line.
175180
dia match
176181
case w: Warning if ctx.run != null =>
177182
val sup = ctx.run.suppressions
@@ -180,7 +185,11 @@ abstract class Reporter extends interfaces.ReporterResult {
180185
case Action.Verbose => w.setVerbose(); go()
181186
case Action.Silent =>
182187
else
183-
sup.addSuspendedMessage(w)
188+
// ParseResult.isIncomplete creates a new source file and reporter to check if the input is complete.
189+
// The reporter's warnings are discarded, and we should not add them to the run's suspended messages,
190+
// otherwise they are later reported.
191+
if !isIncompleteChecking then
192+
sup.addSuspendedMessage(w)
184193
case _ => go()
185194
end issueIfNotSuppressed
186195

compiler/src/dotty/tools/repl/ReplCompiler.scala

+28-26
Original file line numberDiff line numberDiff line change
@@ -38,34 +38,36 @@ class ReplCompiler extends Compiler {
3838
List(new PostTyper),
3939
)
4040

41-
def newRun(initCtx: Context, state: State): Run = new Run(this, initCtx) {
42-
43-
/** Import previous runs and user defined imports */
44-
override protected def rootContext(using Context): Context = {
45-
def importContext(imp: tpd.Import)(using Context) =
46-
ctx.importContext(imp, imp.symbol)
47-
48-
def importPreviousRun(id: Int)(using Context) = {
49-
// we first import the wrapper object id
50-
val path = nme.REPL_PACKAGE ++ "." ++ objectNames(id)
51-
val ctx0 = ctx.fresh
52-
.setNewScope
53-
.withRootImports(RootRef(() => requiredModuleRef(path)) :: Nil)
54-
55-
// then its user defined imports
56-
val imports = state.imports.getOrElse(id, Nil)
57-
if imports.isEmpty then ctx0
58-
else imports.foldLeft(ctx0.fresh.setNewScope)((ctx, imp) =>
59-
importContext(imp)(using ctx))
60-
}
41+
def newRun(initCtx: Context, state: State): Run =
42+
val run = new Run(this, initCtx) {
43+
/** Import previous runs and user defined imports */
44+
override protected def rootContext(using Context): Context = {
45+
def importContext(imp: tpd.Import)(using Context) =
46+
ctx.importContext(imp, imp.symbol)
47+
48+
def importPreviousRun(id: Int)(using Context) = {
49+
// we first import the wrapper object id
50+
val path = nme.REPL_PACKAGE ++ "." ++ objectNames(id)
51+
val ctx0 = ctx.fresh
52+
.setNewScope
53+
.withRootImports(RootRef(() => requiredModuleRef(path)) :: Nil)
54+
55+
// then its user defined imports
56+
val imports = state.imports.getOrElse(id, Nil)
57+
if imports.isEmpty then ctx0
58+
else imports.foldLeft(ctx0.fresh.setNewScope)((ctx, imp) =>
59+
importContext(imp)(using ctx))
60+
}
6161

62-
val rootCtx = super.rootContext
63-
.withRootImports // default root imports
64-
.withRootImports(RootRef(() => defn.EmptyPackageVal.termRef) :: Nil)
65-
(1 to state.objectIndex).foldLeft(rootCtx)((ctx, id) =>
66-
importPreviousRun(id)(using ctx))
62+
val rootCtx = super.rootContext
63+
.withRootImports // default root imports
64+
.withRootImports(RootRef(() => defn.EmptyPackageVal.termRef) :: Nil)
65+
(1 to state.objectIndex).foldLeft(rootCtx)((ctx, id) =>
66+
importPreviousRun(id)(using ctx))
67+
}
6768
}
68-
}
69+
run.suppressions.initSuspendedMessages(state.context.run)
70+
run
6971

7072
private val objectNames = mutable.Map.empty[Int, TermName]
7173

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
scala> @annotation.nowarn def f = try 1 // @nowarn doesn't work on first line, ctx.run is null in issueIfNotSuppressed
2+
-- Warning:
3+
1 | @annotation.nowarn def f = try 1 // @nowarn doesn't work on first line, ctx.run is null in issueIfNotSuppressed
4+
| ^^^^^
5+
| A try without catch or finally is equivalent to putting
6+
| its body in a block; no exceptions are handled.
7+
def f: Int
8+
scala> @annotation.nowarn def f = try 1
9+
def f: Int
10+
scala> def f = try 1
11+
-- Warning:
12+
1 | def f = try 1
13+
| ^^^^^
14+
| A try without catch or finally is equivalent to putting
15+
| its body in a block; no exceptions are handled.
16+
def f: Int
17+
scala> @annotation.nowarn def f = { 1; 2 }
18+
def f: Int
19+
scala> def f = { 1; 2 }
20+
-- Warning:
21+
1 | def f = { 1; 2 }
22+
| ^
23+
|A pure expression does nothing in statement position; you may be omitting necessary parentheses
24+
def f: Int

0 commit comments

Comments
 (0)