Skip to content

Fix completion mode filtering + optimize scopeCompletions #23172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions compiler/src/dotty/tools/dotc/interactive/Completion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,7 @@ object Completion:
case tpd.Select(qual @ tpd.This(_), _) :: _ if qual.span.isSynthetic => completer.scopeCompletions.names
case StringContextApplication(qual) =>
completer.scopeCompletions.names ++ completer.selectionCompletions(qual)
case tpd.Select(qual, _) :: _ if qual.typeOpt.hasSimpleKind =>
completer.selectionCompletions(qual)
case tpd.Select(qual, _) :: _ => Map.empty
case tpd.Select(qual, _) :: _ => completer.selectionCompletions(qual)
case (tree: tpd.ImportOrExport) :: _ => completer.directMemberCompletions(tree.expr)
case _ => completer.scopeCompletions.names

Expand Down Expand Up @@ -370,7 +368,7 @@ object Completion:
* For the results of all `xyzCompletions` methods term names and type names are always treated as different keys in the same map
* and they never conflict with each other.
*/
class Completer(val mode: Mode, pos: SourcePosition, untpdPath: List[untpd.Tree], matches: Name => Boolean):
class Completer(val mode: Mode, pos: SourcePosition, untpdPath: List[untpd.Tree], matches: Name => Boolean)(using Context):
/** Completions for terms and types that are currently in scope:
* the members of the current class, local definitions and the symbols that have been imported,
* recursively adding completions from outer scopes.
Expand All @@ -384,7 +382,7 @@ object Completion:
* (even if the import follows it syntactically)
* - a more deeply nested import shadowing a member or a local definition causes an ambiguity
*/
def scopeCompletions(using context: Context): CompletionResult =
lazy val scopeCompletions: CompletionResult =

/** Temporary data structure representing denotations with the same name introduced in a given scope
* as a member of a type, by a local definition or by an import clause
Expand Down Expand Up @@ -478,17 +476,16 @@ object Completion:
def selectionCompletions(qual: tpd.Tree)(using Context): CompletionMap =
val adjustedQual = widenQualifier(qual)

val implicitConversionMembers = implicitConversionMemberCompletions(adjustedQual)
val extensionMembers = extensionCompletions(adjustedQual)
val directMembers = directMemberCompletions(adjustedQual)
val namedTupleMembers = namedTupleCompletions(adjustedQual)
if qual.symbol.is(Package) then
directMemberCompletions(adjustedQual)
else if qual.typeOpt.hasSimpleKind then
implicitConversionMemberCompletions(adjustedQual) ++
extensionCompletions(adjustedQual) ++
directMemberCompletions(adjustedQual) ++
namedTupleCompletions(adjustedQual)
else
Map.empty

List(
implicitConversionMembers,
extensionMembers,
directMembers,
namedTupleMembers
).reduce(_ ++ _)

/** Completions for members of `qual`'s type.
* These include inherited definitions but not members added by extensions or implicit conversions
Expand Down Expand Up @@ -619,8 +616,7 @@ object Completion:
// There are four possible ways for an extension method to be applicable

// 1. The extension method is visible under a simple name, by being defined or inherited or imported in a scope enclosing the reference.
val termCompleter = new Completer(Mode.Term, pos, untpdPath, matches)
val extMethodsInScope = termCompleter.scopeCompletions.names.toList.flatMap:
val extMethodsInScope = scopeCompletions.names.toList.flatMap:
case (name, denots) => denots.collect:
case d: SymDenotation if d.isTerm && d.termRef.symbol.is(Extension) => (d.termRef, name.asTermName)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2250,3 +2250,28 @@ class CompletionSuite extends BaseCompletionSuite:
|""".stripMargin,
""
)

@Test def `no-completions-on-package-selection` =
check(
"""package one.@@
|""".stripMargin,
""
)

@Test def `no-extension-completion-on-packages` =
check(
"""object M:
| scala.runt@@
|""".stripMargin,
"""runtime scala
|PartialFunction scala""".stripMargin // those are the actual members of scala
)

@Test def `no-extension-completions-on-package-objects` =
check(
"""package object magic { def test: Int = ??? }
|object M:
| magic.@@
|""".stripMargin,
"test: Int"
)
Loading