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 peervar;
034
035 /**
036 * Are peervar'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 peervar,
053 boolean staticContext) {
054 this.parent = parent;
055 this.peervar = peervar;
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 peervar;
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 = peervar.getEnclosingEnv();
109 if (outsideEnv.isStaticContext())
110 return null;
111
112 // Our first enclosing instance is our enclosing type:
113 return peervar.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, peervar, 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, /*@non_null*/Identifier id, int loc) {
149 // Check for a definition in peervar:
150 TypeSig result = peervar.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(/*@non_null*/Identifier id) {
182 if (hasField(id))
183 return peervar;
184
185 return parent.locateFieldOrLocal(id);
186 }
187
188 public boolean isDuplicate(/*@non_null*/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(/*@non_null*/Identifier id) {
205 // Check for a definition in peervar:
206 if (hasMethod(id))
207 return peervar;
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 peervar.hasField(id);
218 }
219
220 public FieldDeclVec getFields(boolean allFields) {
221 return peervar.getFields(allFields);
222 }
223
224 protected boolean hasMethod(Identifier id) {
225 MethodDeclVec methods = peervar.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 + peervar.getExternalName() + " ]]");
253 }
254 }