Chromium Code Reviews| 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 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 f is FieldDeclaration && !f.isStatic && !f.fields.isConst; | 191 f is FieldDeclaration && !f.isStatic && !f.fields.isConst; |
| 192 | 192 |
| 193 /// Attempts to infer the type on [field] from overridden fields or getters if | 193 /// Attempts to infer the type on [field] from overridden fields or getters if |
| 194 /// a type was not specified. If no type could be inferred, but it contains an | 194 /// a type was not specified. If no type could be inferred, but it contains an |
| 195 /// initializer, we add it to [pending] so we can try to infer it using the | 195 /// initializer, we add it to [pending] so we can try to infer it using the |
| 196 /// initializer type instead. | 196 /// initializer type instead. |
| 197 void _inferFieldTypeFromOverride( | 197 void _inferFieldTypeFromOverride( |
| 198 FieldDeclaration field, Set<VariableDeclaration> pending) { | 198 FieldDeclaration field, Set<VariableDeclaration> pending) { |
| 199 var variables = field.fields; | 199 var variables = field.fields; |
| 200 for (var variable in variables.variables) { | 200 for (var variable in variables.variables) { |
| 201 var varElement = variable.element; | 201 var varElement = variable.element as PropertyInducingElement; |
|
Jennifer Messerly
2015/06/01 21:52:10
hmm, this one almost seems like feedback for analy
| |
| 202 if (!varElement.type.isDynamic || variables.type != null) continue; | 202 if (!varElement.type.isDynamic || variables.type != null) continue; |
| 203 var getter = varElement.getter; | 203 var getter = varElement.getter; |
| 204 // Note: type will be null only when there are no overrides. When some | 204 // Note: type will be null only when there are no overrides. When some |
| 205 // override's type was not specified and couldn't be inferred, the type | 205 // override's type was not specified and couldn't be inferred, the type |
| 206 // here will be dynamic. | 206 // here will be dynamic. |
| 207 var type = searchTypeFor(varElement.enclosingElement.type, getter); | 207 var enclosingElement = varElement.enclosingElement as ClassElement; |
| 208 var type = searchTypeFor(enclosingElement.type, getter); | |
| 208 | 209 |
| 209 // Infer from the RHS when there are no overrides. | 210 // Infer from the RHS when there are no overrides. |
| 210 if (type == null) { | 211 if (type == null) { |
| 211 if (variable.initializer != null) pending.add(variable); | 212 if (variable.initializer != null) pending.add(variable); |
| 212 continue; | 213 continue; |
| 213 } | 214 } |
| 214 | 215 |
| 215 // When field is final and overriden getter is dynamic, we can infer from | 216 // When field is final and overriden getter is dynamic, we can infer from |
| 216 // the RHS without breaking subtyping rules (return type is covariant). | 217 // the RHS without breaking subtyping rules (return type is covariant). |
| 217 if (type.returnType.isDynamic) { | 218 if (type.returnType.isDynamic) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 228 if (!varElement.isFinal) varElement.setter.parameters[0].type = newType; | 229 if (!varElement.isFinal) varElement.setter.parameters[0].type = newType; |
| 229 } | 230 } |
| 230 } | 231 } |
| 231 | 232 |
| 232 void _inferMethodReturnTypeFromOverride(MethodDeclaration method) { | 233 void _inferMethodReturnTypeFromOverride(MethodDeclaration method) { |
| 233 var methodElement = method.element; | 234 var methodElement = method.element; |
| 234 if ((methodElement is MethodElement || | 235 if ((methodElement is MethodElement || |
| 235 methodElement is PropertyAccessorElement) && | 236 methodElement is PropertyAccessorElement) && |
| 236 methodElement.returnType.isDynamic && | 237 methodElement.returnType.isDynamic && |
| 237 method.returnType == null) { | 238 method.returnType == null) { |
| 238 var type = | 239 var enclosingElement = methodElement.enclosingElement as ClassElement; |
|
Jennifer Messerly
2015/06/01 21:52:10
not sure if it's any better, but another way to ex
vsm
2015/06/01 22:44:19
This actually fails at runtime when methodElement
Jennifer Messerly
2015/06/01 23:10:56
doh. PropertyAccessorElement strikes again.
| |
| 239 searchTypeFor(methodElement.enclosingElement.type, methodElement); | 240 var type = searchTypeFor(enclosingElement.type, methodElement); |
| 240 if (type != null && !type.returnType.isDynamic) { | 241 if (type != null && !type.returnType.isDynamic) { |
| 241 methodElement.returnType = type.returnType; | 242 methodElement.returnType = type.returnType; |
| 242 } | 243 } |
| 243 } | 244 } |
| 244 } | 245 } |
| 245 | 246 |
| 246 void _inferVariableFromInitializer(Iterable<VariableDeclaration> variables) { | 247 void _inferVariableFromInitializer(Iterable<VariableDeclaration> variables) { |
| 247 for (var variable in variables) { | 248 for (var variable in variables) { |
| 248 var declaration = variable.parent; | 249 var declaration = variable.parent as VariableDeclarationList; |
| 249 // Only infer on variables that don't have any declared type. | 250 // Only infer on variables that don't have any declared type. |
| 250 if (declaration.type != null) continue; | 251 if (declaration.type != null) continue; |
| 251 if (_options.onlyInferConstsAndFinalFields && | 252 if (_options.onlyInferConstsAndFinalFields && |
| 252 !declaration.isFinal && | 253 !declaration.isFinal && |
| 253 !declaration.isConst) { | 254 !declaration.isConst) { |
| 254 return; | 255 return; |
| 255 } | 256 } |
| 256 var initializer = variable.initializer; | 257 var initializer = variable.initializer; |
| 257 if (initializer == null) continue; | 258 if (initializer == null) continue; |
| 258 var type = initializer.staticType; | 259 var type = initializer.staticType; |
| 259 if (type == null || type.isDynamic || type.isBottom) continue; | 260 if (type == null || type.isDynamic || type.isBottom) continue; |
| 260 if (!_canInferFrom(initializer)) continue; | 261 if (!_canInferFrom(initializer)) continue; |
| 261 var element = variable.element; | 262 var element = variable.element as PropertyInducingElement; |
| 262 // Note: it's ok to update the type here, since initializer.staticType | 263 // Note: it's ok to update the type here, since initializer.staticType |
| 263 // is already computed for all declarations in the library cycle. The | 264 // is already computed for all declarations in the library cycle. The |
| 264 // new types will only be propagated on a second run of the | 265 // new types will only be propagated on a second run of the |
| 265 // ResolverVisitor. | 266 // ResolverVisitor. |
| 266 element.type = type; | 267 element.type = type; |
| 267 element.getter.returnType = type; | 268 element.getter.returnType = type; |
| 268 if (!element.isFinal && !element.isConst) { | 269 if (!element.isFinal && !element.isConst) { |
| 269 element.setter.parameters[0].type = type; | 270 element.setter.parameters[0].type = type; |
| 270 } | 271 } |
| 271 } | 272 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 364 try { | 365 try { |
| 365 _revisiting = true; | 366 _revisiting = true; |
| 366 _nodeWasSkipped = false; | 367 _nodeWasSkipped = false; |
| 367 var node = variable.parent.parent; | 368 var node = variable.parent.parent; |
| 368 var oldState; | 369 var oldState; |
| 369 var state = _stateAtDeclaration[node]; | 370 var state = _stateAtDeclaration[node]; |
| 370 if (state != null) { | 371 if (state != null) { |
| 371 oldState = new _ResolverState(this); | 372 oldState = new _ResolverState(this); |
| 372 state.restore(this); | 373 state.restore(this); |
| 373 if (node is FieldDeclaration) { | 374 if (node is FieldDeclaration) { |
| 374 var cls = node.parent; | 375 var cls = node.parent as ClassDeclaration; |
| 375 enclosingClass = cls.element; | 376 enclosingClass = cls.element; |
| 376 } | 377 } |
| 377 } | 378 } |
| 378 visitNode(variable.initializer); | 379 visitNode(variable.initializer); |
| 379 if (!_nodeWasSkipped) _visitedInitializers.add(variable); | 380 if (!_nodeWasSkipped) _visitedInitializers.add(variable); |
| 380 if (oldState != null) oldState.restore(this); | 381 if (oldState != null) oldState.restore(this); |
| 381 } finally { | 382 } finally { |
| 382 _revisiting = false; | 383 _revisiting = false; |
| 383 } | 384 } |
| 384 } | 385 } |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 540 } | 541 } |
| 541 | 542 |
| 542 return null; | 543 return null; |
| 543 } | 544 } |
| 544 | 545 |
| 545 @override | 546 @override |
| 546 visitDeclaredIdentifier(DeclaredIdentifier node) { | 547 visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 547 super.visitDeclaredIdentifier(node); | 548 super.visitDeclaredIdentifier(node); |
| 548 if (node.type != null) return; | 549 if (node.type != null) return; |
| 549 | 550 |
| 550 var parent = node.parent; | 551 var parent = node.parent as ForEachStatement; |
| 551 assert(parent is ForEachStatement); | |
| 552 var expr = parent.iterable; | 552 var expr = parent.iterable; |
| 553 var element = node.element as LocalVariableElementImpl; | 553 var element = node.element as LocalVariableElementImpl; |
| 554 var exprType = expr.staticType; | 554 var exprType = expr.staticType; |
| 555 if (exprType is InterfaceType) { | 555 if (exprType is InterfaceType) { |
| 556 var iteratedType = _findIteratedType(exprType); | 556 var iteratedType = _findIteratedType(exprType); |
| 557 if (iteratedType != null) { | 557 if (iteratedType != null) { |
| 558 element.type = iteratedType; | 558 element.type = iteratedType; |
| 559 } | 559 } |
| 560 } | 560 } |
| 561 } | 561 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 599 e.library.name == '_foreign_helper' && | 599 e.library.name == '_foreign_helper' && |
| 600 e.name == 'JS') { | 600 e.name == 'JS') { |
| 601 // Fix types for JS builtin calls. | 601 // Fix types for JS builtin calls. |
| 602 // | 602 // |
| 603 // This code was taken from analyzer. It's not super sophisticated: | 603 // This code was taken from analyzer. It's not super sophisticated: |
| 604 // only looks for the type name in dart:core, so we just copy it here. | 604 // only looks for the type name in dart:core, so we just copy it here. |
| 605 // | 605 // |
| 606 // TODO(jmesserly): we'll likely need something that can handle a wider | 606 // TODO(jmesserly): we'll likely need something that can handle a wider |
| 607 // variety of types, especially when we get to JS interop. | 607 // variety of types, especially when we get to JS interop. |
| 608 var args = node.argumentList.arguments; | 608 var args = node.argumentList.arguments; |
| 609 if (args.isNotEmpty && args.first is SimpleStringLiteral) { | 609 var first = args.isNotEmpty ? args.first : null; |
| 610 if (first is SimpleStringLiteral) { | |
| 610 var coreLib = _typeProvider.objectType.element.library; | 611 var coreLib = _typeProvider.objectType.element.library; |
| 611 var classElem = coreLib.getType(args.first.stringValue); | 612 var classElem = coreLib.getType(first.stringValue); |
| 612 if (classElem != null) node.staticType = classElem.type; | 613 if (classElem != null) node.staticType = classElem.type; |
| 613 } | 614 } |
| 614 } | 615 } |
| 615 } | 616 } |
| 616 | 617 |
| 617 void _inferObjectAccess( | 618 void _inferObjectAccess( |
| 618 Expression node, Expression target, SimpleIdentifier id) { | 619 Expression node, Expression target, SimpleIdentifier id) { |
| 619 // Search for Object accesses. | 620 // Search for Object accesses. |
| 620 var name = id.name; | 621 var name = id.name; |
| 621 if (node.staticType.isDynamic && | 622 if (node.staticType.isDynamic && |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 665 } | 666 } |
| 666 } | 667 } |
| 667 | 668 |
| 668 // Review note: no longer need to override visitFunctionExpression, this is | 669 // Review note: no longer need to override visitFunctionExpression, this is |
| 669 // handled by the analyzer internally. | 670 // handled by the analyzer internally. |
| 670 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? | 671 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? |
| 671 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression | 672 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression |
| 672 // type in a (...) => expr or just the written type? | 673 // type in a (...) => expr or just the written type? |
| 673 | 674 |
| 674 } | 675 } |
| OLD | NEW |