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 }