Skip to content

Commit 920500a

Browse files
Perl99tgodzik
authored andcommitted
Improve symbol order in completions provided by the presentation compiler (scala#23888)
Extension methods that are not in the same file are placed after all Product methods and even after extension methods like "ensuring". This PR penalizes the following methods, so that they are no longer at the top of the suggestions: - scala.Product.* - scala.Equals.* - scala.Predef.ArrowAssoc.* - scala.Predef.Ensuring.* - scala.Predef.StringFormat.* - scala.Predef.nn - scala.Predef.runtimeChecked Resolves scalameta/metals#7642
1 parent 992cb05 commit 920500a

File tree

3 files changed

+72
-11
lines changed

3 files changed

+72
-11
lines changed

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import dotty.tools.dotc.ast.untpd
1515
import dotty.tools.dotc.core.Comments.Comment
1616
import dotty.tools.dotc.core.Constants.Constant
1717
import dotty.tools.dotc.core.Contexts.*
18+
import dotty.tools.dotc.core.Decorators.toTermName
1819
import dotty.tools.dotc.core.Denotations.SingleDenotation
1920
import dotty.tools.dotc.core.Flags
2021
import dotty.tools.dotc.core.Flags.*
@@ -768,6 +769,13 @@ class Completions(
768769
).flatMap(_.alternatives.map(_.symbol)).toSet
769770
)
770771

772+
private lazy val EqualsClass: ClassSymbol = requiredClass("scala.Equals")
773+
private lazy val ArrowAssocClass: ClassSymbol = requiredClass("scala.Predef.ArrowAssoc")
774+
private lazy val EnsuringClass: ClassSymbol = requiredClass("scala.Predef.Ensuring")
775+
private lazy val StringFormatClass: ClassSymbol = requiredClass("scala.Predef.StringFormat")
776+
private lazy val nnMethod: Symbol = defn.ScalaPredefModule.info.member("nn".toTermName).symbol
777+
private lazy val runtimeCheckedMethod: Symbol = defn.ScalaPredefModule.info.member("runtimeChecked".toTermName).symbol
778+
771779
private def isNotLocalForwardReference(sym: Symbol)(using Context): Boolean =
772780
!sym.isLocalToBlock ||
773781
!sym.srcPos.isAfter(completionPos.originalCursorPosition) ||
@@ -786,6 +794,17 @@ class Completions(
786794
(sym.isField && !isJavaClass && !isModuleOrClass) || sym.getter != NoSymbol
787795
catch case _ => false
788796

797+
def isInheritedFromScalaLibrary(sym: Symbol) =
798+
sym.owner == defn.AnyClass ||
799+
sym.owner == defn.ObjectClass ||
800+
sym.owner == defn.ProductClass ||
801+
sym.owner == EqualsClass ||
802+
sym.owner == ArrowAssocClass ||
803+
sym.owner == EnsuringClass ||
804+
sym.owner == StringFormatClass ||
805+
sym == nnMethod ||
806+
sym == runtimeCheckedMethod
807+
789808
def symbolRelevance(sym: Symbol): Int =
790809
var relevance = 0
791810
// symbols defined in this file are more relevant
@@ -803,7 +822,7 @@ class Completions(
803822
case _ =>
804823

805824
// symbols whose owner is a base class are less relevant
806-
if sym.owner == defn.AnyClass || sym.owner == defn.ObjectClass
825+
if isInheritedFromScalaLibrary(sym)
807826
then relevance |= IsInheritedBaseMethod
808827
// symbols not provided via an implicit are more relevant
809828
if sym.is(Implicit) ||
@@ -815,7 +834,7 @@ class Completions(
815834
// accessors of case class members are more relevant
816835
if !sym.is(CaseAccessor) then relevance |= IsNotCaseAccessor
817836
// public symbols are more relevant
818-
if !sym.isPublic then relevance |= IsNotCaseAccessor
837+
if !sym.isPublic then relevance |= IsNotPublic
819838
// synthetic symbols are less relevant (e.g. `copy` on case classes)
820839
if sym.is(Synthetic) && !sym.isAllOf(EnumCase) then
821840
relevance |= IsSynthetic

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,44 @@ class CompletionExtensionSuite extends BaseCompletionSuite:
437437
|""".stripMargin,
438438
assertSingleItem = false
439439
)
440+
441+
@Test def `extension-for-case-class` =
442+
check(
443+
"""|case class Bar():
444+
| def baz(): Unit = ???
445+
|
446+
|object Bar:
447+
| extension (f: Bar)
448+
| def qux: Unit = ???
449+
|
450+
|object Main:
451+
| val _ = Bar().@@
452+
|""".stripMargin,
453+
"""|baz(): Unit
454+
|copy(): Bar
455+
|qux: Unit
456+
|asInstanceOf[X0]: X0
457+
|canEqual(that: Any): Boolean
458+
|equals(x$0: Any): Boolean
459+
|getClass[X0 >: Bar](): Class[? <: X0]
460+
|hashCode(): Int
461+
|isInstanceOf[X0]: Boolean
462+
|productArity: Int
463+
|productElement(n: Int): Any
464+
|productElementName(n: Int): String
465+
|productElementNames: Iterator[String]
466+
|productIterator: Iterator[Any]
467+
|productPrefix: String
468+
|synchronized[X0](x$0: X0): X0
469+
|toString(): String
470+
|->[B](y: B): (Bar, B)
471+
|ensuring(cond: Boolean): Bar
472+
|ensuring(cond: Bar => Boolean): Bar
473+
|ensuring(cond: Boolean, msg: => Any): Bar
474+
|ensuring(cond: Bar => Boolean, msg: => Any): Bar
475+
|nn: `?1`.type
476+
|runtimeChecked: `?2`.type
477+
|formatted(fmtstr: String): String
478+
|→[B](y: B): (Bar, B)
479+
| """.stripMargin
480+
)

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,9 @@ class CompletionSuite extends BaseCompletionSuite:
109109
|tabulate[A](n: Int)(f: Int => A): List[A]
110110
|unapplySeq[A](x: List[A] @uncheckedVariance): UnapplySeqWrapper[A]
111111
|unfold[A, S](init: S)(f: S => Option[(A, S)]): List[A]
112-
|->[B](y: B): (List.type, B)
113-
|ensuring(cond: Boolean): List.type
114-
|ensuring(cond: List.type => Boolean): List.type
115-
|ensuring(cond: Boolean, msg: => Any): List.type
116-
|ensuring(cond: List.type => Boolean, msg: => Any): List.type
117112
|fromSpecific(from: Any)(it: IterableOnce[Nothing]): List[Nothing]
118113
|fromSpecific(it: IterableOnce[Nothing]): List[Nothing]
119-
|nn: List.type
120114
|toFactory(from: Any): Factory[Nothing, List[Nothing]]
121-
|formatted(fmtstr: String): String
122-
|→[B](y: B): (List.type, B)
123115
|iterableFactory[A]: Factory[A, List[A]]
124116
|asInstanceOf[X0]: X0
125117
|equals(x$0: Any): Boolean
@@ -128,6 +120,15 @@ class CompletionSuite extends BaseCompletionSuite:
128120
|isInstanceOf[X0]: Boolean
129121
|synchronized[X0](x$0: X0): X0
130122
|toString(): String
123+
|->[B](y: B): (List.type, B)
124+
|ensuring(cond: Boolean): List.type
125+
|ensuring(cond: List.type => Boolean): List.type
126+
|ensuring(cond: Boolean, msg: => Any): List.type
127+
|ensuring(cond: List.type => Boolean, msg: => Any): List.type
128+
|nn: List.type
129+
|runtimeChecked scala.collection.immutable
130+
|formatted(fmtstr: String): String
131+
|→[B](y: B): (List.type, B)
131132
|""".stripMargin
132133
)
133134

@@ -2238,7 +2239,7 @@ class CompletionSuite extends BaseCompletionSuite:
22382239
|""".stripMargin,
22392240
"asTerm: Term"
22402241
)
2241-
2242+
22422243
@Test def `derives-no-square-brackets` =
22432244
check(
22442245
"""

0 commit comments

Comments
 (0)