Skip to content

Commit 1699a18

Browse files
committed
make parser warnings and @nowarn work in the repl
1 parent a03f5e2 commit 1699a18

File tree

4 files changed

+70
-27
lines changed

4 files changed

+70
-27
lines changed

Diff for: 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) =

Diff for: 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

@@ -170,6 +172,9 @@ abstract class Reporter extends interfaces.ReporterResult {
170172
}
171173
end go
172174

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

Diff for: compiler/src/dotty/tools/repl/ReplCompiler.scala

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

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

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

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

Diff for: compiler/test-resources/repl/nowarn.scala

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

0 commit comments

Comments
 (0)