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 * type binding.
012 */
013
014 public class EnvForLocalType extends Env implements/*privately*/ Cloneable {
015
016 /***************************************************
017 * *
018 * Creation: *
019 * *
020 **************************************************/
021
022 /**
023 * Our parent environment
024 */
025 //@ invariant !(parent instanceof EnvForCU);
026 protected /*@ non_null @*/ Env parent;
027
028 /**
029 * The new local binding.
030 */
031 //@ invariant decl.id != null;
032 protected /*@ non_null @*/ TypeDecl decl;
033
034
035 /**
036 * Create a environment from an existing one by adding a new
037 * local type binding. <p>
038 *
039 * We report an error to ErrorSet if the new local type binding
040 * is a redefinition of a local type binding not hidden by a type
041 * member.<p>
042 */
043 //@ requires decl.id != null;
044 //@ requires !(parent instanceof EnvForCU);
045 public EnvForLocalType(/*@ non_null @*/ Env parent,
046 /*@ non_null @*/ TypeDecl decl) {
047 this.parent = parent;
048 this.decl = decl;
049
050 /*
051 * Check for duplication:
052 *
053 * (Note that result returns a TypeSig if decl.id refers to a
054 * field.)
055 */
056 // Note: Location.NULL here prevents ambiguous typename errors
057 TypeSig previous = parent.lookupSimpleTypeName(null, decl.id,
058 Location.NULL);
059 if (previous != null && !previous.member)
060 ErrorSet.error(decl.locId,
061 "Local type definitions may not hide"
062 + " already existing local type definitions.");
063 }
064
065
066
067 /***************************************************
068 * *
069 * Current/enclosing instances I: *
070 * *
071 **************************************************/
072
073 /**
074 * Is there a current instance in scope? <p>
075 *
076 * E.g., is "this" (or "<enclosing class>.this") legal here? <p>
077 *
078 * This is also refered to as "are we in a static context?". The
079 * legality of super also depends on this result. <p>
080 *
081 * The legality of C.this, C != <enclosing class> is different; see
082 * canAccessInstance(-).
083 */
084 public boolean isStaticContext() { return parent.isStaticContext(); }
085
086
087 /**
088 * Return the intermost class enclosing the code that is checked
089 * in this environment. <p>
090 *
091 * May return null if there is no enclosing class (aka, for
092 * environments for CompilationUnits). <p>
093 *
094 * If isStaticContext() returns true, then this is the type of "this".
095 */
096 public TypeSig getEnclosingClass() {
097 return parent.getEnclosingClass();
098 }
099
100
101 /**
102 * If there is an enclosing instance in scope, then return the
103 * (exact) type of the innermost such instance. <p>
104 *
105 * Note: this is considered a current instance, not an enclosing
106 * instance, even inside its methods.
107 */
108 public TypeSig getEnclosingInstance() {
109 return parent.getEnclosingInstance();
110 }
111
112
113 /**
114 * Returns a new Env that acts the same as us, except that its
115 * current instance (if any) is not accessible. <p>
116 *
117 * Note: this routine is somewhat inefficient and should be
118 * avoided unless an unknown environment needs to be coerced in
119 * this way. <p>
120 */
121 public Env asStaticContext() {
122 EnvForLocalType n;
123 try {
124 n = (EnvForLocalType)this.clone();
125 } catch (CloneNotSupportedException e) {
126 Assert.fail("clone did not obey its spec!");
127 return null; // keep compiler happy
128 }
129 n.parent = parent.asStaticContext();
130 return n;
131 }
132
133
134 /***************************************************
135 * *
136 * Simple names: *
137 * *
138 **************************************************/
139
140 /**
141 * Attempt to lookup a simple TypeName in this environment to get
142 * the TypeSig it denotes. Returns null if no such type
143 * exists.<p>
144 *
145 * This routine does not check that the resulting type (if any)
146 * is actually accessable. <p>
147 *
148 * If id is ambiguous, then if loc != Location.NULL then a fatal
149 * error is reported at that location via ErrorSet else one of
150 * its possible meanings is returned.<p>
151 */
152 public TypeSig lookupSimpleTypeName(TypeSig caller, /*@non_null*/Identifier id, int loc) {
153 if (id==decl.id) {
154 TypeSig t = TypeSig.getSig(decl);
155 if (caller == null) return t;
156 if (TypeCheck.inst.canAccess(caller,t,decl.modifiers,decl.pmodifiers)) return t;
157 }
158 return parent.lookupSimpleTypeName(caller, id, loc);
159 }
160
161
162 /**
163 * Locate the lexically innermost field or local variable
164 * declaration. <p>
165 *
166 * Let d be the lexically innermost field or local variable
167 * declaration (including formals) of id (if any such declaration
168 * exists). Then this routine returns: <p>
169 *
170 * d (a LocalVarDecl or FormalParaDecl) if d is a local
171 * variable declaration
172 *
173 * the class C that lexically encloses us and contains the
174 * (inherited) field d if d is a field declaration
175 *
176 * null if d does not exist
177 *
178 * Note: inherited fields are considered to lexically enclose the
179 * code of their subclasses. We give the class containing the
180 * field instead of the field itself to postpone dealing with
181 * multiple fields named id visible in the same class.<p>
182 *
183 * In the field case, id disambiguates to C[.this].id.<p>
184 */
185 public ASTNode locateFieldOrLocal(/*@non_null*/Identifier id) {
186 // we bind no fields or local variables/formals ourselves:
187 return parent.locateFieldOrLocal(id);
188 }
189
190 /** Inside a local class declaration we may reuse identifiers, so
191 we stop checking for duplicate variables at this point.
192 */
193 public boolean isDuplicate(/*@non_null*/Identifier id) {
194 return false;
195 }
196
197 /**
198 * Locate the lexically innermost method named id. <p>
199 *
200 * Returns the TypeSig for the innermost lexically enclosing type
201 * that has a method named id or null if no such type exists.<p>
202 *
203 * Note: inherited methods are considered to lexically enclose
204 * the code of their subclasses.<p>
205 *
206 * id disambiguates to C[.this].id.<p>
207 */
208 public TypeSig locateMethod(/*@non_null*/Identifier id) {
209 // we bind no methods ourselves:
210 return parent.locateMethod(id);
211 }
212
213
214 /***************************************************
215 * *
216 * Debugging functions: *
217 * *
218 **************************************************/
219
220 /**
221 * Display information about us to System.out. This function is
222 * intended only for debugging use.
223 */
224 public void display() {
225 parent.display();
226 System.out.println("[[ extended with local type binding of "
227 + decl.id.toString() + " to " + TypeSig.getSig(decl) + " ]]");
228 }
229 }