| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Encapsulates how to invoke the analyzer resolver and overrides how it | 5 /// Encapsulates how to invoke the analyzer resolver and overrides how it |
| 6 /// computes types on expressions to use our restricted set of types. | 6 /// computes types on expressions to use our restricted set of types. |
| 7 library dev_compiler.src.checker.resolver; | 7 library dev_compiler.src.checker.resolver; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
| 10 import 'package:analyzer/src/generated/ast.dart'; | 10 import 'package:analyzer/src/generated/ast.dart'; |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 for (var c in globalsAndStatics) { | 117 for (var c in globalsAndStatics) { |
| 118 for (var e in _VarExtractor.extract(c.initializer)) { | 118 for (var e in _VarExtractor.extract(c.initializer)) { |
| 119 // Note: declaration is null for variables that come from other strongly | 119 // Note: declaration is null for variables that come from other strongly |
| 120 // connected components. | 120 // connected components. |
| 121 var declaration = elementToDeclaration[e]; | 121 var declaration = elementToDeclaration[e]; |
| 122 if (declaration != null) constGraph.addEdge(c, declaration); | 122 if (declaration != null) constGraph.addEdge(c, declaration); |
| 123 } | 123 } |
| 124 } | 124 } |
| 125 | 125 |
| 126 for (var component in constGraph.computeTopologicalSort()) { | 126 for (var component in constGraph.computeTopologicalSort()) { |
| 127 if (_options.inferTransitively) { | 127 component.forEach((v) => _reanalyzeVar(visitors, v)); |
| 128 component.forEach((v) => _reanalyzeVar(visitors, v)); | |
| 129 } | |
| 130 _inferVariableFromInitializer(component); | 128 _inferVariableFromInitializer(component); |
| 131 } | 129 } |
| 132 } | 130 } |
| 133 | 131 |
| 134 _inferInstanceFields(List<ClassDeclaration> classes, | 132 _inferInstanceFields(List<ClassDeclaration> classes, |
| 135 Map<Source, RestrictedResolverVisitor> visitors) { | 133 Map<Source, RestrictedResolverVisitor> visitors) { |
| 136 // First propagate what was inferred from globals to all instance fields. | 134 // First propagate what was inferred from globals to all instance fields. |
| 137 if (_options.inferTransitively) { | 135 |
| 138 // TODO(sigmund): also do a fine-grain propagation between fields. We want | 136 // TODO(sigmund): also do a fine-grain propagation between fields. We want |
| 139 // infer-by-override to take precedence, so we would have to include | 137 // infer-by-override to take precedence, so we would have to include |
| 140 // classes in the dependency graph and ensure that fields depend on their | 138 // classes in the dependency graph and ensure that fields depend on their |
| 141 // class, and classes depend on superclasses. | 139 // class, and classes depend on superclasses. |
| 142 classes | 140 classes |
| 143 .expand((c) => c.members.where(_isInstanceField)) | 141 .expand((c) => c.members.where(_isInstanceField)) |
| 144 .expand((f) => f.fields.variables) | 142 .expand((f) => f.fields.variables) |
| 145 .forEach((v) => _reanalyzeVar(visitors, v)); | 143 .forEach((v) => _reanalyzeVar(visitors, v)); |
| 146 } | |
| 147 | 144 |
| 148 // Track types in this strongly connected component, ensure we visit | 145 // Track types in this strongly connected component, ensure we visit |
| 149 // supertypes before subtypes. | 146 // supertypes before subtypes. |
| 150 var typeToDeclaration = <InterfaceType, ClassDeclaration>{}; | 147 var typeToDeclaration = <InterfaceType, ClassDeclaration>{}; |
| 151 classes.forEach((c) => typeToDeclaration[c.element.type] = c); | 148 classes.forEach((c) => typeToDeclaration[c.element.type] = c); |
| 152 var seen = new Set<InterfaceType>(); | 149 var seen = new Set<InterfaceType>(); |
| 153 visit(ClassDeclaration cls) { | 150 visit(ClassDeclaration cls) { |
| 154 var element = cls.element; | 151 var element = cls.element; |
| 155 var type = element.type; | 152 var type = element.type; |
| 156 if (seen.contains(type)) return; | 153 if (seen.contains(type)) return; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 } | 254 } |
| 258 } | 255 } |
| 259 } | 256 } |
| 260 } | 257 } |
| 261 | 258 |
| 262 void _inferVariableFromInitializer(Iterable<VariableDeclaration> variables) { | 259 void _inferVariableFromInitializer(Iterable<VariableDeclaration> variables) { |
| 263 for (var variable in variables) { | 260 for (var variable in variables) { |
| 264 var declaration = variable.parent as VariableDeclarationList; | 261 var declaration = variable.parent as VariableDeclarationList; |
| 265 // Only infer on variables that don't have any declared type. | 262 // Only infer on variables that don't have any declared type. |
| 266 if (declaration.type != null) continue; | 263 if (declaration.type != null) continue; |
| 267 if (_options.onlyInferConstsAndFinalFields && | |
| 268 !declaration.isFinal && | |
| 269 !declaration.isConst) { | |
| 270 return; | |
| 271 } | |
| 272 var initializer = variable.initializer; | 264 var initializer = variable.initializer; |
| 273 if (initializer == null) continue; | 265 if (initializer == null) continue; |
| 274 var type = initializer.staticType; | 266 var type = initializer.staticType; |
| 275 if (type == null || type.isDynamic || type.isBottom) continue; | 267 if (type == null || type.isDynamic || type.isBottom) continue; |
| 276 if (!_canInferFrom(initializer)) continue; | |
| 277 var element = variable.element as PropertyInducingElement; | 268 var element = variable.element as PropertyInducingElement; |
| 278 // Note: it's ok to update the type here, since initializer.staticType | 269 // Note: it's ok to update the type here, since initializer.staticType |
| 279 // is already computed for all declarations in the library cycle. The | 270 // is already computed for all declarations in the library cycle. The |
| 280 // new types will only be propagated on a second run of the | 271 // new types will only be propagated on a second run of the |
| 281 // ResolverVisitor. | 272 // ResolverVisitor. |
| 282 element.type = type; | 273 element.type = type; |
| 283 element.getter.returnType = type; | 274 element.getter.returnType = type; |
| 284 if (!element.isFinal && !element.isConst) { | 275 if (!element.isFinal && !element.isConst) { |
| 285 element.setter.parameters[0].type = type; | 276 element.setter.parameters[0].type = type; |
| 286 } | 277 } |
| 287 } | 278 } |
| 288 } | 279 } |
| 289 | |
| 290 bool _canInferFrom(Expression expression) { | |
| 291 if (_options.inferTransitively) return true; | |
| 292 if (expression is Literal) return true; | |
| 293 if (expression is InstanceCreationExpression) return true; | |
| 294 if (expression is FunctionExpression) return true; | |
| 295 if (expression is AsExpression) return true; | |
| 296 if (expression is CascadeExpression) { | |
| 297 return _canInferFrom(expression.target); | |
| 298 } | |
| 299 if (expression is SimpleIdentifier || expression is PropertyAccess) { | |
| 300 return false; | |
| 301 } | |
| 302 if (expression is PrefixedIdentifier) { | |
| 303 if (expression.staticElement is PropertyAccessorElement) { | |
| 304 return false; | |
| 305 } | |
| 306 return _canInferFrom(expression.identifier); | |
| 307 } | |
| 308 if (expression is MethodInvocation) { | |
| 309 return _canInferFrom(expression.target); | |
| 310 } | |
| 311 if (expression is BinaryExpression) { | |
| 312 return _canInferFrom(expression.leftOperand); | |
| 313 } | |
| 314 if (expression is ConditionalExpression) { | |
| 315 return _canInferFrom(expression.thenExpression) && | |
| 316 _canInferFrom(expression.elseExpression); | |
| 317 } | |
| 318 if (expression is PrefixExpression) { | |
| 319 return _canInferFrom(expression.operand); | |
| 320 } | |
| 321 if (expression is PostfixExpression) { | |
| 322 return _canInferFrom(expression.operand); | |
| 323 } | |
| 324 return false; | |
| 325 } | |
| 326 } | 280 } |
| 327 | 281 |
| 328 /// Extracts the [VariableElement]s used in an initializer expression. | 282 /// Extracts the [VariableElement]s used in an initializer expression. |
| 329 class _VarExtractor extends RecursiveAstVisitor { | 283 class _VarExtractor extends RecursiveAstVisitor { |
| 330 final elements = <VariableElement>[]; | 284 final elements = <VariableElement>[]; |
| 331 visitSimpleIdentifier(SimpleIdentifier node) { | 285 visitSimpleIdentifier(SimpleIdentifier node) { |
| 332 var e = node.staticElement; | 286 var e = node.staticElement; |
| 333 if (e is PropertyAccessorElement) elements.add(e.variable); | 287 if (e is PropertyAccessorElement) elements.add(e.variable); |
| 334 } | 288 } |
| 335 | 289 |
| (...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 793 } | 747 } |
| 794 } | 748 } |
| 795 | 749 |
| 796 // Review note: no longer need to override visitFunctionExpression, this is | 750 // Review note: no longer need to override visitFunctionExpression, this is |
| 797 // handled by the analyzer internally. | 751 // handled by the analyzer internally. |
| 798 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? | 752 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? |
| 799 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression | 753 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression |
| 800 // type in a (...) => expr or just the written type? | 754 // type in a (...) => expr or just the written type? |
| 801 | 755 |
| 802 } | 756 } |
| OLD | NEW |