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 class 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, /*@non_null*/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(/*@non_null*/Identifier id) {
208 if (id == decl.id)
209 return decl;
210 else
211 return parent.locateFieldOrLocal(id);
212 }
213
214 public boolean isDuplicate(/*@non_null*/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(/*@non_null*/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 }