diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-09-24 14:27:58 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2015-09-24 16:56:18 +1000 |
commit | fb299f80f3f85e935695d5b7cb7f2c712b150e3c (patch) | |
tree | 4d95bc66e8354e0eb9135aaf1fa102761fb59dff /src | |
parent | 2c9e506bc32248f9ae4929790a0cb7484a53a66e (diff) | |
download | scala-fb299f80f3f85e935695d5b7cb7f2c712b150e3c.tar.gz scala-fb299f80f3f85e935695d5b7cb7f2c712b150e3c.tar.bz2 scala-fb299f80f3f85e935695d5b7cb7f2c712b150e3c.zip |
Improve presentation compilation of annotations
A trio of problems were hampering autocompletion of annotations.
First, given that that annotation is written before the annotated
member, it is very common to end parse incomplete code that has a
floating annotation without an anotatee.
The parser was discarding the annotations (ie, the modifiers) and
emitting an `EmptyTree`.
Second, the presetation compiler was only looking for annotations
in the Modifiers of a member def, but after typechecking annotations
are moved into the symbol.
Third, if an annotation failed to typecheck, it was being discarded
in place of `ErroneousAnnotation`.
This commit:
- modifies the parser to uses a dummy class- or type-def tree,
instead of EmptyTree, which can carry the annotations.
- updates the locator to look in the symbol annotations of the
modifiers contains no annotations.
- uses a separate instance of `ErroneousAnnotation` for each
erroneous annotation, and stores the original tree in its
`original` tree.
Diffstat (limited to 'src')
5 files changed, 18 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 70abdf6bc0..4494a8ac8d 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2680,7 +2680,10 @@ self => case t if t == SUPERTYPE || t == SUBTYPE || t == COMMA || t == RBRACE || isStatSep(t) => TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds()) case _ => - syntaxErrorOrIncompleteAnd("`=', `>:', or `<:' expected", skipIt = true)(EmptyTree) + syntaxErrorOrIncompleteAnd("`=', `>:', or `<:' expected", skipIt = true)( + // assume a dummy type def so as to have somewhere to stash the annotations + TypeDef(mods, tpnme.ERROR, Nil, EmptyTree) + ) } } } @@ -2713,7 +2716,10 @@ self => case CASEOBJECT => objectDef(pos, (mods | Flags.CASE) withPosition (Flags.CASE, tokenRange(in.prev /*scanner skips on 'case' to 'object', thus take prev*/))) case _ => - syntaxErrorOrIncompleteAnd("expected start of definition", skipIt = true)(EmptyTree) + syntaxErrorOrIncompleteAnd("expected start of definition", skipIt = true)( + // assume a class definition so as to have somewhere to stash the annotations + atPos(pos)(gen.mkClassDef(mods, tpnme.ERROR, Nil, Template(Nil, noSelfType, Nil))) + ) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 8113cd9b96..6b73a538df 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3558,6 +3558,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def typedAnnotation(ann: Tree, mode: Mode = EXPRmode): AnnotationInfo = { var hasError: Boolean = false val pending = ListBuffer[AbsTypeError]() + def ErroneousAnnotation = new ErroneousAnnotation().setOriginal(ann) def finish(res: AnnotationInfo): AnnotationInfo = { if (hasError) { diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 6863cdfd82..b923541b56 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -404,7 +404,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil) - object ErroneousAnnotation extends CompleteAnnotationInfo(ErrorType, Nil, Nil) + class ErroneousAnnotation() extends CompleteAnnotationInfo(ErrorType, Nil, Nil) /** Extracts symbol of thrown exception from AnnotationInfo. * diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala index 4d0e31b037..15d68bcdfe 100644 --- a/src/reflect/scala/reflect/internal/Positions.scala +++ b/src/reflect/scala/reflect/internal/Positions.scala @@ -252,7 +252,14 @@ trait Positions extends api.Positions { self: SymbolTable => super.traverse(t) } else t match { case mdef: MemberDef => - traverseTrees(mdef.mods.annotations) + val annTrees = mdef.mods.annotations match { + case Nil if mdef.symbol != null => + // After typechecking, annotations are mvoed from the modifiers + // to the annotation on the symbol of the anotatee. + mdef.symbol.annotations.map(_.original) + case anns => anns + } + traverseTrees(annTrees) case _ => } } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 5477bdd6d4..7725e4a2f0 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -106,7 +106,6 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.AnnotationInfo this.Annotation this.UnmappableAnnotation - this.ErroneousAnnotation this.ThrownException this.typeNames this.tpnme |