| Index: lib/src/checker/resolver.dart | 
| diff --git a/lib/src/checker/resolver.dart b/lib/src/checker/resolver.dart | 
| index 8a35e0d153243515af63a9bc370e5b866547f738..24efb989ff12f9c0d90a7d83cd3b12a4a02d8afa 100644 | 
| --- a/lib/src/checker/resolver.dart | 
| +++ b/lib/src/checker/resolver.dart | 
| @@ -664,12 +664,72 @@ 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> _sealedTypes = null; | 
| + | 
| +  bool _isSealed(DartType t) { | 
| +    if (_sealedTypes == null) { | 
| +      // TODO(vsm): Use the analyzer's list - see dartbug.com/23125. | 
| +      _sealedTypes = <DartType>[ | 
| +        _typeProvider.nullType, | 
| +        _typeProvider.numType, | 
| +        _typeProvider.intType, | 
| +        _typeProvider.doubleType, | 
| +        _typeProvider.boolType, | 
| +        _typeProvider.stringType | 
| +      ]; | 
| +    } | 
| +    return _sealedTypes.contains(t); | 
| +  } | 
| + | 
| @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) && | 
| +        isDynamicTarget(node.target)) { | 
| +      var type = objectMap[name]; | 
| +      if (type is FunctionType && node.argumentList.arguments.isEmpty) { | 
| +        node.target.staticType = _typeProvider.objectType; | 
| +        node.methodName.staticType = type; | 
| +        // Only infer the type of the overall expression if we have an exact | 
| +        // type - e.g., a sealed type.  Otherwise, it may be too strict. | 
| +        if (_isSealed(type.returnType)) { | 
| +          node.staticType = type.returnType; | 
| +        } | 
| +      } | 
| +    } | 
| + | 
| var e = node.methodName.staticElement; | 
| if (e is FunctionElement && | 
| e.library.name == '_foreign_helper' && | 
| @@ -690,6 +750,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) && | 
| +        isDynamicTarget(target)) { | 
| +      target.staticType = _typeProvider.objectType; | 
| +      var type = objectMap[name]; | 
| +      id.staticType = type; | 
| +      // Only infer the type of the overall expression if we have an exact | 
| +      // type - e.g., a sealed type.  Otherwise, it may be too strict. | 
| +      if (_isSealed(type)) { | 
| +        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 | 
|  |