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    }