Skip to content

Commit 3e39c73

Browse files
committed
Fix completion
Also, fix a tab complete test. The operands were swapped which led to a misleading error message
1 parent 5951f69 commit 3e39c73

File tree

3 files changed

+82
-78
lines changed

3 files changed

+82
-78
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 78 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,9 @@ object Parsers {
10451045
if in.token == MATCH then matchClause(t) else Select(t, ident())
10461046
}
10471047

1048+
def idSelector(t: Tree): Tree =
1049+
atSpan(startOffset(t), in.offset) { Select(t, ident()) }
1050+
10481051
/** Selectors ::= id { `.' id }
10491052
*
10501053
* Accept `.' separated identifiers acting as a selectors on given tree `t`.
@@ -1066,59 +1069,53 @@ object Parsers {
10661069
if (in.token == DOT) { in.nextToken(); selectors(t, finish) }
10671070
else t
10681071

1072+
def dotSelections(t: Tree): Tree =
1073+
if (in.token == DOT) { in.nextToken(); dotSelections(t) }
1074+
else t
1075+
10691076
private val id: Tree => Tree = x => x
10701077

1071-
/** Path ::= StableId
1072-
* | [id `.'] this
1073-
*
1074-
* @param thisOK If true, the path can end with the keyword `this`.
1075-
* If false, another selection is required after the `this`.
1076-
* @param finish An alternative parse in case the token following a `.' is not an identifier.
1077-
* If the alternative does not apply, its tree argument is returned unchanged.
1078+
/** SimpleRef ::= id
1079+
* | [id ‘.’] ‘this’
1080+
* | [id ‘.’] ‘super’ [ClassQualifier] ‘.’ id
10781081
*/
1079-
def path(thisOK: Boolean, finish: Tree => Tree = id): Tree = {
1082+
def simpleRef(): Tree =
10801083
val start = in.offset
1081-
def handleThis(qual: Ident) = {
1084+
1085+
def handleThis(qual: Ident) =
10821086
in.nextToken()
1083-
val t = atSpan(start) { This(qual) }
1084-
if (!thisOK && in.token != DOT) syntaxError(DanglingThisInPath(), t.span)
1085-
dotSelectors(t, finish)
1086-
}
1087-
def handleSuper(qual: Ident) = {
1087+
atSpan(start) { This(qual) }
1088+
1089+
def handleSuper(qual: Ident) =
10881090
in.nextToken()
10891091
val mix = mixinQualifierOpt()
10901092
val t = atSpan(start) { Super(This(qual), mix) }
10911093
accept(DOT)
1092-
dotSelectors(selector(t), finish)
1093-
}
1094-
if (in.token == THIS) handleThis(EmptyTypeIdent)
1095-
else if (in.token == SUPER) handleSuper(EmptyTypeIdent)
1096-
else {
1094+
idSelector(t)
1095+
1096+
if in.token == THIS then handleThis(EmptyTypeIdent)
1097+
else if in.token == SUPER then handleSuper(EmptyTypeIdent)
1098+
else
10971099
val t = termIdent()
1098-
if (in.token == DOT) {
1100+
if in.token == DOT then
10991101
def qual = cpy.Ident(t)(t.name.toTypeName)
1100-
in.nextToken()
1101-
if (in.token == THIS) handleThis(qual)
1102-
else if (in.token == SUPER) handleSuper(qual)
1103-
else selectors(t, finish)
1104-
}
1102+
in.lookahead.token match
1103+
case THIS =>
1104+
in.nextToken()
1105+
handleThis(qual)
1106+
case SUPER =>
1107+
in.nextToken()
1108+
handleSuper(qual)
1109+
case _ => t
11051110
else t
1106-
}
1107-
}
1111+
end simpleRef
11081112

11091113
/** MixinQualifier ::= `[' id `]'
11101114
*/
11111115
def mixinQualifierOpt(): Ident =
11121116
if (in.token == LBRACKET) inBrackets(atSpan(in.offset) { typeIdent() })
11131117
else EmptyTypeIdent
11141118

1115-
/** StableId ::= id
1116-
* | Path `.' id
1117-
* | [id '.'] super [`[' id `]']`.' id
1118-
*/
1119-
def stableId(): Tree =
1120-
path(thisOK = false)
1121-
11221119
/** QualId ::= id {`.' id}
11231120
*/
11241121
def qualId(): Tree = dotSelectors(termIdent())
@@ -1577,8 +1574,8 @@ object Parsers {
15771574

15781575
/** SimpleType ::= SimpleType TypeArgs
15791576
* | SimpleType `#' id
1580-
* | StableId
1581-
* | Path `.' type
1577+
* | Singleton `.' id
1578+
* | Singleton `.' type
15821579
* | `(' ArgTypes `)'
15831580
* | `_' TypeBounds
15841581
* | Refinement
@@ -1613,18 +1610,22 @@ object Parsers {
16131610
}
16141611
else if (isSplice)
16151612
splice(isType = true)
1616-
else path(thisOK = false, handleSingletonType) match {
1617-
case r @ SingletonTypeTree(_) => r
1618-
case r => convertToTypeId(r)
1619-
}
1613+
else
1614+
singletonCompletion(simpleRef())
16201615
}
16211616

1622-
val handleSingletonType: Tree => Tree = t =>
1623-
if (in.token == TYPE) {
1617+
/** Singleton ::= SimpleRef
1618+
* | Singleton ‘.’ id
1619+
*/
1620+
def singletonCompletion(t: Tree): Tree =
1621+
if in.token == DOT then
16241622
in.nextToken()
1625-
atSpan(startOffset(t)) { SingletonTypeTree(t) }
1626-
}
1627-
else t
1623+
if in.token == TYPE then
1624+
in.nextToken()
1625+
atSpan(startOffset(t)) { SingletonTypeTree(t) }
1626+
else
1627+
singletonCompletion(idSelector(t))
1628+
else convertToTypeId(t)
16281629

16291630
private def simpleTypeRest(t: Tree): Tree = in.token match {
16301631
case HASH => simpleTypeRest(typeProjection(t))
@@ -2207,7 +2208,7 @@ object Parsers {
22072208
* | SimpleExpr1 [`_`]
22082209
* SimpleExpr1 ::= literal
22092210
* | xmlLiteral
2210-
* | Path
2211+
* | SimpleRef
22112212
* | `(` [ExprsInParens] `)`
22122213
* | SimpleExpr `.` id
22132214
* | SimpleExpr `.` MatchClause
@@ -2223,9 +2224,9 @@ object Parsers {
22232224
xmlLiteral()
22242225
case IDENTIFIER =>
22252226
if (isSplice) splice(isType = false)
2226-
else path(thisOK = true)
2227+
else simpleRef()
22272228
case BACKQUOTED_IDENT | THIS | SUPER =>
2228-
path(thisOK = true)
2229+
simpleRef()
22292230
case USCORE =>
22302231
val start = in.skipToken()
22312232
val pname = WildcardParamName.fresh()
@@ -2658,17 +2659,16 @@ object Parsers {
26582659
* | XmlPattern
26592660
* | `(' [Patterns] `)'
26602661
* | SimplePattern1 [TypeArgs] [ArgumentPatterns]
2661-
* SimplePattern1 ::= Path
2662+
* SimplePattern1 ::= SimpleRef
26622663
* | SimplePattern1 `.' id
26632664
* PatVar ::= id
26642665
* | `_'
26652666
*/
26662667
val simplePattern: () => Tree = () => in.token match {
2667-
case IDENTIFIER | BACKQUOTED_IDENT | THIS =>
2668-
path(thisOK = true) match {
2668+
case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER =>
2669+
simpleRef() match
26692670
case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(startOffset(id))
26702671
case t => simplePatternRest(t)
2671-
}
26722672
case USCORE =>
26732673
val wildIdent = wildcardIdent()
26742674

@@ -2694,14 +2694,17 @@ object Parsers {
26942694
}
26952695
}
26962696

2697-
def simplePatternRest(t: Tree): Tree = {
2698-
var p = t
2699-
if (in.token == LBRACKET)
2700-
p = atSpan(startOffset(t), in.offset) { TypeApply(p, typeArgs(namedOK = false, wildOK = false)) }
2701-
if (in.token == LPAREN)
2702-
p = atSpan(startOffset(t), in.offset) { Apply(p, argumentPatterns()) }
2703-
p
2704-
}
2697+
def simplePatternRest(t: Tree): Tree =
2698+
if in.token == DOT then
2699+
in.nextToken()
2700+
simplePatternRest(idSelector(t))
2701+
else
2702+
var p = t
2703+
if (in.token == LBRACKET)
2704+
p = atSpan(startOffset(t), in.offset) { TypeApply(p, typeArgs(namedOK = false, wildOK = false)) }
2705+
if (in.token == LPAREN)
2706+
p = atSpan(startOffset(t), in.offset) { Apply(p, argumentPatterns()) }
2707+
p
27052708

27062709
/** Patterns ::= Pattern [`,' Pattern]
27072710
*/
@@ -3088,7 +3091,7 @@ object Parsers {
30883091
ctx.compilationUnit.sourceVersion = Some(SourceVersion.valueOf(imported.toString))
30893092
Import(tree, selectors)
30903093

3091-
/** ImportExpr ::= StableId ‘.’ ImportSpec
3094+
/** ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
30923095
* ImportSpec ::= id
30933096
* | ‘_’
30943097
* | ‘{’ ImportSelectors) ‘}’
@@ -3135,26 +3138,24 @@ object Parsers {
31353138
Nil
31363139
selector :: rest
31373140

3138-
val handleImport: Tree => Tree = tree =>
3141+
def importSelection(qual: Tree): Tree =
3142+
accept(DOT)
31393143
in.token match
31403144
case USCORE =>
3141-
mkTree(tree, ImportSelector(wildcardSelectorId()) :: Nil)
3145+
mkTree(qual, ImportSelector(wildcardSelectorId()) :: Nil)
31423146
case LBRACE =>
3143-
mkTree(tree, inBraces(importSelectors(idOK = true)))
3147+
mkTree(qual, inBraces(importSelectors(idOK = true)))
31443148
case _ =>
3145-
tree
3146-
3147-
() => {
3148-
val p = path(thisOK = false, handleImport)
3149-
p match
3150-
case _: Import | _: Export => p
3151-
case sel @ Select(qual, name) =>
3152-
val selector = ImportSelector(atSpan(pointOffset(sel)) { Ident(name) })
3153-
mkTree(qual, selector :: Nil).withSpan(sel.span)
3154-
case t =>
3155-
accept(DOT)
3156-
mkTree(t, ImportSelector(Ident(nme.WILDCARD)) :: Nil)
3157-
}
3149+
val start = in.offset
3150+
val name = ident()
3151+
if in.token == DOT then
3152+
importSelection(atSpan(startOffset(qual), start) { Select(qual, name) })
3153+
else
3154+
atSpan(startOffset(qual)) {
3155+
mkTree(qual, ImportSelector(atSpan(start) { Ident(name) }) :: Nil)
3156+
}
3157+
3158+
() => importSelection(simpleRef())
31583159
}
31593160

31603161
def posMods(start: Int, mods: Modifiers): Modifiers = {

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,10 @@ object Scanners {
900900
// Lookahead ---------------------------------------------------------------
901901

902902
/** The next token after this one.
903+
* The token is computed via fetchToken, so complex two word
904+
* tokens such as CASECLASS are not recognized.
903905
* Newlines and indent/unindent tokens are skipped.
906+
*
904907
*/
905908
def lookahead: TokenData =
906909
if next.token == EMPTY then

compiler/test/dotty/tools/repl/TabcompleteTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class TabcompleteTests extends ReplTest {
100100
@Test def importScala = fromInitialState { implicit s =>
101101
val comp = tabComplete("import scala.")
102102
// check that there are no special symbols leaked: <byname>, <special-ops>, ...
103-
assertEquals(comp.find(_.startsWith("<")), Some("<:<"))
103+
assertEquals(Some("<:<"), comp.find(_.startsWith("<")))
104104
assert(!comp.contains("package"))
105105
}
106106

0 commit comments

Comments
 (0)