Skip to content

Commit 518e9fd

Browse files
committed
Improve completion
1 parent 5d3b040 commit 518e9fd

File tree

3 files changed

+55
-41
lines changed

3 files changed

+55
-41
lines changed

compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -896,8 +896,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
896896

897897
def decls: List[Symbol] = tp.decls.toList
898898

899-
def members: List[Symbol] =
900-
tp.memberDenots(takeAllFilter, (name, buf) => buf ++= tp.member(name).alternatives).map(_.symbol).toList
899+
def members: List[Symbol] = tp.allMembers.map(_.symbol).toList
901900

902901
def typeSymbol: Symbol = tp.widenDealias.typeSymbol
903902

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ object Types {
732732
}
733733

734734
/** The set of member classes of this type */
735-
final def memberClasses(implicit ctx: Context): Seq[SingleDenotation] = track("implicitMembers") {
735+
final def memberClasses(implicit ctx: Context): Seq[SingleDenotation] = track("memberClasses") {
736736
memberDenots(typeNameFilter,
737737
(name, buf) => buf ++= member(name).altsWith(x => x.isClass))
738738
}
@@ -743,11 +743,16 @@ object Types {
743743
}
744744

745745
/** The set of members of this type having at least one of `requiredFlags` but none of `excludedFlags` set */
746-
final def membersBasedOnFlags(requiredFlags: FlagSet, excludedFlags: FlagSet)(implicit ctx: Context): Seq[SingleDenotation] = track("implicitMembers") {
746+
final def membersBasedOnFlags(requiredFlags: FlagSet, excludedFlags: FlagSet)(implicit ctx: Context): Seq[SingleDenotation] = track("membersBasedOnFlags") {
747747
memberDenots(takeAllFilter,
748748
(name, buf) => buf ++= memberExcluding(name, excludedFlags).altsWith(x => x.is(requiredFlags)))
749749
}
750750

751+
/** All members of this type. Warning: this can be expensive to compute! */
752+
final def allMembers(implicit ctx: Context): Seq[SingleDenotation] = track("allMembers") {
753+
memberDenots(takeAllFilter, (name, buf) => buf ++= member(name).alternatives)
754+
}
755+
751756
/** The info of `sym`, seen as a member of this type. */
752757
final def memberInfo(sym: Symbol)(implicit ctx: Context): Type =
753758
sym.info.asSeenFrom(this, sym.owner)

compiler/src/dotty/tools/dotc/interactive/Interactive.scala

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import util.Positions._, util.SourcePosition
1212
import core.Denotations.SingleDenotation
1313
import NameKinds.SimpleNameKind
1414
import config.Printers.interactiv
15+
import StdNames.nme
1516

1617
/** High-level API to get information out of typed trees, designed to be used by IDEs.
1718
*
@@ -137,28 +138,49 @@ object Interactive {
137138
private def computeCompletions(pos: SourcePosition, path: List[Tree])(implicit ctx: Context): (Int, List[Symbol]) = {
138139
val completions = Scopes.newScope.openForMutations
139140

140-
val (completionPos, prefix) = path match {
141+
val (completionPos, prefix, termOnly, typeOnly) = path match {
141142
case (ref: RefTree) :: _ =>
142-
(ref.pos.point, ref.name.toString.take(ref.pos.end - ref.pos.point - 1))
143-
case (id @ Ident(name)) :: _ =>
144-
if.pos
145-
getScopeCompletions(ctx)
146-
id.pos.point
143+
if (ref.name == nme.ERROR)
144+
(ref.pos.point, "", false, false)
145+
else
146+
(ref.pos.point,
147+
ref.name.toString.take(pos.pos.point - ref.pos.point),
148+
ref.name.isTermName,
149+
ref.name.isTypeName)
147150
case _ =>
148-
getScopeCompletions(ctx)
149-
0
151+
(0, "", false, false)
152+
}
153+
154+
/** Include in completion sets only symbols that
155+
* - start with given name prefix
156+
* - do not contain '$' except in prefix where it is explicitly written by user
157+
* - have same term/type kind as name prefix given so far
158+
*/
159+
def include(sym: Symbol) =
160+
sym.name.startsWith(prefix) &&
161+
!sym.name.toString.drop(prefix.length).contains('$') &&
162+
(!termOnly || sym.isTerm) &&
163+
(!typeOnly || sym.isType)
164+
165+
def enter(sym: Symbol) =
166+
if (include(sym)) completions.enter(sym)
150167

151168
def add(sym: Symbol) =
152-
if (sym.exists && !completions.lookup(sym.name).exists)
153-
completions.enter(sym)
169+
if (sym.exists && !completions.lookup(sym.name).exists) enter(sym)
154170

155171
def addMember(site: Type, name: Name) =
156172
if (!completions.lookup(name).exists)
157-
for (alt <- site.member(name).alternatives)
158-
completions.enter(alt.symbol)
173+
for (alt <- site.member(name).alternatives) enter(alt.symbol)
159174

160-
def allMembers(site: Type, superAccess: Boolean = true) =
161-
site.membersBasedOnFlags(EmptyFlags, EmptyFlags).map(_.accessibleFrom(site, superAccess))
175+
def accessibleMembers(site: Type, superAccess: Boolean = true): Seq[Symbol] = site match {
176+
case site: NamedType if site.symbol.is(Package) =>
177+
site.decls.toList.filter(include) // Don't look inside package members -- it's too expensive.
178+
case _ =>
179+
site.allMembers.collect {
180+
case mbr if include(mbr.symbol) => mbr.accessibleFrom(site, superAccess).symbol
181+
case _ => NoSymbol
182+
}.filter(_.exists)
183+
}
162184

163185
def getImportCompletions(ictx: Context): Unit = {
164186
implicit val ctx = ictx
@@ -171,7 +193,7 @@ object Interactive {
171193
for (renamed <- imp.reverseMapping.keys) addImport(renamed)
172194
for (imported <- imp.originals if !imp.excluded.contains(imported)) addImport(imported)
173195
if (imp.isWildcardImport)
174-
for (mbr <- allMembers(imp.site) if !imp.excluded.contains(mbr.name.toTermName))
196+
for (mbr <- accessibleMembers(imp.site) if !imp.excluded.contains(mbr.name.toTermName))
175197
addMember(imp.site, mbr.name)
176198
}
177199
}
@@ -180,15 +202,11 @@ object Interactive {
180202
implicit val ctx = ictx
181203

182204
if (ctx.owner.isClass) {
183-
for (sym <- ctx.owner.info.decls) // decls in same class first
184-
addMember(ctx.owner.thisType, sym.name)
185-
if (!ctx.owner.is(Package)) {
186-
for (mbr <- allMembers(ctx.owner.thisType)) // all other members second
187-
addMember(ctx.owner.thisType, mbr.name)
188-
ctx.owner.asClass.classInfo.selfInfo match {
189-
case selfSym: Symbol => add(selfSym)
190-
case _ =>
191-
}
205+
for (mbr <- accessibleMembers(ctx.owner.thisType))
206+
addMember(ctx.owner.thisType, mbr.name)
207+
ctx.owner.asClass.classInfo.selfInfo match {
208+
case selfSym: Symbol => add(selfSym)
209+
case _ =>
192210
}
193211
}
194212
else if (ctx.scope != null) ctx.scope.foreach(add)
@@ -204,22 +222,14 @@ object Interactive {
204222
}
205223

206224
def getMemberCompletions(site: Type): Unit = {
207-
for (mbr <- allMembers(site)) addMember(site, mbr.name)
225+
for (mbr <- accessibleMembers(site)) addMember(site, mbr.name)
208226
}
209227

210-
val completionPos = path match {
211-
case (sel @ Select(qual, name)) :: _ =>
212-
getMemberCompletions(qual.tpe)
213-
// When completing "`a.foo`, return the members of `a`
214-
sel.pos.point
215-
case (id: Ident) :: _ =>
216-
getScopeCompletions(ctx)
217-
id.pos.point
218-
case _ =>
219-
getScopeCompletions(ctx)
220-
0
228+
path match {
229+
case (sel @ Select(qual, name)) :: _ => getMemberCompletions(qual.tpe)
230+
case _ => getScopeCompletions(ctx)
221231
}
222-
interactiv.println(i"completion = ${completions.toList}%, %")
232+
interactiv.println(i"completion with pos = $pos, prefix = $prefix, termOnly = $termOnly, typeOnly = $typeOnly = ${completions.toList}%, %")
223233
(completionPos, completions.toList)
224234
}
225235

0 commit comments

Comments
 (0)