Index: lib/src/compiler/code_generator.dart |
diff --git a/lib/src/compiler/code_generator.dart b/lib/src/compiler/code_generator.dart |
index b17ee5b5a1ab26de6a1b68dbffc7b3ce6761d9a8..0264ab4308775abaf1da22c0907af32f318de4fa 100644 |
--- a/lib/src/compiler/code_generator.dart |
+++ b/lib/src/compiler/code_generator.dart |
@@ -2284,7 +2284,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
// class Foo { Function bar; } |
// new Foo().bar(); // dynamic call |
code = 'dart.dcall(#.#, #)'; |
- } else if (_requiresStaticDispatch(target, name)) { |
+ } else if (_isObjectMemberCall(target, name)) { |
// Object methods require a helper for null checks. |
return js.call('dart.#(#, #)', |
[memberName, _visit(target), _visit(node.argumentList)]); |
@@ -3129,15 +3129,21 @@ class CodeGenerator extends GeneralizingAstVisitor |
} |
} |
- bool _requiresStaticDispatch(Expression target, String memberName) { |
- var type = getStaticType(target); |
+ /// Everything in Dart is an Object and supports the 4 members on Object, |
+ /// so we have to use a runtime helper to handle values such as `null` and |
+ /// native types. |
+ /// |
+ /// For example `null.toString()` is legal in Dart, so we need to generate |
+ /// that as `dart.toString(obj)`. |
+ bool _isObjectMemberCall(Expression target, String memberName) { |
+ // Is this a member on `Object`? |
if (!isObjectProperty(memberName)) { |
return false; |
} |
- // If the target could be `null`, we need static dispatch. |
- // If the target may be an extension type, we also use static dispatch |
- // as we don't symbolize object properties like hashCode. |
+ // Check if the target could be `null`, is dynamic, or may be an extension |
+ // native type. In all of those cases we need defensive code generation. |
+ var type = getStaticType(target); |
return isNullable(target) || |
type.isDynamic || |
(_extensionTypes.contains(type.element) && target is! SuperExpression); |
@@ -3169,13 +3175,11 @@ class CodeGenerator extends GeneralizingAstVisitor |
// Tear-off methods: explicitly bind it. |
if (target is SuperExpression) { |
return js.call('dart.bind(this, #, #.#)', [name, _visit(target), name]); |
- } else if (_requiresStaticDispatch(target, memberId.name)) { |
- var type = member.type; |
- var clos = js.call('dart.#.bind(#)', [name, _visit(target)]); |
- return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]); |
+ } else if (_isObjectMemberCall(target, memberId.name)) { |
+ return js.call('dart.bind(#, #, dart.#)', [_visit(target), name, name]); |
} |
code = 'dart.bind(#, #)'; |
- } else if (_requiresStaticDispatch(target, memberId.name)) { |
+ } else if (_isObjectMemberCall(target, memberId.name)) { |
return js.call('dart.#(#)', [name, _visit(target)]); |
} else { |
code = '#.#'; |