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 |