src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java
changeset 47216 71c04702a3d5
parent 45752 32eb45c44fc8
child 48344 89f6aa26fd6c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,2206 @@
+/*
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.code;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Inherited;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.code.ClassFinder.BadEnclosingMethodAttr;
+import com.sun.tools.javac.code.Directive.RequiresFlag;
+import com.sun.tools.javac.code.Kinds.Kind;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
+import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.comp.Attr;
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Env;
+import com.sun.tools.javac.jvm.*;
+import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.Name;
+
+import static com.sun.tools.javac.code.Flags.*;
+import static com.sun.tools.javac.code.Kinds.*;
+import static com.sun.tools.javac.code.Kinds.Kind.*;
+import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
+import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.FIRSTASGOP;
+import static com.sun.tools.javac.code.TypeTag.CLASS;
+import static com.sun.tools.javac.code.TypeTag.FORALL;
+import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
+import static com.sun.tools.javac.jvm.ByteCodes.iadd;
+import static com.sun.tools.javac.jvm.ByteCodes.ishll;
+import static com.sun.tools.javac.jvm.ByteCodes.lushrl;
+import static com.sun.tools.javac.jvm.ByteCodes.lxor;
+import static com.sun.tools.javac.jvm.ByteCodes.string_add;
+
+/** Root class for Java symbols. It contains subclasses
+ *  for specific sorts of symbols, such as variables, methods and operators,
+ *  types, packages. Each subclass is represented as a static inner class
+ *  inside Symbol.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public abstract class Symbol extends AnnoConstruct implements Element {
+
+    /** The kind of this symbol.
+     *  @see Kinds
+     */
+    public Kind kind;
+
+    /** The flags of this symbol.
+     */
+    public long flags_field;
+
+    /** An accessor method for the flags of this symbol.
+     *  Flags of class symbols should be accessed through the accessor
+     *  method to make sure that the class symbol is loaded.
+     */
+    public long flags() { return flags_field; }
+
+    /** The name of this symbol in Utf8 representation.
+     */
+    public Name name;
+
+    /** The type of this symbol.
+     */
+    public Type type;
+
+    /** The owner of this symbol.
+     */
+    public Symbol owner;
+
+    /** The completer of this symbol.
+     * This should never equal null (NULL_COMPLETER should be used instead).
+     */
+    public Completer completer;
+
+    /** A cache for the type erasure of this symbol.
+     */
+    public Type erasure_field;
+
+    // <editor-fold defaultstate="collapsed" desc="annotations">
+
+    /** The attributes of this symbol are contained in this
+     * SymbolMetadata. The SymbolMetadata instance is NOT immutable.
+     */
+    protected SymbolMetadata metadata;
+
+
+    /** An accessor method for the attributes of this symbol.
+     *  Attributes of class symbols should be accessed through the accessor
+     *  method to make sure that the class symbol is loaded.
+     */
+    public List<Attribute.Compound> getRawAttributes() {
+        return (metadata == null)
+                ? List.nil()
+                : metadata.getDeclarationAttributes();
+    }
+
+    /** An accessor method for the type attributes of this symbol.
+     *  Attributes of class symbols should be accessed through the accessor
+     *  method to make sure that the class symbol is loaded.
+     */
+    public List<Attribute.TypeCompound> getRawTypeAttributes() {
+        return (metadata == null)
+                ? List.nil()
+                : metadata.getTypeAttributes();
+    }
+
+    /** Fetch a particular annotation from a symbol. */
+    public Attribute.Compound attribute(Symbol anno) {
+        for (Attribute.Compound a : getRawAttributes()) {
+            if (a.type.tsym == anno) return a;
+        }
+        return null;
+    }
+
+    public boolean annotationsPendingCompletion() {
+        return metadata == null ? false : metadata.pendingCompletion();
+    }
+
+    public void appendAttributes(List<Attribute.Compound> l) {
+        if (l.nonEmpty()) {
+            initedMetadata().append(l);
+        }
+    }
+
+    public void appendClassInitTypeAttributes(List<Attribute.TypeCompound> l) {
+        if (l.nonEmpty()) {
+            initedMetadata().appendClassInitTypeAttributes(l);
+        }
+    }
+
+    public void appendInitTypeAttributes(List<Attribute.TypeCompound> l) {
+        if (l.nonEmpty()) {
+            initedMetadata().appendInitTypeAttributes(l);
+        }
+    }
+
+    public void appendUniqueTypeAttributes(List<Attribute.TypeCompound> l) {
+        if (l.nonEmpty()) {
+            initedMetadata().appendUniqueTypes(l);
+        }
+    }
+
+    public List<Attribute.TypeCompound> getClassInitTypeAttributes() {
+        return (metadata == null)
+                ? List.nil()
+                : metadata.getClassInitTypeAttributes();
+    }
+
+    public List<Attribute.TypeCompound> getInitTypeAttributes() {
+        return (metadata == null)
+                ? List.nil()
+                : metadata.getInitTypeAttributes();
+    }
+
+    public void setInitTypeAttributes(List<Attribute.TypeCompound> l) {
+        initedMetadata().setInitTypeAttributes(l);
+    }
+
+    public void setClassInitTypeAttributes(List<Attribute.TypeCompound> l) {
+        initedMetadata().setClassInitTypeAttributes(l);
+    }
+
+    public List<Attribute.Compound> getDeclarationAttributes() {
+        return (metadata == null)
+                ? List.nil()
+                : metadata.getDeclarationAttributes();
+    }
+
+    public boolean hasAnnotations() {
+        return (metadata != null && !metadata.isEmpty());
+    }
+
+    public boolean hasTypeAnnotations() {
+        return (metadata != null && !metadata.isTypesEmpty());
+    }
+
+    public boolean isCompleted() {
+        return completer.isTerminal();
+    }
+
+    public void prependAttributes(List<Attribute.Compound> l) {
+        if (l.nonEmpty()) {
+            initedMetadata().prepend(l);
+        }
+    }
+
+    public void resetAnnotations() {
+        initedMetadata().reset();
+    }
+
+    public void setAttributes(Symbol other) {
+        if (metadata != null || other.metadata != null) {
+            initedMetadata().setAttributes(other.metadata);
+        }
+    }
+
+    public void setDeclarationAttributes(List<Attribute.Compound> a) {
+        if (metadata != null || a.nonEmpty()) {
+            initedMetadata().setDeclarationAttributes(a);
+        }
+    }
+
+    public void setTypeAttributes(List<Attribute.TypeCompound> a) {
+        if (metadata != null || a.nonEmpty()) {
+            if (metadata == null)
+                metadata = new SymbolMetadata(this);
+            metadata.setTypeAttributes(a);
+        }
+    }
+
+    private SymbolMetadata initedMetadata() {
+        if (metadata == null)
+            metadata = new SymbolMetadata(this);
+        return metadata;
+    }
+
+    /** This method is intended for debugging only. */
+    public SymbolMetadata getMetadata() {
+        return metadata;
+    }
+
+    // </editor-fold>
+
+    /** Construct a symbol with given kind, flags, name, type and owner.
+     */
+    public Symbol(Kind kind, long flags, Name name, Type type, Symbol owner) {
+        this.kind = kind;
+        this.flags_field = flags;
+        this.type = type;
+        this.owner = owner;
+        this.completer = Completer.NULL_COMPLETER;
+        this.erasure_field = null;
+        this.name = name;
+    }
+
+    /** Clone this symbol with new owner.
+     *  Legal only for fields and methods.
+     */
+    public Symbol clone(Symbol newOwner) {
+        throw new AssertionError();
+    }
+
+    public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
+        return v.visitSymbol(this, p);
+    }
+
+    /** The Java source which this symbol represents.
+     *  A description of this symbol; overrides Object.
+     */
+    public String toString() {
+        return name.toString();
+    }
+
+    /** A Java source description of the location of this symbol; used for
+     *  error reporting.
+     *
+     * @return null if the symbol is a package or a toplevel class defined in
+     * the default package; otherwise, the owner symbol is returned
+     */
+    public Symbol location() {
+        if (owner.name == null || (owner.name.isEmpty() &&
+                                   (owner.flags() & BLOCK) == 0 &&
+                                   owner.kind != PCK &&
+                                   owner.kind != TYP)) {
+            return null;
+        }
+        return owner;
+    }
+
+    public Symbol location(Type site, Types types) {
+        if (owner.name == null || owner.name.isEmpty()) {
+            return location();
+        }
+        if (owner.type.hasTag(CLASS)) {
+            Type ownertype = types.asOuterSuper(site, owner);
+            if (ownertype != null) return ownertype.tsym;
+        }
+        return owner;
+    }
+
+    public Symbol baseSymbol() {
+        return this;
+    }
+
+    /** The symbol's erased type.
+     */
+    public Type erasure(Types types) {
+        if (erasure_field == null)
+            erasure_field = types.erasure(type);
+        return erasure_field;
+    }
+
+    /** The external type of a symbol. This is the symbol's erased type
+     *  except for constructors of inner classes which get the enclosing
+     *  instance class added as first argument.
+     */
+    public Type externalType(Types types) {
+        Type t = erasure(types);
+        if (name == name.table.names.init && owner.hasOuterInstance()) {
+            Type outerThisType = types.erasure(owner.type.getEnclosingType());
+            return new MethodType(t.getParameterTypes().prepend(outerThisType),
+                                  t.getReturnType(),
+                                  t.getThrownTypes(),
+                                  t.tsym);
+        } else {
+            return t;
+        }
+    }
+
+    public boolean isDeprecated() {
+        return (flags_field & DEPRECATED) != 0;
+    }
+
+    public boolean hasDeprecatedAnnotation() {
+        return (flags_field & DEPRECATED_ANNOTATION) != 0;
+    }
+
+    public boolean isDeprecatedForRemoval() {
+        return (flags_field & DEPRECATED_REMOVAL) != 0;
+    }
+
+    public boolean isDeprecatableViaAnnotation() {
+        switch (getKind()) {
+            case LOCAL_VARIABLE:
+            case PACKAGE:
+            case PARAMETER:
+            case RESOURCE_VARIABLE:
+            case EXCEPTION_PARAMETER:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    public boolean isStatic() {
+        return
+            (flags() & STATIC) != 0 ||
+            (owner.flags() & INTERFACE) != 0 && kind != MTH &&
+             name != name.table.names._this;
+    }
+
+    public boolean isInterface() {
+        return (flags() & INTERFACE) != 0;
+    }
+
+    public boolean isPrivate() {
+        return (flags_field & Flags.AccessFlags) == PRIVATE;
+    }
+
+    public boolean isEnum() {
+        return (flags() & ENUM) != 0;
+    }
+
+    /** Is this symbol declared (directly or indirectly) local
+     *  to a method or variable initializer?
+     *  Also includes fields of inner classes which are in
+     *  turn local to a method or variable initializer.
+     */
+    public boolean isLocal() {
+        return
+            (owner.kind.matches(KindSelector.VAL_MTH) ||
+             (owner.kind == TYP && owner.isLocal()));
+    }
+
+    /** Has this symbol an empty name? This includes anonymous
+     *  inner classes.
+     */
+    public boolean isAnonymous() {
+        return name.isEmpty();
+    }
+
+    /** Is this symbol a constructor?
+     */
+    public boolean isConstructor() {
+        return name == name.table.names.init;
+    }
+
+    /** The fully qualified name of this symbol.
+     *  This is the same as the symbol's name except for class symbols,
+     *  which are handled separately.
+     */
+    public Name getQualifiedName() {
+        return name;
+    }
+
+    /** The fully qualified name of this symbol after converting to flat
+     *  representation. This is the same as the symbol's name except for
+     *  class symbols, which are handled separately.
+     */
+    public Name flatName() {
+        return getQualifiedName();
+    }
+
+    /** If this is a class or package, its members, otherwise null.
+     */
+    public WriteableScope members() {
+        return null;
+    }
+
+    /** A class is an inner class if it it has an enclosing instance class.
+     */
+    public boolean isInner() {
+        return kind == TYP && type.getEnclosingType().hasTag(CLASS);
+    }
+
+    /** An inner class has an outer instance if it is not an interface
+     *  it has an enclosing instance class which might be referenced from the class.
+     *  Nested classes can see instance members of their enclosing class.
+     *  Their constructors carry an additional this$n parameter, inserted
+     *  implicitly by the compiler.
+     *
+     *  @see #isInner
+     */
+    public boolean hasOuterInstance() {
+        return
+            type.getEnclosingType().hasTag(CLASS) && (flags() & (INTERFACE | NOOUTERTHIS)) == 0;
+    }
+
+    /** The closest enclosing class of this symbol's declaration.
+     *  Warning: this (misnamed) method returns the receiver itself
+     *  when the receiver is a class (as opposed to its enclosing
+     *  class as one may be misled to believe.)
+     */
+    public ClassSymbol enclClass() {
+        Symbol c = this;
+        while (c != null &&
+               (!c.kind.matches(KindSelector.TYP) || !c.type.hasTag(CLASS))) {
+            c = c.owner;
+        }
+        return (ClassSymbol)c;
+    }
+
+    /** The outermost class which indirectly owns this symbol.
+     */
+    public ClassSymbol outermostClass() {
+        Symbol sym = this;
+        Symbol prev = null;
+        while (sym.kind != PCK) {
+            prev = sym;
+            sym = sym.owner;
+        }
+        return (ClassSymbol) prev;
+    }
+
+    /** The package which indirectly owns this symbol.
+     */
+    public PackageSymbol packge() {
+        Symbol sym = this;
+        while (sym.kind != PCK) {
+            sym = sym.owner;
+        }
+        return (PackageSymbol) sym;
+    }
+
+    /** Is this symbol a subclass of `base'? Only defined for ClassSymbols.
+     */
+    public boolean isSubClass(Symbol base, Types types) {
+        throw new AssertionError("isSubClass " + this);
+    }
+
+    /** Fully check membership: hierarchy, protection, and hiding.
+     *  Does not exclude methods not inherited due to overriding.
+     */
+    public boolean isMemberOf(TypeSymbol clazz, Types types) {
+        return
+            owner == clazz ||
+            clazz.isSubClass(owner, types) &&
+            isInheritedIn(clazz, types) &&
+            !hiddenIn((ClassSymbol)clazz, types);
+    }
+
+    /** Is this symbol the same as or enclosed by the given class? */
+    public boolean isEnclosedBy(ClassSymbol clazz) {
+        for (Symbol sym = this; sym.kind != PCK; sym = sym.owner)
+            if (sym == clazz) return true;
+        return false;
+    }
+
+    private boolean hiddenIn(ClassSymbol clazz, Types types) {
+        Symbol sym = hiddenInInternal(clazz, types);
+        Assert.check(sym != null, "the result of hiddenInInternal() can't be null");
+        /* If we find the current symbol then there is no symbol hiding it
+         */
+        return sym != this;
+    }
+
+    /** This method looks in the supertypes graph that has the current class as the
+     * initial node, till it finds the current symbol or another symbol that hides it.
+     * If the current class has more than one supertype (extends one class and
+     * implements one or more interfaces) then null can be returned, meaning that
+     * a wrong path in the supertypes graph was selected. Null can only be returned
+     * as a temporary value, as a result of the recursive call.
+     */
+    private Symbol hiddenInInternal(ClassSymbol currentClass, Types types) {
+        if (currentClass == owner) {
+            return this;
+        }
+        for (Symbol sym : currentClass.members().getSymbolsByName(name)) {
+            if (sym.kind == kind &&
+                    (kind != MTH ||
+                    (sym.flags() & STATIC) != 0 &&
+                    types.isSubSignature(sym.type, type))) {
+                return sym;
+            }
+        }
+        Symbol hiddenSym = null;
+        for (Type st : types.interfaces(currentClass.type)
+                .prepend(types.supertype(currentClass.type))) {
+            if (st != null && (st.hasTag(CLASS))) {
+                Symbol sym = hiddenInInternal((ClassSymbol)st.tsym, types);
+                if (sym == this) {
+                    return this;
+                } else if (sym != null) {
+                    hiddenSym = sym;
+                }
+            }
+        }
+        return hiddenSym;
+    }
+
+    /** Is this symbol inherited into a given class?
+     *  PRE: If symbol's owner is a interface,
+     *       it is already assumed that the interface is a superinterface
+     *       of given class.
+     *  @param clazz  The class for which we want to establish membership.
+     *                This must be a subclass of the member's owner.
+     */
+    public boolean isInheritedIn(Symbol clazz, Types types) {
+        switch ((int)(flags_field & Flags.AccessFlags)) {
+        default: // error recovery
+        case PUBLIC:
+            return true;
+        case PRIVATE:
+            return this.owner == clazz;
+        case PROTECTED:
+            // we model interfaces as extending Object
+            return (clazz.flags() & INTERFACE) == 0;
+        case 0:
+            PackageSymbol thisPackage = this.packge();
+            for (Symbol sup = clazz;
+                 sup != null && sup != this.owner;
+                 sup = types.supertype(sup.type).tsym) {
+                while (sup.type.hasTag(TYPEVAR))
+                    sup = sup.type.getUpperBound().tsym;
+                if (sup.type.isErroneous())
+                    return true; // error recovery
+                if ((sup.flags() & COMPOUND) != 0)
+                    continue;
+                if (sup.packge() != thisPackage)
+                    return false;
+            }
+            return (clazz.flags() & INTERFACE) == 0;
+        }
+    }
+
+    /** The (variable or method) symbol seen as a member of given
+     *  class type`site' (this might change the symbol's type).
+     *  This is used exclusively for producing diagnostics.
+     */
+    public Symbol asMemberOf(Type site, Types types) {
+        throw new AssertionError();
+    }
+
+    /** Does this method symbol override `other' symbol, when both are seen as
+     *  members of class `origin'?  It is assumed that _other is a member
+     *  of origin.
+     *
+     *  It is assumed that both symbols have the same name.  The static
+     *  modifier is ignored for this test.
+     *
+     *  See JLS 8.4.6.1 (without transitivity) and 8.4.6.4
+     */
+    public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean checkResult) {
+        return false;
+    }
+
+    /** Complete the elaboration of this symbol's definition.
+     */
+    public void complete() throws CompletionFailure {
+        if (completer != Completer.NULL_COMPLETER) {
+            Completer c = completer;
+            completer = Completer.NULL_COMPLETER;
+            c.complete(this);
+        }
+    }
+
+    /** True if the symbol represents an entity that exists.
+     */
+    public boolean exists() {
+        return true;
+    }
+
+    @DefinedBy(Api.LANGUAGE_MODEL)
+    public Type asType() {
+        return type;
+    }
+
+    @DefinedBy(Api.LANGUAGE_MODEL)
+    public Symbol getEnclosingElement() {
+        return owner;
+    }
+
+    @DefinedBy(Api.LANGUAGE_MODEL)
+    public ElementKind getKind() {
+        return ElementKind.OTHER;       // most unkind
+    }
+
+    @DefinedBy(Api.LANGUAGE_MODEL)
+    public Set<Modifier> getModifiers() {
+        return Flags.asModifierSet(flags());
+    }
+
+    @DefinedBy(Api.LANGUAGE_MODEL)
+    public Name getSimpleName() {
+        return name;
+    }
+
+    /**
+     * This is the implementation for {@code
+     * javax.lang.model.element.Element.getAnnotationMirrors()}.
+     */
+    @Override @DefinedBy(Api.LANGUAGE_MODEL)
+    public List<Attribute.Compound> getAnnotationMirrors() {
+        return getRawAttributes();
+    }
+
+
+    // TODO: getEnclosedElements should return a javac List, fix in FilteredMemberList
+    @DefinedBy(Api.LANGUAGE_MODEL)
+    public java.util.List<Symbol> getEnclosedElements() {
+        return List.nil();
+    }
+
+    public List<TypeVariableSymbol> getTypeParameters() {
+        ListBuffer<TypeVariableSymbol> l = new ListBuffer<>();
+        for (Type t : type.getTypeArguments()) {
+            Assert.check(t.tsym.getKind() == ElementKind.TYPE_PARAMETER);
+            l.append((TypeVariableSymbol)t.tsym);
+        }
+        return l.toList();
+    }
+
+    public static class DelegatedSymbol<T extends Symbol> extends Symbol {
+        protected T other;
+        public DelegatedSymbol(T other) {
+            super(other.kind, other.flags_field, other.name, other.type, other.owner);
+            this.other = other;
+        }
+        public String toString() { return other.toString(); }
+        public Symbol location() { return other.location(); }
+        public Symbol location(Type site, Types types) { return other.location(site, types); }
+        public Symbol baseSymbol() { return other; }
+        public Type erasure(Types types) { return other.erasure(types); }
+        public Type externalType(Types types) { return other.externalType(types); }
+        public boolean isLocal() { return other.isLocal(); }
+        public boolean isConstructor() { return other.isConstructor(); }
+        public Name getQualifiedName() { return other.getQualifiedName(); }
+        public Name flatName() { return other.flatName(); }
+        public WriteableScope members() { return other.members(); }
+        public boolean isInner() { return other.isInner(); }
+        public boolean hasOuterInstance() { return other.hasOuterInstance(); }
+        public ClassSymbol enclClass() { return other.enclClass(); }
+        public ClassSymbol outermostClass() { return other.outermostClass(); }
+        public PackageSymbol packge() { return other.packge(); }
+        public boolean isSubClass(Symbol base, Types types) { return other.isSubClass(base, types); }
+        public boolean isMemberOf(TypeSymbol clazz, Types types) { return other.isMemberOf(clazz, types); }
+        public boolean isEnclosedBy(ClassSymbol clazz) { return other.isEnclosedBy(clazz); }
+        public boolean isInheritedIn(Symbol clazz, Types types) { return other.isInheritedIn(clazz, types); }
+        public Symbol asMemberOf(Type site, Types types) { return other.asMemberOf(site, types); }
+        public void complete() throws CompletionFailure { other.complete(); }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+            return other.accept(v, p);
+        }
+
+        public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
+            return v.visitSymbol(other, p);
+        }
+
+        public T getUnderlyingSymbol() {
+            return other;
+        }
+    }
+
+    /** A base class for Symbols representing types.
+     */
+    public static abstract class TypeSymbol extends Symbol {
+        public TypeSymbol(Kind kind, long flags, Name name, Type type, Symbol owner) {
+            super(kind, flags, name, type, owner);
+        }
+        /** form a fully qualified name from a name and an owner
+         */
+        static public Name formFullName(Name name, Symbol owner) {
+            if (owner == null) return name;
+            if ((owner.kind != ERR) &&
+                (owner.kind.matches(KindSelector.VAL_MTH) ||
+                 (owner.kind == TYP && owner.type.hasTag(TYPEVAR))
+                 )) return name;
+            Name prefix = owner.getQualifiedName();
+            if (prefix == null || prefix == prefix.table.names.empty)
+                return name;
+            else return prefix.append('.', name);
+        }
+
+        /** form a fully qualified name from a name and an owner, after
+         *  converting to flat representation
+         */
+        static public Name formFlatName(Name name, Symbol owner) {
+            if (owner == null || owner.kind.matches(KindSelector.VAL_MTH) ||
+                (owner.kind == TYP && owner.type.hasTag(TYPEVAR))
+                ) return name;
+            char sep = owner.kind == TYP ? '$' : '.';
+            Name prefix = owner.flatName();
+            if (prefix == null || prefix == prefix.table.names.empty)
+                return name;
+            else return prefix.append(sep, name);
+        }
+
+        /**
+         * A partial ordering between type symbols that refines the
+         * class inheritance graph.
+         *
+         * Type variables always precede other kinds of symbols.
+         */
+        public final boolean precedes(TypeSymbol that, Types types) {
+            if (this == that)
+                return false;
+            if (type.hasTag(that.type.getTag())) {
+                if (type.hasTag(CLASS)) {
+                    return
+                        types.rank(that.type) < types.rank(this.type) ||
+                        types.rank(that.type) == types.rank(this.type) &&
+                        that.getQualifiedName().compareTo(this.getQualifiedName()) < 0;
+                } else if (type.hasTag(TYPEVAR)) {
+                    return types.isSubtype(this.type, that.type);
+                }
+            }
+            return type.hasTag(TYPEVAR);
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public java.util.List<Symbol> getEnclosedElements() {
+            List<Symbol> list = List.nil();
+            if (kind == TYP && type.hasTag(TYPEVAR)) {
+                return list;
+            }
+            for (Symbol sym : members().getSymbols(NON_RECURSIVE)) {
+                try {
+                    if (sym != null && (sym.flags() & SYNTHETIC) == 0 && sym.owner == this) {
+                        list = list.prepend(sym);
+                    }
+                } catch (BadEnclosingMethodAttr badEnclosingMethod) {
+                    // ignore the exception
+                }
+            }
+            return list;
+        }
+
+        public AnnotationTypeMetadata getAnnotationTypeMetadata() {
+            Assert.error("Only on ClassSymbol");
+            return null; //unreachable
+        }
+
+        public boolean isAnnotationType() { return false; }
+
+        @Override
+        public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
+            return v.visitTypeSymbol(this, p);
+        }
+    }
+
+    /**
+     * Type variables are represented by instances of this class.
+     */
+    public static class TypeVariableSymbol
+            extends TypeSymbol implements TypeParameterElement {
+
+        public TypeVariableSymbol(long flags, Name name, Type type, Symbol owner) {
+            super(TYP, flags, name, type, owner);
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public ElementKind getKind() {
+            return ElementKind.TYPE_PARAMETER;
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public Symbol getGenericElement() {
+            return owner;
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public List<Type> getBounds() {
+            TypeVar t = (TypeVar)type;
+            Type bound = t.getUpperBound();
+            if (!bound.isCompound())
+                return List.of(bound);
+            ClassType ct = (ClassType)bound;
+            if (!ct.tsym.erasure_field.isInterface()) {
+                return ct.interfaces_field.prepend(ct.supertype_field);
+            } else {
+                // No superclass was given in bounds.
+                // In this case, supertype is Object, erasure is first interface.
+                return ct.interfaces_field;
+            }
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public List<Attribute.Compound> getAnnotationMirrors() {
+            // Declaration annotations on type variables are stored in type attributes
+            // on the owner of the TypeVariableSymbol
+            List<Attribute.TypeCompound> candidates = owner.getRawTypeAttributes();
+            int index = owner.getTypeParameters().indexOf(this);
+            List<Attribute.Compound> res = List.nil();
+            for (Attribute.TypeCompound a : candidates) {
+                if (isCurrentSymbolsAnnotation(a, index))
+                    res = res.prepend(a);
+            }
+
+            return res.reverse();
+        }
+
+        // Helper to getAnnotation[s]
+        @Override
+        public <A extends Annotation> Attribute.Compound getAttribute(Class<A> annoType) {
+            String name = annoType.getName();
+
+            // Declaration annotations on type variables are stored in type attributes
+            // on the owner of the TypeVariableSymbol
+            List<Attribute.TypeCompound> candidates = owner.getRawTypeAttributes();
+            int index = owner.getTypeParameters().indexOf(this);
+            for (Attribute.TypeCompound anno : candidates)
+                if (isCurrentSymbolsAnnotation(anno, index) &&
+                    name.contentEquals(anno.type.tsym.flatName()))
+                    return anno;
+
+            return null;
+        }
+            //where:
+            boolean isCurrentSymbolsAnnotation(Attribute.TypeCompound anno, int index) {
+                return (anno.position.type == TargetType.CLASS_TYPE_PARAMETER ||
+                        anno.position.type == TargetType.METHOD_TYPE_PARAMETER) &&
+                        anno.position.parameter_index == index;
+            }
+
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+            return v.visitTypeParameter(this, p);
+        }
+    }
+    /** A class for module symbols.
+     */
+    public static class ModuleSymbol extends TypeSymbol
+            implements ModuleElement {
+
+        public Name version;
+        public JavaFileManager.Location sourceLocation;
+        public JavaFileManager.Location classLocation;
+        public JavaFileManager.Location patchLocation;
+        public JavaFileManager.Location patchOutputLocation;
+
+        /** All directives, in natural order. */
+        public List<com.sun.tools.javac.code.Directive> directives;
+        public List<com.sun.tools.javac.code.Directive.RequiresDirective> requires;
+        public List<com.sun.tools.javac.code.Directive.ExportsDirective> exports;
+        public List<com.sun.tools.javac.code.Directive.OpensDirective> opens;
+        public List<com.sun.tools.javac.code.Directive.ProvidesDirective> provides;
+        public List<com.sun.tools.javac.code.Directive.UsesDirective> uses;
+
+        public ClassSymbol module_info;
+
+        public PackageSymbol unnamedPackage;
+        public Map<Name, PackageSymbol> visiblePackages;
+        public Set<ModuleSymbol> readModules;
+        public List<Symbol> enclosedPackages = List.nil();
+
+        public Completer usesProvidesCompleter = Completer.NULL_COMPLETER;
+        public final Set<ModuleFlags> flags = EnumSet.noneOf(ModuleFlags.class);
+        public final Set<ModuleResolutionFlags> resolutionFlags = EnumSet.noneOf(ModuleResolutionFlags.class);
+
+        /**
+         * Create a ModuleSymbol with an associated module-info ClassSymbol.
+         */
+        public static ModuleSymbol create(Name name, Name module_info) {
+            ModuleSymbol msym = new ModuleSymbol(name, null);
+            ClassSymbol info = new ClassSymbol(Flags.MODULE, module_info, msym);
+            info.fullname = formFullName(module_info, msym);
+            info.flatname = info.fullname;
+            info.members_field = WriteableScope.create(info);
+            msym.module_info = info;
+            return msym;
+        }
+
+        public ModuleSymbol(Name name, Symbol owner) {
+            super(MDL, 0, name, null, owner);
+            Assert.checkNonNull(name);
+            this.type = new ModuleType(this);
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public Name getSimpleName() {
+            return Convert.shortName(name);
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public boolean isOpen() {
+            return flags.contains(ModuleFlags.OPEN);
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public boolean isUnnamed() {
+            return name.isEmpty() && owner == null;
+        }
+
+        @Override
+        public boolean isDeprecated() {
+            return hasDeprecatedAnnotation();
+        }
+
+        public boolean isNoModule() {
+            return false;
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public ElementKind getKind() {
+            return ElementKind.MODULE;
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public java.util.List<Directive> getDirectives() {
+            complete();
+            completeUsesProvides();
+            return Collections.unmodifiableList(directives);
+        }
+
+        public void completeUsesProvides() {
+            if (usesProvidesCompleter != Completer.NULL_COMPLETER) {
+                Completer c = usesProvidesCompleter;
+                usesProvidesCompleter = Completer.NULL_COMPLETER;
+                c.complete(this);
+            }
+        }
+
+        @Override
+        public ClassSymbol outermostClass() {
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            // TODO: the following strings should be localized
+            // Do this with custom anon subtypes in Symtab
+            String n = (name == null) ? "<unknown>"
+                    : (name.isEmpty()) ? "<unnamed>"
+                    : String.valueOf(name);
+            return n;
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+            return v.visitModule(this, p);
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public List<Symbol> getEnclosedElements() {
+            List<Symbol> list = List.nil();
+            for (Symbol sym : enclosedPackages) {
+                if (sym.members().anyMatch(m -> m.kind == TYP))
+                    list = list.prepend(sym);
+            }
+            return list;
+        }
+
+        public void reset() {
+            this.directives = null;
+            this.requires = null;
+            this.exports = null;
+            this.provides = null;
+            this.uses = null;
+            this.visiblePackages = null;
+        }
+
+    }
+
+    public enum ModuleFlags {
+        OPEN(0x0020),
+        SYNTHETIC(0x1000),
+        MANDATED(0x8000);
+
+        public static int value(Set<ModuleFlags> s) {
+            int v = 0;
+            for (ModuleFlags f: s)
+                v |= f.value;
+            return v;
+        }
+
+        private ModuleFlags(int value) {
+            this.value = value;
+        }
+
+        public final int value;
+    }
+
+    public enum ModuleResolutionFlags {
+        DO_NOT_RESOLVE_BY_DEFAULT(0x0001),
+        WARN_DEPRECATED(0x0002),
+        WARN_DEPRECATED_REMOVAL(0x0004),
+        WARN_INCUBATING(0x0008);
+
+        public static int value(Set<ModuleResolutionFlags> s) {
+            int v = 0;
+            for (ModuleResolutionFlags f: s)
+                v |= f.value;
+            return v;
+        }
+
+        private ModuleResolutionFlags(int value) {
+            this.value = value;
+        }
+
+        public final int value;
+    }
+
+    /** A class for package symbols
+     */
+    public static class PackageSymbol extends TypeSymbol
+        implements PackageElement {
+
+        public WriteableScope members_field;
+        public Name fullname;
+        public ClassSymbol package_info; // see bug 6443073
+        public ModuleSymbol modle;
+        // the file containing the documentation comments for the package
+        public JavaFileObject sourcefile;
+
+        public PackageSymbol(Name name, Type type, Symbol owner) {
+            super(PCK, 0, name, type, owner);
+            this.members_field = null;
+            this.fullname = formFullName(name, owner);
+        }
+
+        public PackageSymbol(Name name, Symbol owner) {
+            this(name, null, owner);
+            this.type = new PackageType(this);
+        }
+
+        public String toString() {
+            return fullname.toString();
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public Name getQualifiedName() {
+            return fullname;
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public boolean isUnnamed() {
+            return name.isEmpty() && owner != null;
+        }
+
+        public WriteableScope members() {
+            complete();
+            return members_field;
+        }
+
+        public long flags() {
+            complete();
+            return flags_field;
+        }
+
+        @Override
+        public List<Attribute.Compound> getRawAttributes() {
+            complete();
+            if (package_info != null) {
+                package_info.complete();
+                mergeAttributes();
+            }
+            return super.getRawAttributes();
+        }
+
+        private void mergeAttributes() {
+            if (metadata == null &&
+                package_info.metadata != null) {
+                metadata = new SymbolMetadata(this);
+                metadata.setAttributes(package_info.metadata);
+            }
+        }
+
+        /** A package "exists" if a type or package that exists has
+         *  been seen within it.
+         */
+        public boolean exists() {
+            return (flags_field & EXISTS) != 0;
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public ElementKind getKind() {
+            return ElementKind.PACKAGE;
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public Symbol getEnclosingElement() {
+            return modle != null && !modle.isNoModule() ? modle : null;
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+            return v.visitPackage(this, p);
+        }
+
+        public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
+            return v.visitPackageSymbol(this, p);
+        }
+
+        /**Resets the Symbol into the state good for next round of annotation processing.*/
+        public void reset() {
+            metadata = null;
+        }
+
+    }
+
+    /** A class for class symbols
+     */
+    public static class ClassSymbol extends TypeSymbol implements TypeElement {
+
+        /** a scope for all class members; variables, methods and inner classes
+         *  type parameters are not part of this scope
+         */
+        public WriteableScope members_field;
+
+        /** the fully qualified name of the class, i.e. pck.outer.inner.
+         *  null for anonymous classes
+         */
+        public Name fullname;
+
+        /** the fully qualified name of the class after converting to flat
+         *  representation, i.e. pck.outer$inner,
+         *  set externally for local and anonymous classes
+         */
+        public Name flatname;
+
+        /** the sourcefile where the class came from
+         */
+        public JavaFileObject sourcefile;
+
+        /** the classfile from where to load this class
+         *  this will have extension .class or .java
+         */
+        public JavaFileObject classfile;
+
+        /** the list of translated local classes (used for generating
+         * InnerClasses attribute)
+         */
+        public List<ClassSymbol> trans_local;
+
+        /** the constant pool of the class
+         */
+        public Pool pool;
+
+        /** the annotation metadata attached to this class */
+        private AnnotationTypeMetadata annotationTypeMetadata;
+
+        public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
+            super(TYP, flags, name, type, owner);
+            this.members_field = null;
+            this.fullname = formFullName(name, owner);
+            this.flatname = formFlatName(name, owner);
+            this.sourcefile = null;
+            this.classfile = null;
+            this.pool = null;
+            this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
+        }
+
+        public ClassSymbol(long flags, Name name, Symbol owner) {
+            this(
+                flags,
+                name,
+                new ClassType(Type.noType, null, null),
+                owner);
+            this.type.tsym = this;
+        }
+
+        /** The Java source which this symbol represents.
+         */
+        public String toString() {
+            return className();
+        }
+
+        public long flags() {
+            complete();
+            return flags_field;
+        }
+
+        public WriteableScope members() {
+            complete();
+            return members_field;
+        }
+
+        @Override
+        public List<Attribute.Compound> getRawAttributes() {
+            complete();
+            return super.getRawAttributes();
+        }
+
+        @Override
+        public List<Attribute.TypeCompound> getRawTypeAttributes() {
+            complete();
+            return super.getRawTypeAttributes();
+        }
+
+        public Type erasure(Types types) {
+            if (erasure_field == null)
+                erasure_field = new ClassType(types.erasure(type.getEnclosingType()),
+                                              List.nil(), this,
+                                              type.getMetadata());
+            return erasure_field;
+        }
+
+        public String className() {
+            if (name.isEmpty())
+                return
+                    Log.getLocalizedString("anonymous.class", flatname);
+            else
+                return fullname.toString();
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public Name getQualifiedName() {
+            return fullname;
+        }
+
+        public Name flatName() {
+            return flatname;
+        }
+
+        public boolean isSubClass(Symbol base, Types types) {
+            if (this == base) {
+                return true;
+            } else if ((base.flags() & INTERFACE) != 0) {
+                for (Type t = type; t.hasTag(CLASS); t = types.supertype(t))
+                    for (List<Type> is = types.interfaces(t);
+                         is.nonEmpty();
+                         is = is.tail)
+                        if (is.head.tsym.isSubClass(base, types)) return true;
+            } else {
+                for (Type t = type; t.hasTag(CLASS); t = types.supertype(t))
+                    if (t.tsym == base) return true;
+            }
+            return false;
+        }
+
+        /** Complete the elaboration of this symbol's definition.
+         */
+        public void complete() throws CompletionFailure {
+            try {
+                super.complete();
+            } catch (CompletionFailure ex) {
+                // quiet error recovery
+                flags_field |= (PUBLIC|STATIC);
+                this.type = new ErrorType(this, Type.noType);
+                throw ex;
+            }
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public List<Type> getInterfaces() {
+            complete();
+            if (type instanceof ClassType) {
+                ClassType t = (ClassType)type;
+                if (t.interfaces_field == null) // FIXME: shouldn't be null
+                    t.interfaces_field = List.nil();
+                if (t.all_interfaces_field != null)
+                    return Type.getModelTypes(t.all_interfaces_field);
+                return t.interfaces_field;
+            } else {
+                return List.nil();
+            }
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public Type getSuperclass() {
+            complete();
+            if (type instanceof ClassType) {
+                ClassType t = (ClassType)type;
+                if (t.supertype_field == null) // FIXME: shouldn't be null
+                    t.supertype_field = Type.noType;
+                // An interface has no superclass; its supertype is Object.
+                return t.isInterface()
+                    ? Type.noType
+                    : t.supertype_field.getModelType();
+            } else {
+                return Type.noType;
+            }
+        }
+
+        /**
+         * Returns the next class to search for inherited annotations or {@code null}
+         * if the next class can't be found.
+         */
+        private ClassSymbol getSuperClassToSearchForAnnotations() {
+
+            Type sup = getSuperclass();
+
+            if (!sup.hasTag(CLASS) || sup.isErroneous())
+                return null;
+
+            return (ClassSymbol) sup.tsym;
+        }
+
+
+        @Override
+        protected <A extends Annotation> A[] getInheritedAnnotations(Class<A> annoType) {
+
+            ClassSymbol sup = getSuperClassToSearchForAnnotations();
+
+            return sup == null ? super.getInheritedAnnotations(annoType)
+                               : sup.getAnnotationsByType(annoType);
+        }
+
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public ElementKind getKind() {
+            long flags = flags();
+            if ((flags & ANNOTATION) != 0)
+                return ElementKind.ANNOTATION_TYPE;
+            else if ((flags & INTERFACE) != 0)
+                return ElementKind.INTERFACE;
+            else if ((flags & ENUM) != 0)
+                return ElementKind.ENUM;
+            else
+                return ElementKind.CLASS;
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public Set<Modifier> getModifiers() {
+            long flags = flags();
+            return Flags.asModifierSet(flags & ~DEFAULT);
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public NestingKind getNestingKind() {
+            complete();
+            if (owner.kind == PCK)
+                return NestingKind.TOP_LEVEL;
+            else if (name.isEmpty())
+                return NestingKind.ANONYMOUS;
+            else if (owner.kind == MTH)
+                return NestingKind.LOCAL;
+            else
+                return NestingKind.MEMBER;
+        }
+
+
+        @Override
+        protected <A extends Annotation> Attribute.Compound getAttribute(final Class<A> annoType) {
+
+            Attribute.Compound attrib = super.getAttribute(annoType);
+
+            boolean inherited = annoType.isAnnotationPresent(Inherited.class);
+            if (attrib != null || !inherited)
+                return attrib;
+
+            // Search supertypes
+            ClassSymbol superType = getSuperClassToSearchForAnnotations();
+            return superType == null ? null
+                                     : superType.getAttribute(annoType);
+        }
+
+
+
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+            return v.visitType(this, p);
+        }
+
+        public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
+            return v.visitClassSymbol(this, p);
+        }
+
+        public void markAbstractIfNeeded(Types types) {
+            if (types.enter.getEnv(this) != null &&
+                (flags() & ENUM) != 0 && types.supertype(type).tsym == types.syms.enumSym &&
+                (flags() & (FINAL | ABSTRACT)) == 0) {
+                if (types.firstUnimplementedAbstract(this) != null)
+                    // add the ABSTRACT flag to an enum
+                    flags_field |= ABSTRACT;
+            }
+        }
+
+        /**Resets the Symbol into the state good for next round of annotation processing.*/
+        public void reset() {
+            kind = TYP;
+            erasure_field = null;
+            members_field = null;
+            flags_field = 0;
+            if (type instanceof ClassType) {
+                ClassType t = (ClassType)type;
+                t.setEnclosingType(Type.noType);
+                t.rank_field = -1;
+                t.typarams_field = null;
+                t.allparams_field = null;
+                t.supertype_field = null;
+                t.interfaces_field = null;
+                t.all_interfaces_field = null;
+            }
+            clearAnnotationMetadata();
+        }
+
+        public void clearAnnotationMetadata() {
+            metadata = null;
+            annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
+        }
+
+        @Override
+        public AnnotationTypeMetadata getAnnotationTypeMetadata() {
+            return annotationTypeMetadata;
+        }
+
+        @Override
+        public boolean isAnnotationType() {
+            return (flags_field & Flags.ANNOTATION) != 0;
+        }
+
+        public void setAnnotationTypeMetadata(AnnotationTypeMetadata a) {
+            Assert.checkNonNull(a);
+            Assert.check(!annotationTypeMetadata.isMetadataForAnnotationType());
+            this.annotationTypeMetadata = a;
+        }
+    }
+
+
+    /** A class for variable symbols
+     */
+    public static class VarSymbol extends Symbol implements VariableElement {
+
+        /** The variable's declaration position.
+         */
+        public int pos = Position.NOPOS;
+
+        /** The variable's address. Used for different purposes during
+         *  flow analysis, translation and code generation.
+         *  Flow analysis:
+         *    If this is a blank final or local variable, its sequence number.
+         *  Translation:
+         *    If this is a private field, its access number.
+         *  Code generation:
+         *    If this is a local variable, its logical slot number.
+         */
+        public int adr = -1;
+
+        /** Construct a variable symbol, given its flags, name, type and owner.
+         */
+        public VarSymbol(long flags, Name name, Type type, Symbol owner) {
+            super(VAR, flags, name, type, owner);
+        }
+
+        /** Clone this symbol with new owner.
+         */
+        public VarSymbol clone(Symbol newOwner) {
+            VarSymbol v = new VarSymbol(flags_field, name, type, newOwner) {
+                @Override
+                public Symbol baseSymbol() {
+                    return VarSymbol.this;
+                }
+            };
+            v.pos = pos;
+            v.adr = adr;
+            v.data = data;
+//          System.out.println("clone " + v + " in " + newOwner);//DEBUG
+            return v;
+        }
+
+        public String toString() {
+            return name.toString();
+        }
+
+        public Symbol asMemberOf(Type site, Types types) {
+            return new VarSymbol(flags_field, name, types.memberType(site, this), owner);
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public ElementKind getKind() {
+            long flags = flags();
+            if ((flags & PARAMETER) != 0) {
+                if (isExceptionParameter())
+                    return ElementKind.EXCEPTION_PARAMETER;
+                else
+                    return ElementKind.PARAMETER;
+            } else if ((flags & ENUM) != 0) {
+                return ElementKind.ENUM_CONSTANT;
+            } else if (owner.kind == TYP || owner.kind == ERR) {
+                return ElementKind.FIELD;
+            } else if (isResourceVariable()) {
+                return ElementKind.RESOURCE_VARIABLE;
+            } else {
+                return ElementKind.LOCAL_VARIABLE;
+            }
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+            return v.visitVariable(this, p);
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public Object getConstantValue() { // Mirror API
+            return Constants.decode(getConstValue(), type);
+        }
+
+        public void setLazyConstValue(final Env<AttrContext> env,
+                                      final Attr attr,
+                                      final JCVariableDecl variable)
+        {
+            setData((Callable<Object>)() -> attr.attribLazyConstantValue(env, variable, type));
+        }
+
+        /**
+         * The variable's constant value, if this is a constant.
+         * Before the constant value is evaluated, it points to an
+         * initializer environment.  If this is not a constant, it can
+         * be used for other stuff.
+         */
+        private Object data;
+
+        public boolean isExceptionParameter() {
+            return data == ElementKind.EXCEPTION_PARAMETER;
+        }
+
+        public boolean isResourceVariable() {
+            return data == ElementKind.RESOURCE_VARIABLE;
+        }
+
+        public Object getConstValue() {
+            // TODO: Consider if getConstValue and getConstantValue can be collapsed
+            if (data == ElementKind.EXCEPTION_PARAMETER ||
+                data == ElementKind.RESOURCE_VARIABLE) {
+                return null;
+            } else if (data instanceof Callable<?>) {
+                // In this case, this is a final variable, with an as
+                // yet unevaluated initializer.
+                Callable<?> eval = (Callable<?>)data;
+                data = null; // to make sure we don't evaluate this twice.
+                try {
+                    data = eval.call();
+                } catch (Exception ex) {
+                    throw new AssertionError(ex);
+                }
+            }
+            return data;
+        }
+
+        public void setData(Object data) {
+            Assert.check(!(data instanceof Env<?>), this);
+            this.data = data;
+        }
+
+        public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
+            return v.visitVarSymbol(this, p);
+        }
+    }
+
+    /** A class for method symbols.
+     */
+    public static class MethodSymbol extends Symbol implements ExecutableElement {
+
+        /** The code of the method. */
+        public Code code = null;
+
+        /** The extra (synthetic/mandated) parameters of the method. */
+        public List<VarSymbol> extraParams = List.nil();
+
+        /** The captured local variables in an anonymous class */
+        public List<VarSymbol> capturedLocals = List.nil();
+
+        /** The parameters of the method. */
+        public List<VarSymbol> params = null;
+
+        /** The names of the parameters */
+        public List<Name> savedParameterNames;
+
+        /** For an annotation type element, its default value if any.
+         *  The value is null if none appeared in the method
+         *  declaration.
+         */
+        public Attribute defaultValue = null;
+
+        /** Construct a method symbol, given its flags, name, type and owner.
+         */
+        public MethodSymbol(long flags, Name name, Type type, Symbol owner) {
+            super(MTH, flags, name, type, owner);
+            if (owner.type.hasTag(TYPEVAR)) Assert.error(owner + "." + name);
+        }
+
+        /** Clone this symbol with new owner.
+         */
+        public MethodSymbol clone(Symbol newOwner) {
+            MethodSymbol m = new MethodSymbol(flags_field, name, type, newOwner) {
+                @Override
+                public Symbol baseSymbol() {
+                    return MethodSymbol.this;
+                }
+            };
+            m.code = code;
+            return m;
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public Set<Modifier> getModifiers() {
+            long flags = flags();
+            return Flags.asModifierSet((flags & DEFAULT) != 0 ? flags & ~ABSTRACT : flags);
+        }
+
+        /** The Java source which this symbol represents.
+         */
+        public String toString() {
+            if ((flags() & BLOCK) != 0) {
+                return owner.name.toString();
+            } else {
+                String s = (name == name.table.names.init)
+                    ? owner.name.toString()
+                    : name.toString();
+                if (type != null) {
+                    if (type.hasTag(FORALL))
+                        s = "<" + ((ForAll)type).getTypeArguments() + ">" + s;
+                    s += "(" + type.argtypes((flags() & VARARGS) != 0) + ")";
+                }
+                return s;
+            }
+        }
+
+        public boolean isDynamic() {
+            return false;
+        }
+
+        /** find a symbol that this (proxy method) symbol implements.
+         *  @param    c       The class whose members are searched for
+         *                    implementations
+         */
+        public Symbol implemented(TypeSymbol c, Types types) {
+            Symbol impl = null;
+            for (List<Type> is = types.interfaces(c.type);
+                 impl == null && is.nonEmpty();
+                 is = is.tail) {
+                TypeSymbol i = is.head.tsym;
+                impl = implementedIn(i, types);
+                if (impl == null)
+                    impl = implemented(i, types);
+            }
+            return impl;
+        }
+
+        public Symbol implementedIn(TypeSymbol c, Types types) {
+            Symbol impl = null;
+            for (Symbol sym : c.members().getSymbolsByName(name)) {
+                if (this.overrides(sym, (TypeSymbol)owner, types, true) &&
+                    // FIXME: I suspect the following requires a
+                    // subst() for a parametric return type.
+                    types.isSameType(type.getReturnType(),
+                                     types.memberType(owner.type, sym).getReturnType())) {
+                    impl = sym;
+                }
+            }
+            return impl;
+        }
+
+        /** Will the erasure of this method be considered by the VM to
+         *  override the erasure of the other when seen from class `origin'?
+         */
+        public boolean binaryOverrides(Symbol _other, TypeSymbol origin, Types types) {
+            if (isConstructor() || _other.kind != MTH) return false;
+
+            if (this == _other) return true;
+            MethodSymbol other = (MethodSymbol)_other;
+
+            // check for a direct implementation
+            if (other.isOverridableIn((TypeSymbol)owner) &&
+                types.asSuper(owner.type, other.owner) != null &&
+                types.isSameType(erasure(types), other.erasure(types)))
+                return true;
+
+            // check for an inherited implementation
+            return
+                (flags() & ABSTRACT) == 0 &&
+                other.isOverridableIn(origin) &&
+                this.isMemberOf(origin, types) &&
+                types.isSameType(erasure(types), other.erasure(types));
+        }
+
+        /** The implementation of this (abstract) symbol in class origin,
+         *  from the VM's point of view, null if method does not have an
+         *  implementation in class.
+         *  @param origin   The class of which the implementation is a member.
+         */
+        public MethodSymbol binaryImplementation(ClassSymbol origin, Types types) {
+            for (TypeSymbol c = origin; c != null; c = types.supertype(c.type).tsym) {
+                for (Symbol sym : c.members().getSymbolsByName(name)) {
+                    if (sym.kind == MTH &&
+                        ((MethodSymbol)sym).binaryOverrides(this, origin, types))
+                        return (MethodSymbol)sym;
+                }
+            }
+            return null;
+        }
+
+        /** Does this symbol override `other' symbol, when both are seen as
+         *  members of class `origin'?  It is assumed that _other is a member
+         *  of origin.
+         *
+         *  It is assumed that both symbols have the same name.  The static
+         *  modifier is ignored for this test.
+         *
+         *  A quirk in the works is that if the receiver is a method symbol for
+         *  an inherited abstract method we answer false summarily all else being
+         *  immaterial. Abstract "own" methods (i.e `this' is a direct member of
+         *  origin) don't get rejected as summarily and are put to test against the
+         *  suitable criteria.
+         *
+         *  See JLS 8.4.6.1 (without transitivity) and 8.4.6.4
+         */
+        public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean checkResult) {
+            return overrides(_other, origin, types, checkResult, true);
+        }
+
+        /** Does this symbol override `other' symbol, when both are seen as
+         *  members of class `origin'?  It is assumed that _other is a member
+         *  of origin.
+         *
+         *  Caveat: If `this' is an abstract inherited member of origin, it is
+         *  deemed to override `other' only when `requireConcreteIfInherited'
+         *  is false.
+         *
+         *  It is assumed that both symbols have the same name.  The static
+         *  modifier is ignored for this test.
+         *
+         *  See JLS 8.4.6.1 (without transitivity) and 8.4.6.4
+         */
+        public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean checkResult,
+                                            boolean requireConcreteIfInherited) {
+            if (isConstructor() || _other.kind != MTH) return false;
+
+            if (this == _other) return true;
+            MethodSymbol other = (MethodSymbol)_other;
+
+            // check for a direct implementation
+            if (other.isOverridableIn((TypeSymbol)owner) &&
+                types.asSuper(owner.type, other.owner) != null) {
+                Type mt = types.memberType(owner.type, this);
+                Type ot = types.memberType(owner.type, other);
+                if (types.isSubSignature(mt, ot)) {
+                    if (!checkResult)
+                        return true;
+                    if (types.returnTypeSubstitutable(mt, ot))
+                        return true;
+                }
+            }
+
+            // check for an inherited implementation
+            if (((flags() & ABSTRACT) != 0 && requireConcreteIfInherited) ||
+                    ((other.flags() & ABSTRACT) == 0 && (other.flags() & DEFAULT) == 0) ||
+                    !other.isOverridableIn(origin) ||
+                    !this.isMemberOf(origin, types))
+                return false;
+
+            // assert types.asSuper(origin.type, other.owner) != null;
+            Type mt = types.memberType(origin.type, this);
+            Type ot = types.memberType(origin.type, other);
+            return
+                types.isSubSignature(mt, ot) &&
+                (!checkResult || types.resultSubtype(mt, ot, types.noWarnings));
+        }
+
+        private boolean isOverridableIn(TypeSymbol origin) {
+            // JLS 8.4.6.1
+            switch ((int)(flags_field & Flags.AccessFlags)) {
+            case Flags.PRIVATE:
+                return false;
+            case Flags.PUBLIC:
+                return !this.owner.isInterface() ||
+                        (flags_field & STATIC) == 0;
+            case Flags.PROTECTED:
+                return (origin.flags() & INTERFACE) == 0;
+            case 0:
+                // for package private: can only override in the same
+                // package
+                return
+                    this.packge() == origin.packge() &&
+                    (origin.flags() & INTERFACE) == 0;
+            default:
+                return false;
+            }
+        }
+
+        @Override
+        public boolean isInheritedIn(Symbol clazz, Types types) {
+            switch ((int)(flags_field & Flags.AccessFlags)) {
+                case PUBLIC:
+                    return !this.owner.isInterface() ||
+                            clazz == owner ||
+                            (flags_field & STATIC) == 0;
+                default:
+                    return super.isInheritedIn(clazz, types);
+            }
+        }
+
+        public boolean isLambdaMethod() {
+            return (flags() & LAMBDA_METHOD) == LAMBDA_METHOD;
+        }
+
+        /** The implementation of this (abstract) symbol in class origin;
+         *  null if none exists. Synthetic methods are not considered
+         *  as possible implementations.
+         */
+        public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult) {
+            return implementation(origin, types, checkResult, implementation_filter);
+        }
+        // where
+            public static final Filter<Symbol> implementation_filter = s ->
+                    s.kind == MTH && (s.flags() & SYNTHETIC) == 0;
+
+        public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult, Filter<Symbol> implFilter) {
+            MethodSymbol res = types.implementation(this, origin, checkResult, implFilter);
+            if (res != null)
+                return res;
+            // if origin is derived from a raw type, we might have missed
+            // an implementation because we do not know enough about instantiations.
+            // in this case continue with the supertype as origin.
+            if (types.isDerivedRaw(origin.type) && !origin.isInterface())
+                return implementation(types.supertype(origin.type).tsym, types, checkResult);
+            else
+                return null;
+        }
+
+        public List<VarSymbol> params() {
+            owner.complete();
+            if (params == null) {
+                // If ClassReader.saveParameterNames has been set true, then
+                // savedParameterNames will be set to a list of names that
+                // matches the types in type.getParameterTypes().  If any names
+                // were not found in the class file, those names in the list will
+                // be set to the empty name.
+                // If ClassReader.saveParameterNames has been set false, then
+                // savedParameterNames will be null.
+                List<Name> paramNames = savedParameterNames;
+                savedParameterNames = null;
+                // discard the provided names if the list of names is the wrong size.
+                if (paramNames == null || paramNames.size() != type.getParameterTypes().size()) {
+                    paramNames = List.nil();
+                }
+                ListBuffer<VarSymbol> buf = new ListBuffer<>();
+                List<Name> remaining = paramNames;
+                // assert: remaining and paramNames are both empty or both
+                // have same cardinality as type.getParameterTypes()
+                int i = 0;
+                for (Type t : type.getParameterTypes()) {
+                    Name paramName;
+                    if (remaining.isEmpty()) {
+                        // no names for any parameters available
+                        paramName = createArgName(i, paramNames);
+                    } else {
+                        paramName = remaining.head;
+                        remaining = remaining.tail;
+                        if (paramName.isEmpty()) {
+                            // no name for this specific parameter
+                            paramName = createArgName(i, paramNames);
+                        }
+                    }
+                    buf.append(new VarSymbol(PARAMETER, paramName, t, this));
+                    i++;
+                }
+                params = buf.toList();
+            }
+            return params;
+        }
+
+        // Create a name for the argument at position 'index' that is not in
+        // the exclude list. In normal use, either no names will have been
+        // provided, in which case the exclude list is empty, or all the names
+        // will have been provided, in which case this method will not be called.
+        private Name createArgName(int index, List<Name> exclude) {
+            String prefix = "arg";
+            while (true) {
+                Name argName = name.table.fromString(prefix + index);
+                if (!exclude.contains(argName))
+                    return argName;
+                prefix += "$";
+            }
+        }
+
+        public Symbol asMemberOf(Type site, Types types) {
+            return new MethodSymbol(flags_field, name, types.memberType(site, this), owner);
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public ElementKind getKind() {
+            if (name == name.table.names.init)
+                return ElementKind.CONSTRUCTOR;
+            else if (name == name.table.names.clinit)
+                return ElementKind.STATIC_INIT;
+            else if ((flags() & BLOCK) != 0)
+                return isStatic() ? ElementKind.STATIC_INIT : ElementKind.INSTANCE_INIT;
+            else
+                return ElementKind.METHOD;
+        }
+
+        public boolean isStaticOrInstanceInit() {
+            return getKind() == ElementKind.STATIC_INIT ||
+                    getKind() == ElementKind.INSTANCE_INIT;
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public Attribute getDefaultValue() {
+            return defaultValue;
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public List<VarSymbol> getParameters() {
+            return params();
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public boolean isVarArgs() {
+            return (flags() & VARARGS) != 0;
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public boolean isDefault() {
+            return (flags() & DEFAULT) != 0;
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+            return v.visitExecutable(this, p);
+        }
+
+        public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
+            return v.visitMethodSymbol(this, p);
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public Type getReceiverType() {
+            return asType().getReceiverType();
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public Type getReturnType() {
+            return asType().getReturnType();
+        }
+
+        @DefinedBy(Api.LANGUAGE_MODEL)
+        public List<Type> getThrownTypes() {
+            return asType().getThrownTypes();
+        }
+    }
+
+    /** A class for invokedynamic method calls.
+     */
+    public static class DynamicMethodSymbol extends MethodSymbol {
+
+        public Object[] staticArgs;
+        public Symbol bsm;
+        public int bsmKind;
+
+        public DynamicMethodSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) {
+            super(0, name, type, owner);
+            this.bsm = bsm;
+            this.bsmKind = bsmKind;
+            this.staticArgs = staticArgs;
+        }
+
+        @Override
+        public boolean isDynamic() {
+            return true;
+        }
+    }
+
+    /** A class for predefined operators.
+     */
+    public static class OperatorSymbol extends MethodSymbol {
+
+        public int opcode;
+        private int accessCode = Integer.MIN_VALUE;
+
+        public OperatorSymbol(Name name, Type type, int opcode, Symbol owner) {
+            super(PUBLIC | STATIC, name, type, owner);
+            this.opcode = opcode;
+        }
+
+        @Override
+        public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
+            return v.visitOperatorSymbol(this, p);
+        }
+
+        public int getAccessCode(Tag tag) {
+            if (accessCode != Integer.MIN_VALUE && !tag.isIncOrDecUnaryOp()) {
+                return accessCode;
+            }
+            accessCode = AccessCode.from(tag, opcode);
+            return accessCode;
+        }
+
+        /** Access codes for dereferencing, assignment,
+         *  and pre/post increment/decrement.
+
+         *  All access codes for accesses to the current class are even.
+         *  If a member of the superclass should be accessed instead (because
+         *  access was via a qualified super), add one to the corresponding code
+         *  for the current class, making the number odd.
+         *  This numbering scheme is used by the backend to decide whether
+         *  to issue an invokevirtual or invokespecial call.
+         *
+         *  @see Gen#visitSelect(JCFieldAccess tree)
+         */
+        public enum AccessCode {
+            UNKNOWN(-1, Tag.NO_TAG),
+            DEREF(0, Tag.NO_TAG),
+            ASSIGN(2, Tag.ASSIGN),
+            PREINC(4, Tag.PREINC),
+            PREDEC(6, Tag.PREDEC),
+            POSTINC(8, Tag.POSTINC),
+            POSTDEC(10, Tag.POSTDEC),
+            FIRSTASGOP(12, Tag.NO_TAG);
+
+            public final int code;
+            public final Tag tag;
+            public static final int numberOfAccessCodes = (lushrl - ishll + lxor + 2 - iadd) * 2 + FIRSTASGOP.code + 2;
+
+            AccessCode(int code, Tag tag) {
+                this.code = code;
+                this.tag = tag;
+            }
+
+            static public AccessCode getFromCode(int code) {
+                for (AccessCode aCodes : AccessCode.values()) {
+                    if (aCodes.code == code) {
+                        return aCodes;
+                    }
+                }
+                return UNKNOWN;
+            }
+
+            static int from(Tag tag, int opcode) {
+                /** Map bytecode of binary operation to access code of corresponding
+                *  assignment operation. This is always an even number.
+                */
+                switch (tag) {
+                    case PREINC:
+                        return AccessCode.PREINC.code;
+                    case PREDEC:
+                        return AccessCode.PREDEC.code;
+                    case POSTINC:
+                        return AccessCode.POSTINC.code;
+                    case POSTDEC:
+                        return AccessCode.POSTDEC.code;
+                }
+                if (iadd <= opcode && opcode <= lxor) {
+                    return (opcode - iadd) * 2 + FIRSTASGOP.code;
+                } else if (opcode == string_add) {
+                    return (lxor + 1 - iadd) * 2 + FIRSTASGOP.code;
+                } else if (ishll <= opcode && opcode <= lushrl) {
+                    return (opcode - ishll + lxor + 2 - iadd) * 2 + FIRSTASGOP.code;
+                }
+                return -1;
+            }
+        }
+    }
+
+    /** Symbol completer interface.
+     */
+    public static interface Completer {
+
+        /** Dummy completer to be used when the symbol has been completed or
+         * does not need completion.
+         */
+        public final static Completer NULL_COMPLETER = new Completer() {
+            public void complete(Symbol sym) { }
+            public boolean isTerminal() { return true; }
+        };
+
+        void complete(Symbol sym) throws CompletionFailure;
+
+        /** Returns true if this completer is <em>terminal</em>. A terminal
+         * completer is used as a place holder when the symbol is completed.
+         * Calling complete on a terminal completer will not affect the symbol.
+         *
+         * The dummy NULL_COMPLETER and the GraphDependencies completer are
+         * examples of terminal completers.
+         *
+         * @return true iff this completer is terminal
+         */
+        default boolean isTerminal() {
+            return false;
+        }
+    }
+
+    public static class CompletionFailure extends RuntimeException {
+        private static final long serialVersionUID = 0;
+        public Symbol sym;
+
+        /** A diagnostic object describing the failure
+         */
+        public JCDiagnostic diag;
+
+        public CompletionFailure(Symbol sym, JCDiagnostic diag) {
+            this.sym = sym;
+            this.diag = diag;
+//          this.printStackTrace();//DEBUG
+        }
+
+        public JCDiagnostic getDiagnostic() {
+            return diag;
+        }
+
+        @Override
+        public String getMessage() {
+            return diag.getMessage(null);
+        }
+
+        public JCDiagnostic getDetailValue() {
+            return diag;
+        }
+
+        @Override
+        public CompletionFailure initCause(Throwable cause) {
+            super.initCause(cause);
+            return this;
+        }
+
+    }
+
+    /**
+     * A visitor for symbols.  A visitor is used to implement operations
+     * (or relations) on symbols.  Most common operations on types are
+     * binary relations and this interface is designed for binary
+     * relations, that is, operations on the form
+     * Symbol&nbsp;&times;&nbsp;P&nbsp;&rarr;&nbsp;R.
+     * <!-- In plain text: Type x P -> R -->
+     *
+     * @param <R> the return type of the operation implemented by this
+     * visitor; use Void if no return type is needed.
+     * @param <P> the type of the second argument (the first being the
+     * symbol itself) of the operation implemented by this visitor; use
+     * Void if a second argument is not needed.
+     */
+    public interface Visitor<R,P> {
+        R visitClassSymbol(ClassSymbol s, P arg);
+        R visitMethodSymbol(MethodSymbol s, P arg);
+        R visitPackageSymbol(PackageSymbol s, P arg);
+        R visitOperatorSymbol(OperatorSymbol s, P arg);
+        R visitVarSymbol(VarSymbol s, P arg);
+        R visitTypeSymbol(TypeSymbol s, P arg);
+        R visitSymbol(Symbol s, P arg);
+    }
+}