Skip to content

Commit fe53185

Browse files
committed
Merge pull request scala#4766 from retronym/topic/completely-tweaks
Improvements to REPL completion for annotations and string interpolation
2 parents a6c1687 + fb299f8 commit fe53185

File tree

7 files changed

+38
-6
lines changed

7 files changed

+38
-6
lines changed

src/compiler/scala/tools/nsc/ast/parser/Parsers.scala

+8-2
Original file line numberDiff line numberDiff line change
@@ -2680,7 +2680,10 @@ self =>
26802680
case t if t == SUPERTYPE || t == SUBTYPE || t == COMMA || t == RBRACE || isStatSep(t) =>
26812681
TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds())
26822682
case _ =>
2683-
syntaxErrorOrIncompleteAnd("`=', `>:', or `<:' expected", skipIt = true)(EmptyTree)
2683+
syntaxErrorOrIncompleteAnd("`=', `>:', or `<:' expected", skipIt = true)(
2684+
// assume a dummy type def so as to have somewhere to stash the annotations
2685+
TypeDef(mods, tpnme.ERROR, Nil, EmptyTree)
2686+
)
26842687
}
26852688
}
26862689
}
@@ -2713,7 +2716,10 @@ self =>
27132716
case CASEOBJECT =>
27142717
objectDef(pos, (mods | Flags.CASE) withPosition (Flags.CASE, tokenRange(in.prev /*scanner skips on 'case' to 'object', thus take prev*/)))
27152718
case _ =>
2716-
syntaxErrorOrIncompleteAnd("expected start of definition", skipIt = true)(EmptyTree)
2719+
syntaxErrorOrIncompleteAnd("expected start of definition", skipIt = true)(
2720+
// assume a class definition so as to have somewhere to stash the annotations
2721+
atPos(pos)(gen.mkClassDef(mods, tpnme.ERROR, Nil, Template(Nil, noSelfType, Nil)))
2722+
)
27172723
}
27182724
}
27192725

src/compiler/scala/tools/nsc/typechecker/Typers.scala

+1
Original file line numberDiff line numberDiff line change
@@ -3558,6 +3558,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
35583558
def typedAnnotation(ann: Tree, mode: Mode = EXPRmode): AnnotationInfo = {
35593559
var hasError: Boolean = false
35603560
val pending = ListBuffer[AbsTypeError]()
3561+
def ErroneousAnnotation = new ErroneousAnnotation().setOriginal(ann)
35613562

35623563
def finish(res: AnnotationInfo): AnnotationInfo = {
35633564
if (hasError) {

src/reflect/scala/reflect/internal/AnnotationInfos.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
404404

405405
object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil)
406406

407-
object ErroneousAnnotation extends CompleteAnnotationInfo(ErrorType, Nil, Nil)
407+
class ErroneousAnnotation() extends CompleteAnnotationInfo(ErrorType, Nil, Nil)
408408

409409
/** Extracts symbol of thrown exception from AnnotationInfo.
410410
*

src/reflect/scala/reflect/internal/Positions.scala

+8-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,14 @@ trait Positions extends api.Positions { self: SymbolTable =>
252252
super.traverse(t)
253253
} else t match {
254254
case mdef: MemberDef =>
255-
traverseTrees(mdef.mods.annotations)
255+
val annTrees = mdef.mods.annotations match {
256+
case Nil if mdef.symbol != null =>
257+
// After typechecking, annotations are mvoed from the modifiers
258+
// to the annotation on the symbol of the anotatee.
259+
mdef.symbol.annotations.map(_.original)
260+
case anns => anns
261+
}
262+
traverseTrees(annTrees)
256263
case _ =>
257264
}
258265
}

src/reflect/scala/reflect/runtime/JavaUniverseForce.scala

-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
106106
this.AnnotationInfo
107107
this.Annotation
108108
this.UnmappableAnnotation
109-
this.ErroneousAnnotation
110109
this.ThrownException
111110
this.typeNames
112111
this.tpnme

src/repl/scala/tools/nsc/interpreter/PresentationCompilerCompleter.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class PresentationCompilerCompleter(intp: IMain) extends Completion with ScalaCo
3636
// secret handshakes
3737
val slashPrint = """.*// *print *""".r
3838
val slashTypeAt = """.*// *typeAt *(\d+) *(\d+) *""".r
39-
val Cursor = IMain.DummyCursorFragment
39+
val Cursor = IMain.DummyCursorFragment + " "
4040

4141
def print(result: Result) = {
4242
val offset = result.preambleLength

test/junit/scala/tools/nsc/interpreter/CompletionTest.scala

+19
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,25 @@ class CompletionTest {
5151
assertEquals(List("prefix_aaa", "prefix_nnn", "prefix_zzz"), completer.complete( """class C { def prefix_nnn = 0; def prefix_zzz = 0; def prefix_aaa = 0; prefix_""").candidates)
5252
}
5353

54+
@Test
55+
def annotations(): Unit = {
56+
val intp = newIMain()
57+
val completer = new PresentationCompilerCompleter(intp)
58+
checkExact(completer, "def foo[@specialize", " A]")("specialized")
59+
checkExact(completer, "def foo[@specialize")("specialized")
60+
checkExact(completer, """@deprecatedN""", """ class Foo""")("deprecatedName")
61+
checkExact(completer, """@deprecateN""")("deprecatedName")
62+
checkExact(completer, """{@deprecateN""")("deprecatedName")
63+
}
64+
65+
@Test
66+
def incompleteStringInterpolation(): Unit = {
67+
val intp = newIMain()
68+
val completer = new PresentationCompilerCompleter(intp)
69+
checkExact(completer, """val x_y_z = 1; s"${x_""", "}\"")("x_y_z")
70+
checkExact(completer, """val x_y_z = 1; s"${x_""", "\"")("x_y_z")
71+
}
72+
5473
@Test
5574
def symbolically(): Unit = {
5675
val intp = newIMain()

0 commit comments

Comments
 (0)