Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down Expand Up @@ -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) ||
Expand All @@ -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
Expand All @@ -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) ||
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
)

Expand Down Expand Up @@ -2238,7 +2239,7 @@ class CompletionSuite extends BaseCompletionSuite:
|""".stripMargin,
"asTerm: Term"
)

@Test def `derives-no-square-brackets` =
check(
"""
Expand Down