Skip to content

Commit 82fb01e

Browse files
Fix scala#5895: REPL autocompletion crushes in certain cases
The crashes happen due to the fact that in certain cases, certain trees get mispositioned during code completion. E.g. this happens with `opaque type T = Int` or `object Foo { type T = Int`. The tree spans are set incorrectly because repl doesn't set the sources of these trees correctly. Precisely, when typechecking on code completion, a virtual source is used. However, when parsing for autocompletion, a line source is used which is created by the parsing logic. This commit makes sure that REPL is consistent in its source choices when computing code completions.
1 parent cab020d commit 82fb01e

File tree

3 files changed

+12
-3
lines changed

3 files changed

+12
-3
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ object ParseResult {
116116
}
117117

118118
/** Extract a `ParseResult` from the string `sourceCode` */
119-
def apply(sourceCode: String)(implicit state: State): ParseResult =
119+
def apply(sourceCodeOrFile: Either[String, SourceFile])(implicit state: State): ParseResult = {
120+
val sourceCode = sourceCodeOrFile.map(_.content().mkString).merge
120121
sourceCode match {
121122
case "" => Newline
122123
case CommandExtract(cmd, arg) => cmd match {
@@ -132,7 +133,7 @@ object ParseResult {
132133
case _ =>
133134
implicit val ctx: Context = state.context
134135

135-
val source = SourceFile.virtual(str.REPL_SESSION_LINE + (state.objectIndex + 1), sourceCode)
136+
val source = sourceCodeOrFile.toOption.getOrElse(SourceFile.virtual(str.REPL_SESSION_LINE + (state.objectIndex + 1), sourceCode))
136137

137138
val reporter = newStoreReporter
138139
val stats = parseStats(sourceCode)(state.context.fresh.setReporter(reporter).withSource(source))
@@ -145,6 +146,10 @@ object ParseResult {
145146
else
146147
Parsed(source, stats)
147148
}
149+
}
150+
151+
def apply(sourceFile: SourceFile)(implicit state: State): ParseResult = apply(Right(sourceFile))
152+
def apply(sourceCode: String)(implicit state: State): ParseResult = apply(Left(sourceCode))
148153

149154
/** Check if the input is incomplete
150155
*

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ class ReplCompiler extends Compiler {
241241
PackageDef(Ident(nme.EMPTY_PACKAGE), List(wrapper))
242242
}
243243

244-
ParseResult(expr)(state) match {
244+
ParseResult(sourceFile)(state) match {
245245
case Parsed(_, trees) =>
246246
wrap(trees).result
247247
case SyntaxErrors(_, reported, trees) =>

compiler/test/dotty/tools/repl/TabcompleteTests.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,8 @@ class TabcompleteTests extends ReplTest {
124124
val comp = tabComplete("???.")
125125
assertEquals(Nil, comp)
126126
}
127+
128+
@Test def moduleCompletion = fromInitialState { implicit s =>
129+
assertEquals(List("Predef"), tabComplete("object Foo { type T = Pre"))
130+
}
127131
}

0 commit comments

Comments
 (0)