root/trunk/ProjectFortress/src/com/sun/fortress/compiler/typechecker/TypeEnv.java @ 3915

Revision 3915, 20.7 KB (checked in by jrhil47, 5 months ago)

[index] Changed all Functional indices to store a thunk to get the return types, since during type checking the return types might need to be lazily evaluated. Also changed Functional indices to yield an Option for return types.
[type checker] Started implementing extraction of bindings from nodes for type environments.

Line 
1/*******************************************************************************
2    Copyright 2009 Sun Microsystems, Inc.,
3    4150 Network Circle, Santa Clara, California 95054, U.S.A.
4    All rights reserved.
5
6    U.S. Government Rights - Commercial software.
7    Government users are subject to the Sun Microsystems, Inc. standard
8    license agreement and applicable provisions of the FAR and its supplements.
9
10    Use is subject to license terms.
11
12    This distribution may include materials developed by third parties.
13
14    Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
15    trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
16 ******************************************************************************/
17
18package com.sun.fortress.compiler.typechecker;
19
20import static com.sun.fortress.nodes_util.NodeFactory.makeEffect;
21import static com.sun.fortress.nodes_util.NodeFactory.makeId;
22import static com.sun.fortress.nodes_util.NodeFactory.makeKeywordType;
23import static com.sun.fortress.nodes_util.NodeFactory.typeSpan;
24import static edu.rice.cs.plt.tuple.Option.none;
25import static edu.rice.cs.plt.tuple.Option.some;
26import static edu.rice.cs.plt.tuple.Option.wrap;
27import static com.sun.fortress.scala_src.useful.Lists.*;
28
29import java.util.ArrayList;
30import java.util.Arrays;
31import java.util.Collection;
32import java.util.List;
33import java.util.Map;
34import java.util.Set;
35
36import com.sun.fortress.compiler.Types;
37import com.sun.fortress.compiler.index.CompilationUnitIndex;
38import com.sun.fortress.compiler.index.Function;
39import com.sun.fortress.compiler.index.Method;
40import com.sun.fortress.compiler.index.TypeConsIndex;
41import com.sun.fortress.compiler.index.Variable;
42import com.sun.fortress.nodes.APIName;
43import com.sun.fortress.nodes.AnonymousFnName;
44import com.sun.fortress.nodes.ArrowType;
45import com.sun.fortress.nodes.ConstructorFnName;
46import com.sun.fortress.nodes.FnDecl;
47import com.sun.fortress.nodes.Id;
48import com.sun.fortress.nodes.IdOrOp;
49import com.sun.fortress.nodes.IdOrOpOrAnonymousName;
50import com.sun.fortress.nodes.KeywordType;
51import com.sun.fortress.nodes.KindBool;
52import com.sun.fortress.nodes.KindDim;
53import com.sun.fortress.nodes.KindInt;
54import com.sun.fortress.nodes.KindNat;
55import com.sun.fortress.nodes.KindOp;
56import com.sun.fortress.nodes.KindType;
57import com.sun.fortress.nodes.KindUnit;
58import com.sun.fortress.nodes.LValue;
59import com.sun.fortress.nodes.LocalVarDecl;
60import com.sun.fortress.nodes.Node;
61import com.sun.fortress.nodes.NodeAbstractVisitor;
62import com.sun.fortress.nodes.NodeDepthFirstVisitor;
63import com.sun.fortress.nodes.Op;
64import com.sun.fortress.nodes.Param;
65import com.sun.fortress.nodes.StaticArg;
66import com.sun.fortress.nodes.StaticParam;
67import com.sun.fortress.nodes.Type;
68import com.sun.fortress.nodes._InferenceVarType;
69import com.sun.fortress.nodes_util.ExprFactory;
70import com.sun.fortress.nodes_util.Modifiers;
71import com.sun.fortress.nodes_util.NodeFactory;
72import com.sun.fortress.nodes_util.NodeUtil;
73import edu.rice.cs.plt.collect.Relation;
74import edu.rice.cs.plt.tuple.Option;
75
76/**
77 * This class is used by the type checker to represent static type environments,
78 * mapping bound variables to their types.
79 * Where-clause bound variables are not yet supported.
80 */
81public abstract class TypeEnv {
82
83    /**
84     * Construct a new TypeEnv for a given CompilationUnitIndex.
85     */
86    public static TypeEnv make(CompilationUnitIndex cu) {
87        TypeEnv typeEnv = TypeEnv.make();
88
89        // Add all top-level function names to the component-level environment.
90        typeEnv = typeEnv.extendWithFunctions(cu.functions());
91
92        // Iterate over top-level variables, adding each to the component-level environment.
93        typeEnv = typeEnv.extend(cu.variables());
94
95        //Iterate over top level types, adding each to component-level environment
96
97        typeEnv = typeEnv.extendWithTypeConses(cu.typeConses());
98
99
100        return typeEnv;
101    }
102
103    /**
104     * Construct a new TypeEnv from the given bindings.
105     */
106    public static TypeEnv make(LValue... entries) {
107        return EmptyTypeEnv.ONLY.extend(entries);
108    }
109
110    /**
111     * Construct a new TypeEnv from the given bindings.
112     */
113    public static TypeEnv make(Map<Id, Variable> entries) {
114        return EmptyTypeEnv.ONLY.extend(entries);
115    }
116
117    /**
118     * Get a type from a Param.
119     */
120    protected static Option<Type> typeFromParam(Param param) {
121        if ( ! NodeUtil.isVarargsParam(param) ) {
122            return param.getIdType();
123        } else { // a varargs param
124            // Convert the declared varargs type into a reference to
125            // FortressBuiltin.ImmutableHeapSequence.
126            Type result = Types.makeVarargsParamType(param.getVarargsType().unwrap());
127            return some(result);
128        }
129    }
130
131    protected static ArrowType genericArrowFromDecl(FnDecl decl) {
132        return NodeFactory.makeArrowType(NodeUtil.getSpan(decl), false,
133                             domainFromParams(NodeUtil.getParams(decl)),
134                             // all types have been filled in at this point
135                             NodeUtil.getReturnType(decl).unwrap(),
136                             makeEffect(NodeUtil.getSpan(decl).getEnd(),
137                                        NodeUtil.getThrowsClause(decl)),
138                             NodeUtil.getStaticParams(decl),
139                             NodeUtil.getWhereClause(decl));
140    }
141
142    /**
143     * Get a domain from a list of params.
144     */
145    protected static Type domainFromParams(List<Param> params) {
146        List<Type> paramTypes = new ArrayList<Type>();
147        List<KeywordType> keywordTypes = new ArrayList<KeywordType>();
148        Option<Type> varargsType = none();
149
150        for (Param param: params) {
151            if ( ! NodeUtil.isVarargsParam(param) ) {
152                Option<Type> maybeType = param.getIdType();
153
154                if (maybeType.isSome()) { // An explicit type is declared.
155                    if (param.getDefaultExpr().isSome()) { // We have a keyword param.
156                        keywordTypes.add(makeKeywordType(param.getName(), maybeType.unwrap()));
157                    } else { // We have an ordinary param.
158                        paramTypes.add(maybeType.unwrap());
159                    }
160                } else { // No type is explicitly declared for this parameter.
161                    if (param.getDefaultExpr().isSome()) { // We have a keyword param.
162                        keywordTypes.add(makeKeywordType(param.getName(), NodeFactory.make_InferenceVarType(NodeUtil.getSpan(param))));
163                    } else { // We have an ordinary param.
164                        paramTypes.add(NodeFactory.make_InferenceVarType(NodeUtil.getSpan(param)));
165                    }
166                }
167            } else { // We have a varargs param.
168                varargsType = some(param.getVarargsType().unwrap());
169            }
170        }
171
172        return NodeFactory.makeDomain(NodeFactory.makeSpan("TypeEnv_bogus_span_for_empty_list", params), paramTypes, varargsType, keywordTypes);
173    }
174
175    public static List<StaticArg> staticParamsToArgs(List<StaticParam> params) {
176        List<StaticArg> result = new ArrayList<StaticArg>();
177
178        for (StaticParam param: params) {
179            final IdOrOp name = param.getName();
180            result.add(param.getKind().accept(new NodeAbstractVisitor<StaticArg>() {
181                        public StaticArg forKindBool(KindBool k) {
182                            return NodeFactory.makeBoolArg(typeSpan,
183                                                           NodeFactory.makeBoolRef(typeSpan, (Id)name));
184                        }
185                        public StaticArg forKindDim(KindDim k) {
186                            return NodeFactory.makeDimArg(typeSpan,
187                                                          NodeFactory.makeDimRef(typeSpan, (Id)name));
188                        }
189                        public StaticArg forKindInt(KindInt k) {
190                            return NodeFactory.makeIntArg(typeSpan,
191                                                          NodeFactory.makeIntRef(typeSpan, (Id)name));
192                        }
193                        public StaticArg forKindNat(KindNat k) {
194                            return NodeFactory.makeIntArg(typeSpan,
195                                                          NodeFactory.makeIntRef(typeSpan, (Id)name));
196                        }
197                        public StaticArg forKindType(KindType k) {
198                            return NodeFactory.makeTypeArg(typeSpan,
199                                                           NodeFactory.makeVarType(typeSpan, (Id)name));
200                        }
201                        public StaticArg forKindUnit(KindUnit k) {
202                            return NodeFactory.makeUnitArg(typeSpan, NodeFactory.makeUnitRef(typeSpan, false, (Id)name));
203                        }
204                        public StaticArg forKindOp(KindOp that) {
205                            return NodeFactory.makeOpArg(typeSpan,
206                                                         ExprFactory.makeOpRef((Op)name));
207                        }
208                    }));
209        }
210        return result;
211    }
212
213    static Id removeApi(Id id) {
214        return NodeFactory.makeIdFromLast(id);
215    }
216
217    static Op removeApi(Op id) {
218        return NodeFactory.makeOp(NodeUtil.getSpan(id), Option.<APIName>none(),
219                                  id.getText(), id.getFixity(), id.isEnclosing());
220    }
221
222    static IdOrOpOrAnonymousName removeApi(IdOrOpOrAnonymousName id) {
223        return id.accept(new NodeDepthFirstVisitor<IdOrOpOrAnonymousName>(){
224                        @Override public IdOrOpOrAnonymousName forId(Id that) { return removeApi(that); }
225                        @Override
226                        public IdOrOpOrAnonymousName forOp(Op that) {
227                            return NodeFactory.makeOp(NodeUtil.getSpan(that), Option.<APIName>none(),
228                                          that.getText(), that.getFixity(), that.isEnclosing());
229                        }
230                        @Override
231                        public IdOrOpOrAnonymousName forAnonymousFnName(AnonymousFnName that) {
232                                return NodeFactory.makeAnonymousFnName(NodeUtil.getSpan(that),
233                                                           Option.<APIName>none());
234                        }
235                        @Override
236                        public IdOrOpOrAnonymousName forConstructorFnName(ConstructorFnName that) {
237                                return NodeFactory.makeConstructorFnName(NodeUtil.getSpan(that),
238                                                             Option.<APIName>none(),
239                                                             that.getConstructor());
240                        }
241        });
242    }
243
244    /**
245     * Return a BindingLookup that binds the given IdOrOpOrAnonymousName to a type
246     * (if the given IdOrOpOrAnonymousName is in this type environment).
247     */
248    public abstract Option<BindingLookup> binding(IdOrOpOrAnonymousName var);
249
250    /**
251     * Return the {@code StaticParam} that declared the given id, or none if it
252     * is not in scope.
253     */
254    public abstract Option<StaticParam> staticParam(IdOrOpOrAnonymousName id);
255
256    /**
257     * Return true iff the given id is bound as a StaticParam.
258     */
259    public boolean boundStaticParam(Id id) { return staticParam(id).isSome(); }
260
261    /**
262     * Return the {@code Node} that declared the given id, or None if the id does not
263     * exist. Note that this method should not be passed the id of a function, since
264     * functions have multiple declaration sites. You can tell if an id is a function
265     * or not by calling type() on the same id.
266     *
267     * @exception IllegalArgumentException If var is a function, since functions have
268     * multiple declaration sites.
269     */
270    public abstract Option<Node> declarationSite(IdOrOpOrAnonymousName var);
271
272    /**
273     * Return the type of the given IdOrOpOrAnonymousName (if the given IdOrOpOrAnonymousName is in
274     * this type environment).
275     */
276    public final Option<Type> getType(IdOrOpOrAnonymousName var) {
277        Option<BindingLookup> _binding = binding(var);
278        if (_binding.isSome()) {
279            Option<Type> type = _binding.unwrap().getType();
280            if (type.isSome()) {
281                return type;
282            } else {
283                // When an explicit type is not given in the source code, the
284                // type environment returns a fresh implicit type. Note that
285                // a distinct implicit type is returned each time type() is
286                // called. This is necessary because TypeEnvs are immutable.
287                // It's up to the type checker to accumulate the constraints
288                // on implicit types.
289                return Option.<Type>wrap(NodeFactory.make_InferenceVarType(NodeUtil.getSpan(var)));
290            }
291        } else {
292            return Option.none();
293        }
294    }
295
296    /**
297     * Return the list of modifiers for the given IdOrOpOrAnonymousName (if that
298     * IdOrOpOrAnonymousName is in this type environment).
299     */
300    public final Option<Modifiers> mods(IdOrOpOrAnonymousName var) {
301        Option<BindingLookup> binding = binding(var);
302
303        if (binding.isSome()) { return wrap(binding.unwrap().getMods()); }
304        else { return Option.none(); }
305    }
306
307    /**
308     * Indicate whether the given IdOrOpOrAnonymousName is bound as a mutable
309     * variable (if the given IdOrOpOrAnonymousName is in this type environment).
310     */
311    public final Option<Boolean> mutable(IdOrOpOrAnonymousName var) {
312        Option<BindingLookup> binding = binding(var);
313
314        if (binding.isSome()) { return wrap(binding.unwrap().isMutable()); }
315        else { return Option.none(); }
316    }
317
318    /**
319     * Convenience method that takes a String and returns the type of the
320     * corresponding Id in this type environment.
321     */
322    public final Option<Type> type(String var) { return getType(makeId(NodeFactory.internalSpan,var)); }
323
324    /**
325     * Convenience method that takes a String and returns the modifiers for the
326     * corresponding Id in this type environment.
327     */
328    public final Option<Modifiers> mods(String var) {
329        return mods(makeId(NodeFactory.internalSpan,var));
330    }
331
332    /**
333     * Convenience method that takes a String and indicates whether the
334     * corresponding Id in this type environment is mutable or not.
335     */
336    public final Option<Boolean> mutable(String var) {
337        return mutable(makeId(NodeFactory.internalSpan,var));
338    }
339
340    public abstract List<BindingLookup> contents();
341    public final String description() {
342        StringBuffer sb = new StringBuffer();
343        sb.append('(');
344        for (BindingLookup b : contents()) {
345            sb.append(b);
346            sb.append(", ");
347        }
348        sb.delete(sb.length()-2, sb.length());
349        sb.append(')');
350        return sb.toString();
351    }
352
353    /**
354     * Produce a new type environment extending this with the given variable bindings.
355     * Unfortunately, we must give some variants of 'extend' long names to allow the
356     * compiler to distinguish them from other variants with the same _erased_ signature.
357     */
358    // DONE
359    public final TypeEnv extend(LValue... entries) {
360        if (entries.length == 0) { return this; }
361        else { return new LValueTypeEnv(entries, this); }
362    }
363    // DONE
364    public final TypeEnv extendWithLValues(List<LValue> entries) {
365        if (entries.size() == 0) { return this; }
366        else { return new LValueTypeEnv(entries, this); }
367    }
368    // DONE
369    public final TypeEnv extend(LocalVarDecl decl) {
370        if (decl.getLhs().size() == 0) { return this; }
371        else { return new LocalVarTypeEnv(decl, this); }
372    }
373    // CALLED WITH CompilationUnitIndex.variables()
374    // DONE
375    public final TypeEnv extend(Map<Id, Variable> vars) {
376        if (vars.size() == 0) { return this; }
377        else { return new VarTypeEnv(vars, this); }
378    }
379    // DONE
380    public final TypeEnv extendWithFunctions(Relation<IdOrOpOrAnonymousName, ? extends Function> fns) {
381        if (fns.size() == 0) { return this; }
382        else { return new FnTypeEnv(fns, this); }
383    }
384    // UNNECESSARY
385    public final TypeEnv extendWithFnDecls(Relation<IdOrOpOrAnonymousName, FnDecl> fns) {
386        if (fns.size() == 0) { return this; }
387        else { return new FnDeclTypeEnv(fns, this); }
388    }
389    // DERIVED
390    public final TypeEnv extendWithMethods(Relation<IdOrOpOrAnonymousName, Method> methods) {
391        if (methods.size() == 0) { return this; }
392        else { return new MethodTypeEnv(methods, this); }
393    }
394    // DERIVED
395    public final TypeEnv extendWithParams(List<Param> params) {
396        if (params.size() == 0) { return this; }
397        else { return new ParamTypeEnv(params, this); }
398    }
399    // DERIVED
400    public final TypeEnv extendWithParams(scala.List<Param> params) {
401        return extendWithParams(toJavaList(params));
402    }
403
404    public final TypeEnv extendWithStaticParams(List<StaticParam> params) {
405        if( params.size() == 0 ) {return this; }
406        else { return new StaticParamTypeEnv(params,this); }
407    }
408
409    public final TypeEnv extendWithStaticParams(scala.List<StaticParam> params) {
410        return extendWithStaticParams(toJavaList(params));
411    }
412    // DONE
413    public final TypeEnv extendWithTypeConses(Map<Id, TypeConsIndex> typeConses) {
414        if (typeConses.isEmpty()) {
415            return this;
416        } else {
417            return new ObjectTypeEnv(typeConses, this);
418        }
419    }
420
421    public final TypeEnv extend(Option<List<Param>> params) {
422        if (params.isNone()) { return this; }
423        else { return extendWithParams(params.unwrap()); }
424    }
425
426    public final TypeEnv extend(Param param) {
427        return new ParamTypeEnv(Arrays.asList(param), this);
428    }
429
430    public final TypeEnv extendWithout(Node declSite, Set<? extends IdOrOpOrAnonymousName> entries) {
431        return new ConcealingTypeEnv(declSite, entries, this);
432    }
433
434    /**
435     * A wrapper around the binding found in the TypeEnv.  Since some bindings
436     * do not have an Id to be indexed, there is no way to create the LValue
437     * node to represent the binding.  In the case of operators, for example,
438     * only a IdOrOpOrAnonymousName exists, so the BindingLookup exports the same methods
439     * that LValue does, since an LValue cannot be created.
440     */
441    public static class BindingLookup {
442
443        private final IdOrOpOrAnonymousName var;
444        private final Option<Type> type;
445        private final Modifiers mods;
446        private final boolean mutable;
447
448        public BindingLookup(LValue binding) {
449            var = binding.getName();
450            type = binding.getIdType();
451            mods = binding.getMods();
452            mutable = binding.isMutable();
453        }
454
455        public BindingLookup(IdOrOpOrAnonymousName _var, FnDecl decl) {
456            var = _var;
457            type = Option.<Type>wrap(genericArrowFromDecl(decl));
458            mods = NodeUtil.getMods(decl);
459            mutable = false;
460        }
461
462        public BindingLookup(IdOrOpOrAnonymousName _var, Collection<FnDecl> decls) {
463            var = _var;
464            List<Type> overloads = new ArrayList<Type>();
465            Modifiers mods = Modifiers.None;
466            for (FnDecl decl : decls) {
467                overloads.add(genericArrowFromDecl(decl));
468            }
469            this.mods = mods;
470            type = Option.<Type>some(NodeFactory.makeIntersectionType(NodeFactory.makeSetSpan("impossible", overloads), overloads));
471            mutable = false;
472        }
473
474        public BindingLookup(IdOrOpOrAnonymousName _var, Type _type) {
475            this(_var, _type, Modifiers.None, false);
476        }
477
478        public BindingLookup(IdOrOpOrAnonymousName _var, Option<Type> _type) {
479            this(_var, _type, Modifiers.None, false);
480        }
481
482        public BindingLookup(IdOrOpOrAnonymousName _var, Type _type, Modifiers _mods) {
483            this(_var, _type, _mods, false);
484        }
485
486        public BindingLookup(IdOrOpOrAnonymousName _var, Option<Type> _type, Modifiers _mods) {
487            this(_var, _type, _mods, false);
488        }
489
490        public BindingLookup(IdOrOpOrAnonymousName _var, Type _type, Modifiers _mods, boolean _mutable) {
491            var = _var;
492            type = some(_type);
493            mods = _mods;
494            mutable = _mutable;
495        }
496
497        public BindingLookup(IdOrOpOrAnonymousName _var, Option<Type> _type, Modifiers _mods, boolean _mutable) {
498            var = _var;
499            type = _type;
500            mods = _mods;
501            mutable = _mutable;
502        }
503
504        public IdOrOpOrAnonymousName getVar() { return var; }
505        public Option<Type> getType() { return type; }
506        public Modifiers getMods() { return mods; }
507
508        public boolean isMutable() {
509            if( mutable )
510                return true;
511
512            return mods.isMutable();
513        }
514
515        @Override
516        public String toString() {
517            return String.format("%s:%s", var, type);
518        }
519
520    }
521
522    /**
523     * Replace all of the inference variables given with their corresponding types.
524     */
525        public abstract TypeEnv replaceAllIVars(Map<_InferenceVarType, Type> ivars);
526}
Note: See TracBrowser for help on using the browser.