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