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    }