    001    /* Copyright 2000, 2001, Compaq Computer Corporation */
    002
    003    package javafe.tc;
    004
    005    import javafe.ast.*;
    006
    007    /**
    008     * EnvForTypeSigs are used to extend an existing Env with the
    009     * bindings of a TypeSig. <p>
    010     *
    011     * Each TypeSig has two different internal environments, depending on
    012     * whether or not its instance members are considered to be
    013     * accessible.  (Static members are always visible.)  The creator
    014     * specifies which of the two environments are desired.
    015     */
    016
    017    public class EnvForTypeSig extends Env {
    018
    019        /***************************************************
    020         *                                                 *
    021         * Creation:                                       *
    022         *                                                 *
    023         **************************************************/
    024
    025        /**
    026         * Our parent environment
    027         */
    028        protected /*@ non_null @*/ Env parent;
    029
    030        /**
    031         * The TypeSig providing new bindings
    032         */
    033        protected /*@ non_null @*/ TypeSig peer;
    034
    035        /**
    036         * Are peer's instance members accessible? <p>
    037         *
    038         * WARNING: never modify this variable after creation -- Env's
    039         * need to be immutible.
    040         */
    041        protected boolean staticContext;
    042
    043
    044        /**
    045         * Create an environment from an existing one by adding a new
    046         * TypeSigs bindings. <p>
    047         *
    048         * The instance members of the TypeSig are considered accessible
    049         * iff staticContext is true.
    050         */
    051        public EnvForTypeSig(/*@ non_null @*/ Env parent,
    052                             /*@ non_null @*/ TypeSig peer,
    053                             boolean staticContext) {
    054            this.parent = parent;
    055            this.peer = peer;
    056            this.staticContext = staticContext;
    057        }
    058
    059
    060        /***************************************************
    061         *                                                 *
    062         * Current/enclosing instances I:                  *
    063         *                                                 *
    064         **************************************************/
    065
    066        /**
    067         * Is there a current instance in scope? <p>
    068         *
    069         * E.g., is "this" (or "<enclosing class>.this") legal here? <p>
    070         *
    071         * This is also refered to as "are we in a static context?".  The
    072         * legality of super also depends on this result. <p>
    073         *
    074         * The legality of C.this, C != <enclosing class> is different; see
    075         * canAccessInstance(-).
    076         */
    077        public boolean isStaticContext() {
    078            return staticContext;
    079        }
    080
    081
    082        /**
    083         * Return the intermost class enclosing the code that is checked
    084         * in this environment. <p>
    085         *
    086         * May return null if there is no enclosing class (aka, for
    087         * environments for CompilationUnits). <p>
    088         *
    089         * If isStaticContext() returns true, then this is the type of "this".
    090         */
    091        public TypeSig getEnclosingClass() {
    092            return peer;
    093        }
    094
    095
    096        /**
    097         * If there is an enclosing instance in scope, then return the
    098         * (exact) type of the innermost such instance. <p>
    099         *
    100         * Note: this is considered a current instance, not an enclosing
    101         * instance, even inside its methods.
    102         */
    103        public TypeSig getEnclosingInstance() {
    104            /*
    105             * For now, the rule is: we have enclosing instances iff we
    106             * are not in a static context: !!!!
    107             */
    108            Env outsideEnv = peer.getEnclosingEnv();
    109            if (outsideEnv.isStaticContext())
    110                return null;
    111
    112            // Our first enclosing instance is our enclosing type:
    113            return peer.enclosingType;
    114        }
    115
    116
    117        /**
    118         * Returns a new Env that acts the same as us, except that its
    119         * current instance (if any) is not accessible. <p>
    120         *
    121         * Note: this routine is somewhat inefficient and should be
    122         * avoided unless an unknown environment needs to be coerced in
    123         * this way. <p>
    124         */
    125        public Env asStaticContext() {
    126            return new EnvForTypeSig(parent, peer, true);
    127        }
    128
    129
    130        /***************************************************
    131         *                                                 *
    132         * Simple names:                                   *
    133         *                                                 *
    134         **************************************************/
    135
    136        /**
    137         * Attempt to lookup a simple TypeName in this environment to get
    138         * the TypeSig it denotes.  Returns null if no such type
    139         * exists.<p>
    140         *
    141         * This routine does not check that the resulting type (if any)
    142         * is actually accessable. <p>
    143         *
    144         * If id is ambiguous, then if loc != Location.NULL then a fatal
    145         * error is reported at that location via ErrorSet else one of
    146         * its possible meanings is returned.<p>
    147         */
    148        public TypeSig lookupSimpleTypeName(TypeSig caller, Identifier id, int loc) {
    149            // Check for a definition in peer:
    150            TypeSig result = peer.lookupType(caller, id, loc);
    151            if (result != null) return result;
    152
    153            // Otherwise, look to enclosing scopes...
    154            return parent.lookupSimpleTypeName(caller, id, loc);
    155        }
    156
    157
    158        /**
    159         * Locate the lexically innermost field or local variable
    160         * declaration. <p>
    161         *
    162         * Let d be the lexically innermost field or local variable
    163         * declaration (including formals) of id (if any such declaration
    164         * exists).  Then this routine returns: <p>
    165         *
    166         *    d (a LocalVarDecl or FormalParaDecl) if d is a local
    167         *                                            variable declaration
    168         *
    169         *    the class C that lexically encloses us and contains the
    170         *    (inherited) field d if d is a field declaration
    171         *
    172         *    null if d does not exist
    173         *
    174         * Note: inherited fields are considered to lexically enclose the
    175         * code of their subclasses.  We give the class containing the
    176         * field instead of the field itself to postpone dealing with
    177         * multiple fields named id visible in the same class.<p>
    178         *
    179         * In the field case, id disambiguates to C[.this].id.<p>
    180         */
    181        public ASTNode locateFieldOrLocal(Identifier id) {
    182            if (hasField(id))
    183                return peer;
    184
    185            return parent.locateFieldOrLocal(id);
    186        }
    187
    188        public boolean isDuplicate(Identifier id) {
    189            if (hasField(id)) return true;
    190            return false;
    191        }
    192
    193        /**
    194         * Locate the lexically innermost method named id. <p>
    195         *
    196         * Returns the TypeSig for the innermost lexically enclosing type
    197         * that has a method named id or null if no such type exists.<p>
    198         *
    199         * Note: inherited methods are considered to lexically enclose
    200         * the code of their subclasses.<p>
    201         *
    202         * id disambiguates to C[.this].id.<p>
    203         */
    204        public TypeSig locateMethod(Identifier id) {
    205            // Check for a definition in peer:
    206            if (hasMethod(id))
    207                return peer;
    208
    209            // Otherwise, look to enclosing scopes...
    210            return parent.locateMethod(id);
    211        }
    212
    213
    214        /** This is to allow overriding by subclasses */
    215
    216        protected boolean hasField(Identifier id) {
    217            return peer.hasField(id);
    218        }
    219
    220        public FieldDeclVec getFields(boolean allFields) {
    221            return peer.getFields(allFields);
    222        }
    223
    224        protected boolean hasMethod(Identifier id) {
    225            MethodDeclVec methods = peer.getMethods();
    226
    227            for (int i = 0; i < methods.size(); i++) {
    228                MethodDecl md = methods.elementAt(i);
    229                if (md.id == id)
    230                    return true;
    231            }
    232
    233            return false;
    234        }
    235
    236
    237        /***************************************************
    238         *                                                 *
    239         * Debugging functions:                            *
    240         *                                                 *
    241         **************************************************/
    242
    243        /**
    244         * Display information about an Env to System.out.  This function
    245         * is intended only for debugging use.
    246         */
    247        public void display() {
    248            parent.display();
    249            System.out.println("[[ extended with the "
    250                               + (staticContext ? "static" : "complete")
    251                               + " bindings of type "
    252                               + peer.getExternalName() + " ]]");
    253        }
    254    }