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

Revision 3865, 15.8 KB (checked in by sukyoungryu, 5 months ago)

[static checker] Check that if the comprises clause of trait T includes ..., any subtrait of T is not exposed by the API. Added tests.

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