src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java
changeset 47216 71c04702a3d5
parent 44393 ce94820fa9d1
child 47268 48ec75306997
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,3117 @@
+/*
+ * 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.tree;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.*;
+
+import javax.lang.model.element.Modifier;
+import javax.lang.model.type.TypeKind;
+import javax.tools.JavaFileObject;
+
+import com.sun.source.tree.*;
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Directive.RequiresDirective;
+import com.sun.tools.javac.code.Scope.*;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.List;
+
+import static com.sun.tools.javac.tree.JCTree.Tag.*;
+
+import javax.tools.JavaFileManager.Location;
+
+import com.sun.source.tree.ModuleTree.ModuleKind;
+import com.sun.tools.javac.code.Directive.ExportsDirective;
+import com.sun.tools.javac.code.Directive.OpensDirective;
+import com.sun.tools.javac.code.Type.ModuleType;
+
+/**
+ * Root class for abstract syntax tree nodes. It provides definitions
+ * for specific tree nodes as subclasses nested inside.
+ *
+ * <p>Each subclass is highly standardized.  It generally contains
+ * only tree fields for the syntactic subcomponents of the node.  Some
+ * classes that represent identifier uses or definitions also define a
+ * Symbol field that denotes the represented identifier.  Classes for
+ * non-local jumps also carry the jump target as a field.  The root
+ * class Tree itself defines fields for the tree's type and position.
+ * No other fields are kept in a tree node; instead parameters are
+ * passed to methods accessing the node.
+ *
+ * <p>Except for the methods defined by com.sun.source, the only
+ * method defined in subclasses is `visit' which applies a given
+ * visitor to the tree. The actual tree processing is done by visitor
+ * classes in other packages. The abstract class Visitor, as well as
+ * an Factory interface for trees, are defined as inner classes in
+ * Tree.
+ *
+ * <p>To avoid ambiguities with the Tree API in com.sun.source all sub
+ * classes should, by convention, start with JC (javac).
+ *
+ * <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>
+ *
+ * @see TreeMaker
+ * @see TreeInfo
+ * @see TreeTranslator
+ * @see Pretty
+ */
+public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
+
+    /* Tree tag values, identifying kinds of trees */
+    public enum Tag {
+        /** For methods that return an invalid tag if a given condition is not met
+         */
+        NO_TAG,
+
+        /** Toplevel nodes, of type TopLevel, representing entire source files.
+        */
+        TOPLEVEL,
+
+        /** Package level definitions.
+         */
+        PACKAGEDEF,
+
+        /** Import clauses, of type Import.
+         */
+        IMPORT,
+
+        /** Class definitions, of type ClassDef.
+         */
+        CLASSDEF,
+
+        /** Method definitions, of type MethodDef.
+         */
+        METHODDEF,
+
+        /** Variable definitions, of type VarDef.
+         */
+        VARDEF,
+
+        /** The no-op statement ";", of type Skip
+         */
+        SKIP,
+
+        /** Blocks, of type Block.
+         */
+        BLOCK,
+
+        /** Do-while loops, of type DoLoop.
+         */
+        DOLOOP,
+
+        /** While-loops, of type WhileLoop.
+         */
+        WHILELOOP,
+
+        /** For-loops, of type ForLoop.
+         */
+        FORLOOP,
+
+        /** Foreach-loops, of type ForeachLoop.
+         */
+        FOREACHLOOP,
+
+        /** Labelled statements, of type Labelled.
+         */
+        LABELLED,
+
+        /** Switch statements, of type Switch.
+         */
+        SWITCH,
+
+        /** Case parts in switch statements, of type Case.
+         */
+        CASE,
+
+        /** Synchronized statements, of type Synchonized.
+         */
+        SYNCHRONIZED,
+
+        /** Try statements, of type Try.
+         */
+        TRY,
+
+        /** Catch clauses in try statements, of type Catch.
+         */
+        CATCH,
+
+        /** Conditional expressions, of type Conditional.
+         */
+        CONDEXPR,
+
+        /** Conditional statements, of type If.
+         */
+        IF,
+
+        /** Expression statements, of type Exec.
+         */
+        EXEC,
+
+        /** Break statements, of type Break.
+         */
+        BREAK,
+
+        /** Continue statements, of type Continue.
+         */
+        CONTINUE,
+
+        /** Return statements, of type Return.
+         */
+        RETURN,
+
+        /** Throw statements, of type Throw.
+         */
+        THROW,
+
+        /** Assert statements, of type Assert.
+         */
+        ASSERT,
+
+        /** Method invocation expressions, of type Apply.
+         */
+        APPLY,
+
+        /** Class instance creation expressions, of type NewClass.
+         */
+        NEWCLASS,
+
+        /** Array creation expressions, of type NewArray.
+         */
+        NEWARRAY,
+
+        /** Lambda expression, of type Lambda.
+         */
+        LAMBDA,
+
+        /** Parenthesized subexpressions, of type Parens.
+         */
+        PARENS,
+
+        /** Assignment expressions, of type Assign.
+         */
+        ASSIGN,
+
+        /** Type cast expressions, of type TypeCast.
+         */
+        TYPECAST,
+
+        /** Type test expressions, of type TypeTest.
+         */
+        TYPETEST,
+
+        /** Indexed array expressions, of type Indexed.
+         */
+        INDEXED,
+
+        /** Selections, of type Select.
+         */
+        SELECT,
+
+        /** Member references, of type Reference.
+         */
+        REFERENCE,
+
+        /** Simple identifiers, of type Ident.
+         */
+        IDENT,
+
+        /** Literals, of type Literal.
+         */
+        LITERAL,
+
+        /** Basic type identifiers, of type TypeIdent.
+         */
+        TYPEIDENT,
+
+        /** Array types, of type TypeArray.
+         */
+        TYPEARRAY,
+
+        /** Parameterized types, of type TypeApply.
+         */
+        TYPEAPPLY,
+
+        /** Union types, of type TypeUnion.
+         */
+        TYPEUNION,
+
+        /** Intersection types, of type TypeIntersection.
+         */
+        TYPEINTERSECTION,
+
+        /** Formal type parameters, of type TypeParameter.
+         */
+        TYPEPARAMETER,
+
+        /** Type argument.
+         */
+        WILDCARD,
+
+        /** Bound kind: extends, super, exact, or unbound
+         */
+        TYPEBOUNDKIND,
+
+        /** metadata: Annotation.
+         */
+        ANNOTATION,
+
+        /** metadata: Type annotation.
+         */
+        TYPE_ANNOTATION,
+
+        /** metadata: Modifiers
+         */
+        MODIFIERS,
+
+        /** An annotated type tree.
+         */
+        ANNOTATED_TYPE,
+
+        /** Error trees, of type Erroneous.
+         */
+        ERRONEOUS,
+
+        /** Unary operators, of type Unary.
+         */
+        POS,                             // +
+        NEG,                             // -
+        NOT,                             // !
+        COMPL,                           // ~
+        PREINC,                          // ++ _
+        PREDEC,                          // -- _
+        POSTINC,                         // _ ++
+        POSTDEC,                         // _ --
+
+        /** unary operator for null reference checks, only used internally.
+         */
+        NULLCHK,
+
+        /** Binary operators, of type Binary.
+         */
+        OR,                              // ||
+        AND,                             // &&
+        BITOR,                           // |
+        BITXOR,                          // ^
+        BITAND,                          // &
+        EQ,                              // ==
+        NE,                              // !=
+        LT,                              // <
+        GT,                              // >
+        LE,                              // <=
+        GE,                              // >=
+        SL,                              // <<
+        SR,                              // >>
+        USR,                             // >>>
+        PLUS,                            // +
+        MINUS,                           // -
+        MUL,                             // *
+        DIV,                             // /
+        MOD,                             // %
+
+        /** Assignment operators, of type Assignop.
+         */
+        BITOR_ASG(BITOR),                // |=
+        BITXOR_ASG(BITXOR),              // ^=
+        BITAND_ASG(BITAND),              // &=
+
+        SL_ASG(SL),                      // <<=
+        SR_ASG(SR),                      // >>=
+        USR_ASG(USR),                    // >>>=
+        PLUS_ASG(PLUS),                  // +=
+        MINUS_ASG(MINUS),                // -=
+        MUL_ASG(MUL),                    // *=
+        DIV_ASG(DIV),                    // /=
+        MOD_ASG(MOD),                    // %=
+
+        MODULEDEF,
+        EXPORTS,
+        OPENS,
+        PROVIDES,
+        REQUIRES,
+        USES,
+
+        /** A synthetic let expression, of type LetExpr.
+         */
+        LETEXPR;                         // ala scheme
+
+        private final Tag noAssignTag;
+
+        private static final int numberOfOperators = MOD.ordinal() - POS.ordinal() + 1;
+
+        private Tag(Tag noAssignTag) {
+            this.noAssignTag = noAssignTag;
+        }
+
+        private Tag() {
+            this(null);
+        }
+
+        public static int getNumberOfOperators() {
+            return numberOfOperators;
+        }
+
+        public Tag noAssignOp() {
+            if (noAssignTag != null)
+                return noAssignTag;
+            throw new AssertionError("noAssignOp() method is not available for non assignment tags");
+        }
+
+        public boolean isPostUnaryOp() {
+            return (this == POSTINC || this == POSTDEC);
+        }
+
+        public boolean isIncOrDecUnaryOp() {
+            return (this == PREINC || this == PREDEC || this == POSTINC || this == POSTDEC);
+        }
+
+        public boolean isAssignop() {
+            return noAssignTag != null;
+        }
+
+        public int operatorIndex() {
+            return (this.ordinal() - POS.ordinal());
+        }
+    }
+
+    /* The (encoded) position in the source file. @see util.Position.
+     */
+    public int pos;
+
+    /* The type of this node.
+     */
+    public Type type;
+
+    /* The tag of this node -- one of the constants declared above.
+     */
+    public abstract Tag getTag();
+
+    /* Returns true if the tag of this node is equals to tag.
+     */
+    public boolean hasTag(Tag tag) {
+        return tag == getTag();
+    }
+
+    /** Convert a tree to a pretty-printed string. */
+    @Override
+    public String toString() {
+        StringWriter s = new StringWriter();
+        try {
+            new Pretty(s, false).printExpr(this);
+        }
+        catch (IOException e) {
+            // should never happen, because StringWriter is defined
+            // never to throw any IOExceptions
+            throw new AssertionError(e);
+        }
+        return s.toString();
+    }
+
+    /** Set position field and return this tree.
+     */
+    public JCTree setPos(int pos) {
+        this.pos = pos;
+        return this;
+    }
+
+    /** Set type field and return this tree.
+     */
+    public JCTree setType(Type type) {
+        this.type = type;
+        return this;
+    }
+
+    /** Visit this tree with a given visitor.
+     */
+    public abstract void accept(Visitor v);
+
+    @DefinedBy(Api.COMPILER_TREE)
+    public abstract <R,D> R accept(TreeVisitor<R,D> v, D d);
+
+    /** Return a shallow copy of this tree.
+     */
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch(CloneNotSupportedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Get a default position for this tree node.
+     */
+    public DiagnosticPosition pos() {
+        return this;
+    }
+
+    // for default DiagnosticPosition
+    public JCTree getTree() {
+        return this;
+    }
+
+    // for default DiagnosticPosition
+    public int getStartPosition() {
+        return TreeInfo.getStartPos(this);
+    }
+
+    // for default DiagnosticPosition
+    public int getPreferredPosition() {
+        return pos;
+    }
+
+    // for default DiagnosticPosition
+    public int getEndPosition(EndPosTable endPosTable) {
+        return TreeInfo.getEndPos(this, endPosTable);
+    }
+
+    /**
+     * Everything in one source file is kept in a {@linkplain JCCompilationUnit} structure.
+     */
+    public static class JCCompilationUnit extends JCTree implements CompilationUnitTree {
+        /** All definitions in this file (ClassDef, Import, and Skip) */
+        public List<JCTree> defs;
+        /** The source file name. */
+        public JavaFileObject sourcefile;
+        /** The module to which this compilation unit belongs. */
+        public ModuleSymbol modle;
+        /** The location in which this compilation unit was found. */
+        public Location locn;
+        /** The package to which this compilation unit belongs. */
+        public PackageSymbol packge;
+        /** A scope containing top level classes. */
+        public WriteableScope toplevelScope;
+        /** A scope for all named imports. */
+        public NamedImportScope namedImportScope;
+        /** A scope for all import-on-demands. */
+        public StarImportScope starImportScope;
+        /** Line starting positions, defined only if option -g is set. */
+        public Position.LineMap lineMap = null;
+        /** A table that stores all documentation comments indexed by the tree
+         * nodes they refer to. defined only if option -s is set. */
+        public DocCommentTable docComments = null;
+        /* An object encapsulating ending positions of source ranges indexed by
+         * the tree nodes they belong to. Defined only if option -Xjcov is set. */
+        public EndPosTable endPositions = null;
+        protected JCCompilationUnit(List<JCTree> defs) {
+            this.defs = defs;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTopLevel(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.COMPILATION_UNIT; }
+
+        public JCModuleDecl getModuleDecl() {
+            for (JCTree tree : defs) {
+                if (tree.hasTag(MODULEDEF)) {
+                    return (JCModuleDecl) tree;
+                }
+            }
+
+            return null;
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCPackageDecl getPackage() {
+            // PackageDecl must be the first entry if it exists
+            if (!defs.isEmpty() && defs.head.hasTag(PACKAGEDEF))
+                return (JCPackageDecl)defs.head;
+            return null;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCAnnotation> getPackageAnnotations() {
+            JCPackageDecl pd = getPackage();
+            return pd != null ? pd.getAnnotations() : List.nil();
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public ExpressionTree getPackageName() {
+            JCPackageDecl pd = getPackage();
+            return pd != null ? pd.getPackageName() : null;
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCImport> getImports() {
+            ListBuffer<JCImport> imports = new ListBuffer<>();
+            for (JCTree tree : defs) {
+                if (tree.hasTag(IMPORT))
+                    imports.append((JCImport)tree);
+                else if (!tree.hasTag(PACKAGEDEF) && !tree.hasTag(SKIP))
+                    break;
+            }
+            return imports.toList();
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JavaFileObject getSourceFile() {
+            return sourcefile;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Position.LineMap getLineMap() {
+            return lineMap;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCTree> getTypeDecls() {
+            List<JCTree> typeDefs;
+            for (typeDefs = defs; !typeDefs.isEmpty(); typeDefs = typeDefs.tail)
+                if (!typeDefs.head.hasTag(PACKAGEDEF) && !typeDefs.head.hasTag(IMPORT))
+                    break;
+            return typeDefs;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitCompilationUnit(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return TOPLEVEL;
+        }
+    }
+
+    /**
+     * Package definition.
+     */
+    public static class JCPackageDecl extends JCTree implements PackageTree {
+        public List<JCAnnotation> annotations;
+        /** The tree representing the package clause. */
+        public JCExpression pid;
+        public PackageSymbol packge;
+        public JCPackageDecl(List<JCAnnotation> annotations, JCExpression pid) {
+            this.annotations = annotations;
+            this.pid = pid;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitPackageDef(this); }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.PACKAGE;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCAnnotation> getAnnotations() {
+            return annotations;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getPackageName() {
+            return pid;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitPackage(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return PACKAGEDEF;
+        }
+    }
+
+    /**
+     * An import clause.
+     */
+    public static class JCImport extends JCTree implements ImportTree {
+        public boolean staticImport;
+        /** The imported class(es). */
+        public JCTree qualid;
+        public com.sun.tools.javac.code.Scope importScope;
+        protected JCImport(JCTree qualid, boolean importStatic) {
+            this.qualid = qualid;
+            this.staticImport = importStatic;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitImport(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public boolean isStatic() { return staticImport; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getQualifiedIdentifier() { return qualid; }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.IMPORT; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitImport(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return IMPORT;
+        }
+    }
+
+    public static abstract class JCStatement extends JCTree implements StatementTree {
+        @Override
+        public JCStatement setType(Type type) {
+            super.setType(type);
+            return this;
+        }
+        @Override
+        public JCStatement setPos(int pos) {
+            super.setPos(pos);
+            return this;
+        }
+    }
+
+    public static abstract class JCExpression extends JCTree implements ExpressionTree {
+        @Override
+        public JCExpression setType(Type type) {
+            super.setType(type);
+            return this;
+        }
+        @Override
+        public JCExpression setPos(int pos) {
+            super.setPos(pos);
+            return this;
+        }
+
+        public boolean isPoly() { return false; }
+        public boolean isStandalone() { return true; }
+    }
+
+    /**
+     * Common supertype for all poly expression trees (lambda, method references,
+     * conditionals, method and constructor calls)
+     */
+    public static abstract class JCPolyExpression extends JCExpression {
+
+        /**
+         * A poly expression can only be truly 'poly' in certain contexts
+         */
+        public enum PolyKind {
+            /** poly expression to be treated as a standalone expression */
+            STANDALONE,
+            /** true poly expression */
+            POLY
+        }
+
+        /** is this poly expression a 'true' poly expression? */
+        public PolyKind polyKind;
+
+        @Override public boolean isPoly() { return polyKind == PolyKind.POLY; }
+        @Override public boolean isStandalone() { return polyKind == PolyKind.STANDALONE; }
+    }
+
+    /**
+     * Common supertype for all functional expression trees (lambda and method references)
+     */
+    public static abstract class JCFunctionalExpression extends JCPolyExpression {
+
+        public JCFunctionalExpression() {
+            //a functional expression is always a 'true' poly
+            polyKind = PolyKind.POLY;
+        }
+
+        /** list of target types inferred for this functional expression. */
+        public List<Type> targets;
+
+        public Type getDescriptorType(Types types) {
+            return targets.nonEmpty() ? types.findDescriptorType(targets.head) : types.createErrorType(null);
+        }
+    }
+
+    /**
+     * A class definition.
+     */
+    public static class JCClassDecl extends JCStatement implements ClassTree {
+        /** the modifiers */
+        public JCModifiers mods;
+        /** the name of the class */
+        public Name name;
+        /** formal class parameters */
+        public List<JCTypeParameter> typarams;
+        /** the classes this class extends */
+        public JCExpression extending;
+        /** the interfaces implemented by this class */
+        public List<JCExpression> implementing;
+        /** all variables and methods defined in this class */
+        public List<JCTree> defs;
+        /** the symbol */
+        public ClassSymbol sym;
+        protected JCClassDecl(JCModifiers mods,
+                           Name name,
+                           List<JCTypeParameter> typarams,
+                           JCExpression extending,
+                           List<JCExpression> implementing,
+                           List<JCTree> defs,
+                           ClassSymbol sym)
+        {
+            this.mods = mods;
+            this.name = name;
+            this.typarams = typarams;
+            this.extending = extending;
+            this.implementing = implementing;
+            this.defs = defs;
+            this.sym = sym;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitClassDef(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            if ((mods.flags & Flags.ANNOTATION) != 0)
+                return Kind.ANNOTATION_TYPE;
+            else if ((mods.flags & Flags.INTERFACE) != 0)
+                return Kind.INTERFACE;
+            else if ((mods.flags & Flags.ENUM) != 0)
+                return Kind.ENUM;
+            else
+                return Kind.CLASS;
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCModifiers getModifiers() { return mods; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getSimpleName() { return name; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCTypeParameter> getTypeParameters() {
+            return typarams;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExtendsClause() { return extending; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getImplementsClause() {
+            return implementing;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCTree> getMembers() {
+            return defs;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitClass(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return CLASSDEF;
+        }
+    }
+
+    /**
+     * A method definition.
+     */
+    public static class JCMethodDecl extends JCTree implements MethodTree {
+        /** method modifiers */
+        public JCModifiers mods;
+        /** method name */
+        public Name name;
+        /** type of method return value */
+        public JCExpression restype;
+        /** type parameters */
+        public List<JCTypeParameter> typarams;
+        /** receiver parameter */
+        public JCVariableDecl recvparam;
+        /** value parameters */
+        public List<JCVariableDecl> params;
+        /** exceptions thrown by this method */
+        public List<JCExpression> thrown;
+        /** statements in the method */
+        public JCBlock body;
+        /** default value, for annotation types */
+        public JCExpression defaultValue;
+        /** method symbol */
+        public MethodSymbol sym;
+        protected JCMethodDecl(JCModifiers mods,
+                            Name name,
+                            JCExpression restype,
+                            List<JCTypeParameter> typarams,
+                            JCVariableDecl recvparam,
+                            List<JCVariableDecl> params,
+                            List<JCExpression> thrown,
+                            JCBlock body,
+                            JCExpression defaultValue,
+                            MethodSymbol sym)
+        {
+            this.mods = mods;
+            this.name = name;
+            this.restype = restype;
+            this.typarams = typarams;
+            this.params = params;
+            this.recvparam = recvparam;
+            // TODO: do something special if the given type is null?
+            // receiver != null ? receiver : List.<JCTypeAnnotation>nil());
+            this.thrown = thrown;
+            this.body = body;
+            this.defaultValue = defaultValue;
+            this.sym = sym;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitMethodDef(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.METHOD; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCModifiers getModifiers() { return mods; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getName() { return name; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getReturnType() { return restype; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCTypeParameter> getTypeParameters() {
+            return typarams;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCVariableDecl> getParameters() {
+            return params;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCVariableDecl getReceiverParameter() { return recvparam; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getThrows() {
+            return thrown;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCBlock getBody() { return body; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getDefaultValue() { // for annotation types
+            return defaultValue;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitMethod(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return METHODDEF;
+        }
+  }
+
+    /**
+     * A variable definition.
+     */
+    public static class JCVariableDecl extends JCStatement implements VariableTree {
+        /** variable modifiers */
+        public JCModifiers mods;
+        /** variable name */
+        public Name name;
+        /** variable name expression */
+        public JCExpression nameexpr;
+        /** type of the variable */
+        public JCExpression vartype;
+        /** variable's initial value */
+        public JCExpression init;
+        /** symbol */
+        public VarSymbol sym;
+
+        protected JCVariableDecl(JCModifiers mods,
+                         Name name,
+                         JCExpression vartype,
+                         JCExpression init,
+                         VarSymbol sym) {
+            this.mods = mods;
+            this.name = name;
+            this.vartype = vartype;
+            this.init = init;
+            this.sym = sym;
+        }
+
+        protected JCVariableDecl(JCModifiers mods,
+                         JCExpression nameexpr,
+                         JCExpression vartype) {
+            this(mods, null, vartype, null, null);
+            this.nameexpr = nameexpr;
+            if (nameexpr.hasTag(Tag.IDENT)) {
+                this.name = ((JCIdent)nameexpr).name;
+            } else {
+                // Only other option is qualified name x.y.this;
+                this.name = ((JCFieldAccess)nameexpr).name;
+            }
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitVarDef(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.VARIABLE; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCModifiers getModifiers() { return mods; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getName() { return name; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getNameExpression() { return nameexpr; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getType() { return vartype; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getInitializer() {
+            return init;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitVariable(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return VARDEF;
+        }
+    }
+
+    /**
+     * A no-op statement ";".
+     */
+    public static class JCSkip extends JCStatement implements EmptyStatementTree {
+        protected JCSkip() {
+        }
+        @Override
+        public void accept(Visitor v) { v.visitSkip(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.EMPTY_STATEMENT; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitEmptyStatement(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return SKIP;
+        }
+    }
+
+    /**
+     * A statement block.
+     */
+    public static class JCBlock extends JCStatement implements BlockTree {
+        /** flags */
+        public long flags;
+        /** statements */
+        public List<JCStatement> stats;
+        /** Position of closing brace, optional. */
+        public int endpos = Position.NOPOS;
+        protected JCBlock(long flags, List<JCStatement> stats) {
+            this.stats = stats;
+            this.flags = flags;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitBlock(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.BLOCK; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCStatement> getStatements() {
+            return stats;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public boolean isStatic() { return (flags & Flags.STATIC) != 0; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitBlock(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return BLOCK;
+        }
+    }
+
+    /**
+     * A do loop
+     */
+    public static class JCDoWhileLoop extends JCStatement implements DoWhileLoopTree {
+        public JCStatement body;
+        public JCExpression cond;
+        protected JCDoWhileLoop(JCStatement body, JCExpression cond) {
+            this.body = body;
+            this.cond = cond;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitDoLoop(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.DO_WHILE_LOOP; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getCondition() { return cond; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCStatement getStatement() { return body; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitDoWhileLoop(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return DOLOOP;
+        }
+    }
+
+    /**
+     * A while loop
+     */
+    public static class JCWhileLoop extends JCStatement implements WhileLoopTree {
+        public JCExpression cond;
+        public JCStatement body;
+        protected JCWhileLoop(JCExpression cond, JCStatement body) {
+            this.cond = cond;
+            this.body = body;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitWhileLoop(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.WHILE_LOOP; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getCondition() { return cond; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCStatement getStatement() { return body; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitWhileLoop(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return WHILELOOP;
+        }
+    }
+
+    /**
+     * A for loop.
+     */
+    public static class JCForLoop extends JCStatement implements ForLoopTree {
+        public List<JCStatement> init;
+        public JCExpression cond;
+        public List<JCExpressionStatement> step;
+        public JCStatement body;
+        protected JCForLoop(List<JCStatement> init,
+                          JCExpression cond,
+                          List<JCExpressionStatement> update,
+                          JCStatement body)
+        {
+            this.init = init;
+            this.cond = cond;
+            this.step = update;
+            this.body = body;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitForLoop(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.FOR_LOOP; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getCondition() { return cond; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCStatement getStatement() { return body; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCStatement> getInitializer() {
+            return init;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpressionStatement> getUpdate() {
+            return step;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitForLoop(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return FORLOOP;
+        }
+    }
+
+    /**
+     * The enhanced for loop.
+     */
+    public static class JCEnhancedForLoop extends JCStatement implements EnhancedForLoopTree {
+        public JCVariableDecl var;
+        public JCExpression expr;
+        public JCStatement body;
+        protected JCEnhancedForLoop(JCVariableDecl var, JCExpression expr, JCStatement body) {
+            this.var = var;
+            this.expr = expr;
+            this.body = body;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitForeachLoop(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.ENHANCED_FOR_LOOP; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCVariableDecl getVariable() { return var; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return expr; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCStatement getStatement() { return body; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitEnhancedForLoop(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return FOREACHLOOP;
+        }
+    }
+
+    /**
+     * A labelled expression or statement.
+     */
+    public static class JCLabeledStatement extends JCStatement implements LabeledStatementTree {
+        public Name label;
+        public JCStatement body;
+        protected JCLabeledStatement(Name label, JCStatement body) {
+            this.label = label;
+            this.body = body;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitLabelled(this); }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.LABELED_STATEMENT; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getLabel() { return label; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCStatement getStatement() { return body; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitLabeledStatement(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return LABELLED;
+        }
+    }
+
+    /**
+     * A "switch ( ) { }" construction.
+     */
+    public static class JCSwitch extends JCStatement implements SwitchTree {
+        public JCExpression selector;
+        public List<JCCase> cases;
+        protected JCSwitch(JCExpression selector, List<JCCase> cases) {
+            this.selector = selector;
+            this.cases = cases;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitSwitch(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.SWITCH; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return selector; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCCase> getCases() { return cases; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitSwitch(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return SWITCH;
+        }
+    }
+
+    /**
+     * A "case  :" of a switch.
+     */
+    public static class JCCase extends JCStatement implements CaseTree {
+        public JCExpression pat;
+        public List<JCStatement> stats;
+        protected JCCase(JCExpression pat, List<JCStatement> stats) {
+            this.pat = pat;
+            this.stats = stats;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitCase(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.CASE; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return pat; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCStatement> getStatements() { return stats; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitCase(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return CASE;
+        }
+    }
+
+    /**
+     * A synchronized block.
+     */
+    public static class JCSynchronized extends JCStatement implements SynchronizedTree {
+        public JCExpression lock;
+        public JCBlock body;
+        protected JCSynchronized(JCExpression lock, JCBlock body) {
+            this.lock = lock;
+            this.body = body;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitSynchronized(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.SYNCHRONIZED; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return lock; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCBlock getBlock() { return body; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitSynchronized(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return SYNCHRONIZED;
+        }
+    }
+
+    /**
+     * A "try { } catch ( ) { } finally { }" block.
+     */
+    public static class JCTry extends JCStatement implements TryTree {
+        public JCBlock body;
+        public List<JCCatch> catchers;
+        public JCBlock finalizer;
+        public List<JCTree> resources;
+        public boolean finallyCanCompleteNormally;
+        protected JCTry(List<JCTree> resources,
+                        JCBlock body,
+                        List<JCCatch> catchers,
+                        JCBlock finalizer) {
+            this.body = body;
+            this.catchers = catchers;
+            this.finalizer = finalizer;
+            this.resources = resources;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTry(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.TRY; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCBlock getBlock() { return body; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCCatch> getCatches() {
+            return catchers;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCBlock getFinallyBlock() { return finalizer; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitTry(this, d);
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<JCTree> getResources() {
+            return resources;
+        }
+        @Override
+        public Tag getTag() {
+            return TRY;
+        }
+    }
+
+    /**
+     * A catch block.
+     */
+    public static class JCCatch extends JCTree implements CatchTree {
+        public JCVariableDecl param;
+        public JCBlock body;
+        protected JCCatch(JCVariableDecl param, JCBlock body) {
+            this.param = param;
+            this.body = body;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitCatch(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.CATCH; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCVariableDecl getParameter() { return param; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCBlock getBlock() { return body; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitCatch(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return CATCH;
+        }
+    }
+
+    /**
+     * A ( ) ? ( ) : ( ) conditional expression
+     */
+    public static class JCConditional extends JCPolyExpression implements ConditionalExpressionTree {
+        public JCExpression cond;
+        public JCExpression truepart;
+        public JCExpression falsepart;
+        protected JCConditional(JCExpression cond,
+                              JCExpression truepart,
+                              JCExpression falsepart)
+        {
+            this.cond = cond;
+            this.truepart = truepart;
+            this.falsepart = falsepart;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitConditional(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.CONDITIONAL_EXPRESSION; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getCondition() { return cond; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getTrueExpression() { return truepart; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getFalseExpression() { return falsepart; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitConditionalExpression(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return CONDEXPR;
+        }
+    }
+
+    /**
+     * An "if ( ) { } else { }" block
+     */
+    public static class JCIf extends JCStatement implements IfTree {
+        public JCExpression cond;
+        public JCStatement thenpart;
+        public JCStatement elsepart;
+        protected JCIf(JCExpression cond,
+                     JCStatement thenpart,
+                     JCStatement elsepart)
+        {
+            this.cond = cond;
+            this.thenpart = thenpart;
+            this.elsepart = elsepart;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitIf(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.IF; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getCondition() { return cond; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCStatement getThenStatement() { return thenpart; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCStatement getElseStatement() { return elsepart; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitIf(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return IF;
+        }
+    }
+
+    /**
+     * an expression statement
+     */
+    public static class JCExpressionStatement extends JCStatement implements ExpressionStatementTree {
+        /** expression structure */
+        public JCExpression expr;
+        protected JCExpressionStatement(JCExpression expr)
+        {
+            this.expr = expr;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitExec(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.EXPRESSION_STATEMENT; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return expr; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitExpressionStatement(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return EXEC;
+        }
+
+        /** Convert a expression-statement tree to a pretty-printed string. */
+        @Override
+        public String toString() {
+            StringWriter s = new StringWriter();
+            try {
+                new Pretty(s, false).printStat(this);
+            }
+            catch (IOException e) {
+                // should never happen, because StringWriter is defined
+                // never to throw any IOExceptions
+                throw new AssertionError(e);
+            }
+            return s.toString();
+        }
+    }
+
+    /**
+     * A break from a loop or switch.
+     */
+    public static class JCBreak extends JCStatement implements BreakTree {
+        public Name label;
+        public JCTree target;
+        protected JCBreak(Name label, JCTree target) {
+            this.label = label;
+            this.target = target;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitBreak(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.BREAK; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getLabel() { return label; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitBreak(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return BREAK;
+        }
+    }
+
+    /**
+     * A continue of a loop.
+     */
+    public static class JCContinue extends JCStatement implements ContinueTree {
+        public Name label;
+        public JCTree target;
+        protected JCContinue(Name label, JCTree target) {
+            this.label = label;
+            this.target = target;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitContinue(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.CONTINUE; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getLabel() { return label; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitContinue(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return CONTINUE;
+        }
+    }
+
+    /**
+     * A return statement.
+     */
+    public static class JCReturn extends JCStatement implements ReturnTree {
+        public JCExpression expr;
+        protected JCReturn(JCExpression expr) {
+            this.expr = expr;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitReturn(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.RETURN; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return expr; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitReturn(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return RETURN;
+        }
+    }
+
+    /**
+     * A throw statement.
+     */
+    public static class JCThrow extends JCStatement implements ThrowTree {
+        public JCExpression expr;
+        protected JCThrow(JCExpression expr) {
+            this.expr = expr;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitThrow(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.THROW; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return expr; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitThrow(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return THROW;
+        }
+    }
+
+    /**
+     * An assert statement.
+     */
+    public static class JCAssert extends JCStatement implements AssertTree {
+        public JCExpression cond;
+        public JCExpression detail;
+        protected JCAssert(JCExpression cond, JCExpression detail) {
+            this.cond = cond;
+            this.detail = detail;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitAssert(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.ASSERT; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getCondition() { return cond; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getDetail() { return detail; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitAssert(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return ASSERT;
+        }
+    }
+
+    /**
+     * A method invocation
+     */
+    public static class JCMethodInvocation extends JCPolyExpression implements MethodInvocationTree {
+        public List<JCExpression> typeargs;
+        public JCExpression meth;
+        public List<JCExpression> args;
+        public Type varargsElement;
+        protected JCMethodInvocation(List<JCExpression> typeargs,
+                        JCExpression meth,
+                        List<JCExpression> args)
+        {
+            this.typeargs = (typeargs == null) ? List.nil()
+                                               : typeargs;
+            this.meth = meth;
+            this.args = args;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitApply(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.METHOD_INVOCATION; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getTypeArguments() {
+            return typeargs;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getMethodSelect() { return meth; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getArguments() {
+            return args;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitMethodInvocation(this, d);
+        }
+        @Override
+        public JCMethodInvocation setType(Type type) {
+            super.setType(type);
+            return this;
+        }
+        @Override
+        public Tag getTag() {
+            return(APPLY);
+        }
+    }
+
+    /**
+     * A new(...) operation.
+     */
+    public static class JCNewClass extends JCPolyExpression implements NewClassTree {
+        public JCExpression encl;
+        public List<JCExpression> typeargs;
+        public JCExpression clazz;
+        public List<JCExpression> args;
+        public JCClassDecl def;
+        public Symbol constructor;
+        public Type varargsElement;
+        public Type constructorType;
+        protected JCNewClass(JCExpression encl,
+                           List<JCExpression> typeargs,
+                           JCExpression clazz,
+                           List<JCExpression> args,
+                           JCClassDecl def)
+        {
+            this.encl = encl;
+            this.typeargs = (typeargs == null) ? List.nil()
+                                               : typeargs;
+            this.clazz = clazz;
+            this.args = args;
+            this.def = def;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitNewClass(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.NEW_CLASS; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getEnclosingExpression() { // expr.new C< ... > ( ... )
+            return encl;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getTypeArguments() {
+            return typeargs;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getIdentifier() { return clazz; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getArguments() {
+            return args;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCClassDecl getClassBody() { return def; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitNewClass(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return NEWCLASS;
+        }
+    }
+
+    /**
+     * A new[...] operation.
+     */
+    public static class JCNewArray extends JCExpression implements NewArrayTree {
+        public JCExpression elemtype;
+        public List<JCExpression> dims;
+        // type annotations on inner-most component
+        public List<JCAnnotation> annotations;
+        // type annotations on dimensions
+        public List<List<JCAnnotation>> dimAnnotations;
+        public List<JCExpression> elems;
+        protected JCNewArray(JCExpression elemtype,
+                           List<JCExpression> dims,
+                           List<JCExpression> elems)
+        {
+            this.elemtype = elemtype;
+            this.dims = dims;
+            this.annotations = List.nil();
+            this.dimAnnotations = List.nil();
+            this.elems = elems;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitNewArray(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.NEW_ARRAY; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getType() { return elemtype; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getDimensions() {
+            return dims;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getInitializers() {
+            return elems;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitNewArray(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return NEWARRAY;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<JCAnnotation> getAnnotations() {
+            return annotations;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<List<JCAnnotation>> getDimAnnotations() {
+            return dimAnnotations;
+        }
+    }
+
+    /**
+     * A lambda expression.
+     */
+    public static class JCLambda extends JCFunctionalExpression implements LambdaExpressionTree {
+
+        public enum ParameterKind {
+            IMPLICIT,
+            EXPLICIT
+        }
+
+        public List<JCVariableDecl> params;
+        public JCTree body;
+        public boolean canCompleteNormally = true;
+        public ParameterKind paramKind;
+
+        public JCLambda(List<JCVariableDecl> params,
+                        JCTree body) {
+            this.params = params;
+            this.body = body;
+            if (params.isEmpty() ||
+                params.head.vartype != null) {
+                paramKind = ParameterKind.EXPLICIT;
+            } else {
+                paramKind = ParameterKind.IMPLICIT;
+            }
+        }
+        @Override
+        public Tag getTag() {
+            return LAMBDA;
+        }
+        @Override
+        public void accept(Visitor v) {
+            v.visitLambda(this);
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitLambdaExpression(this, d);
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.LAMBDA_EXPRESSION;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getBody() {
+            return body;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public java.util.List<? extends VariableTree> getParameters() {
+            return params;
+        }
+        @Override
+        public JCLambda setType(Type type) {
+            super.setType(type);
+            return this;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public BodyKind getBodyKind() {
+            return body.hasTag(BLOCK) ?
+                    BodyKind.STATEMENT :
+                    BodyKind.EXPRESSION;
+        }
+    }
+
+    /**
+     * A parenthesized subexpression ( ... )
+     */
+    public static class JCParens extends JCExpression implements ParenthesizedTree {
+        public JCExpression expr;
+        protected JCParens(JCExpression expr) {
+            this.expr = expr;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitParens(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.PARENTHESIZED; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return expr; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitParenthesized(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return PARENS;
+        }
+    }
+
+    /**
+     * A assignment with "=".
+     */
+    public static class JCAssign extends JCExpression implements AssignmentTree {
+        public JCExpression lhs;
+        public JCExpression rhs;
+        protected JCAssign(JCExpression lhs, JCExpression rhs) {
+            this.lhs = lhs;
+            this.rhs = rhs;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitAssign(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.ASSIGNMENT; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getVariable() { return lhs; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return rhs; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitAssignment(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return ASSIGN;
+        }
+    }
+
+    public static abstract class JCOperatorExpression extends JCExpression {
+        public enum OperandPos {
+            LEFT,
+            RIGHT
+        }
+
+        protected Tag opcode;
+        public OperatorSymbol operator;
+
+        public OperatorSymbol getOperator() {
+            return operator;
+        }
+
+        @Override
+        public Tag getTag() {
+            return opcode;
+        }
+
+        public abstract JCExpression getOperand(OperandPos pos);
+    }
+
+    /**
+     * An assignment with "+=", "|=" ...
+     */
+    public static class JCAssignOp extends JCOperatorExpression implements CompoundAssignmentTree {
+        public JCExpression lhs;
+        public JCExpression rhs;
+        protected JCAssignOp(Tag opcode, JCTree lhs, JCTree rhs, OperatorSymbol operator) {
+            this.opcode = opcode;
+            this.lhs = (JCExpression)lhs;
+            this.rhs = (JCExpression)rhs;
+            this.operator = operator;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitAssignop(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return TreeInfo.tagToKind(getTag()); }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getVariable() { return lhs; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return rhs; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitCompoundAssignment(this, d);
+        }
+        @Override
+        public JCExpression getOperand(OperandPos pos) {
+            return pos == OperandPos.LEFT ? lhs : rhs;
+        }
+    }
+
+    /**
+     * A unary operation.
+     */
+    public static class JCUnary extends JCOperatorExpression implements UnaryTree {
+        public JCExpression arg;
+        protected JCUnary(Tag opcode, JCExpression arg) {
+            this.opcode = opcode;
+            this.arg = arg;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitUnary(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return TreeInfo.tagToKind(getTag()); }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return arg; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitUnary(this, d);
+        }
+        public void setTag(Tag tag) {
+            opcode = tag;
+        }
+        @Override
+        public JCExpression getOperand(OperandPos pos) {
+            return arg;
+        }
+    }
+
+    /**
+     * A binary operation.
+     */
+    public static class JCBinary extends JCOperatorExpression implements BinaryTree {
+        public JCExpression lhs;
+        public JCExpression rhs;
+        protected JCBinary(Tag opcode,
+                         JCExpression lhs,
+                         JCExpression rhs,
+                         OperatorSymbol operator) {
+            this.opcode = opcode;
+            this.lhs = lhs;
+            this.rhs = rhs;
+            this.operator = operator;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitBinary(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return TreeInfo.tagToKind(getTag()); }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getLeftOperand() { return lhs; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getRightOperand() { return rhs; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitBinary(this, d);
+        }
+        @Override
+        public JCExpression getOperand(OperandPos pos) {
+            return pos == OperandPos.LEFT ? lhs : rhs;
+        }
+    }
+
+    /**
+     * A type cast.
+     */
+    public static class JCTypeCast extends JCExpression implements TypeCastTree {
+        public JCTree clazz;
+        public JCExpression expr;
+        protected JCTypeCast(JCTree clazz, JCExpression expr) {
+            this.clazz = clazz;
+            this.expr = expr;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeCast(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.TYPE_CAST; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getType() { return clazz; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return expr; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitTypeCast(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return TYPECAST;
+        }
+    }
+
+    /**
+     * A type test.
+     */
+    public static class JCInstanceOf extends JCExpression implements InstanceOfTree {
+        public JCExpression expr;
+        public JCTree clazz;
+        protected JCInstanceOf(JCExpression expr, JCTree clazz) {
+            this.expr = expr;
+            this.clazz = clazz;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeTest(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.INSTANCE_OF; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getType() { return clazz; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return expr; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitInstanceOf(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return TYPETEST;
+        }
+    }
+
+    /**
+     * An array selection
+     */
+    public static class JCArrayAccess extends JCExpression implements ArrayAccessTree {
+        public JCExpression indexed;
+        public JCExpression index;
+        protected JCArrayAccess(JCExpression indexed, JCExpression index) {
+            this.indexed = indexed;
+            this.index = index;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitIndexed(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.ARRAY_ACCESS; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return indexed; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getIndex() { return index; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitArrayAccess(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return INDEXED;
+        }
+    }
+
+    /**
+     * Selects through packages and classes
+     */
+    public static class JCFieldAccess extends JCExpression implements MemberSelectTree {
+        /** selected Tree hierarchy */
+        public JCExpression selected;
+        /** name of field to select thru */
+        public Name name;
+        /** symbol of the selected class */
+        public Symbol sym;
+        protected JCFieldAccess(JCExpression selected, Name name, Symbol sym) {
+            this.selected = selected;
+            this.name = name;
+            this.sym = sym;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitSelect(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.MEMBER_SELECT; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return selected; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitMemberSelect(this, d);
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getIdentifier() { return name; }
+        @Override
+        public Tag getTag() {
+            return SELECT;
+        }
+    }
+
+    /**
+     * Selects a member expression.
+     */
+    public static class JCMemberReference extends JCFunctionalExpression implements MemberReferenceTree {
+
+        public ReferenceMode mode;
+        public ReferenceKind kind;
+        public Name name;
+        public JCExpression expr;
+        public List<JCExpression> typeargs;
+        public Symbol sym;
+        public Type varargsElement;
+        public PolyKind refPolyKind;
+        public boolean ownerAccessible;
+        private OverloadKind overloadKind;
+        public Type referentType;
+
+        public enum OverloadKind {
+            OVERLOADED,
+            UNOVERLOADED
+        }
+
+        /**
+         * Javac-dependent classification for member references, based
+         * on relevant properties w.r.t. code-generation
+         */
+        public enum ReferenceKind {
+            /** super # instMethod */
+            SUPER(ReferenceMode.INVOKE, false),
+            /** Type # instMethod */
+            UNBOUND(ReferenceMode.INVOKE, true),
+            /** Type # staticMethod */
+            STATIC(ReferenceMode.INVOKE, false),
+            /** Expr # instMethod */
+            BOUND(ReferenceMode.INVOKE, false),
+            /** Inner # new */
+            IMPLICIT_INNER(ReferenceMode.NEW, false),
+            /** Toplevel # new */
+            TOPLEVEL(ReferenceMode.NEW, false),
+            /** ArrayType # new */
+            ARRAY_CTOR(ReferenceMode.NEW, false);
+
+            final ReferenceMode mode;
+            final boolean unbound;
+
+            private ReferenceKind(ReferenceMode mode, boolean unbound) {
+                this.mode = mode;
+                this.unbound = unbound;
+            }
+
+            public boolean isUnbound() {
+                return unbound;
+            }
+        }
+
+        public JCMemberReference(ReferenceMode mode, Name name, JCExpression expr, List<JCExpression> typeargs) {
+            this.mode = mode;
+            this.name = name;
+            this.expr = expr;
+            this.typeargs = typeargs;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitReference(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.MEMBER_REFERENCE; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public ReferenceMode getMode() { return mode; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getQualifierExpression() { return expr; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Name getName() { return name; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getTypeArguments() { return typeargs; }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitMemberReference(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return REFERENCE;
+        }
+        public boolean hasKind(ReferenceKind kind) {
+            return this.kind == kind;
+        }
+
+        /**
+         * @return the overloadKind
+         */
+        public OverloadKind getOverloadKind() {
+            return overloadKind;
+        }
+
+        /**
+         * @param overloadKind the overloadKind to set
+         */
+        public void setOverloadKind(OverloadKind overloadKind) {
+            this.overloadKind = overloadKind;
+        }
+    }
+
+    /**
+     * An identifier
+     */
+    public static class JCIdent extends JCExpression implements IdentifierTree {
+        /** the name */
+        public Name name;
+        /** the symbol */
+        public Symbol sym;
+        protected JCIdent(Name name, Symbol sym) {
+            this.name = name;
+            this.sym = sym;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitIdent(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.IDENTIFIER; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getName() { return name; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitIdentifier(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return IDENT;
+        }
+    }
+
+    /**
+     * A constant value given literally.
+     */
+    public static class JCLiteral extends JCExpression implements LiteralTree {
+        public TypeTag typetag;
+        /** value representation */
+        public Object value;
+        protected JCLiteral(TypeTag typetag, Object value) {
+            this.typetag = typetag;
+            this.value = value;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitLiteral(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return typetag.getKindLiteral();
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Object getValue() {
+            switch (typetag) {
+                case BOOLEAN:
+                    int bi = (Integer) value;
+                    return (bi != 0);
+                case CHAR:
+                    int ci = (Integer) value;
+                    char c = (char) ci;
+                    if (c != ci)
+                        throw new AssertionError("bad value for char literal");
+                    return c;
+                default:
+                    return value;
+            }
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitLiteral(this, d);
+        }
+        @Override
+        public JCLiteral setType(Type type) {
+            super.setType(type);
+            return this;
+        }
+        @Override
+        public Tag getTag() {
+            return LITERAL;
+        }
+    }
+
+    /**
+     * Identifies a basic type.
+     * @see TypeTag
+     */
+    public static class JCPrimitiveTypeTree extends JCExpression implements PrimitiveTypeTree {
+        /** the basic type id */
+        public TypeTag typetag;
+        protected JCPrimitiveTypeTree(TypeTag typetag) {
+            this.typetag = typetag;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeIdent(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.PRIMITIVE_TYPE; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public TypeKind getPrimitiveTypeKind() {
+            return typetag.getPrimitiveTypeKind();
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitPrimitiveType(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return TYPEIDENT;
+        }
+    }
+
+    /**
+     * An array type, A[]
+     */
+    public static class JCArrayTypeTree extends JCExpression implements ArrayTypeTree {
+        public JCExpression elemtype;
+        protected JCArrayTypeTree(JCExpression elemtype) {
+            this.elemtype = elemtype;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeArray(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.ARRAY_TYPE; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getType() { return elemtype; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitArrayType(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return TYPEARRAY;
+        }
+    }
+
+    /**
+     * A parameterized type, {@literal T<...>}
+     */
+    public static class JCTypeApply extends JCExpression implements ParameterizedTypeTree {
+        public JCExpression clazz;
+        public List<JCExpression> arguments;
+        protected JCTypeApply(JCExpression clazz, List<JCExpression> arguments) {
+            this.clazz = clazz;
+            this.arguments = arguments;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeApply(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.PARAMETERIZED_TYPE; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getType() { return clazz; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getTypeArguments() {
+            return arguments;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitParameterizedType(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return TYPEAPPLY;
+        }
+    }
+
+    /**
+     * A union type, T1 | T2 | ... Tn (used in multicatch statements)
+     */
+    public static class JCTypeUnion extends JCExpression implements UnionTypeTree {
+
+        public List<JCExpression> alternatives;
+
+        protected JCTypeUnion(List<JCExpression> components) {
+            this.alternatives = components;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeUnion(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.UNION_TYPE; }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getTypeAlternatives() {
+            return alternatives;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitUnionType(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return TYPEUNION;
+        }
+    }
+
+    /**
+     * An intersection type, {@code T1 & T2 & ... Tn} (used in cast expressions)
+     */
+    public static class JCTypeIntersection extends JCExpression implements IntersectionTypeTree {
+
+        public List<JCExpression> bounds;
+
+        protected JCTypeIntersection(List<JCExpression> bounds) {
+            this.bounds = bounds;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeIntersection(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.INTERSECTION_TYPE; }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getBounds() {
+            return bounds;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitIntersectionType(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return TYPEINTERSECTION;
+        }
+    }
+
+    /**
+     * A formal class parameter.
+     */
+    public static class JCTypeParameter extends JCTree implements TypeParameterTree {
+        /** name */
+        public Name name;
+        /** bounds */
+        public List<JCExpression> bounds;
+        /** type annotations on type parameter */
+        public List<JCAnnotation> annotations;
+        protected JCTypeParameter(Name name, List<JCExpression> bounds, List<JCAnnotation> annotations) {
+            this.name = name;
+            this.bounds = bounds;
+            this.annotations = annotations;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeParameter(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.TYPE_PARAMETER; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getName() { return name; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getBounds() {
+            return bounds;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCAnnotation> getAnnotations() {
+            return annotations;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitTypeParameter(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return TYPEPARAMETER;
+        }
+    }
+
+    public static class JCWildcard extends JCExpression implements WildcardTree {
+        public TypeBoundKind kind;
+        public JCTree inner;
+        protected JCWildcard(TypeBoundKind kind, JCTree inner) {
+            this.kind = Assert.checkNonNull(kind);
+            this.inner = inner;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitWildcard(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            switch (kind.kind) {
+            case UNBOUND:
+                return Kind.UNBOUNDED_WILDCARD;
+            case EXTENDS:
+                return Kind.EXTENDS_WILDCARD;
+            case SUPER:
+                return Kind.SUPER_WILDCARD;
+            default:
+                throw new AssertionError("Unknown wildcard bound " + kind);
+            }
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getBound() { return inner; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitWildcard(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return Tag.WILDCARD;
+        }
+    }
+
+    public static class TypeBoundKind extends JCTree {
+        public BoundKind kind;
+        protected TypeBoundKind(BoundKind kind) {
+            this.kind = kind;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitTypeBoundKind(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            throw new AssertionError("TypeBoundKind is not part of a public API");
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            throw new AssertionError("TypeBoundKind is not part of a public API");
+        }
+        @Override
+        public Tag getTag() {
+            return TYPEBOUNDKIND;
+        }
+    }
+
+    public static class JCAnnotation extends JCExpression implements AnnotationTree {
+        // Either Tag.ANNOTATION or Tag.TYPE_ANNOTATION
+        private Tag tag;
+
+        public JCTree annotationType;
+        public List<JCExpression> args;
+        public Attribute.Compound attribute;
+
+        protected JCAnnotation(Tag tag, JCTree annotationType, List<JCExpression> args) {
+            this.tag = tag;
+            this.annotationType = annotationType;
+            this.args = args;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitAnnotation(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return TreeInfo.tagToKind(getTag()); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCTree getAnnotationType() { return annotationType; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getArguments() {
+            return args;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitAnnotation(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return tag;
+        }
+    }
+
+    public static class JCModifiers extends JCTree implements com.sun.source.tree.ModifiersTree {
+        public long flags;
+        public List<JCAnnotation> annotations;
+        protected JCModifiers(long flags, List<JCAnnotation> annotations) {
+            this.flags = flags;
+            this.annotations = annotations;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitModifiers(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.MODIFIERS; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public Set<Modifier> getFlags() {
+            return Flags.asModifierSet(flags);
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCAnnotation> getAnnotations() {
+            return annotations;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitModifiers(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return MODIFIERS;
+        }
+    }
+
+    public static class JCAnnotatedType extends JCExpression implements com.sun.source.tree.AnnotatedTypeTree {
+        // type annotations
+        public List<JCAnnotation> annotations;
+        public JCExpression underlyingType;
+
+        protected JCAnnotatedType(List<JCAnnotation> annotations, JCExpression underlyingType) {
+            Assert.check(annotations != null && annotations.nonEmpty());
+            this.annotations = annotations;
+            this.underlyingType = underlyingType;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitAnnotatedType(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.ANNOTATED_TYPE; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCAnnotation> getAnnotations() {
+            return annotations;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getUnderlyingType() {
+            return underlyingType;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitAnnotatedType(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return ANNOTATED_TYPE;
+        }
+    }
+
+    public static abstract class JCDirective extends JCTree
+        implements DirectiveTree {
+    }
+
+    public static class JCModuleDecl extends JCTree implements ModuleTree {
+        public JCModifiers mods;
+        public ModuleType type;
+        private final ModuleKind kind;
+        public JCExpression qualId;
+        public List<JCDirective> directives;
+        public ModuleSymbol sym;
+
+        protected JCModuleDecl(JCModifiers mods, ModuleKind kind,
+                JCExpression qualId, List<JCDirective> directives) {
+            this.mods = mods;
+            this.kind = kind;
+            this.qualId = qualId;
+            this.directives = directives;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitModuleDef(this); }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.MODULE;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<? extends AnnotationTree> getAnnotations() {
+            return mods.annotations;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public ModuleKind getModuleType() {
+            return kind;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getName() {
+            return qualId;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<JCDirective> getDirectives() {
+            return directives;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitModule(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return MODULEDEF;
+        }
+    }
+
+    public static class JCExports extends JCDirective
+            implements ExportsTree {
+        public JCExpression qualid;
+        public List<JCExpression> moduleNames;
+        public ExportsDirective directive;
+
+        protected JCExports(JCExpression qualId, List<JCExpression> moduleNames) {
+            this.qualid = qualId;
+            this.moduleNames = moduleNames;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitExports(this); }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.EXPORTS;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getPackageName() {
+            return qualid;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getModuleNames() {
+            return moduleNames;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitExports(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return Tag.EXPORTS;
+        }
+    }
+
+    public static class JCOpens extends JCDirective
+            implements OpensTree {
+        public JCExpression qualid;
+        public List<JCExpression> moduleNames;
+        public OpensDirective directive;
+
+        protected JCOpens(JCExpression qualId, List<JCExpression> moduleNames) {
+            this.qualid = qualId;
+            this.moduleNames = moduleNames;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitOpens(this); }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.OPENS;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getPackageName() {
+            return qualid;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getModuleNames() {
+            return moduleNames;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitOpens(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return Tag.OPENS;
+        }
+    }
+
+    public static class JCProvides extends JCDirective
+            implements ProvidesTree {
+        public JCExpression serviceName;
+        public List<JCExpression> implNames;
+
+        protected JCProvides(JCExpression serviceName, List<JCExpression> implNames) {
+            this.serviceName = serviceName;
+            this.implNames = implNames;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitProvides(this); }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.PROVIDES;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitProvides(this, d);
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getServiceName() {
+            return serviceName;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<JCExpression> getImplementationNames() {
+            return implNames;
+        }
+
+        @Override
+        public Tag getTag() {
+            return PROVIDES;
+        }
+    }
+
+    public static class JCRequires extends JCDirective
+            implements RequiresTree {
+        public boolean isTransitive;
+        public boolean isStaticPhase;
+        public JCExpression moduleName;
+        public RequiresDirective directive;
+
+        protected JCRequires(boolean isTransitive, boolean isStaticPhase, JCExpression moduleName) {
+            this.isTransitive = isTransitive;
+            this.isStaticPhase = isStaticPhase;
+            this.moduleName = moduleName;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitRequires(this); }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.REQUIRES;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitRequires(this, d);
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public boolean isTransitive() {
+            return isTransitive;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public boolean isStatic() {
+            return isStaticPhase;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getModuleName() {
+            return moduleName;
+        }
+
+        @Override
+        public Tag getTag() {
+            return REQUIRES;
+        }
+    }
+
+    public static class JCUses extends JCDirective
+            implements UsesTree {
+        public JCExpression qualid;
+
+        protected JCUses(JCExpression qualId) {
+            this.qualid = qualId;
+        }
+
+        @Override
+        public void accept(Visitor v) { v.visitUses(this); }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.USES;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getServiceName() {
+            return qualid;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitUses(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return USES;
+        }
+    }
+
+    public static class JCErroneous extends JCExpression
+            implements ErroneousTree {
+        public List<? extends JCTree> errs;
+        protected JCErroneous(List<? extends JCTree> errs) {
+            this.errs = errs;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitErroneous(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.ERRONEOUS; }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<? extends JCTree> getErrorTrees() {
+            return errs;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitErroneous(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return ERRONEOUS;
+        }
+    }
+
+    /** (let int x = 3; in x+2) */
+    public static class LetExpr extends JCExpression {
+        public List<JCVariableDecl> defs;
+        public JCExpression expr;
+        protected LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
+            this.defs = defs;
+            this.expr = expr;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitLetExpr(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            throw new AssertionError("LetExpr is not part of a public API");
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            throw new AssertionError("LetExpr is not part of a public API");
+        }
+        @Override
+        public Tag getTag() {
+            return LETEXPR;
+        }
+    }
+
+    /** An interface for tree factories
+     */
+    public interface Factory {
+        JCCompilationUnit TopLevel(List<JCTree> defs);
+        JCPackageDecl PackageDecl(List<JCAnnotation> annotations,
+                                  JCExpression pid);
+        JCImport Import(JCTree qualid, boolean staticImport);
+        JCClassDecl ClassDef(JCModifiers mods,
+                          Name name,
+                          List<JCTypeParameter> typarams,
+                          JCExpression extending,
+                          List<JCExpression> implementing,
+                          List<JCTree> defs);
+        JCMethodDecl MethodDef(JCModifiers mods,
+                            Name name,
+                            JCExpression restype,
+                            List<JCTypeParameter> typarams,
+                            JCVariableDecl recvparam,
+                            List<JCVariableDecl> params,
+                            List<JCExpression> thrown,
+                            JCBlock body,
+                            JCExpression defaultValue);
+        JCVariableDecl VarDef(JCModifiers mods,
+                      Name name,
+                      JCExpression vartype,
+                      JCExpression init);
+        JCSkip Skip();
+        JCBlock Block(long flags, List<JCStatement> stats);
+        JCDoWhileLoop DoLoop(JCStatement body, JCExpression cond);
+        JCWhileLoop WhileLoop(JCExpression cond, JCStatement body);
+        JCForLoop ForLoop(List<JCStatement> init,
+                        JCExpression cond,
+                        List<JCExpressionStatement> step,
+                        JCStatement body);
+        JCEnhancedForLoop ForeachLoop(JCVariableDecl var, JCExpression expr, JCStatement body);
+        JCLabeledStatement Labelled(Name label, JCStatement body);
+        JCSwitch Switch(JCExpression selector, List<JCCase> cases);
+        JCCase Case(JCExpression pat, List<JCStatement> stats);
+        JCSynchronized Synchronized(JCExpression lock, JCBlock body);
+        JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
+        JCTry Try(List<JCTree> resources,
+                  JCBlock body,
+                  List<JCCatch> catchers,
+                  JCBlock finalizer);
+        JCCatch Catch(JCVariableDecl param, JCBlock body);
+        JCConditional Conditional(JCExpression cond,
+                                JCExpression thenpart,
+                                JCExpression elsepart);
+        JCIf If(JCExpression cond, JCStatement thenpart, JCStatement elsepart);
+        JCExpressionStatement Exec(JCExpression expr);
+        JCBreak Break(Name label);
+        JCContinue Continue(Name label);
+        JCReturn Return(JCExpression expr);
+        JCThrow Throw(JCExpression expr);
+        JCAssert Assert(JCExpression cond, JCExpression detail);
+        JCMethodInvocation Apply(List<JCExpression> typeargs,
+                    JCExpression fn,
+                    List<JCExpression> args);
+        JCNewClass NewClass(JCExpression encl,
+                          List<JCExpression> typeargs,
+                          JCExpression clazz,
+                          List<JCExpression> args,
+                          JCClassDecl def);
+        JCNewArray NewArray(JCExpression elemtype,
+                          List<JCExpression> dims,
+                          List<JCExpression> elems);
+        JCParens Parens(JCExpression expr);
+        JCAssign Assign(JCExpression lhs, JCExpression rhs);
+        JCAssignOp Assignop(Tag opcode, JCTree lhs, JCTree rhs);
+        JCUnary Unary(Tag opcode, JCExpression arg);
+        JCBinary Binary(Tag opcode, JCExpression lhs, JCExpression rhs);
+        JCTypeCast TypeCast(JCTree expr, JCExpression type);
+        JCInstanceOf TypeTest(JCExpression expr, JCTree clazz);
+        JCArrayAccess Indexed(JCExpression indexed, JCExpression index);
+        JCFieldAccess Select(JCExpression selected, Name selector);
+        JCIdent Ident(Name idname);
+        JCLiteral Literal(TypeTag tag, Object value);
+        JCPrimitiveTypeTree TypeIdent(TypeTag typetag);
+        JCArrayTypeTree TypeArray(JCExpression elemtype);
+        JCTypeApply TypeApply(JCExpression clazz, List<JCExpression> arguments);
+        JCTypeParameter TypeParameter(Name name, List<JCExpression> bounds);
+        JCWildcard Wildcard(TypeBoundKind kind, JCTree type);
+        TypeBoundKind TypeBoundKind(BoundKind kind);
+        JCAnnotation Annotation(JCTree annotationType, List<JCExpression> args);
+        JCModifiers Modifiers(long flags, List<JCAnnotation> annotations);
+        JCErroneous Erroneous(List<? extends JCTree> errs);
+        JCModuleDecl ModuleDef(JCModifiers mods, ModuleKind kind, JCExpression qualId, List<JCDirective> directives);
+        JCExports Exports(JCExpression qualId, List<JCExpression> moduleNames);
+        JCOpens Opens(JCExpression qualId, List<JCExpression> moduleNames);
+        JCProvides Provides(JCExpression serviceName, List<JCExpression> implNames);
+        JCRequires Requires(boolean isTransitive, boolean isStaticPhase, JCExpression qualId);
+        JCUses Uses(JCExpression qualId);
+        LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr);
+    }
+
+    /** A generic visitor class for trees.
+     */
+    public static abstract class Visitor {
+        public void visitTopLevel(JCCompilationUnit that)    { visitTree(that); }
+        public void visitPackageDef(JCPackageDecl that)      { visitTree(that); }
+        public void visitImport(JCImport that)               { visitTree(that); }
+        public void visitClassDef(JCClassDecl that)          { visitTree(that); }
+        public void visitMethodDef(JCMethodDecl that)        { visitTree(that); }
+        public void visitVarDef(JCVariableDecl that)         { visitTree(that); }
+        public void visitSkip(JCSkip that)                   { visitTree(that); }
+        public void visitBlock(JCBlock that)                 { visitTree(that); }
+        public void visitDoLoop(JCDoWhileLoop that)          { visitTree(that); }
+        public void visitWhileLoop(JCWhileLoop that)         { visitTree(that); }
+        public void visitForLoop(JCForLoop that)             { visitTree(that); }
+        public void visitForeachLoop(JCEnhancedForLoop that) { visitTree(that); }
+        public void visitLabelled(JCLabeledStatement that)   { visitTree(that); }
+        public void visitSwitch(JCSwitch that)               { visitTree(that); }
+        public void visitCase(JCCase that)                   { visitTree(that); }
+        public void visitSynchronized(JCSynchronized that)   { visitTree(that); }
+        public void visitTry(JCTry that)                     { visitTree(that); }
+        public void visitCatch(JCCatch that)                 { visitTree(that); }
+        public void visitConditional(JCConditional that)     { visitTree(that); }
+        public void visitIf(JCIf that)                       { visitTree(that); }
+        public void visitExec(JCExpressionStatement that)    { visitTree(that); }
+        public void visitBreak(JCBreak that)                 { visitTree(that); }
+        public void visitContinue(JCContinue that)           { visitTree(that); }
+        public void visitReturn(JCReturn that)               { visitTree(that); }
+        public void visitThrow(JCThrow that)                 { visitTree(that); }
+        public void visitAssert(JCAssert that)               { visitTree(that); }
+        public void visitApply(JCMethodInvocation that)      { visitTree(that); }
+        public void visitNewClass(JCNewClass that)           { visitTree(that); }
+        public void visitNewArray(JCNewArray that)           { visitTree(that); }
+        public void visitLambda(JCLambda that)               { visitTree(that); }
+        public void visitParens(JCParens that)               { visitTree(that); }
+        public void visitAssign(JCAssign that)               { visitTree(that); }
+        public void visitAssignop(JCAssignOp that)           { visitTree(that); }
+        public void visitUnary(JCUnary that)                 { visitTree(that); }
+        public void visitBinary(JCBinary that)               { visitTree(that); }
+        public void visitTypeCast(JCTypeCast that)           { visitTree(that); }
+        public void visitTypeTest(JCInstanceOf that)         { visitTree(that); }
+        public void visitIndexed(JCArrayAccess that)         { visitTree(that); }
+        public void visitSelect(JCFieldAccess that)          { visitTree(that); }
+        public void visitReference(JCMemberReference that)   { visitTree(that); }
+        public void visitIdent(JCIdent that)                 { visitTree(that); }
+        public void visitLiteral(JCLiteral that)             { visitTree(that); }
+        public void visitTypeIdent(JCPrimitiveTypeTree that) { visitTree(that); }
+        public void visitTypeArray(JCArrayTypeTree that)     { visitTree(that); }
+        public void visitTypeApply(JCTypeApply that)         { visitTree(that); }
+        public void visitTypeUnion(JCTypeUnion that)         { visitTree(that); }
+        public void visitTypeIntersection(JCTypeIntersection that)  { visitTree(that); }
+        public void visitTypeParameter(JCTypeParameter that) { visitTree(that); }
+        public void visitWildcard(JCWildcard that)           { visitTree(that); }
+        public void visitTypeBoundKind(TypeBoundKind that)   { visitTree(that); }
+        public void visitAnnotation(JCAnnotation that)       { visitTree(that); }
+        public void visitModifiers(JCModifiers that)         { visitTree(that); }
+        public void visitAnnotatedType(JCAnnotatedType that) { visitTree(that); }
+        public void visitErroneous(JCErroneous that)         { visitTree(that); }
+        public void visitModuleDef(JCModuleDecl that)        { visitTree(that); }
+        public void visitExports(JCExports that)             { visitTree(that); }
+        public void visitOpens(JCOpens that)                 { visitTree(that); }
+        public void visitProvides(JCProvides that)           { visitTree(that); }
+        public void visitRequires(JCRequires that)           { visitTree(that); }
+        public void visitUses(JCUses that)                   { visitTree(that); }
+        public void visitLetExpr(LetExpr that)               { visitTree(that); }
+
+        public void visitTree(JCTree that)                   { Assert.error(); }
+    }
+
+}