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 * Env's are the environments used during typechecking to keep track 011 * of what types, local variables, fields, and current/enclosing 012 * instances are in scope. 013 */ 014 015 public abstract class Env { 016 017 /////////////////////////////////////////////////////////////////////// 018 // // 019 // Methods implemented by each instance of Env // 020 // // 021 /////////////////////////////////////////////////////////////////////// 022 023 024 /*************************************************** 025 * * 026 * Current/enclosing instances I: * 027 * * 028 **************************************************/ 029 030 /** 031 * Is there a current instance in scope? <p> 032 * 033 * E.g., is "this" (or "<enclosing class>.this") legal here? <p> 034 * 035 * This is also refered to as "are we in a static context?". The 036 * legality of super also depends on this result. <p> 037 * 038 * The legality of C.this, C != <enclosing class> is different; see 039 * canAccessInstance(-). 040 */ 041 abstract public boolean isStaticContext(); 042 043 044 /** 045 * Return the intermost class enclosing the code that is checked 046 * in this environment. <p> 047 * 048 * May return null if there is no enclosing class (aka, for 049 * environments for CompilationUnits). <p> 050 * 051 * If isStaticContext() returns true, then this is the type of "this". 052 */ 053 //@ ensures (this instanceof EnvForCU) == (\result==null); 054 abstract public TypeSig getEnclosingClass(); 055 056 057 /** 058 * If there is an enclosing instance in scope, then return the 059 * (exact) type of the innermost such instance. <p> 060 * 061 * Note: this is considered a current instance, not an enclosing 062 * instance, even inside its methods. 063 */ 064 abstract public TypeSig getEnclosingInstance(); 065 066 067 /** 068 * Returns a new Env that acts the same as us, except that its 069 * current instance (if any) is not accessible. <p> 070 * 071 * Note: this routine is somewhat inefficient and should be 072 * avoided unless an unknown environment needs to be coerced in 073 * this way. <p> 074 */ 075 //@ ensures \result != null; 076 //@ ensures (this instanceof EnvForCU) == (\result instanceof EnvForCU); 077 abstract public Env asStaticContext(); 078 079 080 /*************************************************** 081 * * 082 * Simple names: * 083 * * 084 **************************************************/ 085 086 /** 087 * Attempt to lookup a simple TypeName in this environment to get 088 * the TypeSig it denotes. Returns null if no such type 089 * exists.<p> 090 * 091 * This routine does not check that the resulting type (if any) 092 * is actually accessible, if caller is null. <p> 093 * 094 * If id is ambiguous, then if loc != Location.NULL then a fatal 095 * error is reported at that location via ErrorSet else one of 096 * its possible meanings is returned.<p> 097 */ 098 abstract public TypeSig lookupSimpleTypeName( 099 TypeSig caller, /*@ non_null @*/ Identifier id, 100 int loc); 101 102 103 /** 104 * Locate the lexically innermost field or local variable 105 * declaration with a given name. <p> 106 * 107 * Let d be the lexically innermost field or local variable 108 * declaration (including formals) of id (if any such declaration 109 * exists). Then this routine returns: <p> 110 * 111 * d (a LocalVarDecl or FormalParaDecl) if d is a local 112 * variable declaration 113 * 114 * the class C that lexically encloses us and contains the 115 * (inherited) field d if d is a field declaration 116 * 117 * null if d does not exist 118 * 119 * Note: inherited fields are considered to lexically enclose the 120 * code of their subclasses. We give the class containing the 121 * field instead of the field itself to postpone dealing with 122 * multiple fields named id visible in the same class.<p> 123 * 124 * In the field case, id disambiguates to C[.this].id.<p> 125 * 126 * This routine does not check that a resulting field 127 * is actually accessible. <p> 128 */ 129 /*@ ensures \result==null || (\result instanceof GenericVarDecl) 130 || (\result instanceof TypeSig); */ 131 /*@ ensures \result instanceof GenericVarDecl ==> 132 ((GenericVarDecl)\result).id == id; */ 133 //@ ensures (this instanceof EnvForCU) ==> \result==null; 134 abstract public ASTNode locateFieldOrLocal(/*@ non_null @*/ Identifier id); 135 136 public boolean isDuplicate(/*@ non_null */ Identifier id) { 137 return locateFieldOrLocal(id) instanceof GenericVarDecl; 138 } 139 140 /** 141 * Locate the lexically innermost method named id. <p> 142 * 143 * Returns the TypeSig for the innermost lexically enclosing type 144 * that has a method named id or null if no such type exists.<p> 145 * 146 * Note: inherited methods are considered to lexically enclose 147 * the code of their subclasses.<p> 148 * 149 * id disambiguates to C[.this].id.<p> 150 * 151 * This routine does not check that a resulting method 152 * is actually accessible. <p> 153 */ 154 //@ ensures (this instanceof EnvForCU) ==> \result==null; 155 abstract public TypeSig locateMethod(/*@ non_null @*/ Identifier id); 156 157 158 /*************************************************** 159 * * 160 * Debugging functions: * 161 * * 162 **************************************************/ 163 164 /** 165 * Display information about us to System.out. This function is 166 * intended only for debugging use. 167 */ 168 abstract public void display(); 169 170 171 /////////////////////////////////////////////////////////////////////// 172 // // 173 // Derived Methods // 174 // // 175 /////////////////////////////////////////////////////////////////////// 176 177 178 /*************************************************** 179 * * 180 * Type variable names: * 181 * * 182 **************************************************/ 183 184 /** 185 * Attempts to find the canonical prefix of a given name that 186 * denotes a TypeName in this environment. <p> 187 * 188 * A canonical prefix is composed of a base type name (either the 189 * leftmost identifer or a fully-quantified outside type name 190 * (P.I) depending), extended by some number of type member 191 * accesses (.C1.C2...). 192 * 193 * If ignoreFields is not set, then we stop extending the base 194 * type name as soon as we encounter an access that can refer to 195 * a field. If it is set, then we stop extending only when we 196 * reach the end of the name or an access that cannot refer to a 197 * type member. <p> 198 * 199 * If we encounter an ambiguous prefix, we report a fatal error 200 * at loc via ErrorSet.<p> 201 * 202 * Otherwise, we return the TypeSig that the found prefix denotes 203 * (null if the prefix is of length 0) and sets prefixSize to the 204 * prefix's size. <p> 205 * 206 * This routine does not check that the resulting type (if any) 207 * is actually accessible, unless caller is not null. <p> 208 */ 209 //@ modifies prefixSize; 210 //@ ensures \result==null ==> 0==prefixSize; 211 //@ ensures \result != null ==> 0<prefixSize && prefixSize <= n.length; 212 public TypeSig findTypeNamePrefix(TypeSig caller, 213 /*@ non_null @*/ Name n, 214 boolean ignoreFields) { 215 // Check for an unqualified name first: 216 TypeSig sig = lookupSimpleTypeName(caller,n.identifierAt(0), 217 n.getStartLoc()); 218 prefixSize = 1; 219 if (sig==null) { 220 // Nope; must be a qualified name with a non-empty package prefix: 221 while (++prefixSize<=n.size()) { 222 // Lookup n[0]..n[prefixSize-2] . n[prefixSize-1]: 223 sig = OutsideEnv.lookup(n.prefix(prefixSize-1).toStrings(), 224 n.identifierAt(prefixSize-1).toString()); 225 if (sig != null) 226 break; // Stop at smallest qualified name 227 } 228 if (prefixSize>n.size()) { 229 prefixSize = 0; 230 return null; 231 } 232 } 233 234 // Here we have that n[0]..n[prefixSize-1] denotes the type sig 235 236 // Try and extend it as much as possible via nested types 237 while (prefixSize<n.size()) { 238 Identifier id = n.identifierAt(prefixSize); 239 int idLoc = n.locIdAt(prefixSize); 240 241 // Stop if next access refers to a field & !ignoreFields: 242 if (!ignoreFields && sig.hasField(id)) 243 break; 244 245 // Stop if next access cannot refer to a type member: 246 TypeSig next = sig.lookupType(caller, id, idLoc); 247 if (next==null) 248 break; 249 250 sig = next; 251 prefixSize++; 252 } 253 254 return sig; 255 } 256 //* Holds the second return value of findTypeNamePrefix 257 public int prefixSize; 258 259 260 /** 261 * Attempt to lookup a TypeName using this environment. <p> 262 * 263 * If it encounters an ambiguous prefix, a fatal error is 264 * reported via ErrorSet.<p> 265 * 266 * Otherwise, returns the TypeSig that n denotes or null if n 267 * does not denote a type.<p> 268 * 269 * This routine does not check that the resulting type (if any) 270 * is actually accessible, unless caller is not null. <p> 271 */ 272 public TypeSig lookupTypeName(TypeSig caller, /*@ non_null @*/ Name n) { 273 TypeSig sig = findTypeNamePrefix(caller, n, true); 274 if (prefixSize != n.size()) 275 return null; 276 277 return sig; 278 } 279 280 281 /** 282 * This processes the annotations on a type name 283 */ 284 //@ ensures \result != null; 285 public TypeSig processTypeNameAnnotations(/*@ non_null @*/ TypeName n, 286 /*@ non_null @*/ TypeSig sig) { 287 return PrepTypeDeclaration.inst.processTypeNameAnnotations(n,sig,this); 288 } 289 290 291 /** 292 * Attempt to resolve a TypeName using this environment. <p> 293 * 294 * If an error occurs (including no such type), reports it to 295 * ErrorSet via a fatal error.<p> 296 * 297 * Otherwise, returns the TypeSig that n denotes. This TypeSig 298 * may also later be obtained by using TypeSig.getSig on n.<p> 299 * 300 * This routine does not check that the resulting type (if any) 301 * is actually accessible, unless caller is not null. <p> 302 */ 303 //@ ensures \result != null; 304 public TypeSig resolveTypeName(TypeSig caller, /*@ non_null @*/ TypeName tn) { 305 Name n = tn.name; 306 307 TypeSig sig = TypeSig.getRawSig(tn); // FIXME - use caller ? 308 if (sig != null) 309 return sig; 310 311 sig = lookupTypeName(caller, n); 312 if (sig==null) { 313 ErrorSet.fatal(tn.name.locIdAt(0), 314 "Can't find type named \"" 315 + tn.name.printName() + "\""); 316 } 317 318 sig = processTypeNameAnnotations(tn, sig); // FIXME - use caller? 319 TypeSig.setSig(tn, sig); 320 return sig; 321 } 322 323 /** 324 * decoration holding the type environment in which a type is resolved. 325 */ 326 //@ invariant typeEnv != null; 327 //@ invariant typeEnv.decorationType == \type(Env); 328 static public ASTDecoration typeEnv = 329 new ASTDecoration("environment"); 330 331 /** 332 * Attempt to resolve a Type using this environment. <p> 333 * 334 * If an error occurs, reports it to ErrorSet via a fatal error.<p> 335 * 336 * This routine does not check that (immediate) types (if any) 337 * are actually accessible, if caller is null. <p> 338 */ 339 public void resolveType(TypeSig caller, /*@ non_null @*/ Type t) { 340 typeEnv.set(t,this); 341 switch(t.getTag()) { 342 case TagConstants.ARRAYTYPE: 343 resolveType(caller, ((ArrayType)t).elemType); 344 break; 345 346 case TagConstants.TYPENAME: 347 resolveTypeName(caller, (TypeName)t); 348 break; 349 350 // No need to resolve primitive types or TypeSigs... 351 } 352 } 353 354 355 /*************************************************** 356 * * 357 * Expr names: * 358 * * 359 **************************************************/ 360 361 /** 362 * Attempt to disambiguate an Expr Name. Either returns the 363 * disambiguated Name as an Expr or null if it does not denote 364 * anything. <p> 365 * 366 * If non-null, the result will always be a field access of some 367 * kind. 368 * 369 * If a prefix of n is ambiguous because of multiple 370 * import-on-demand declarations, a fatal error will result. 371 * Nothing is reported if n does not name anything.<p> 372 * 373 * 374 * If n is a reference to a field f in lexically enclosing class 375 * C, then the result will be of the form "[C.]this.n" if C's 376 * instance fields are accessible and "C.n" otherwise.<p> 377 * 378 * (At this point we haven't decided which field f refers to so 379 * we don't know if it is an instance field or not.) 380 */ 381 //@ ensures !(\result instanceof AmbiguousVariableAccess); 382 public Expr disambiguateExprName(/*@ non_null @*/ Name n) { 383 /* 384 * Find the smallest prefix of n, n[0]..n[prefix-1], such that 385 * it denotes an Expr, call it left: 386 */ 387 Expr left = null; 388 Identifier leftmost = n.identifierAt(0); 389 int leftmostLoc = n.getStartLoc(); 390 391 ASTNode result = locateFieldOrLocal(leftmost); 392 int prefix = 1; 393 if (result instanceof GenericVarDecl) { 394 // leftmost is a local variable: 395 left = VariableAccess.make(leftmost, leftmostLoc, 396 (GenericVarDecl)result); 397 } else if (result instanceof TypeSig) { 398 // leftmost is a field in class result: 399 ObjectDesignator od = getObjectDesignator((TypeSig)result, 400 leftmostLoc); 401 left = FieldAccess.make(od, leftmost, leftmostLoc); 402 } else { 403 // n *must* start with a typename then: 404 TypeSig sig = findTypeNamePrefix(null, n, false); // FIXME - a caller for access checking? 405 if (sig==null || prefixSize==n.size()) 406 return null; 407 408 prefix = prefixSize+1; 409 TypeName tn = TypeName.make(n.prefix(prefixSize)); 410 TypeSig.setSig(tn, sig); 411 int leftmostDot = leftmostLoc; 412 if (prefixSize>0) 413 leftmostDot = n.locDotAfter(prefixSize-1); 414 ObjectDesignator od = 415 TypeObjectDesignator.make(leftmostDot, tn); 416 left = FieldAccess.make(od, n.identifierAt(prefixSize), 417 n.locIdAt(prefixSize)); 418 } 419 420 421 /* 422 * Extend the prefix to the full n by using field dereferences: 423 */ 424 for (; prefix<n.size(); prefix++) { 425 left = FieldAccess.make( 426 ExprObjectDesignator.make(n.locDotAfter(prefix-1), 427 left), 428 n.identifierAt(prefix), 429 n.locIdAt(prefix)); 430 } 431 432 return left; 433 } 434 435 public Object disambiguateTypeOrFieldName(/*@ non_null */ Name n) { 436 /* 437 * Find the smallest prefix of n, n[0]..n[prefix-1], such that 438 * it denotes an Expr, call it left: 439 */ 440 Expr left = null; 441 Identifier leftmost = n.identifierAt(0); 442 int leftmostLoc = n.getStartLoc(); 443 444 ASTNode result = locateFieldOrLocal(leftmost); 445 int prefix = 1; 446 if (result instanceof GenericVarDecl) { 447 // leftmost is a local variable: 448 left = VariableAccess.make(leftmost, leftmostLoc, 449 (GenericVarDecl)result); 450 } else if (result instanceof TypeSig) { 451 // leftmost is a field in class result: 452 ObjectDesignator od = getObjectDesignator((TypeSig)result, 453 leftmostLoc); 454 left = FieldAccess.make(od, leftmost, leftmostLoc); 455 } else { 456 // n *must* start with a typename then: 457 TypeSig sig = findTypeNamePrefix(null, n, false); // FIXME - a caller for access checking? 458 if (sig==null) return null; 459 if (prefixSize==n.size()) return sig; 460 461 prefix = prefixSize+1; 462 TypeName tn = TypeName.make(n.prefix(prefixSize)); 463 TypeSig.setSig(tn, sig); 464 int leftmostDot = leftmostLoc; 465 if (prefixSize>0) 466 leftmostDot = n.locDotAfter(prefixSize-1); 467 ObjectDesignator od = 468 TypeObjectDesignator.make(leftmostDot, tn); 469 left = FieldAccess.make(od, n.identifierAt(prefixSize), 470 n.locIdAt(prefixSize)); 471 } 472 473 474 /* 475 * Extend the prefix to the full n by using field dereferences: 476 */ 477 for (; prefix<n.size(); prefix++) { 478 left = FieldAccess.make( 479 ExprObjectDesignator.make(n.locDotAfter(prefix-1), 480 left), 481 n.identifierAt(prefix), 482 n.locIdAt(prefix)); 483 } 484 485 return left; 486 } 487 488 489 /*************************************************** 490 * * 491 * Routine names: * 492 * * 493 **************************************************/ 494 495 /** 496 * Attempt to disambiguate an AmbiguousMethodInvocation. Either 497 * returns the disambiguated method invocation as an Expr or 498 * reports a fatal error to ErrorSet if it does not denote 499 * anything.<p> 500 * 501 * The result will always be a method invocation.<p> 502 * 503 * If a prefix of n is ambiguous because of multiple 504 * import-on-demand declarations, a fatal error will result. 505 * 506 * 507 * If n is a reference to a method m in lexically enclosing class 508 * C, then the result will be of the form "[C.]this.m" if C's 509 * instance methods are accessible and "C.m" otherwise.<p> 510 * 511 * (At this point we haven't decided which method m refers to so 512 * we don't know if it is an instance method or not.) 513 */ 514 public MethodInvocation disambiguateMethodName( 515 /*@ non_null @*/ AmbiguousMethodInvocation inv) { 516 ObjectDesignator where; // Where the method comes from 517 518 Name n = inv.name; 519 int size = n.size(); 520 int nStart = n.getStartLoc(); 521 522 523 /* 524 * Handle the simple name case first: 525 */ 526 if (n.size()==1) { 527 Identifier id = n.identifierAt(0); 528 TypeSig container = locateMethod(id); 529 if (container==null) 530 ErrorSet.fatal(nStart, 531 "No method named " + id + " is in scope here."); 532 533 where = getObjectDesignator(container, nStart); 534 } else { 535 /* 536 * Not a simple name; try preceeding name as an ExprName first: 537 */ 538 Name butRight = n.prefix(size-1); 539 Expr e = disambiguateExprName(butRight); 540 if (e != null) 541 where = ExprObjectDesignator.make(n.locDotAfter(size-2), e); 542 else { 543 /* 544 * then try preceeding name as a TypeName: 545 */ 546 TypeSig t = lookupTypeName(null,butRight); // FIXME - a caller for access checking? 547 if (t != null) { 548 TypeName tn = TypeName.make(butRight); 549 TypeSig.setSig(tn, t); 550 where = TypeObjectDesignator.make(n.locDotAfter(size-2), 551 tn); 552 } else { 553 /* 554 * Give up! 555 */ 556 ErrorSet.fatal(nStart, 557 "Can't disambiguate method name " + n.printName()); 558 where = null; // keep compiler happy 559 } 560 } 561 } 562 563 564 // Return <where>.rightmost(...): 565 Identifier rightmost = n.identifierAt(size-1); 566 int rightmostLoc = n.locIdAt(size-1); 567 return MethodInvocation.make(where, rightmost, null, rightmostLoc, 568 inv.locOpenParen, inv.args); 569 } 570 571 572 /*************************************************** 573 * * 574 * Current/enclosing instances II: * 575 * * 576 **************************************************/ 577 578 /** 579 * Returns the innermost current or enclosing instance, or null 580 * if none exists. 581 */ 582 public TypeSig getInnermostInstance() { 583 if (!isStaticContext()) 584 return getEnclosingClass(); 585 else 586 return getEnclosingInstance(); 587 } 588 589 590 /** 591 * Are C's instance variables accessible? <p> 592 * 593 * If C is getEnclosingClass(), then this is equivalent to 594 * isStaticContext(). 595 */ 596 public boolean canAccessInstance(/*@ non_null @*/ TypeSig C) { 597 /* 598 * C's instance variables are accessible iff C is one of our 599 * current or enclosing instances: 600 */ 601 for (TypeSig instance = getInnermostInstance(); 602 instance != null; 603 instance = instance.getEnv(true).getEnclosingInstance()) { 604 if (instance==C) 605 return true; 606 } 607 608 return false; 609 } 610 611 612 /** 613 * Attempt to locate a current or enclosing instance that has 614 * type T. <p> 615 * 616 * If such exist, return an inferred "<actual class>.this" Expr 617 * for the innermost such one; otherwise, return null. The 618 * location fields of the Expr will be set to loc.<p> 619 * 620 * Note: The returned instance may have be of a subtype of T.<p> 621 */ 622 //@ requires loc != Location.NULL; 623 public Expr lookupEnclosingInstance(/*@ non_null @*/ TypeSig T, 624 int loc) { 625 TypeSig instance; 626 627 // Find innermost satisfactory instance if it exists: 628 for (instance = getInnermostInstance(); 629 instance != null; 630 instance = instance.getEnv(true).getEnclosingInstance()) { 631 if (instance.isSubtypeOf(T)) 632 break; 633 } 634 635 if (instance==null) 636 return null; 637 638 return getInferredThisExpr(instance, loc); 639 } 640 641 642 /*************************************************** 643 * * 644 * Finding where something is declared: * 645 * * 646 **************************************************/ 647 648 /** 649 * Decorates LocalVarDecl and FormalParaDecl nodes to point to 650 * the TypeSig of the type they are declared in. <p> 651 * 652 * Set by the EnvForLocals constructor.<p> 653 */ 654 //@ invariant whereDecoration.decorationType == \type(TypeSig); 655 protected static final ASTDecoration whereDecoration 656 = new ASTDecoration("whereDecoration"); 657 658 659 /** 660 * What type is a GenericVarDecl declared in? <p> 661 * 662 * Precondition: decl's type has been "parsed"; an Env containing 663 * decl has been constructed.<p> 664 */ 665 //@ requires (decl instanceof FieldDecl) ==> ((FieldDecl)decl).hasParent; 666 //@ ensures \result != null; 667 public static TypeSig whereDeclared(/*@ non_null @*/ GenericVarDecl decl) { 668 TypeSig result; 669 670 if (decl instanceof FieldDecl) { 671 TypeDecl parent = ((FieldDecl)decl).getParent(); 672 Assert.notNull(parent); 673 result = TypeSig.getSig(parent); 674 } else { 675 // LocalVarDecl or FormalParaDecl left here: 676 result = (TypeSig)whereDecoration.get(decl); 677 } 678 679 Assert.notNull(result); //@ nowarn Pre; 680 return result; 681 } 682 683 684 /*************************************************** 685 * * 686 * Expr-construction utility functions: * 687 * * 688 **************************************************/ 689 690 /** 691 * Return an inferred ThisExpr for "[C.]this", using location loc. <p> 692 * 693 * The "C." part is omitted if C is the type of this (e.g., 694 * getEnclosingClass()). 695 */ 696 //@ requires loc != Location.NULL; 697 //@ ensures \result != null; 698 public final ThisExpr getInferredThisExpr(/*@ non_null @*/ TypeSig C, 699 int loc) { 700 ThisExpr newThis = ThisExpr.make((C == getEnclosingClass()) 701 ? null : C, loc); 702 newThis.inferred = true; 703 704 return newThis; 705 } 706 707 708 /** 709 * Return an inferred ObjectDesignator for use in a reference to 710 * a possibly-instance member of class C from here. <p> 711 * 712 * 713 * If C's instance variables are not accessible from this point 714 * (see canAccessInstance(-)), then returns "C.". <p> 715 * 716 * Otherwise returns an inferred "[C.]this.". 717 * (cf. getInferredThisExpr(-)) 718 * 719 * loc is used as the location for the this. and C. parts. 720 */ 721 //@ requires loc != Location.NULL; 722 //@ ensures \result != null; 723 public final ObjectDesignator getObjectDesignator(/*@ non_null @*/ TypeSig C, 724 int loc) { 725 if (!canAccessInstance(C)) 726 return TypeObjectDesignator.make(loc, C); 727 else 728 return ExprObjectDesignator.make(loc, 729 getInferredThisExpr(C, loc)); 730 } 731 }