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    }