Skip to content

Commit ff5bc2f

Browse files
rochalaWojciechMazur
authored andcommitted
Don't show enum completions in new keyword context (#20304)
Fixes #19968 [Cherry-picked c5f2064]
1 parent d2e5d85 commit ff5bc2f

File tree

4 files changed

+76
-12
lines changed

4 files changed

+76
-12
lines changed

compiler/src/dotty/tools/dotc/interactive/Completion.scala

+24-7
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ object Completion:
7575
customMatcher: Option[Name => Boolean] = None
7676
)(using Context): CompletionMap =
7777
val adjustedPath = typeCheckExtensionConstructPath(untpdPath, tpdPath, pos)
78-
computeCompletions(pos, mode, rawPrefix, adjustedPath, customMatcher)
78+
computeCompletions(pos, mode, rawPrefix, adjustedPath, untpdPath, customMatcher)
7979

8080
/**
8181
* Inspect `path` to determine what kinds of symbols should be considered.
@@ -199,12 +199,16 @@ object Completion:
199199
.flatten.getOrElse(tpdPath)
200200

201201
private def computeCompletions(
202-
pos: SourcePosition, mode: Mode, rawPrefix: String, adjustedPath: List[tpd.Tree], matches: Option[Name => Boolean]
202+
pos: SourcePosition,
203+
mode: Mode, rawPrefix: String,
204+
adjustedPath: List[tpd.Tree],
205+
untpdPath: List[untpd.Tree],
206+
matches: Option[Name => Boolean]
203207
)(using Context): CompletionMap =
204208
val hasBackTick = rawPrefix.headOption.contains('`')
205209
val prefix = if hasBackTick then rawPrefix.drop(1) else rawPrefix
206210
val matches0 = matches.getOrElse(_.startsWith(prefix))
207-
val completer = new Completer(mode, pos, matches0)
211+
val completer = new Completer(mode, pos, untpdPath, matches0)
208212

209213
val result = adjustedPath match
210214
// Ignore synthetic select from `This` because in code it was `Ident`
@@ -279,6 +283,12 @@ object Completion:
279283
if denot.isType then denot.symbol.showFullName
280284
else denot.info.widenTermRefExpr.show
281285

286+
287+
def isInNewContext(untpdPath: List[untpd.Tree]): Boolean =
288+
untpdPath match
289+
case _ :: untpd.New(selectOrIdent: (untpd.Select | untpd.Ident)) :: _ => true
290+
case _ => false
291+
282292
/** Include in completion sets only symbols that
283293
* 1. is not absent (info is not NoType)
284294
* 2. are not a primary constructor,
@@ -290,7 +300,11 @@ object Completion:
290300
* 8. symbol is not a constructor proxy module when in type completion mode
291301
* 9. have same term/type kind as name prefix given so far
292302
*/
293-
def isValidCompletionSymbol(sym: Symbol, completionMode: Mode)(using Context): Boolean =
303+
def isValidCompletionSymbol(sym: Symbol, completionMode: Mode, isNew: Boolean)(using Context): Boolean =
304+
305+
lazy val isEnum = sym.is(Enum) ||
306+
(sym.companionClass.exists && sym.companionClass.is(Enum))
307+
294308
sym.exists &&
295309
!sym.isAbsent() &&
296310
!sym.isPrimaryConstructor &&
@@ -300,6 +314,7 @@ object Completion:
300314
!sym.isPackageObject &&
301315
!sym.is(Artifact) &&
302316
!(completionMode.is(Mode.Type) && sym.isAllOf(ConstructorProxyModule)) &&
317+
!(isNew && isEnum) &&
303318
(
304319
(completionMode.is(Mode.Term) && (sym.isTerm || sym.is(ModuleClass))
305320
|| (completionMode.is(Mode.Type) && (sym.isType || sym.isStableMember)))
@@ -323,7 +338,7 @@ object Completion:
323338
* For the results of all `xyzCompletions` methods term names and type names are always treated as different keys in the same map
324339
* and they never conflict with each other.
325340
*/
326-
class Completer(val mode: Mode, pos: SourcePosition, matches: Name => Boolean):
341+
class Completer(val mode: Mode, pos: SourcePosition, untpdPath: List[untpd.Tree], matches: Name => Boolean):
327342
/** Completions for terms and types that are currently in scope:
328343
* the members of the current class, local definitions and the symbols that have been imported,
329344
* recursively adding completions from outer scopes.
@@ -530,7 +545,7 @@ object Completion:
530545
// There are four possible ways for an extension method to be applicable
531546

532547
// 1. The extension method is visible under a simple name, by being defined or inherited or imported in a scope enclosing the reference.
533-
val termCompleter = new Completer(Mode.Term, pos, matches)
548+
val termCompleter = new Completer(Mode.Term, pos, untpdPath, matches)
534549
val extMethodsInScope = termCompleter.scopeCompletions.toList.flatMap:
535550
case (name, denots) => denots.collect:
536551
case d: SymDenotation if d.isTerm && d.termRef.symbol.is(Extension) => (d.termRef, name.asTermName)
@@ -557,14 +572,16 @@ object Completion:
557572
}
558573
extMethodsWithAppliedReceiver.groupByName
559574

575+
lazy val isNew: Boolean = isInNewContext(untpdPath)
576+
560577
/** Include in completion sets only symbols that
561578
* 1. match the filter method,
562579
* 2. satisfy [[Completion.isValidCompletionSymbol]]
563580
*/
564581
private def include(denot: SingleDenotation, nameInScope: Name)(using Context): Boolean =
565582
matches(nameInScope) &&
566583
completionsFilter(NoType, nameInScope) &&
567-
isValidCompletionSymbol(denot.symbol, mode)
584+
isValidCompletionSymbol(denot.symbol, mode, isNew)
568585

569586
private def extractRefinements(site: Type)(using Context): Seq[SingleDenotation] =
570587
site match

language-server/test/dotty/tools/languageserver/CompletionTest.scala

+19
Original file line numberDiff line numberDiff line change
@@ -1704,4 +1704,23 @@ class CompletionTest {
17041704
.completion(m1, Set(
17051705
("getOrElse", Method, "[V1 >: String](key: Int, default: => V1): V1"),
17061706
))
1707+
1708+
@Test def noEnumCompletionInNewContext: Unit =
1709+
code"""|enum TestEnum:
1710+
| case TestCase
1711+
|object M:
1712+
| TestEnu$m1
1713+
| TestEnum.TestCa$m2
1714+
| val x: TestEnu$m3
1715+
| val y: TestEnum.Tes$m4
1716+
| new TestEnu$m5
1717+
| new TestEnum.TestCas$m6
1718+
|"""
1719+
.completion(m1, Set(("TestEnum", Module, "TestEnum")))
1720+
.completion(m2, Set(("TestCase", Field, "TestEnum")))
1721+
.completion(m3, Set(("TestEnum", Module, "TestEnum"), ("TestEnum", Class, "TestEnum")))
1722+
.completion(m4, Set(("TestCase", Field, "TestEnum")))
1723+
.completion(m5, Set())
1724+
.completion(m6, Set())
1725+
17071726
}

presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala

+2-5
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,7 @@ class Completions(
7272
case _ :: (_: (Import | Export)) :: _ => false
7373
case _ => true
7474

75-
private lazy val isNew: Boolean =
76-
path match
77-
case _ :: New(selectOrIdent: (Select | Ident)) :: _ => true
78-
case _ => false
75+
private lazy val isNew: Boolean = Completion.isInNewContext(adjustedPath)
7976

8077
def includeSymbol(sym: Symbol)(using Context): Boolean =
8178
def hasSyntheticCursorSuffix: Boolean =
@@ -539,7 +536,7 @@ class Completions(
539536
val query = completionPos.query
540537
if completionMode.is(Mode.Scope) && query.nonEmpty then
541538
val visitor = new CompilerSearchVisitor(sym =>
542-
if Completion.isValidCompletionSymbol(sym, completionMode) &&
539+
if Completion.isValidCompletionSymbol(sym, completionMode, isNew) &&
543540
!(sym.is(Flags.ExtensionMethod) || (sym.maybeOwner.is(Flags.Implicit) && sym.maybeOwner.isClass))
544541
then
545542
indexedContext.lookupSym(sym) match

presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala

+31
Original file line numberDiff line numberDiff line change
@@ -1877,3 +1877,34 @@ class CompletionSuite extends BaseCompletionSuite:
18771877
|""".stripMargin,
18781878
topLines = Some(2)
18791879
)
1880+
1881+
@Test def `no-enum-completions-in-new-context` =
1882+
check(
1883+
"""enum TestEnum:
1884+
| case TestCase
1885+
|object M:
1886+
| new TestEnu@@
1887+
|""".stripMargin,
1888+
""
1889+
)
1890+
1891+
@Test def `no-enum-case-completions-in-new-context` =
1892+
check(
1893+
"""enum TestEnum:
1894+
| case TestCase
1895+
|object M:
1896+
| new TestEnum.TestCas@@
1897+
|""".stripMargin,
1898+
""
1899+
)
1900+
1901+
@Test def `deduplicated-enum-completions` =
1902+
check(
1903+
"""enum TestEnum:
1904+
| case TestCase
1905+
|object M:
1906+
| val x: TestEn@@
1907+
|""".stripMargin,
1908+
"""TestEnum test
1909+
|""".stripMargin,
1910+
)

0 commit comments

Comments
 (0)