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    }