root/trunk/ProjectFortress/src/com/sun/fortress/compiler/StaticChecker.java @ 3876

Revision 3876, 16.3 KB (checked in by EricAllen, 5 months ago)

Added API linker and associated hooks (work in progress).
Added some testing of cache cleaning.

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;
19
20import static com.sun.fortress.exceptions.InterpreterBug.bug;
21
22import java.util.ArrayList;
23import java.util.HashSet;
24import java.util.List;
25import java.util.Map;
26
27import com.sun.fortress.Shell;
28import com.sun.fortress.compiler.index.ApiIndex;
29import com.sun.fortress.compiler.index.ComponentIndex;
30import com.sun.fortress.compiler.typechecker.InferenceVarInserter;
31import com.sun.fortress.compiler.typechecker.InferenceVarReplacer;
32import com.sun.fortress.compiler.typechecker.TypeChecker;
33import com.sun.fortress.compiler.typechecker.TypeCheckerOutput;
34import com.sun.fortress.compiler.typechecker.TypeCheckerResult;
35import com.sun.fortress.compiler.typechecker.TypeEnv;
36import com.sun.fortress.compiler.typechecker.TypeNormalizer;
37import com.sun.fortress.compiler.typechecker.TypesUtil;
38import com.sun.fortress.compiler.typechecker.constraints.ConstraintUtil;
39import com.sun.fortress.compiler.typechecker.TypeAnalyzer;
40import com.sun.fortress.exceptions.StaticError;
41import com.sun.fortress.nodes.Api;
42import com.sun.fortress.nodes.APIName;
43import com.sun.fortress.nodes.Component;
44import com.sun.fortress.nodes.Node;
45import com.sun.fortress.nodes.Type;
46import com.sun.fortress.repository.FortressRepository;
47import com.sun.fortress.scala_src.linker.ApiLinker;
48import com.sun.fortress.scala_src.linker.CompoundApiChecker;
49import com.sun.fortress.scala_src.typechecker.CoercionTest;
50import com.sun.fortress.scala_src.typechecker.ExportChecker;
51import com.sun.fortress.scala_src.typechecker.TraitTable;
52import com.sun.fortress.scala_src.typechecker.TypeHierarchyChecker;
53import com.sun.fortress.scala_src.typechecker.TypeWellFormedChecker;
54import com.sun.fortress.scala_src.typechecker.OverloadingChecker;
55import com.sun.fortress.scala_src.typechecker.STypeChecker;
56import com.sun.fortress.scala_src.typechecker.STypeCheckerFactory;
57import com.sun.fortress.scala_src.useful.Lists;
58import edu.rice.cs.plt.iter.IterUtil;
59import edu.rice.cs.plt.tuple.Option;
60import edu.rice.cs.plt.tuple.Pair;
61
62/**
63 * Verifies all static properties of a valid Fortress program that require
64 * interpreting types.  Assumes all names referring to APIs are fully-qualified,
65 * and that the other transformations handled by the {@link Disambiguator} have
66 * been performed.  In addition to checking the program, performs the following
67 * transformations:
68 * <ul>
69 * <li>All unknown placeholder types are provided explicit (inferred) values.</li>
70 * <li>Explicit coercions are added where needed. (Not yet!) </li>
71 * <li>Juxtapositions are given a binary structure.</li>
72 * <li>FieldRefs that refer to methods and that are followed by an argument expression
73 *     become MethodInvocations.</li>
74 * </li>
75 */
76public class StaticChecker {
77
78    public static class ApiResult extends StaticPhaseResult {
79        private final Map<APIName, ApiIndex> _apis;
80        private final List<APIName> _failedApis;
81        private final TypeCheckerOutput _typeCheckerOutput;
82
83        public ApiResult(Map<APIName, ApiIndex> apis,
84                               List<APIName> failedApis,
85                               Iterable<? extends StaticError> errors,
86                               TypeCheckerOutput typeCheckerOutput) {
87            super(errors);
88            _apis = apis;
89            _failedApis = failedApis;
90            _typeCheckerOutput = typeCheckerOutput;
91        }
92        public Map<APIName, ApiIndex> apis() { return _apis; }
93        public List<APIName> failed() { return _failedApis; }
94
95        public TypeCheckerOutput typeCheckerOutput() {
96            return this._typeCheckerOutput;
97        }
98    }
99
100    /**
101     * Check the given apis. To support circular references, the apis should appear
102     * in the given environment.
103     */
104    public static ApiResult checkApis(Map<APIName, ApiIndex> apis,
105                                      GlobalEnvironment env,
106                                      FortressRepository repository) {
107        List<APIName> failedApis = new ArrayList<APIName>();
108        Iterable<? extends StaticError> errors = new HashSet<StaticError>();
109        if ( Shell.getTypeChecking() == true &&
110             WellKnownNames.areCompilerLibraries() ) {
111            HashSet<Api> checkedApis = new HashSet<Api>();
112            TypeCheckerOutput type_checker_output = TypeCheckerOutput.emptyOutput();
113
114            for (APIName apiName : apis.keySet()) {
115                TypeCheckerResult checked = checkApi(apis.get(apiName), env, repository);
116                checkedApis.add((Api)checked.ast());
117                if (!checked.isSuccessful()) failedApis.add(apiName);
118                errors = IterUtil.compose(checked.errors(), errors);
119                type_checker_output = new TypeCheckerOutput( type_checker_output,
120                                                             checked.getTypeCheckerOutput() );
121            }
122            return new ApiResult
123                (IndexBuilder.buildApis(checkedApis,
124                                        System.currentTimeMillis()).apis(),
125                 failedApis,
126                 errors,
127                 type_checker_output);
128        } else
129            return new ApiResult(apis, failedApis, errors,
130                                 TypeCheckerOutput.emptyOutput());
131    }
132
133    public static class ComponentResult extends StaticPhaseResult {
134        private final Map<APIName, ComponentIndex> _components;
135        private final List<APIName> _failedComponents;
136        private final TypeCheckerOutput _typeCheckerOutput;
137
138        public ComponentResult(Map<APIName, ComponentIndex> components,
139                               List<APIName> failedComponents,
140                               Iterable<? extends StaticError> errors,
141                               TypeCheckerOutput typeCheckerOutput) {
142            super(errors);
143            _components = components;
144            _failedComponents = failedComponents;
145            _typeCheckerOutput = typeCheckerOutput;
146        }
147        public Map<APIName, ComponentIndex> components() { return _components; }
148        public List<APIName> failed() { return _failedComponents; }
149
150        public TypeCheckerOutput typeCheckerOutput() {
151            return this._typeCheckerOutput;
152        }
153    }
154
155    /** Statically check the given components. */
156    public static ComponentResult
157        checkComponents(Map<APIName, ComponentIndex> components,
158                        GlobalEnvironment env,
159                        FortressRepository repository)
160    {
161        HashSet<Component> checkedComponents = new HashSet<Component>();
162        Iterable<? extends StaticError> errors = new HashSet<StaticError>();
163        List<APIName> failedComponents = new ArrayList<APIName>();
164
165        TypeCheckerOutput type_checker_output = TypeCheckerOutput.emptyOutput();
166
167        for (APIName componentName : components.keySet()) {
168            TypeCheckerResult checked = checkComponent(components.get(componentName), env,
169                                                       repository);
170            checkedComponents.add((Component)checked.ast());
171            if (!checked.isSuccessful())
172                failedComponents.add(componentName);
173
174            errors = IterUtil.compose(checked.errors(), errors);
175            type_checker_output = new TypeCheckerOutput( type_checker_output, checked.getTypeCheckerOutput() );
176        }
177        return new ComponentResult
178            (IndexBuilder.buildComponents(checkedComponents,
179                                          System.currentTimeMillis()).
180             components(),
181             failedComponents,
182             errors,
183             type_checker_output);
184    }
185
186    public static TypeCheckerResult checkComponent(ComponentIndex component,
187                                                   GlobalEnvironment env,
188                                                   FortressRepository repository) {
189        if (Shell.getTypeChecking() == true) {
190            // Check type hierarchy to ensure acyclicity.
191            List<StaticError> errors = new TypeHierarchyChecker(component, env, repository).checkHierarchy();
192            if (! errors.isEmpty()) {
193                return new TypeCheckerResult(component.ast(), errors);
194            }
195
196            Node component_ast = component.ast();
197            // Replace implicit types with explicit ones.
198            if (!Shell.getScala()) {
199                component_ast = component_ast.accept(new InferenceVarInserter());
200            } else {
201                errors.addAll(new ReturnTypeChecker().getErrors(component_ast));
202                if(!errors.isEmpty())
203                    return new TypeCheckerResult(component_ast,errors);
204            }
205            component_ast = component_ast.accept(new TypeNormalizer());
206            component = IndexBuilder.builder.buildComponentIndex((Component)component_ast,
207                                                                 System.currentTimeMillis());
208            TraitTable traitTable = new TraitTable(component, env);
209            TypeAnalyzer typeAnalyzer = TypeAnalyzer.make(traitTable);
210
211            if (Shell.testCoercion())
212                errors.addAll(new CoercionTest(typeAnalyzer).run());
213
214            errors.addAll(new TypeHierarchyChecker(component, env, repository).checkAcyclicHierarchy());
215            errors.addAll(new TypeWellFormedChecker(component, env, typeAnalyzer).check());
216
217            TypeCheckerResult result;
218            if ( ! Shell.getScala() ) {
219                // typecheck...
220                result = typeCheck(component, env, traitTable, component_ast, false);
221                // then replace inference variables...
222                InferenceVarReplacer rep = new InferenceVarReplacer(result.getIVarResults());
223                component_ast = (Component)result.ast().accept(rep);
224                // then typecheck again!!!
225                component = IndexBuilder.builder.buildComponentIndex((Component)component_ast,
226                                                                     System.currentTimeMillis());
227                result = typeCheck(component, env, traitTable, component_ast, true);
228            } else {
229                TypeEnv typeEnv = typeCheckEnv(component, env);
230                ConstraintUtil.useScalaFormulas();
231                STypeChecker typeChecker = STypeCheckerFactory.make(component, traitTable, typeEnv, typeAnalyzer);
232                component_ast = typeChecker.typecheck(component_ast);
233                component = IndexBuilder.builder.buildComponentIndex((Component)component_ast,
234                    System.currentTimeMillis());
235                errors.addAll(Lists.toJavaList(typeChecker.getErrors()));
236                result = new TypeCheckerResult(component_ast, errors);
237            }
238            result.setAst(result.ast().accept(new TypeNormalizer()));
239            // There should be no Inference vars left at this point
240            if( TypesUtil.assertAfterTypeChecking(result.ast()) )
241                bug("Result of typechecking still contains ArrayType/MatrixType/_InferenceVarType.\n" +
242                    result.ast());
243
244            errors.addAll(new TypeWellFormedChecker(component, env, typeAnalyzer).check());
245            if ( ! errors.isEmpty() ) {
246                result = addErrors(errors, result);
247                return result;
248            }
249
250            // Check overloadings in this component.
251            errors.addAll(new OverloadingChecker(component, env, repository).checkOverloading());
252            if ( ! errors.isEmpty() ) {
253                result = addErrors(errors, result);
254                return result;
255            }
256
257            // Check the set of exported APIs in this component.
258            errors.addAll(ExportChecker.checkExports(component, env, repository));
259            result = addErrors(errors, result);
260            return result;
261         } else {
262             return new TypeCheckerResult(component.ast(), IterUtil.<StaticError>empty());
263         }
264    }
265
266    private static TypeCheckerResult typeCheck(ComponentIndex component,
267                                               GlobalEnvironment env,
268                                               TraitTable traitTable,
269                                               Node component_ast,
270                                               boolean postInference) {
271        TypeEnv typeEnv = typeCheckEnv(component, env);
272        ConstraintUtil.useJavaFormulas();
273        TypeChecker typeChecker = new TypeChecker(traitTable, typeEnv,
274                                                  component, postInference);
275        return component_ast.accept(typeChecker);
276    }
277
278    private static TypeEnv typeCheckEnv(ComponentIndex component,
279                                        GlobalEnvironment env) {
280        TypeEnv typeEnv = TypeEnv.make(component);
281        // Add all top-level function names to the component-level environment.
282        typeEnv = typeEnv.extendWithFunctions(component.functions());
283        // Iterate over top-level variables,
284        // adding each to the component-level environment.
285        typeEnv = typeEnv.extend(component.variables());
286        // Add all top-level object names to the component-level environment.
287        typeEnv = typeEnv.extendWithTypeConses(component.typeConses());
288        return typeEnv;
289    }
290
291    public static TypeCheckerResult checkApi(ApiIndex api,
292                                             GlobalEnvironment env,
293                                             FortressRepository repository) {
294
295        // Check if this is a compound API, and, if so, link it into a single API.
296        List<StaticError> errors = new CompoundApiChecker(env, repository).check(api);
297        if (! errors.isEmpty()) {
298            return new TypeCheckerResult(api.ast(), errors);
299        }
300        api = new ApiLinker(env, repository).link(api);
301
302        // Check type hierarchy to ensure acyclicity.
303        errors = new TypeHierarchyChecker(api, env, repository).checkHierarchy();
304        if (! errors.isEmpty()) {
305            return new TypeCheckerResult(api.ast(), errors);
306        }
307        Node api_ast = api.ast();
308        api_ast = api_ast.accept(new TypeNormalizer());
309        api = IndexBuilder.builder.buildApiIndex((Api)api_ast,
310                                                 System.currentTimeMillis());
311        TraitTable traitTable = new TraitTable(api, env);
312        TypeAnalyzer typeAnalyzer = TypeAnalyzer.make(traitTable);
313
314        if (Shell.testCoercion())
315            errors.addAll(new CoercionTest(typeAnalyzer).run());
316
317        errors.addAll(new TypeHierarchyChecker(api, env, repository).checkAcyclicHierarchy());
318        errors.addAll(new TypeWellFormedChecker(api, env, typeAnalyzer).check());
319
320        TypeCheckerResult result = new TypeCheckerResult(api_ast, errors);
321        result.setAst(result.ast().accept(new TypeNormalizer()));
322        // There should be no Inference vars left at this point
323        if( TypesUtil.assertAfterTypeChecking(result.ast()) )
324            bug("Result of typechecking still contains ArrayType/MatrixType/_InferenceVarType.\n" +
325                result.ast());
326
327        errors.addAll(new TypeWellFormedChecker(api, env, typeAnalyzer).check());
328        if ( ! errors.isEmpty() ) {
329            result = addErrors(errors, result);
330            return result;
331        }
332
333        // Check overloadings in this API.
334        errors = new OverloadingChecker(api, env, repository).checkOverloading();
335        if ( ! errors.isEmpty() ) {
336            result = addErrors(errors, result);
337        }
338        return result;
339    }
340
341    private static TypeCheckerResult addErrors(List<StaticError> errors,
342                                               TypeCheckerResult result) {
343        if ( ! errors.isEmpty() ) {
344            for ( StaticError error : errors ) {
345                result = TypeCheckerResult.addError(result, error);
346            }
347        }
348        return result;
349    }
350
351}
Note: See TracBrowser for help on using the browser.