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