diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala index 17790c226ba0..5d845afe0947 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala @@ -15,6 +15,7 @@ import dotty.tools.dotc.ast.untpd import dotty.tools.dotc.core.Comments.Comment import dotty.tools.dotc.core.Constants.Constant import dotty.tools.dotc.core.Contexts.* +import dotty.tools.dotc.core.Decorators.toTermName import dotty.tools.dotc.core.Denotations.SingleDenotation import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Flags.* @@ -768,6 +769,13 @@ class Completions( ).flatMap(_.alternatives.map(_.symbol)).toSet ) + private lazy val EqualsClass: ClassSymbol = requiredClass("scala.Equals") + private lazy val ArrowAssocClass: ClassSymbol = requiredClass("scala.Predef.ArrowAssoc") + private lazy val EnsuringClass: ClassSymbol = requiredClass("scala.Predef.Ensuring") + private lazy val StringFormatClass: ClassSymbol = requiredClass("scala.Predef.StringFormat") + private lazy val nnMethod: Symbol = defn.ScalaPredefModule.info.member("nn".toTermName).symbol + private lazy val runtimeCheckedMethod: Symbol = defn.ScalaPredefModule.info.member("runtimeChecked".toTermName).symbol + private def isNotLocalForwardReference(sym: Symbol)(using Context): Boolean = !sym.isLocalToBlock || !sym.srcPos.isAfter(completionPos.originalCursorPosition) || @@ -786,6 +794,17 @@ class Completions( (sym.isField && !isJavaClass && !isModuleOrClass) || sym.getter != NoSymbol catch case _ => false + def isInheritedFromScalaLibrary(sym: Symbol) = + sym.owner == defn.AnyClass || + sym.owner == defn.ObjectClass || + sym.owner == defn.ProductClass || + sym.owner == EqualsClass || + sym.owner == ArrowAssocClass || + sym.owner == EnsuringClass || + sym.owner == StringFormatClass || + sym == nnMethod || + sym == runtimeCheckedMethod + def symbolRelevance(sym: Symbol): Int = var relevance = 0 // symbols defined in this file are more relevant @@ -803,7 +822,7 @@ class Completions( case _ => // symbols whose owner is a base class are less relevant - if sym.owner == defn.AnyClass || sym.owner == defn.ObjectClass + if isInheritedFromScalaLibrary(sym) then relevance |= IsInheritedBaseMethod // symbols not provided via an implicit are more relevant if sym.is(Implicit) || @@ -815,7 +834,7 @@ class Completions( // accessors of case class members are more relevant if !sym.is(CaseAccessor) then relevance |= IsNotCaseAccessor // public symbols are more relevant - if !sym.isPublic then relevance |= IsNotCaseAccessor + if !sym.isPublic then relevance |= IsNotPublic // synthetic symbols are less relevant (e.g. `copy` on case classes) if sym.is(Synthetic) && !sym.isAllOf(EnumCase) then relevance |= IsSynthetic diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionExtensionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionExtensionSuite.scala index b41084af4a8e..16535381165c 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionExtensionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionExtensionSuite.scala @@ -437,3 +437,44 @@ class CompletionExtensionSuite extends BaseCompletionSuite: |""".stripMargin, assertSingleItem = false ) + + @Test def `extension-for-case-class` = + check( + """|case class Bar(): + | def baz(): Unit = ??? + | + |object Bar: + | extension (f: Bar) + | def qux: Unit = ??? + | + |object Main: + | val _ = Bar().@@ + |""".stripMargin, + """|baz(): Unit + |copy(): Bar + |qux: Unit + |asInstanceOf[X0]: X0 + |canEqual(that: Any): Boolean + |equals(x$0: Any): Boolean + |getClass[X0 >: Bar](): Class[? <: X0] + |hashCode(): Int + |isInstanceOf[X0]: Boolean + |productArity: Int + |productElement(n: Int): Any + |productElementName(n: Int): String + |productElementNames: Iterator[String] + |productIterator: Iterator[Any] + |productPrefix: String + |synchronized[X0](x$0: X0): X0 + |toString(): String + |->[B](y: B): (Bar, B) + |ensuring(cond: Boolean): Bar + |ensuring(cond: Bar => Boolean): Bar + |ensuring(cond: Boolean, msg: => Any): Bar + |ensuring(cond: Bar => Boolean, msg: => Any): Bar + |nn: `?1`.type + |runtimeChecked: `?2`.type + |formatted(fmtstr: String): String + |→[B](y: B): (Bar, B) + | """.stripMargin + ) diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala index 9e3d1e1240be..1efbef6930bf 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala @@ -109,17 +109,9 @@ class CompletionSuite extends BaseCompletionSuite: |tabulate[A](n: Int)(f: Int => A): List[A] |unapplySeq[A](x: List[A] @uncheckedVariance): UnapplySeqWrapper[A] |unfold[A, S](init: S)(f: S => Option[(A, S)]): List[A] - |->[B](y: B): (List.type, B) - |ensuring(cond: Boolean): List.type - |ensuring(cond: List.type => Boolean): List.type - |ensuring(cond: Boolean, msg: => Any): List.type - |ensuring(cond: List.type => Boolean, msg: => Any): List.type |fromSpecific(from: Any)(it: IterableOnce[Nothing]): List[Nothing] |fromSpecific(it: IterableOnce[Nothing]): List[Nothing] - |nn: List.type |toFactory(from: Any): Factory[Nothing, List[Nothing]] - |formatted(fmtstr: String): String - |→[B](y: B): (List.type, B) |iterableFactory[A]: Factory[A, List[A]] |asInstanceOf[X0]: X0 |equals(x$0: Any): Boolean @@ -128,6 +120,15 @@ class CompletionSuite extends BaseCompletionSuite: |isInstanceOf[X0]: Boolean |synchronized[X0](x$0: X0): X0 |toString(): String + |->[B](y: B): (List.type, B) + |ensuring(cond: Boolean): List.type + |ensuring(cond: List.type => Boolean): List.type + |ensuring(cond: Boolean, msg: => Any): List.type + |ensuring(cond: List.type => Boolean, msg: => Any): List.type + |nn: List.type + |runtimeChecked scala.collection.immutable + |formatted(fmtstr: String): String + |→[B](y: B): (List.type, B) |""".stripMargin ) @@ -2238,7 +2239,7 @@ class CompletionSuite extends BaseCompletionSuite: |""".stripMargin, "asTerm: Term" ) - + @Test def `derives-no-square-brackets` = check( """