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, 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(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(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(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 }