    001    /* Copyright 2000, 2001, Compaq Computer Corporation */
    002
    003    package escjava.tc;
    004
    005
    006    import java.util.Hashtable;
    007
    008    import javafe.ast.*;
    009    import javafe.util.*;
    010    import javafe.tc.*;
    011    import javafe.tc.TypeSig;
    012
    013
    014    /**
    015     * EnvForGhostLocals are used to extend an existing Env with one new local
    016     * binding, either a local variable definition or a formal parameter. <p>
    017     *
    018     * See EnvForLocalType for how to extend an existing Env with one new
    019     * local type binding.<p>
    020     */
    021
    022    public class EnvForGhostLocals extends Env implements/*privately*/ Cloneable {
    023
    024        /***************************************************
    025         *                                                 *
    026         * Creation:                                       *
    027         *                                                 *
    028         **************************************************/
    029
    030        /**
    031         * Our parent environment
    032         */
    033        //@ invariant !(parent instanceof EnvForCU);
    034        protected /*@ non_null @*/ Env parent;
    035
    036        /**
    037         * The new local binding.
    038         */
    039        //@ invariant decl.id != null;
    040        protected /*@ non_null @*/ GenericVarDecl decl;
    041
    042
    043        /**
    044         * Create a environment from an existing one by adding a new
    045         * local binding. <p>
    046         *
    047         * We report an error to ErrorSet if the new local binding is a
    048         * redefinition of a local binding not hidden by a field.<p>
    049         */
    050        //@ requires decl.id != null;
    051        //@ requires !(parent instanceof EnvForCU);
    052        public EnvForGhostLocals(/*@ non_null @*/ Env parent,
    053                            /*@ non_null @*/ GenericVarDecl decl) {
    054            this.parent = parent;
    055            this.decl = decl;
    056
    057            TypeSig declaringClass = parent.getEnclosingClass();
    058            Assert.notNull(declaringClass);
    059            whereDecoration.set(decl, declaringClass);
    060
    061            /*
    062             * Check for duplication:
    063             *
    064             * (Note that result returns a TypeSig if decl.id refers to a
    065             * field.)
    066             */
    067            ASTNode result = parent.locateFieldOrLocal(decl.id);
    068            if (result instanceof GenericVarDecl)
    069                // && whereDeclared((GenericVarDecl)result)==declaringClass)
    070                ErrorSet.error(decl.locId, "Variable '" + decl.id +
    071                       "' is already defined here.", result.getStartLoc());
    072        }
    073
    074
    075
    076        /***************************************************
    077         *                                                 *
    078         * Current/enclosing instances I:                  *
    079         *                                                 *
    080         **************************************************/
    081
    082        /**
    083         * Is there a current instance in scope? <p>
    084         *
    085         * E.g., is "this" (or "<enclosing class>.this") legal here? <p>
    086         *
    087         * This is also refered to as "are we in a static context?".  The
    088         * legality of super also depends on this result. <p>
    089         *
    090         * The legality of C.this, C!=<enclosing class> is different; see
    091         * canAccessInstance(-).
    092         */
    093        public boolean isStaticContext() { return parent.isStaticContext(); }
    094
    095
    096        /**
    097         * Return the intermost class enclosing the code that is checked
    098         * in this environment. <p>
    099         *
    100         * May return null if there is no enclosing class (aka, for
    101         * environments for CompilationUnits). <p>
    102         *
    103         * If isStaticContext() returns true, then this is the type of "this".
    104         */
    105        public TypeSig getEnclosingClass() {
    106            return parent.getEnclosingClass();
    107        }
    108
    109
    110        /**
    111         * If there is an enclosing instance in scope, then return the
    112         * (exact) type of the innermost such instance. <p>
    113         *
    114         * Note: this is considered a current instance, not an enclosing
    115         * instance, even inside its methods.
    116         */
    117        public TypeSig getEnclosingInstance() {
    118            return parent.getEnclosingInstance();
    119        }
    120
    121
    122        /**
    123         * Returns a new Env that acts the same as us, except that its
    124         * current instance (if any) is not accessible. <p>
    125         *
    126         * Note: this routine is somewhat inefficient and should be
    127         * avoided unless an unknown environment needs to be coerced in
    128         * this way. <p>
    129         */
    130        public /*@ non_null @*/ Env asStaticContext() {
    131            EnvForGhostLocals n;
    132            try {
    133                n = (EnvForGhostLocals)this.clone();
    134            } catch (CloneNotSupportedException e) {
    135                Assert.fail("clone did not obey its spec!");
    136                return null;  // keep compiler happy
    137            }
    138            n.parent = parent.asStaticContext();
    139            return n;
    140        }
    141
    142
    143        /***************************************************
    144         *                                                 *
    145         * Simple names:                                   *
    146         *                                                 *
    147         **************************************************/
    148
    149        /**
    150         * Attempt to lookup a simple TypeName in this environment to get
    151         * the TypeSig it denotes.  Returns null if no such type
    152         * exists.<p>
    153         *
    154         * This routine does not check that the resulting type (if any)
    155         * is actually accessable, if caller is null. <p>
    156         *
    157         * If id is ambiguous, then if loc != Location.NULL then a fatal
    158         * error is reported at that location via ErrorSet else one of
    159         * its possible meanings is returned.<p>
    160         */
    161        public TypeSig lookupSimpleTypeName(TypeSig caller, Identifier id, int loc) {
    162            // We bind no type variables ourshelves:
    163            return parent.lookupSimpleTypeName(caller, id, loc);
    164        }
    165
    166
    167        /**
    168         * Locate the lexically innermost field or local variable
    169         * declaration. <p>
    170         *
    171         * Let d be the lexically innermost field or local variable
    172         * declaration (including formals) of id (if any such declaration
    173         * exists).  Then this routine returns: <p>
    174         *
    175         *    d (a LocalVarDecl or FormalParaDecl) if d is a local
    176         *                                            variable declaration
    177         *
    178         *    the class C that lexically encloses us and contains the
    179         *    (inherited) field d if d is a field declaration
    180         *
    181         *    null if d does not exist
    182         *
    183         * Note: inherited fields are considered to lexically enclose the
    184         * code of their subclasses.  We give the class containing the
    185         * field instead of the field itself to postpone dealing with
    186         * multiple fields named id visible in the same class.<p>
    187         *
    188         * In the field case, id disambiguates to C[.this].id.<p>
    189         */
    190        public ASTNode locateFieldOrLocal(Identifier id) {
    191            // Only return my declaration if it matches and we are in an
    192            // annotation environment
    193            if (id == decl.id && FlowInsensitiveChecks.inAnnotation)
    194                return decl;
    195            else
    196                return parent.locateFieldOrLocal(id);
    197        }
    198
    199
    200        /**
    201         * Locate the lexically innermost method named id. <p>
    202         *
    203         * Returns the TypeSig for the innermost lexically enclosing type
    204         * that has a method named id or null if no such type exists.<p>
    205         *
    206         * Note: inherited methods are considered to lexically enclose
    207         * the code of their subclasses.<p>
    208         *
    209         * id disambiguates to C[.this].id.<p>
    210         */
    211        public TypeSig locateMethod(Identifier id) {
    212            // we bind no methods ourshelves:
    213            return parent.locateMethod(id);
    214        }
    215
    216
    217        /***************************************************
    218         *                                                 *
    219         * Debugging functions:                            *
    220         *                                                 *
    221         **************************************************/
    222
    223        /**
    224         * Display information about us to System.out.  This function is
    225         * intended only for debugging use.
    226         */
    227        public void display() {
    228            parent.display();
    229            System.out.println("[[ extended with local binding of "
    230                + decl.id.toString() + " bound to:");
    231            PrettyPrint.inst.print(System.out, decl);
    232            System.out.println("]]");
    233        }
    234    }