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