Chromium Code Reviews| Index: lib/src/checker/resolver.dart |
| diff --git a/lib/src/checker/resolver.dart b/lib/src/checker/resolver.dart |
| index 8a35e0d153243515af63a9bc370e5b866547f738..a335ea7fe5e18b3a64afaabe269d2c38a9135c92 100644 |
| --- a/lib/src/checker/resolver.dart |
| +++ b/lib/src/checker/resolver.dart |
| @@ -664,12 +664,73 @@ class RestrictedStaticTypeAnalyzer extends StaticTypeAnalyzer { |
| } |
| } |
| + Map<String, DartType> _objectMemberMap = null; |
| + |
| + Map<String, DartType> _getObjectMemberMap() { |
| + if (_objectMemberMap == null) { |
| + _objectMemberMap = new Map<String, DartType>(); |
| + var objectType = _typeProvider.objectType; |
| + var element = objectType.element; |
| + // Only record methods (including getters) with no parameters. As parameters are contravariant wrt |
| + // type, using Object's version may be too strict. |
| + // Add instance methods. |
| + element.methods |
| + .where((method) => !method.isStatic && method.parameters.isEmpty) |
| + .forEach((method) { |
| + _objectMemberMap[method.name] = method.type; |
| + }); |
| + // Add getters. |
| + element.accessors |
| + .where((member) => !member.isStatic && member.isGetter) |
| + .forEach((member) { |
| + _objectMemberMap[member.name] = member.type.returnType; |
| + }); |
| + } |
| + return _objectMemberMap; |
| + } |
| + |
| + List<DartType> _nonExtendableTypes = null; |
| + |
| + bool _isExtendable(DartType t) { |
| + if (_nonExtendableTypes == null) { |
| + // TODO(vsm): Use the analyzer's list - see dartbug.com/23125. |
| + _nonExtendableTypes = <DartType>[ |
| + _typeProvider.nullType, |
| + _typeProvider.numType, |
| + _typeProvider.intType, |
| + _typeProvider.doubleType, |
| + _typeProvider.boolType, |
| + _typeProvider.stringType |
| + ]; |
| + } |
| + return !_nonExtendableTypes.contains(t); |
|
Jennifer Messerly
2015/04/07 19:05:49
whenever you're calling _isExtendable it's being i
vsm
2015/04/07 19:48:46
Done.
|
| + } |
| + |
| @override // to propagate types to identifiers |
| visitMethodInvocation(MethodInvocation node) { |
| // TODO(sigmund): follow up with analyzer team - why is this needed? |
| visitSimpleIdentifier(node.methodName); |
| super.visitMethodInvocation(node); |
| + // Search for Object methods. |
| + var objectMap = _getObjectMemberMap(); |
| + var name = node.methodName.name; |
| + if (node.staticType.isDynamic && objectMap.containsKey(name)) { |
| + var target = node.target; |
| + if (target is SimpleIdentifier && |
|
Jennifer Messerly
2015/04/07 19:05:49
why does target need to be a SimpleIdentifier? doe
vsm
2015/04/07 19:48:46
Good point. Fixed and test added.
|
| + target.staticElement is! PrefixElement) { |
|
Jennifer Messerly
2015/04/07 19:05:49
follow up to above suggestion, I wonder if somethi
vsm
2015/04/07 19:48:46
It cleans it up. Done.
|
| + var type = objectMap[name]; |
| + if (type is FunctionType && node.argumentList.arguments.isEmpty) { |
| + node.methodName.staticType = type; |
| + if (!_isExtendable(type.returnType)) { |
| + // Don't infer the type of the overall expression in this case - |
| + // it may be too strict. |
|
Jennifer Messerly
2015/04/07 19:05:49
can this actually happen? I thought we didn't allo
vsm
2015/04/07 19:48:46
Note: my comment was in a confusing place - fixed
|
| + node.staticType = type.returnType; |
| + } |
| + } |
| + } |
| + } |
| + |
| var e = node.methodName.staticElement; |
| if (e is FunctionElement && |
| e.library.name == '_foreign_helper' && |
| @@ -690,6 +751,39 @@ class RestrictedStaticTypeAnalyzer extends StaticTypeAnalyzer { |
| } |
| } |
| + void _inferObjectAccess( |
| + Expression node, Expression target, SimpleIdentifier id) { |
| + // Search for Object accesses. |
| + var objectMap = _getObjectMemberMap(); |
| + var name = id.name; |
| + if (node.staticType.isDynamic && objectMap.containsKey(name)) { |
| + if (target is SimpleIdentifier && |
| + target.staticElement is! PrefixElement) { |
| + var type = objectMap[name]; |
| + id.staticType = type; |
| + if (!_isExtendable(type)) { |
| + // Don't infer the type of the overall expression in this case - |
| + // it may be too strict. |
| + node.staticType = type; |
| + } |
| + } |
| + } |
| + } |
| + |
| + @override |
| + visitPropertyAccess(PropertyAccess node) { |
| + super.visitPropertyAccess(node); |
| + |
| + _inferObjectAccess(node, node.target, node.propertyName); |
| + } |
| + |
| + @override |
| + visitPrefixedIdentifier(PrefixedIdentifier node) { |
| + super.visitPrefixedIdentifier(node); |
| + |
| + _inferObjectAccess(node, node.prefix, node.identifier); |
| + } |
| + |
| @override |
| visitConditionalExpression(ConditionalExpression node) { |
| // TODO(vsm): The static type of a conditional should be the LUB of the |