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