@@ -370,7 +370,7 @@ object Completion:
370
370
* For the results of all `xyzCompletions` methods term names and type names are always treated as different keys in the same map
371
371
* and they never conflict with each other.
372
372
*/
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 ) :
374
374
/** Completions for terms and types that are currently in scope:
375
375
* the members of the current class, local definitions and the symbols that have been imported,
376
376
* recursively adding completions from outer scopes.
@@ -384,7 +384,52 @@ object Completion:
384
384
* (even if the import follows it syntactically)
385
385
* - a more deeply nested import shadowing a member or a local definition causes an ambiguity
386
386
*/
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
388
433
389
434
/** Temporary data structure representing denotations with the same name introduced in a given scope
390
435
* as a member of a type, by a local definition or by an import clause
@@ -399,31 +444,27 @@ object Completion:
399
444
def addMapping (name : Name , denots : ScopedDenotations ) =
400
445
mappings(name) = mappings(name) :+ denots
401
446
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) =>
414
452
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)))
423
464
424
465
var resultMappings = Map .empty[Name , Seq [SingleDenotation ]]
425
466
426
- mappings.foreach { (name, denotss) =>
467
+ mappings.foreach: (name, denotss) =>
427
468
val first = denotss.head
428
469
429
470
// import a.c
@@ -447,7 +488,7 @@ object Completion:
447
488
def notConflictingWithDefaults = // is imported symbol
448
489
denotss.filterNot(_.denots.exists(denot => Interactive .isImportedByDefault(denot.symbol))).size <= 1
449
490
450
- denotss.find(! _.ctx.isImportContext) match {
491
+ denotss.find(! _.ctx.isImportContext) match
451
492
// most deeply nested member or local definition if not shadowed by an import
452
493
case Some (local) if local.ctx.scope == first.ctx.scope =>
453
494
resultMappings += name -> local.denots
@@ -457,15 +498,14 @@ object Completion:
457
498
val ordered = denotss.map(_.denots).sorted
458
499
resultMappings += name -> ordered.head
459
500
case _ =>
460
- }
461
- }
501
+
462
502
463
503
CompletionResult (resultMappings, renames.toMap)
464
504
end scopeCompletions
465
505
466
506
/** Widen only those types which are applied or are exactly nothing
467
507
*/
468
- def widenQualifier (qual : tpd.Tree )( using Context ) : tpd.Tree =
508
+ def widenQualifier (qual : tpd.Tree ): tpd.Tree =
469
509
qual.typeOpt.widenDealias match
470
510
case widenedType if widenedType.isExactlyNothing => qual.withType(widenedType)
471
511
case appliedType : AppliedType => qual.withType(appliedType)
@@ -475,7 +515,7 @@ object Completion:
475
515
* Direct members take priority over members from extensions
476
516
* and so do members from extensions over members from implicit conversions
477
517
*/
478
- def selectionCompletions (qual : tpd.Tree )( using Context ) : CompletionMap =
518
+ def selectionCompletions (qual : tpd.Tree ): CompletionMap =
479
519
val adjustedQual = widenQualifier(qual)
480
520
481
521
val implicitConversionMembers = implicitConversionMemberCompletions(adjustedQual)
@@ -493,60 +533,14 @@ object Completion:
493
533
/** Completions for members of `qual`'s type.
494
534
* These include inherited definitions but not members added by extensions or implicit conversions
495
535
*/
496
- def directMemberCompletions (qual : tpd.Tree )( using Context ) : CompletionMap =
536
+ def directMemberCompletions (qual : tpd.Tree ): CompletionMap =
497
537
if qual.typeOpt.isExactlyNothing then
498
538
Map .empty
499
539
else
500
540
accessibleMembers(qual.typeOpt).groupByName
501
541
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
-
548
542
/** 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 =
550
544
551
545
def tryToInstantiateTypeVars (conversionTarget : SearchSuccess ): Type =
552
546
try
@@ -567,16 +561,15 @@ object Completion:
567
561
.groupByName
568
562
569
563
/** Completions for named tuples */
570
- private def namedTupleCompletions (qual : tpd.Tree )( using Context ) : CompletionMap =
564
+ private def namedTupleCompletions (qual : tpd.Tree ): CompletionMap =
571
565
def namedTupleCompletionsFromType (tpe : Type ): CompletionMap =
572
566
val freshCtx = ctx.fresh.setExploreTyperState()
573
567
inContext(freshCtx):
574
568
tpe.namedTupleElementTypes(true )
575
- .map { (name, tpe) =>
569
+ .map: (name, tpe) =>
576
570
val symbol = newSymbol(owner = NoSymbol , name, EmptyFlags , tpe)
577
571
val denot = SymDenotation (symbol, NoSymbol , name, EmptyFlags , tpe)
578
572
name -> denot
579
- }
580
573
.toSeq
581
574
.filter((name, denot) => include(denot, name))
582
575
.groupByName
@@ -591,17 +584,16 @@ object Completion:
591
584
else Map .empty
592
585
593
586
/** Completions from extension methods */
594
- private def extensionCompletions (qual : tpd.Tree )( using Context ) : CompletionMap =
587
+ private def extensionCompletions (qual : tpd.Tree ): CompletionMap =
595
588
def asDefLikeType (tpe : Type ): Type = tpe match
596
589
case _ : MethodOrPoly => tpe
597
590
case _ => ExprType (tpe)
598
591
599
592
def tryApplyingReceiverToExtension (termRef : TermRef ): Option [SingleDenotation ] =
600
593
ctx.typer.tryApplyingExtensionMethod(termRef, qual)
601
- .map { tree =>
594
+ .map: tree =>
602
595
val tpe = asDefLikeType(tree.typeOpt.dealias)
603
596
termRef.denot.asSingleDenotation.mapInfo(_ => tpe)
604
- }
605
597
606
598
def extractMemberExtensionMethods (types : Seq [Type ]): Seq [(TermRef , TermName )] =
607
599
object DenotWithMatchingName :
@@ -610,17 +602,15 @@ object Completion:
610
602
case name : TermName if include(denot, name) => Some ((denot, name))
611
603
case _ => None
612
604
613
- types.flatMap { tp =>
605
+ types.flatMap: tp =>
614
606
val tpe = tp.widenExpr
615
607
tpe.membersBasedOnFlags(required = ExtensionMethod , excluded = EmptyFlags )
616
608
.collect { case DenotWithMatchingName (denot, name) => TermRef (tpe, denot.symbol) -> name }
617
- }
618
609
619
610
// There are four possible ways for an extension method to be applicable
620
611
621
612
// 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:
624
614
case (name, denots) => denots.collect:
625
615
case d : SymDenotation if d.isTerm && d.termRef.symbol.is(Extension ) => (d.termRef, name.asTermName)
626
616
@@ -637,13 +627,13 @@ object Completion:
637
627
val extMethodsFromGivensInImplicitScope = extractMemberExtensionMethods(givensInImplicitScope)
638
628
639
629
val availableExtMethods = extMethodsFromGivensInImplicitScope ++ extMethodsFromImplicitScope ++ extMethodsFromGivensInScope ++ extMethodsInScope
640
- val extMethodsWithAppliedReceiver = availableExtMethods.flatMap {
630
+ val extMethodsWithAppliedReceiver = availableExtMethods.flatMap:
641
631
case (termRef, termName) =>
642
632
if termRef.symbol.is(ExtensionMethod ) && ! qual.typeOpt.isBottomType then
643
633
tryApplyingReceiverToExtension(termRef)
644
634
.map(denot => termName -> denot)
645
635
else None
646
- }
636
+
647
637
extMethodsWithAppliedReceiver.groupByName
648
638
649
639
lazy val isNew : Boolean = isInNewContext(untpdPath)
@@ -683,10 +673,9 @@ object Completion:
683
673
catch
684
674
case ex : TypeError =>
685
675
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
+
690
679
val refinements = extractRefinements(site).filter(mbr => include(mbr, mbr.name))
691
680
692
681
members ++ refinements
@@ -699,13 +688,12 @@ object Completion:
699
688
* @param qual The argument to which the implicit conversion should be applied.
700
689
* @return The set of types after `qual` implicit conversion.
701
690
*/
702
- private def implicitConversionTargets (qual : tpd.Tree )(using Context ): Set [SearchSuccess ] = {
691
+ private def implicitConversionTargets (qual : tpd.Tree )(using Context ): Set [SearchSuccess ] =
703
692
val typer = ctx.typer
704
693
val conversions = new typer.ImplicitSearch (defn.AnyType , qual, pos.span, Set .empty).allImplicits
705
694
706
695
interactiv.println(i " implicit conversion targets considered: ${conversions.toList}%, % " )
707
696
conversions
708
- }
709
697
710
698
/** Filter for names that should appear when looking for completions. */
711
699
private object completionsFilter extends NameFilter :
0 commit comments