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, /*@non_null*/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(/*@non_null*/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(/*@non_null*/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 }