@@ -370,7 +370,7 @@ object Completion:
370370 * For the results of all `xyzCompletions` methods term names and type names are always treated as different keys in the same map
371371 * and they never conflict with each other.
372372 */
373- class Completer (val mode : Mode , pos : SourcePosition , untpdPath : List [untpd.Tree ], matches : Name => Boolean ):
373+ class Completer (val mode : Mode , pos : SourcePosition , untpdPath : List [untpd.Tree ], matches : Name => Boolean )( using Context ) :
374374 /** Completions for terms and types that are currently in scope:
375375 * the members of the current class, local definitions and the symbols that have been imported,
376376 * recursively adding completions from outer scopes.
@@ -384,7 +384,52 @@ object Completion:
384384 * (even if the import follows it syntactically)
385385 * - a more deeply nested import shadowing a member or a local definition causes an ambiguity
386386 */
387- def scopeCompletions (using context : Context ): CompletionResult =
387+ lazy val scopeCompletions : CompletionResult =
388+
389+ /** Completions introduced by imports directly in this context.
390+ * Completions from outer contexts are not included.
391+ */
392+ def importedCompletions (using Context ): CompletionResult =
393+ val imp = ctx.importInfo
394+ val renames = collection.mutable.Map .empty[Symbol , Name ]
395+
396+ if imp == null then
397+ CompletionResult (Map .empty, Map .empty)
398+ else
399+ def fromImport (name : Name , nameInScope : Name ): Seq [(Name , SingleDenotation )] =
400+ imp.site.member(name).alternatives
401+ .collect:
402+ case denot if include(denot, nameInScope) =>
403+ if name != nameInScope then renames(denot.symbol) = nameInScope
404+ nameInScope -> denot
405+
406+ val givenImports = imp.importedImplicits
407+ .map { ref => (ref.implicitName: Name , ref.underlyingRef.denot.asSingleDenotation) }
408+ .filter((name, denot) => include(denot, name))
409+ .groupByName
410+
411+ val wildcardMembers =
412+ if imp.selectors.exists(_.imported.name == nme.WILDCARD ) then
413+ val denots = accessibleMembers(imp.site)
414+ .filter(mbr => ! mbr.symbol.is(Given ) && ! imp.excluded.contains(mbr.name.toTermName))
415+ denots.groupByName
416+ else
417+ Map .empty
418+
419+ val explicitMembers =
420+ val importNamesInScope = imp.forwardMapping.toList.map(_._2)
421+ val duplicatedNames = importNamesInScope.diff(importNamesInScope.distinct)
422+ val discardedNames = duplicatedNames ++ imp.excluded
423+ imp.reverseMapping.toList
424+ .filter { (nameInScope, _) => ! discardedNames.contains(nameInScope) }
425+ .flatMap: (nameInScope, original) =>
426+ fromImport(original, nameInScope) ++
427+ fromImport(original.toTypeName, nameInScope.toTypeName)
428+ .toSeq.groupByName
429+
430+ val results = givenImports ++ wildcardMembers ++ explicitMembers
431+ CompletionResult (results, renames.toMap)
432+ end importedCompletions
388433
389434 /** Temporary data structure representing denotations with the same name introduced in a given scope
390435 * as a member of a type, by a local definition or by an import clause
@@ -399,31 +444,27 @@ object Completion:
399444 def addMapping (name : Name , denots : ScopedDenotations ) =
400445 mappings(name) = mappings(name) :+ denots
401446
402- ctx.outersIterator.foreach { case ctx @ given Context =>
403- if ctx.isImportContext then
404- val imported = importedCompletions
405- imported.names.foreach { (name, denots) =>
406- addMapping(name, ScopedDenotations (denots, ctx, include(_, name)))
407- }
408- imported.renames.foreach { (name, newName) =>
409- renames(name) = newName
410- }
411- else if ctx.owner.isClass then
412- accessibleMembers(ctx.owner.thisType)
413- .groupByName.foreach { (name, denots) =>
447+ ctx.outersIterator.foreach:
448+ case ctx @ given Context =>
449+ if ctx.isImportContext then
450+ val imported = importedCompletions
451+ imported.names.foreach: (name, denots) =>
414452 addMapping(name, ScopedDenotations (denots, ctx, include(_, name)))
415- }
416- else if ctx.scope ne EmptyScope then
417- ctx.scope.toList.filter(symbol => include(symbol, symbol.name))
418- .flatMap(_.alternatives)
419- .groupByName.foreach { (name, denots) =>
420- addMapping(name, ScopedDenotations (denots, ctx, include(_, name)))
421- }
422- }
453+ imported.renames.foreach: (name, newName) =>
454+ renames(name) = newName
455+ else if ctx.owner.isClass then
456+ accessibleMembers(ctx.owner.thisType)
457+ .groupByName.foreach: (name, denots) =>
458+ addMapping(name, ScopedDenotations (denots, ctx, include(_, name)))
459+ else if ctx.scope ne EmptyScope then
460+ ctx.scope.toList.filter(symbol => include(symbol, symbol.name))
461+ .flatMap(_.alternatives)
462+ .groupByName.foreach: (name, denots) =>
463+ addMapping(name, ScopedDenotations (denots, ctx, include(_, name)))
423464
424465 var resultMappings = Map .empty[Name , Seq [SingleDenotation ]]
425466
426- mappings.foreach { (name, denotss) =>
467+ mappings.foreach: (name, denotss) =>
427468 val first = denotss.head
428469
429470 // import a.c
@@ -447,7 +488,7 @@ object Completion:
447488 def notConflictingWithDefaults = // is imported symbol
448489 denotss.filterNot(_.denots.exists(denot => Interactive .isImportedByDefault(denot.symbol))).size <= 1
449490
450- denotss.find(! _.ctx.isImportContext) match {
491+ denotss.find(! _.ctx.isImportContext) match
451492 // most deeply nested member or local definition if not shadowed by an import
452493 case Some (local) if local.ctx.scope == first.ctx.scope =>
453494 resultMappings += name -> local.denots
@@ -457,15 +498,14 @@ object Completion:
457498 val ordered = denotss.map(_.denots).sorted
458499 resultMappings += name -> ordered.head
459500 case _ =>
460- }
461- }
501+
462502
463503 CompletionResult (resultMappings, renames.toMap)
464504 end scopeCompletions
465505
466506 /** Widen only those types which are applied or are exactly nothing
467507 */
468- def widenQualifier (qual : tpd.Tree )( using Context ) : tpd.Tree =
508+ def widenQualifier (qual : tpd.Tree ): tpd.Tree =
469509 qual.typeOpt.widenDealias match
470510 case widenedType if widenedType.isExactlyNothing => qual.withType(widenedType)
471511 case appliedType : AppliedType => qual.withType(appliedType)
@@ -475,7 +515,7 @@ object Completion:
475515 * Direct members take priority over members from extensions
476516 * and so do members from extensions over members from implicit conversions
477517 */
478- def selectionCompletions (qual : tpd.Tree )( using Context ) : CompletionMap =
518+ def selectionCompletions (qual : tpd.Tree ): CompletionMap =
479519 val adjustedQual = widenQualifier(qual)
480520
481521 val implicitConversionMembers = implicitConversionMemberCompletions(adjustedQual)
@@ -493,60 +533,14 @@ object Completion:
493533 /** Completions for members of `qual`'s type.
494534 * These include inherited definitions but not members added by extensions or implicit conversions
495535 */
496- def directMemberCompletions (qual : tpd.Tree )( using Context ) : CompletionMap =
536+ def directMemberCompletions (qual : tpd.Tree ): CompletionMap =
497537 if qual.typeOpt.isExactlyNothing then
498538 Map .empty
499539 else
500540 accessibleMembers(qual.typeOpt).groupByName
501541
502- /** Completions introduced by imports directly in this context.
503- * Completions from outer contexts are not included.
504- */
505- private def importedCompletions (using Context ): CompletionResult =
506- val imp = ctx.importInfo
507- val renames = collection.mutable.Map .empty[Symbol , Name ]
508-
509- if imp == null then
510- CompletionResult (Map .empty, Map .empty)
511- else
512- def fromImport (name : Name , nameInScope : Name ): Seq [(Name , SingleDenotation )] =
513- imp.site.member(name).alternatives
514- .collect { case denot if include(denot, nameInScope) =>
515- if name != nameInScope then
516- renames(denot.symbol) = nameInScope
517- nameInScope -> denot
518- }
519-
520- val givenImports = imp.importedImplicits
521- .map { ref => (ref.implicitName: Name , ref.underlyingRef.denot.asSingleDenotation) }
522- .filter((name, denot) => include(denot, name))
523- .groupByName
524-
525- val wildcardMembers =
526- if imp.selectors.exists(_.imported.name == nme.WILDCARD ) then
527- val denots = accessibleMembers(imp.site)
528- .filter(mbr => ! mbr.symbol.is(Given ) && ! imp.excluded.contains(mbr.name.toTermName))
529- denots.groupByName
530- else
531- Map .empty
532-
533- val explicitMembers =
534- val importNamesInScope = imp.forwardMapping.toList.map(_._2)
535- val duplicatedNames = importNamesInScope.diff(importNamesInScope.distinct)
536- val discardedNames = duplicatedNames ++ imp.excluded
537- imp.reverseMapping.toList
538- .filter { (nameInScope, _) => ! discardedNames.contains(nameInScope) }
539- .flatMap { (nameInScope, original) =>
540- fromImport(original, nameInScope) ++
541- fromImport(original.toTypeName, nameInScope.toTypeName)
542- }.toSeq.groupByName
543-
544- val results = givenImports ++ wildcardMembers ++ explicitMembers
545- CompletionResult (results, renames.toMap)
546- end importedCompletions
547-
548542 /** Completions from implicit conversions including old style extensions using implicit classes */
549- private def implicitConversionMemberCompletions (qual : tpd.Tree )( using Context ) : CompletionMap =
543+ private def implicitConversionMemberCompletions (qual : tpd.Tree ): CompletionMap =
550544
551545 def tryToInstantiateTypeVars (conversionTarget : SearchSuccess ): Type =
552546 try
@@ -567,16 +561,15 @@ object Completion:
567561 .groupByName
568562
569563 /** Completions for named tuples */
570- private def namedTupleCompletions (qual : tpd.Tree )( using Context ) : CompletionMap =
564+ private def namedTupleCompletions (qual : tpd.Tree ): CompletionMap =
571565 def namedTupleCompletionsFromType (tpe : Type ): CompletionMap =
572566 val freshCtx = ctx.fresh.setExploreTyperState()
573567 inContext(freshCtx):
574568 tpe.namedTupleElementTypes(true )
575- .map { (name, tpe) =>
569+ .map: (name, tpe) =>
576570 val symbol = newSymbol(owner = NoSymbol , name, EmptyFlags , tpe)
577571 val denot = SymDenotation (symbol, NoSymbol , name, EmptyFlags , tpe)
578572 name -> denot
579- }
580573 .toSeq
581574 .filter((name, denot) => include(denot, name))
582575 .groupByName
@@ -591,17 +584,16 @@ object Completion:
591584 else Map .empty
592585
593586 /** Completions from extension methods */
594- private def extensionCompletions (qual : tpd.Tree )( using Context ) : CompletionMap =
587+ private def extensionCompletions (qual : tpd.Tree ): CompletionMap =
595588 def asDefLikeType (tpe : Type ): Type = tpe match
596589 case _ : MethodOrPoly => tpe
597590 case _ => ExprType (tpe)
598591
599592 def tryApplyingReceiverToExtension (termRef : TermRef ): Option [SingleDenotation ] =
600593 ctx.typer.tryApplyingExtensionMethod(termRef, qual)
601- .map { tree =>
594+ .map: tree =>
602595 val tpe = asDefLikeType(tree.typeOpt.dealias)
603596 termRef.denot.asSingleDenotation.mapInfo(_ => tpe)
604- }
605597
606598 def extractMemberExtensionMethods (types : Seq [Type ]): Seq [(TermRef , TermName )] =
607599 object DenotWithMatchingName :
@@ -610,17 +602,15 @@ object Completion:
610602 case name : TermName if include(denot, name) => Some ((denot, name))
611603 case _ => None
612604
613- types.flatMap { tp =>
605+ types.flatMap: tp =>
614606 val tpe = tp.widenExpr
615607 tpe.membersBasedOnFlags(required = ExtensionMethod , excluded = EmptyFlags )
616608 .collect { case DenotWithMatchingName (denot, name) => TermRef (tpe, denot.symbol) -> name }
617- }
618609
619610 // There are four possible ways for an extension method to be applicable
620611
621612 // 1. The extension method is visible under a simple name, by being defined or inherited or imported in a scope enclosing the reference.
622- val termCompleter = new Completer (Mode .Term , pos, untpdPath, matches)
623- val extMethodsInScope = termCompleter.scopeCompletions.names.toList.flatMap:
613+ val extMethodsInScope = scopeCompletions.names.toList.flatMap:
624614 case (name, denots) => denots.collect:
625615 case d : SymDenotation if d.isTerm && d.termRef.symbol.is(Extension ) => (d.termRef, name.asTermName)
626616
@@ -637,13 +627,13 @@ object Completion:
637627 val extMethodsFromGivensInImplicitScope = extractMemberExtensionMethods(givensInImplicitScope)
638628
639629 val availableExtMethods = extMethodsFromGivensInImplicitScope ++ extMethodsFromImplicitScope ++ extMethodsFromGivensInScope ++ extMethodsInScope
640- val extMethodsWithAppliedReceiver = availableExtMethods.flatMap {
630+ val extMethodsWithAppliedReceiver = availableExtMethods.flatMap:
641631 case (termRef, termName) =>
642632 if termRef.symbol.is(ExtensionMethod ) && ! qual.typeOpt.isBottomType then
643633 tryApplyingReceiverToExtension(termRef)
644634 .map(denot => termName -> denot)
645635 else None
646- }
636+
647637 extMethodsWithAppliedReceiver.groupByName
648638
649639 lazy val isNew : Boolean = isInNewContext(untpdPath)
@@ -683,10 +673,9 @@ object Completion:
683673 catch
684674 case ex : TypeError =>
685675
686- val members = site.memberDenots(completionsFilter, appendMemberSyms).collect {
687- case mbr if include(mbr, mbr.name)
688- && mbr.symbol.isAccessibleFrom(site) => mbr
689- }
676+ val members = site.memberDenots(completionsFilter, appendMemberSyms).collect:
677+ case mbr if include(mbr, mbr.name) && mbr.symbol.isAccessibleFrom(site) => mbr
678+
690679 val refinements = extractRefinements(site).filter(mbr => include(mbr, mbr.name))
691680
692681 members ++ refinements
@@ -699,13 +688,12 @@ object Completion:
699688 * @param qual The argument to which the implicit conversion should be applied.
700689 * @return The set of types after `qual` implicit conversion.
701690 */
702- private def implicitConversionTargets (qual : tpd.Tree )(using Context ): Set [SearchSuccess ] = {
691+ private def implicitConversionTargets (qual : tpd.Tree )(using Context ): Set [SearchSuccess ] =
703692 val typer = ctx.typer
704693 val conversions = new typer.ImplicitSearch (defn.AnyType , qual, pos.span, Set .empty).allImplicits
705694
706695 interactiv.println(i " implicit conversion targets considered: ${conversions.toList}%, % " )
707696 conversions
708- }
709697
710698 /** Filter for names that should appear when looking for completions. */
711699 private object completionsFilter extends NameFilter :
0 commit comments