src/share/classes/com/sun/tools/javac/comp/Annotate.java

Print this page

        

@@ -27,16 +27,18 @@
 
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+import javax.lang.model.type.TypeKind;
 import javax.tools.JavaFileObject;
 
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.TypeAnnotationPosition.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.tree.JCTree.*;
 
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.TypeTag.ARRAY;

@@ -263,34 +265,32 @@
      *  Attribute. Used from MemberEnter for attaching the attributes
      *  to the annotated symbol.
      */
     Attribute.Compound enterAnnotation(JCAnnotation a,
                                        Type expected,
-                                       Env<AttrContext> env) {
-        List<Pair<MethodSymbol,Attribute>> elems =
-            enterAttributeValues(a, expected, env);
-        Attribute.Compound ac = new Attribute.Compound(a.type, elems);
+                                       Env<AttrContext> env,
+                                       TypeAnnotationPosition position) {
+        List<Pair<MethodSymbol,Attribute>> buf =
+            enterAttributeValues(a, expected, env, position);
+        Attribute.Compound ac =
+            new Attribute.Compound(a.type, buf, position);
         a.attribute = ac;
 
         return ac;
     }
 
     Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a,
                                                Type expected,
-                                               Env<AttrContext> env) {
-        List<Pair<MethodSymbol,Attribute>> elems =
-            enterAttributeValues(a, expected, env);
+                                               Env<AttrContext> env,
+                                               TypeAnnotationPosition position) {
+        List<Pair<MethodSymbol,Attribute>> buf =
+            enterAttributeValues(a, expected, env, position);
 
         if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) {
             // Create a new TypeCompound
-
             Attribute.TypeCompound tc =
-                new Attribute.TypeCompound(a.type, elems,
-                // TODO: Eventually, we will get rid of this use of
-                // unknown, because we'll get a position from
-                // MemberEnter (task 8027262).
-                                           TypeAnnotationPosition.unknown);
+                new Attribute.TypeCompound(a.type, buf, position);
             a.attribute = tc;
             return tc;
         } else {
             // Use an existing TypeCompound
             return (Attribute.TypeCompound)a.attribute;

@@ -298,11 +298,12 @@
     }
 
     private List<Pair<MethodSymbol,Attribute>>
             enterAttributeValues(JCAnnotation a,
                                  Type expected,
-                                 Env<AttrContext> env) {
+                                 Env<AttrContext> env,
+                                 TypeAnnotationPosition position) {
         // The annotation might have had its type attributed (but not
         // checked) by attr.attribAnnotationTypes during MemberEnter,
         // in which case we do not need to do it again.
         Type at = (a.annotationType.type != null ? a.annotationType.type
                   : attr.attribType(a.annotationType, env));

@@ -323,17 +324,17 @@
             new ListBuffer<>();
         for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
             JCExpression t = tl.head;
             if (!t.hasTag(ASSIGN)) {
                 log.error(t.pos(), "annotation.value.must.be.name.value");
-                enterAttributeValue(t.type = syms.errType, t, env);
+                enterAttributeValue(t.type = syms.errType, t, env, position);
                 continue;
             }
             JCAssign assign = (JCAssign)t;
             if (!assign.lhs.hasTag(IDENT)) {
                 log.error(t.pos(), "annotation.value.must.be.name.value");
-                enterAttributeValue(t.type = syms.errType, t, env);
+                enterAttributeValue(t.type = syms.errType, t, env, position);
                 continue;
             }
             JCIdent left = (JCIdent)assign.lhs;
             Symbol method = rs.resolveQualifiedMethod(assign.rhs.pos(),
                                                           env,

@@ -344,21 +345,22 @@
             left.sym = method;
             left.type = method.type;
             if (method.owner != a.type.tsym && !isError)
                 log.error(left.pos(), "no.annotation.member", left.name, a.type);
             Type result = method.type.getReturnType();
-            Attribute value = enterAttributeValue(result, assign.rhs, env);
+            Attribute value = enterAttributeValue(result, assign.rhs, env, position);
             if (!method.type.isErroneous())
                 buf.append(new Pair<>((MethodSymbol)method, value));
             t.type = result;
         }
         return buf.toList();
     }
 
     Attribute enterAttributeValue(Type expected,
                                   JCExpression tree,
-                                  Env<AttrContext> env) {
+                                  Env<AttrContext> env,
+                                  TypeAnnotationPosition position) {
         //first, try completing the attribution value sym - if a completion
         //error is thrown, we should recover gracefully, and display an
         //ordinary resolution diagnostic.
         try {
             expected.tsym.complete();

@@ -376,12 +378,11 @@
                 log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
             }
             ListBuffer<Attribute> buf = new ListBuffer<>();
             for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
                 buf.append(enterAttributeValue(types.elemtype(expected),
-                                               l.head,
-                                               env));
+                                               l.head, env, position));
             }
             na.type = expected;
             return new Attribute.
                 Array(expected, buf.toArray(new Attribute[buf.length()]));
         }

@@ -391,28 +392,26 @@
             JCNewArray na = (JCNewArray)tree;
             if (na.elemtype != null) {
                 log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
             }
             for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
-                enterAttributeValue(syms.errType,
-                                    l.head,
-                                    env);
+                enterAttributeValue(syms.errType, l.head, env, position);
             }
             return new Attribute.Error(syms.errType);
         }
         if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
             if (tree.hasTag(ANNOTATION)) {
-                return enterAnnotation((JCAnnotation)tree, expected, env);
+                return enterAnnotation((JCAnnotation)tree, expected, env, position);
             } else {
                 log.error(tree.pos(), "annotation.value.must.be.annotation");
                 expected = syms.errType;
             }
         }
         if (tree.hasTag(ANNOTATION)) { //error recovery
             if (!expected.isErroneous())
                 log.error(tree.pos(), "annotation.not.valid.for.type", expected);
-            enterAnnotation((JCAnnotation)tree, syms.errType, env);
+            enterAnnotation((JCAnnotation)tree, syms.errType, env, position);
             return new Attribute.Error(((JCAnnotation)tree).annotationType.type);
         }
         if (expected.isPrimitive() ||
             (types.isSameType(expected, syms.stringType) && !expected.hasTag(TypeTag.ERROR))) {
             Type result = attr.attribExpr(tree, env, expected);

@@ -477,11 +476,12 @@
      * synthesized container annotation or null IFF all repeating
      * annotation are invalid.  This method reports errors/warnings.
      */
     private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
             AnnotationContext<T> ctx,
-            Symbol on) {
+            Symbol on,
+            TypeAnnotationPosition position) {
         T firstOccurrence = annotations.head;
         List<Attribute> repeated = List.nil();
         Type origAnnoType = null;
         Type arrayOfOrigAnnoType = null;
         Type targetContainerType = null;

@@ -489,16 +489,12 @@
 
         Assert.check(!annotations.isEmpty() &&
                      !annotations.tail.isEmpty()); // i.e. size() > 1
 
         int count = 0;
-        for (List<T> al = annotations;
-             !al.isEmpty();
-             al = al.tail)
-        {
+        for (List<T> al = annotations; !al.isEmpty(); al = al.tail) {
             count++;
-
             // There must be more than a single anno in the annotation list
             Assert.check(count > 1 || !al.tail.isEmpty());
 
             T currentAnno = al.head;
 

@@ -534,39 +530,29 @@
             TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
             Pair<MethodSymbol, Attribute> p =
                     new Pair<MethodSymbol, Attribute>(containerValueSymbol,
                                new Attribute.Array(arrayOfOrigAnnoType, repeated));
             if (ctx.isTypeCompound) {
-                /* TODO: the following code would be cleaner:
-                Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
-                        ((Attribute.TypeCompound)annotations.head).position);
-                JCTypeAnnotation annoTree = m.TypeAnnotation(at);
-                at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env);
-                */
-                // However, we directly construct the TypeCompound to keep the
-                // direct relation to the contained TypeCompounds.
-                Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
-                        ((Attribute.TypeCompound)annotations.head).position);
-
-                // TODO: annotation applicability checks from below?
-
+                Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p), position);
                 at.setSynthesized(true);
 
                 @SuppressWarnings("unchecked")
                 T x = (T) at;
                 return x;
             } else {
-                Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p));
+                Attribute.Compound c = new Attribute.Compound(targetContainerType,
+                                                              List.of(p),
+                                                              position);
                 JCAnnotation annoTree = m.Annotation(c);
 
                 if (!chk.annotationApplicable(annoTree, on))
                     log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType);
 
                 if (!chk.validateAnnotationDeferErrors(annoTree))
                     log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType);
 
-                c = enterAnnotation(annoTree, targetContainerType, ctx.env);
+                c = enterAnnotation(annoTree, targetContainerType, ctx.env, position);
                 c.setSynthesized(true);
 
                 @SuppressWarnings("unchecked")
                 T x = (T) c;
                 return x;

@@ -574,10 +560,11 @@
         } else {
             return null; // errors should have been reported elsewhere
         }
     }
 
+
     /** Fetches the actual Type that should be the containing annotation. */
     private Type getContainingType(Attribute.Compound currentAnno,
             DiagnosticPosition pos,
             boolean reportError)
     {

@@ -708,17 +695,18 @@
     private <T extends Attribute.Compound> AnnotationContext<T>
             prepareEnterAnnotations(List<JCAnnotation> annotations,
                                     Env<AttrContext> env,
                                     Symbol sym,
                                     AttributeCreator<T> creator,
-                                    boolean isTypeCompound) {
+                                    boolean isTypeCompound,
+                                    TypeAnnotationPosition position) {
         Map<TypeSymbol, ListBuffer<T>> annotated = new LinkedHashMap<>();
         Map<T, DiagnosticPosition> pos = new HashMap<>();
 
         for (List<JCAnnotation> al = annotations; !al.isEmpty(); al = al.tail) {
             JCAnnotation a = al.head;
-            T c = creator.create(a, syms.annotationType, env);
+            T c = creator.create(a, syms.annotationType, env, position);
 
             Assert.checkNonNull(c, "Failed to create annotation");
 
             if (annotated.containsKey(a.type.tsym)) {
                 if (!allowRepeatedAnnos) {

@@ -752,14 +740,16 @@
     private <T extends Attribute.Compound>
             void attachAttributesLater(final List<JCAnnotation> annotations,
                                        final Env<AttrContext> env,
                                        final Symbol sym,
                                        final boolean isTypeCompound,
+                                       final TypeAnnotationPosition position,
                                        final AttributeCreator<T> creator,
                                        final AttributeAttacher<T> attacher) {
         final AnnotationContext<T> ctx =
-            prepareEnterAnnotations(annotations, env, sym, creator, isTypeCompound);
+            prepareEnterAnnotations(annotations, env, sym, creator,
+                                    isTypeCompound, position);
         final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated =
             ctx.annotated;
         boolean hasRepeated = false;
 
         List<T> buf = List.<T>nil();

@@ -779,13 +769,28 @@
         if (!isTypeCompound) {
             // Attach declaration attributes early, so
             // that @Repeatable and other annotations get attached.
             // Since the attacher uses setDeclarationAttributes, this
             // will be overwritten later.
-            attacher.attach(sym, attrs);
+            @SuppressWarnings("unchecked")
+            List<Attribute.Compound> tempattrs = (List<Attribute.Compound>) attrs;
+            sym.setDeclarationAttributes(tempattrs);
         }
+
         if (hasRepeated) {
+            replacePlaceholdersAndAttach(attrs, ctx, env, sym, attacher);
+        } else {
+            attachAttributesAfterRepeated(attrs, env, attacher);
+        }
+    }
+
+    private <T extends Attribute.Compound>
+            void replacePlaceholdersAndAttach(final List<T> attrs,
+                                              final AnnotationContext<T> ctx,
+                                              final Env<AttrContext> env,
+                                              final Symbol sym,
+                                              final AttributeAttacher<T> attacher) {
             repeated(new Annotate.Worker() {
                     @Override
                     public String toString() {
                         return "repeated annotation pass of: " + sym + " in: " + sym.owner;
                     }

@@ -793,41 +798,278 @@
                     @Override
                     public void run() {
                         JavaFileObject oldSource =
                             log.useSource(env.toplevel.sourcefile);
                         try {
-                            attacher.attach(sym, replacePlaceholders(attrs, ctx, sym));
+                        final List<T> replaced =
+                            replacePlaceholders(attrs, ctx, sym);
+                        attachAttributesAfterRepeated(replaced, env, attacher);
                         } finally {
                             log.useSource(oldSource);
                         }
                     }
                 });
+    }
+
+    private <T extends Attribute.Compound>
+            void attachAttributesAfterRepeated(final List<T> attrs,
+                                               final Env<AttrContext> env,
+                                               final AttributeAttacher<T> attacher) {
+        afterRepeated(new Worker() {
+                @Override
+                public String toString() {
+                    return "attach pass for: " + attrs;
+                }
+
+                @Override
+                public void run() {
+                    JavaFileObject oldSource =
+                        log.useSource(env.toplevel.sourcefile);
+                    try {
+                        attacher.attach(attrs);
+                    } finally {
+                        log.useSource(oldSource);
+                    }
+                }
+            });
+    }
+
+    public interface AttributeAttacher<T extends Attribute.Compound> {
+        public void attach(List<T> attrs);
+    }
+
+    public interface Reporter<T extends Attribute.Compound> {
+        public void report(List<T> attrs);
+    }
+
+    public enum AnnotationType { DECLARATION, TYPE, BOTH }
+
+    /**
+     * Determine whether an annotation is a declaration annotation,
+     * a type annotation, or both.
+     */
+    public AnnotationType annotationType(Attribute.Compound a, Symbol s) {
+        Attribute.Compound atTarget =
+            a.type.tsym.attribute(syms.annotationTargetType.tsym);
+        if (atTarget == null) {
+            return inferTargetMetaInfo(a, s);
+        }
+        Attribute atValue = atTarget.member(names.value);
+        if (!(atValue instanceof Attribute.Array)) {
+            Assert.error("annotationType(): bad @Target argument " + atValue +
+                    " (" + atValue.getClass() + ")");
+            return AnnotationType.DECLARATION; // error recovery
+        }
+        Attribute.Array arr = (Attribute.Array) atValue;
+        boolean isDecl = false, isType = false;
+        for (Attribute app : arr.values) {
+            if (!(app instanceof Attribute.Enum)) {
+                Assert.error("annotationType(): unrecognized Attribute kind " + app +
+                        " (" + app.getClass() + ")");
+                isDecl = true;
+                continue;
+            }
+            Attribute.Enum e = (Attribute.Enum) app;
+            if (e.value.name == names.TYPE) {
+                if (s.kind == Kinds.TYP)
+                    isDecl = true;
+            } else if (e.value.name == names.FIELD) {
+                if (s.kind == Kinds.VAR &&
+                        s.owner.kind != Kinds.MTH)
+                    isDecl = true;
+            } else if (e.value.name == names.METHOD) {
+                if (s.kind == Kinds.MTH &&
+                        !s.isConstructor())
+                    isDecl = true;
+            } else if (e.value.name == names.PARAMETER) {
+                if (s.kind == Kinds.VAR &&
+                        s.owner.kind == Kinds.MTH &&
+                        (s.flags() & Flags.PARAMETER) != 0)
+                    isDecl = true;
+            } else if (e.value.name == names.CONSTRUCTOR) {
+                if (s.kind == Kinds.MTH &&
+                        s.isConstructor())
+                    isDecl = true;
+            } else if (e.value.name == names.LOCAL_VARIABLE) {
+                if (s.kind == Kinds.VAR &&
+                        s.owner.kind == Kinds.MTH &&
+                        (s.flags() & Flags.PARAMETER) == 0)
+                    isDecl = true;
+            } else if (e.value.name == names.ANNOTATION_TYPE) {
+                if (s.kind == Kinds.TYP &&
+                        (s.flags() & Flags.ANNOTATION) != 0)
+                    isDecl = true;
+            } else if (e.value.name == names.PACKAGE) {
+                if (s.kind == Kinds.PCK)
+                    isDecl = true;
+            } else if (e.value.name == names.TYPE_USE) {
+                if (s.kind == Kinds.TYP ||
+                    s.kind == Kinds.VAR ||
+                    (s.kind == Kinds.MTH && !s.isConstructor() &&
+                     !s.type.getReturnType().hasTag(TypeTag.VOID)) ||
+                    (s.kind == Kinds.MTH && s.isConstructor()))
+                    isType = true;
+            } else if (e.value.name == names.TYPE_PARAMETER) {
+                /* Irrelevant in this case */
+                // TYPE_PARAMETER doesn't aid in distinguishing between
+                // Type annotations and declaration annotations on an
+                // Element
+            } else {
+                Assert.error("annotationType(): unrecognized Attribute name " + e.value.name +
+                        " (" + e.value.name.getClass() + ")");
+                isDecl = true;
+            }
+        }
+        if (isDecl && isType) {
+            return AnnotationType.BOTH;
+        } else if (isType) {
+            return AnnotationType.TYPE;
         } else {
-            attacher.attach(sym, attrs);
+            return AnnotationType.DECLARATION;
         }
     }
 
-    private interface AttributeAttacher<T extends Attribute.Compound> {
-        public void attach(Symbol sym, List<T> attrs);
+    private Attribute.TypeCompound toTypeCompound(Attribute.Compound a) {
+        // It is safe to alias the position.
+        return new Attribute.TypeCompound(a, a.position);
     }
 
-    private final AttributeAttacher<Attribute.Compound> declAnnotationsAttacher =
-        new AttributeAttacher<Attribute.Compound>() {
+    /** Infer the target annotation kind, if none is given.
+     * We only infer declaration annotations.
+     */
+    private static AnnotationType inferTargetMetaInfo(Attribute.Compound a, Symbol s) {
+        return AnnotationType.DECLARATION;
+    }
+
+    private AttributeAttacher<Attribute.Compound>
+            declAnnotationsAttacher(final Symbol sym) {
+        return new AttributeAttacher<Attribute.Compound>() {
             @Override
-            public void attach(Symbol sym, List<Attribute.Compound> attrs) {
+            public void attach(List<Attribute.Compound> attrs) {
                 sym.resetAnnotations();
                 sym.setDeclarationAttributes(attrs);
             }
         };
+    }
 
-    private final AttributeAttacher<Attribute.TypeCompound> typeAnnotationsAttacher =
-        new AttributeAttacher<Attribute.TypeCompound>() {
+    private AttributeAttacher<Attribute.TypeCompound>
+            typeAnnotationsAttacher(final Symbol sym) {
+        return new AttributeAttacher<Attribute.TypeCompound>() {
             @Override
-            public void attach(Symbol sym, List<Attribute.TypeCompound> attrs) {
-                sym.appendUniqueTypeAttributes(attrs);
+            public void attach(List<Attribute.TypeCompound> attrs) {
+                if (!attrs.isEmpty()) {
+                    attachTypeAnnotations(sym, attrs);
+                }
             }
         };
+    }
+
+    private void reportIllegalScoping(List<Attribute.TypeCompound> attrs,
+                                      int pos) {
+        switch (attrs.size()) {
+        case 0:
+            // Don't issue an error if all type annotations are
+            // also declaration annotations.
+            // If the annotations are also declaration annotations, they are
+            // illegal as type annotations but might be legal as declaration annotations.
+            // The normal declaration annotation checks make sure that the use is valid.
+            break;
+        case 1:
+            //System.err.println("Reporting illegal scoping");
+            log.error(pos, "cant.type.annotate.scoping.1", attrs);
+            break;
+        default:
+            //System.err.println("Reporting illegal scoping");
+            log.error(pos, "cant.type.annotate.scoping", attrs);
+        }
+    }
+
+    private Reporter<Attribute.TypeCompound>
+            illegalScopingReporter(final int pos) {
+        return new Reporter<Attribute.TypeCompound>() {
+            @Override
+            public void report(List<Attribute.TypeCompound> attrs) {
+                reportIllegalScoping(attrs, pos);
+            }
+        };
+    }
+
+    private AttributeAttacher<Attribute.Compound>
+            classifyingAttacher(final Symbol sym) {
+        return classifyingAttacher(sym, declAnnotationsAttacher(sym),
+                                   typeAnnotationsAttacher(sym),
+                                   null);
+    }
+
+
+    private AttributeAttacher<Attribute.Compound>
+            classifyingAttacher(final Symbol sym,
+                                final AttributeAttacher<Attribute.Compound> declAttacher,
+                                final AttributeAttacher<Attribute.TypeCompound> typeAttacher,
+                                final Reporter<Attribute.TypeCompound> reporter) {
+        return new AttributeAttacher<Attribute.Compound>() {
+            @Override
+            public void attach(List<Attribute.Compound> attrs) {
+                ListBuffer<Attribute.Compound> declAnnos = new ListBuffer<>();
+                ListBuffer<Attribute.TypeCompound> typeAnnos = new ListBuffer<>();
+                ListBuffer<Attribute.TypeCompound> onlyTypeAnnos = new ListBuffer<>();
+
+                for (Attribute.Compound a : attrs) {
+                    Assert.check(!(a instanceof Placeholder),
+                                 "Placeholders found in annotations being attached!");
+                    switch (annotationType(a, sym)) {
+                    case DECLARATION:
+                        declAnnos.append(a);
+                        break;
+                    case BOTH: {
+                        declAnnos.append(a);
+                        Attribute.TypeCompound ta = toTypeCompound(a);
+                        Assert.checkNonNull(ta.position);
+                        typeAnnos.append(ta);
+                        break;
+                    }
+                    case TYPE: {
+                        Attribute.TypeCompound ta = toTypeCompound(a);
+                        Assert.checkNonNull(ta.position);
+                        typeAnnos.append(ta);
+                        // Also keep track which annotations are only type annotations
+                        onlyTypeAnnos.append(ta);
+                        break;
+                    }
+                    default:
+                        throw new AssertionError("Unknown annotation type");
+                    }
+                }
+
+                if (declAttacher != null)
+                    declAttacher.attach(declAnnos.toList());
+
+                if (typeAttacher != null)
+                    typeAttacher.attach(typeAnnos.toList());
+
+                if (reporter != null)
+                    reporter.report(onlyTypeAnnos.toList());
+            }
+        };
+    }
+
+    public void attachTypeAnnotations(Symbol sym, List<Attribute.TypeCompound> attrs) {
+        sym.appendUniqueTypeAttributes(attrs);
+
+        // For type annotations on variables in methods, make
+        // sure they are attached to the owner too.
+        switch(sym.getKind()) {
+        case PARAMETER:
+        case LOCAL_VARIABLE:
+        case RESOURCE_VARIABLE:
+        case EXCEPTION_PARAMETER:
+            // Make sure all type annotations from the symbol are also
+            // on the owner.
+            sym.owner.appendUniqueTypeAttributes(attrs);
+            break;
+        }
+    }
 
     private <T extends Attribute.Compound> List<T>
             replacePlaceholders(List<T> buf,
                                 Annotate.AnnotationContext<T> ctx,
                                 Symbol sym) {

@@ -852,11 +1094,11 @@
                                                         Annotate.AnnotationContext<T> ctx,
                                                         Symbol sym) {
         // Process repeated annotations
         T validRepeated =
             processRepeatedAnnotations(placeholder.getPlaceholderFor(),
-                                       ctx, sym);
+                                       ctx, sym, placeholder.position);
 
         if (validRepeated != null) {
             // Check that the container isn't manually
             // present along with repeated instances of
             // its contained annotation.

@@ -873,15 +1115,39 @@
 
 /* ********************************************************************
  * Annotation processing
  *********************************************************************/
 
-    /** Queue annotations for later processing. */
+    void annotateLater(final List<JCAnnotation> annotations,
+                       final Env<AttrContext> localEnv,
+                       final Symbol s) {
+        annotateLater(annotations, localEnv, s, null);
+    }
+
     void annotateLater(final List<JCAnnotation> annotations,
                        final Env<AttrContext> localEnv,
                        final Symbol s,
                        final DiagnosticPosition deferPos) {
+        annotateLater(annotations, localEnv, s, deferPos, null,
+                      declAnnotationsAttacher(s));
+    }
+
+    void annotateLater(final List<JCAnnotation> annotations,
+                       final Env<AttrContext> localEnv,
+                       final Symbol s,
+                       final DiagnosticPosition deferPos,
+                       final TypeAnnotationPosition tapos) {
+        annotateLater(annotations, localEnv, s, deferPos, tapos,
+                      classifyingAttacher(s));
+    }
+
+    void annotateLater(final List<JCAnnotation> annotations,
+                       final Env<AttrContext> localEnv,
+                       final Symbol s,
+                       final DiagnosticPosition deferPos,
+                       final TypeAnnotationPosition tapos,
+                       final AttributeAttacher<Attribute.Compound> attacher) {
         if (annotations.isEmpty()) {
             return;
         }
         if (s.kind != PCK) {
             s.resetAnnotations(); // mark Annotations as incomplete for now

@@ -892,189 +1158,792 @@
                     return "annotate " + annotations + " onto " + s + " in " + s.owner;
                 }
 
                 @Override
                 public void run() {
+                    annotateNow(annotations, localEnv, s, deferPos,
+                                tapos, attacher);
+                }
+            });
+
+        validate(annotationValidator(annotations, localEnv, s));
+    }
+
+    private void annotateNow(final List<JCAnnotation> annotations,
+                             final Env<AttrContext> localEnv,
+                             final Symbol s,
+                             final DiagnosticPosition deferPos,
+                             final TypeAnnotationPosition position,
+                             final AttributeAttacher<Attribute.Compound> attacher) {
+        if (annotations.isEmpty()) {
+            return;
+        }
                     Assert.check(s.kind == PCK || s.annotationsPendingCompletion());
                     JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
-                    DiagnosticPosition prevLintPos =
-                        deferPos != null
-                        ? deferredLintHandler.setPos(deferPos)
-                        : deferredLintHandler.immediate();
+        DiagnosticPosition prevLintPos = deferPos != null ?
+            deferredLintHandler.setPos(deferPos) :
+            deferredLintHandler.immediate();
                     Lint prevLint = deferPos != null ? null : chk.setLint(lint);
                     try {
                         if (s.hasAnnotations() &&
                             annotations.nonEmpty())
                             log.error(annotations.head.pos,
                                       "already.annotated",
                                       kindName(s), s);
-                        actualEnterAnnotations(annotations, localEnv, s);
+            actualEnterAnnotations(annotations, localEnv, s, position, attacher);
                     } finally {
                         if (prevLint != null)
                             chk.setLint(prevLint);
                         deferredLintHandler.setPos(prevLintPos);
                         log.useSource(prev);
                     }
                 }
-            });
 
-        validate(new Annotate.Worker() { //validate annotations
+    private Annotate.Worker annotationValidator(final List<JCAnnotation> annotations,
+                                                final Env<AttrContext> localEnv,
+                                                final Symbol s) {
+        return new Annotate.Worker() { //validate annotations
             @Override
             public void run() {
                 JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
                 try {
                     chk.validateAnnotations(annotations, s);
                 } finally {
                     log.useSource(prev);
                 }
             }
-        });
+        };
+    }
+
+    private Annotate.Worker typeAnnotationValidator(final List<JCAnnotation> annotations,
+                                                    final Env<AttrContext> localEnv,
+                                                    final boolean isTypeParameter) {
+        return new Annotate.Worker() { //validate annotations
+            @Override
+            public void run() {
+                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
+                try {
+                    chk.validateTypeAnnotations(annotations, isTypeParameter);
+                } finally {
+                    log.useSource(prev);
+                }
+            }
+        };
     }
 
     private interface AttributeCreator<T extends Attribute.Compound> {
-        public T create(JCAnnotation a, Type expected, Env<AttrContext> env);
+        public T create(JCAnnotation a,
+                        Type expected,
+                        Env<AttrContext> env,
+                        TypeAnnotationPosition position);
     }
 
     // TODO: When SE8 features can be used, these can go away and be
     // replaced by method refs.
     private final AttributeCreator<Attribute.Compound> enterAnnotationsCreator =
         new AttributeCreator<Attribute.Compound>() {
         @Override
         public Attribute.Compound create(JCAnnotation a,
                                          Type expected,
-                                         Env<AttrContext> env) {
-            return enterAnnotation(a, syms.annotationType, env);
+                                         Env<AttrContext> env,
+                                         TypeAnnotationPosition position) {
+            return enterAnnotation(a, syms.annotationType, env, position);
         }
     };
     private final AttributeCreator<Attribute.TypeCompound> enterTypeAnnotationsCreator =
         new AttributeCreator<Attribute.TypeCompound>() {
         @Override
         public Attribute.TypeCompound create(JCAnnotation a,
                                              Type expected,
-                                             Env<AttrContext> env) {
-            return enterTypeAnnotation(a, syms.annotationType, env);
+                                             Env<AttrContext> env,
+                                             TypeAnnotationPosition position) {
+            return enterTypeAnnotation(a, syms.annotationType, env, position);
         }
     };
 
     /** Enter a set of annotations. */
     private void actualEnterAnnotations(List<JCAnnotation> annotations,
                                         Env<AttrContext> env,
-                                        Symbol s) {
-        Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null");
-        attachAttributesLater(annotations, env, s, false,
-                              enterAnnotationsCreator,
-                              declAnnotationsAttacher);
+                                        Symbol s,
+                                        TypeAnnotationPosition position,
+                                        AttributeAttacher<Attribute.Compound> attacher) {
+        Assert.checkNonNull(s);
+        attachAttributesLater(annotations, env, s, false, position,
+                              enterAnnotationsCreator, attacher);
     }
 
     /*
      * If the symbol is non-null, attach the type annotation to it.
      */
     private void actualEnterTypeAnnotations(final List<JCAnnotation> annotations,
                                             final Env<AttrContext> env,
                                             final Symbol s,
-                                            final DiagnosticPosition deferPos) {
-        Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/");
+                                            final DiagnosticPosition deferPos,
+                                            final TypeAnnotationPosition position,
+                                            final AttributeAttacher<Attribute.TypeCompound> attacher) {
+        Assert.checkNonNull(s);
         JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
         DiagnosticPosition prevLintPos = null;
 
         if (deferPos != null) {
             prevLintPos = deferredLintHandler.setPos(deferPos);
         }
         try {
-            attachAttributesLater(annotations, env, s, true,
-                                  enterTypeAnnotationsCreator,
-                                  typeAnnotationsAttacher);
+            attachAttributesLater(annotations, env, s, true, position,
+                                  enterTypeAnnotationsCreator, attacher);
         } finally {
             if (prevLintPos != null)
                 deferredLintHandler.setPos(prevLintPos);
             log.useSource(prev);
         }
     }
 
     public void annotateTypeLater(final JCTree tree,
                                   final Env<AttrContext> env,
                                   final Symbol sym,
-                                  final DiagnosticPosition deferPos) {
+                                  final DiagnosticPosition deferPos,
+                                  final JCLambda currentLambda,
+                                  final PositionCreator creator,
+                                  final boolean speculative) {
+        annotateTypeLater(tree, List.<JCAnnotation>nil(), env, sym,
+                          deferPos, currentLambda, creator, speculative);
+    }
+
+    public void annotateTypeLater(final JCTree tree,
+                                  final List<JCAnnotation> declAnnos,
+                                  final Env<AttrContext> env,
+                                  final Symbol sym,
+                                  final DiagnosticPosition deferPos,
+                                  final JCLambda currentLambda,
+                                  final PositionCreator creator,
+                                  final boolean speculative) {
         Assert.checkNonNull(sym);
+        Assert.checkNonNull(declAnnos);
+        Assert.checkNonNull(creator);
+
         normal(new Annotate.Worker() {
                 @Override
                 public String toString() {
                     return "type annotate " + tree + " onto " + sym + " in " + sym.owner;
                 }
                 @Override
                 public void run() {
-                    tree.accept(new TypeAnnotate(env, sym, deferPos));
+                    if (!declAnnos.isEmpty()) {
+                        sym.resetAnnotations(); // mark Annotations as incomplete for now
+                    }
+
+                    tree.accept(typeAnnotater(declAnnos, sym, env, deferPos,
+                                              currentLambda, creator, speculative));
                 }
             });
     }
 
     /**
-     * We need to use a TreeScanner, because it is not enough to visit the top-level
-     * annotations. We also need to visit type arguments, etc.
+     * A client passed into various visitors that takes a type path as
+     * an argument and performs an action (typically creating a
+     * TypeAnnotationPosition and then creating a {@code Worker} and
+     * adding it to a queue.
      */
+    public abstract class PositionCreator {
+        public TypeAnnotationPosition create() {
+            return create(List.<TypePathEntry>nil(), null, 0);
+        }
+
+        public TypeAnnotationPosition createNonNull(List<TypePathEntry> path,
+                                                    JCLambda lambda,
+                                                    int typeIndex) {
+            final TypeAnnotationPosition out = create(path, lambda, typeIndex);
+
+            if (out != null)
+                return out;
+            else
+                throw new AssertionError("No annotation creator registered");
+        }
+
+        public abstract TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                      JCLambda lambda,
+                                                      int typeIndex);
+    }
+
+    // For when we don't have a creator.  Creates null.
+    public final PositionCreator noCreator =
+        new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return null;
+            }
+        };
+
+    // Create class extension positions
+    public final PositionCreator extendsCreator =
+        new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.classExtends(path, lambda, -1);
+            }
+        };
+
+    // Create interface implementation positions
+    public PositionCreator implementsCreator(final int idx) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.classExtends(path, lambda, idx, -1);
+            }
+        };
+    }
+
+    // Create method parameter positions
+    public final PositionCreator paramCreator(final int idx) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.methodParameter(path, lambda, idx, -1);
+            }
+        };
+    }
+
+    // Create class type parameter positions
+    public PositionCreator typeParamCreator(final int idx) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.typeParameter(path, lambda, idx, -1);
+            }
+        };
+    }
+
+    public PositionCreator typeParamBoundCreator(final JCTypeParameter typaram,
+                                                 final int param_idx,
+                                                 final int bound_idx) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                final int real_bound_idx =
+                    typaram.bounds.head.type.isInterface() ? bound_idx + 1 : bound_idx;
+                return TypeAnnotationPosition
+                    .typeParameterBound(path, lambda, param_idx, real_bound_idx, -1);
+            }
+        };
+    }
+
+    // Create field positions
+    public final PositionCreator fieldCreator = 
+        new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.field(path, lambda, -1);
+            }
+        };
+
+    // Create local variable positions
+    public PositionCreator localVarCreator(final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.localVariable(path, lambda, pos);
+            }
+        };
+    }
+
+    public PositionCreator resourceVarCreator(final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.resourceVariable(path, lambda, pos);
+            }
+        };
+    }
+
+    public PositionCreator exceptionParamCreator(final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.exceptionParameter(path, lambda,
+                                                                 typeIndex, pos);
+            }
+        };
+    }
+
+    public PositionCreator methodTypeParamCreator(final int idx) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.methodTypeParameter(path, lambda, idx, -1);
+            }
+        };
+    }
+
+    public PositionCreator methodRefTypeArgCreator(final int idx,
+                                                   final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.methodRefTypeArg(path, lambda, idx, pos);
+            }
+        };
+    }
+
+    public PositionCreator constructorRefTypeArgCreator(final int idx,
+                                                        final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition
+                    .constructorRefTypeArg(path, lambda, idx, pos);
+            }
+        };
+    }
+
+    public PositionCreator methodInvokeTypeArgCreator(final int idx,
+                                                      final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.methodInvocationTypeArg(path, lambda, idx, pos);
+            }
+        };
+    }
+
+    public PositionCreator constructorInvokeTypeArgCreator(final int idx,
+                                                           final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.constructorInvocationTypeArg(path, lambda, idx, pos);
+            }
+        };
+    }
+
+    public PositionCreator methodTypeParamBoundCreator(final JCTypeParameter typaram,
+                                                       final int param_idx,
+                                                       final int bound_idx) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                final int real_bound_idx =
+                    typaram.bounds.head.type.isInterface() ? bound_idx + 1 : bound_idx;
+                return TypeAnnotationPosition
+                    .methodTypeParameterBound(path, lambda, param_idx, real_bound_idx, -1);
+            }
+        };
+    }
+
+    public PositionCreator throwCreator(final int idx) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.methodThrows(path, lambda, idx, -1);
+            }
+        };
+    }
+
+    public final PositionCreator returnCreator =
+        new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.methodReturn(path, lambda, -1);
+            }
+        };
+
+    public PositionCreator receiverCreator =
+        new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.methodReceiver(path, lambda, -1);
+            }
+        };
+
+    public PositionCreator methodRefCreator(final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.methodRef(path, lambda, pos);
+            }
+        };
+    }
+
+    public PositionCreator constructorRefCreator(final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.constructorRef(path, lambda, pos);
+            }
+        };
+    }
+
+    public PositionCreator instanceOfCreator(final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.instanceOf(path, lambda, pos);
+            }
+        };
+    }
+
+    public PositionCreator newObjCreator(final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.newObj(path, lambda, pos);
+            }
+        };
+    }
+
+    public PositionCreator castCreator(final int pos) {
+        return new PositionCreator() {
+            @Override
+            public TypeAnnotationPosition create(List<TypePathEntry> path,
+                                                 JCLambda lambda,
+                                                 int typeIndex) {
+                return TypeAnnotationPosition.typeCast(path, lambda, typeIndex, pos);
+            }
+        };
+    }
+
+    private static List<TypePathEntry> addInners(Type type,
+                                                 List<TypePathEntry> typepath) {
+        Type encl = type.getEnclosingType();
+        while (encl != null && encl.getKind() != TypeKind.NONE &&
+               encl.getKind() != TypeKind.ERROR) {
+            typepath = typepath.append(TypePathEntry.INNER_TYPE);
+            encl = encl.getEnclosingType();
+        }
+        return typepath;
+    }
+
+    public TypeAnnotate typeAnnotater(final List<JCAnnotation> declAnnos,
+                                      final Symbol sym,
+                                      final Env<AttrContext> env,
+                                      final DiagnosticPosition deferPos,
+                                      final JCLambda currentLambda,
+                                      final PositionCreator creator,
+                                      final boolean speculative) {
+        if (!speculative) {
+            return new TypeAnnotate(declAnnos, sym, env, deferPos,
+                                    currentLambda, creator,
+                                    declAnnotationsAttacher(sym),
+                                    typeAnnotationsAttacher(sym));
+        } else {
+            return new TypeAnnotate(declAnnos, sym, env, deferPos,
+                                    currentLambda, creator, null, null);
+        }
+    }
+
     private class TypeAnnotate extends TreeScanner {
-        private final Env<AttrContext> env;
+        protected PositionCreator creator;
+        private List<TypePathEntry> typepath = List.nil();
+        private JCLambda currentLambda;
+        private int type_index = 0;
+        private boolean innermost;
+        // These attachers are for declaration annotations
+        private AttributeAttacher<Attribute.Compound> declAttacher;
+        private AttributeAttacher<Attribute.TypeCompound> typeAttacher;
+        private Reporter<Attribute.TypeCompound> reporter;
         private final Symbol sym;
-        private DiagnosticPosition deferPos;
+        private final DiagnosticPosition deferPos;
+        private final Env<AttrContext> env;
+        private final List<JCAnnotation> declAnnos;
 
-        public TypeAnnotate(final Env<AttrContext> env,
+        public TypeAnnotate(final List<JCAnnotation> declAnnos,
                             final Symbol sym,
-                            final DiagnosticPosition deferPos) {
-
-            this.env = env;
+                            final Env<AttrContext> env,
+                            final DiagnosticPosition deferPos,
+                            final JCLambda currentLambda,
+                            final PositionCreator creator,
+                            final AttributeAttacher<Attribute.Compound> declAttacher,
+                            final AttributeAttacher<Attribute.TypeCompound> typeAttacher) {
+            this.declAnnos = declAnnos;
             this.sym = sym;
+            this.env = env;
             this.deferPos = deferPos;
+            this.currentLambda = currentLambda;
+            this.creator = creator;
+            this.innermost = true;
+            this.declAttacher = declAttacher;
+            this.typeAttacher = typeAttacher;
+            this.reporter = null;
+        }
+
+        private void doDeclAnnos() {
+            if (!declAnnos.isEmpty()) {
+                final TypeAnnotationPosition tapos =
+                    creator.createNonNull(typepath, currentLambda, type_index);
+                annotateNow(declAnnos, env, sym, deferPos, tapos,
+                            classifyingAttacher(sym, declAttacher,
+                                                typeAttacher, reporter));
+                validate(annotationValidator(declAnnos, env, sym));
+            }
+        }
+
+        private void doTypeAnnos(List<JCAnnotation> annos,
+                                 boolean isTypeParameter) {
+            if (!annos.isEmpty()) {
+                final AttributeAttacher<Attribute.TypeCompound> currTypeAttacher = typeAttacher;
+                final Reporter<Attribute.TypeCompound> currReporter = reporter;
+                final AttributeAttacher<Attribute.TypeCompound> attacher =
+                    new AttributeAttacher<Attribute.TypeCompound>() {
+                    @Override
+                    public void attach(List<Attribute.TypeCompound> attrs) {
+                        if (currTypeAttacher != null)
+                            currTypeAttacher.attach(attrs);
+                        if (currReporter != null)
+                            currReporter.report(attrs);
+                    }
+                };
+                final TypeAnnotationPosition tapos =
+                    creator.createNonNull(typepath, currentLambda, type_index);
+                actualEnterTypeAnnotations(annos, env, sym, deferPos, tapos,
+                                           attacher);
+                validate(typeAnnotationValidator(annos, env, isTypeParameter));
+            }
+        }
+
+        @Override
+        public void visitTypeIdent(final JCPrimitiveTypeTree tree) {
+            if (innermost) {
+                final AttributeAttacher<Attribute.TypeCompound> oldTypeAttacher = typeAttacher;
+                typeAttacher =
+                    new AttributeAttacher<Attribute.TypeCompound>() {
+                        @Override
+                        public void attach(List<Attribute.TypeCompound> attrs) {
+                            if (null != oldTypeAttacher)
+                                oldTypeAttacher.attach(attrs);
+
+                            if (!attrs.isEmpty()) {
+                                tree.type = tree.type.annotatedType(attrs);
+                            }
+                        }
+                    };
+                doDeclAnnos();
+                typeAttacher = oldTypeAttacher;
+            }
+        }
+
+        @Override
+        public void visitIdent(final JCIdent tree) {
+            if (innermost) {
+                final AttributeAttacher<Attribute.TypeCompound> oldTypeAttacher = typeAttacher;
+                final Reporter<Attribute.TypeCompound> oldReporter = reporter;
+                typeAttacher =
+                    new AttributeAttacher<Attribute.TypeCompound>() {
+                        @Override
+                        public void attach(List<Attribute.TypeCompound> attrs) {
+                            if (null != oldTypeAttacher)
+                                oldTypeAttacher.attach(attrs);
+
+                            if (!attrs.isEmpty() &&
+                                !tree.type.hasTag(TypeTag.PACKAGE)) {
+                                tree.type = tree.type.annotatedType(attrs);
+                            }
+                        }
+                    };
+                if (tree.type != null) {
+                    final List<TypePathEntry> oldpath = typepath;
+                    typepath = addInners(tree.type, typepath);
+                    doDeclAnnos();
+                    typepath = oldpath;
+                } else {
+                    doDeclAnnos();
+                }
+                reporter = oldReporter;
+                typeAttacher = oldTypeAttacher;
+            }
+        }
+
+        @Override
+        public void visitAnnotatedType(JCAnnotatedType tree) {
+            Assert.checkNonNull(tree.getUnderlyingType().type);
+            final boolean oldinnermost = innermost;
+            innermost = false;
+            scan(tree.annotations);
+            innermost = oldinnermost;
+            scan(tree.underlyingType);
+            final Reporter<Attribute.TypeCompound> oldReporter = reporter;
+            final List<TypePathEntry> oldpath = typepath;
+            typepath = addInners(tree.getUnderlyingType().type, typepath);
+            doTypeAnnos(tree.annotations, false);
+            typepath = oldpath;
+            reporter = oldReporter;
         }
 
         @Override
-        public void visitAnnotatedType(final JCAnnotatedType tree) {
-            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
-            super.visitAnnotatedType(tree);
+        public void visitTypeArray(JCArrayTypeTree tree) {
+            final List<TypePathEntry> oldpath = typepath;
+            typepath = typepath.append(TypePathEntry.ARRAY);
+            super.visitTypeArray(tree);
+            typepath = oldpath;
         }
 
         @Override
-        public void visitTypeParameter(final JCTypeParameter tree) {
-            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
-            super.visitTypeParameter(tree);
+        public void visitTypeApply(JCTypeApply tree) {
+            Assert.checkNonNull(tree.getType().type);
+            final List<TypePathEntry> oldpath = typepath;
+            scan(tree.clazz);
+
+
+            if (tree.getType() != null && tree.getType().type != null) {
+                typepath = addInners(tree.getType().type, typepath);
+            }
+            final boolean oldinnermost = innermost;
+            innermost = false;
+            int i = 0;
+            for (List<JCExpression> l = tree.arguments; l.nonEmpty();
+                 l = l.tail, i++) {
+                final JCExpression arg = l.head;
+                final List<TypePathEntry> noargpath = typepath;
+                typepath = typepath.append(new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, i));
+                scan(arg);
+                typepath = noargpath;
+            }
+            typepath = oldpath;
+            innermost = oldinnermost;
+        }
+
+        @Override
+        public void visitNewArray(JCNewArray tree) {
+            final List<TypePathEntry> oldpath = typepath;
+            final PositionCreator oldcreator = creator;
+            creator = newObjCreator(tree.pos);
+            doTypeAnnos(tree.annotations, false);
+
+            for (int i = 0; i < tree.dimAnnotations.size(); i++) {
+                final List<JCAnnotation> dimAnnos = tree.dimAnnotations.get(i);
+                doTypeAnnos(dimAnnos, false);
+                // This is right.  As per the type annotations spec,
+                // the first array dimension has no arrays in the type
+                // path, the second has one, and so on, and the
+                // element type has n for n dimensions.
+                typepath = typepath.append(TypePathEntry.ARRAY);
+            }
+
+            // The element type is sometimes null, in the case of
+            // array literals.
+            scan(tree.elemtype);
+            typepath = oldpath;
+            creator = oldcreator;
+        }
+
+        @Override
+        public void visitWildcard(JCWildcard tree) {
+            final List<TypePathEntry> oldpath = typepath;
+            typepath = typepath.append(TypePathEntry.WILDCARD);
+            super.visitWildcard(tree);
+            typepath = oldpath;
         }
 
         @Override
-        public void visitNewArray(final JCNewArray tree) {
-            actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos);
-            for (List<JCAnnotation> dimAnnos : tree.dimAnnotations)
-                actualEnterTypeAnnotations(dimAnnos, env, sym, deferPos);
-            super.visitNewArray(tree);
+        public void visitTypeParameter(JCTypeParameter tree) {
+            scan(tree.annotations);
+            Assert.checkNonNull(tree.type);
+            doTypeAnnos(tree.annotations, true);
         }
 
         @Override
-        public void visitMethodDef(final JCMethodDecl tree) {
-            scan(tree.mods);
-            scan(tree.restype);
-            scan(tree.typarams);
-            scan(tree.recvparam);
+        public void visitLambda(JCLambda tree) {
+            final JCLambda oldLambda = currentLambda;
+            currentLambda = tree;
+            scan(tree.body);
             scan(tree.params);
-            scan(tree.thrown);
-            scan(tree.defaultValue);
-            // Do not annotate the body, just the signature.
-            // scan(tree.body);
+            currentLambda = oldLambda;
+            
         }
 
         @Override
-        public void visitVarDef(final JCVariableDecl tree) {
-            DiagnosticPosition prevPos = deferPos;
-            deferPos = tree.pos();
-            try {
-                if (sym != null && sym.kind == Kinds.VAR) {
-                    // Don't visit a parameter once when the sym is the method
-                    // and once when the sym is the parameter.
-                    scan(tree.mods);
-                    scan(tree.vartype);
+        public void visitTypeIntersection(JCTypeIntersection tree) {
+            final boolean oldinnermost = innermost;
+            for (List<JCExpression> l = tree.bounds; l.nonEmpty();
+                 l = l.tail, type_index++) {
+                scan(l.head);
+                // Set innermost to false after the first element
+                innermost = false;
                 }
-                scan(tree.init);
-            } finally {
-                deferPos = prevPos;
+            innermost = oldinnermost;
             }
+
+        @Override
+        public void visitTypeUnion(JCTypeUnion tree) {
+            final boolean oldinnermost = innermost;
+            for (List<JCExpression> l = tree.alternatives; l.nonEmpty();
+                 l = l.tail, type_index++) {
+                scan(l.head);
+                // Set innermost to false after the first element
+                innermost = false;
+            }
+            innermost = oldinnermost;
+        }
+
+        @Override
+        public void visitSelect(JCFieldAccess tree) {
+            Symbol sym = tree.sym;
+            //System.err.println("visitSelect " + tree);
+            final AttributeAttacher<Attribute.TypeCompound> oldTypeAttacher = typeAttacher;
+            final Reporter<Attribute.TypeCompound> oldReporter = reporter;
+            // If we're selecting from an interface or a static class,
+            // set up attachers that will only attach declaration
+            // annotations and will report type annotations as errors.
+            Type selectedTy = tree.selected.type;
+            if (sym != null && (sym.isStatic() || sym.isInterface() ||
+                                selectedTy.hasTag(TypeTag.PACKAGE))) {
+                typeAttacher = null;
+                reporter = illegalScopingReporter(tree.pos);
+            }
+            super.visitSelect(tree);
+            typeAttacher = oldTypeAttacher;
+            reporter = oldReporter;
+        }
+
+        // These methods stop the visitor from continuing on when it
+        // sees a definition.
+        @Override
+        public void visitVarDef(final JCVariableDecl tree) {
         }
 
         @Override
         public void visitClassDef(JCClassDecl tree) {
             // We can only hit a classdef if it is declared within

@@ -1082,13 +1951,59 @@
             // separately later.
         }
 
         @Override
         public void visitNewClass(JCNewClass tree) {
-            if (tree.def == null) {
-                // For an anonymous class instantiation the class
-                // will be visited separately.
-                super.visitNewClass(tree);
+            // This will be visited by Attr later, so don't do
+            // anything.
             }
         }
+
+    private class TypeAnnotateExpr extends TypeAnnotate {
+        public TypeAnnotateExpr(final Symbol sym,
+                                final Env<AttrContext> env,
+                                final DiagnosticPosition deferPos,
+                                final JCLambda currentLambda,
+                                final PositionCreator creator) {
+            super(List.<JCAnnotation>nil(), sym, env, deferPos,
+                  currentLambda, creator, null, null);
+        }
+
+        @Override
+        public void visitTypeCast(final JCTypeCast tree) {
+            final PositionCreator oldcreator = creator;
+            creator = castCreator(tree.pos);
+            super.visitTypeCast(tree);
+            creator = oldcreator;
+        }
+
+        @Override
+        public void visitTypeTest(JCInstanceOf tree) {
+            final PositionCreator oldcreator = creator;
+            creator = instanceOfCreator(tree.pos);
+            super.visitTypeTest(tree);
+            creator = oldcreator;
+        }
+    }
+
+    public void typeAnnotateExprLater(final JCTree tree,
+                                      final Env<AttrContext> env,
+                                      final Symbol sym,
+                                      final DiagnosticPosition deferPos,
+                                      final JCLambda currentLambda,
+                                      final PositionCreator creator) {
+        Assert.checkNonNull(sym);
+        Assert.checkNonNull(creator);
+
+        normal(new Annotate.Worker() {
+                @Override
+                public String toString() {
+                    return "type annotate " + tree + " onto " + sym + " in " + sym.owner;
+                }
+                @Override
+                public void run() {
+                    tree.accept(new TypeAnnotateExpr(sym, env, deferPos,
+                                                     currentLambda, creator));
+                }
+            });
     }
 }