Chromium Code Reviews| Index: lib/src/codegen/js_codegen.dart |
| diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart |
| index 8b46f8c86225157c3f6678f58ddac5a59fbd8a83..c5ef5f81cc20d4fd852fc22e922e1d4cbc8c404a 100644 |
| --- a/lib/src/codegen/js_codegen.dart |
| +++ b/lib/src/codegen/js_codegen.dart |
| @@ -600,7 +600,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| var memberName = _emitMemberName(name, |
| type: cType, unary: unary, isStatic: node.isStatic); |
| var property = |
| - new JS.Property(memberName, _emitTypeName(element.type)); |
| + new JS.Property(memberName, _emitFunctionRTTI(element.type)); |
| if (node.isStatic) { |
| tStatics.add(property); |
| sNames.add(memberName); |
| @@ -1025,9 +1025,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| return js.call('dart.fn(#)', [clos]); |
| } |
| if (lazy) { |
| - return js.call('dart.fn(#, () => #)', [clos, _emitTypeName(type)]); |
| + return js.call('dart.fn(#, () => #)', [clos, _emitFunctionRTTI(type)]); |
| } |
| - return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]); |
| + return js.call('dart.fn(#, #)', [ |
| + clos, |
| + _emitFunctionTypeParts(type, dynamicIsObject: true) |
| + ]); |
| } |
| throw 'Function has non function type: $type'; |
| } |
| @@ -1159,54 +1162,69 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| JS.TemporaryId _getTemp(Object key, String name) => |
| _temps.putIfAbsent(key, () => new JS.TemporaryId(name)); |
| - JS.ArrayInitializer _emitTypeNames(List<DartType> types) { |
| - return new JS.ArrayInitializer(types.map(_emitTypeName).toList()); |
| + JS.ArrayInitializer _emitTypeNames(List<DartType> types, |
| + {dynamicIsBottom: false}) { |
| + var build = (t) => _emitTypeName(t, dynamicIsBottom: dynamicIsBottom); |
| + return new JS.ArrayInitializer(types.map(build).toList()); |
| } |
| - JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { |
| + JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types, |
| + {dynamicIsBottom: false}) { |
| var properties = <JS.Property>[]; |
| types.forEach((name, type) { |
| var key = new JS.LiteralString(name); |
| - var value = _emitTypeName(type); |
| + var value = _emitTypeName(type, dynamicIsBottom: dynamicIsBottom); |
| properties.add(new JS.Property(key, value)); |
| }); |
| return new JS.ObjectInitializer(properties); |
| } |
| - List<JS.Expression> _emitFunctionTypeParts(FunctionType type) { |
| + /// Emit the pieces of a function type, as an array of return type, |
| + /// regular args, and optional/named args. |
| + /// If [dynamicIsObject] is set, then dynamics in argument positions |
| + /// will be lowered to Object instead of bottom. |
| + List<JS.Expression> _emitFunctionTypeParts(FunctionType type, |
| + {bool dynamicIsObject: false}) { |
|
vsm
2015/05/20 23:03:10
Perhaps use either dynamicIsBottom here or dynamic
Leaf
2015/05/20 23:35:28
Done.
|
| var returnType = type.returnType; |
| var parameterTypes = type.normalParameterTypes; |
| var optionalTypes = type.optionalParameterTypes; |
| var namedTypes = type.namedParameterTypes; |
| var rt = _emitTypeName(returnType); |
| - var ra = _emitTypeNames(parameterTypes); |
| + var ra = _emitTypeNames(parameterTypes, dynamicIsBottom: !dynamicIsObject); |
| if (!namedTypes.isEmpty) { |
| assert(optionalTypes.isEmpty); |
| - var na = _emitTypeProperties(namedTypes); |
| + var na = |
| + _emitTypeProperties(namedTypes, dynamicIsBottom: !dynamicIsObject); |
| return [rt, ra, na]; |
| } |
| if (!optionalTypes.isEmpty) { |
| assert(namedTypes.isEmpty); |
| - var oa = _emitTypeNames(optionalTypes); |
| + var oa = _emitTypeNames(optionalTypes, dynamicIsBottom: !dynamicIsObject); |
| return [rt, ra, oa]; |
| } |
| return [rt, ra]; |
| } |
| + JS.Expression _emitFunctionRTTI(FunctionType type) { |
| + var parts = _emitFunctionTypeParts(type, dynamicIsObject: true); |
| + return js.call('dart.functionType(#)', [parts]); |
| + } |
| + |
| /// Emits a Dart [type] into code. |
| /// |
| /// If [lowerTypedef] is set, a typedef will be expanded as if it were a |
| /// function type. Similarly if [lowerGeneric] is set, the `List$()` form |
| /// will be used instead of `List`. These flags are used when generating |
| /// the definitions for typedefs and generic types, respectively. |
| - JS.Expression _emitTypeName(DartType type, |
| - {bool lowerTypedef: false, bool lowerGeneric: false}) { |
| + JS.Expression _emitTypeName(DartType type, {bool lowerTypedef: false, |
| + bool lowerGeneric: false, bool dynamicIsBottom: false}) { |
| // The void and dynamic types are not defined in core. |
| if (type.isVoid) { |
| return js.call('dart.void'); |
| } else if (type.isDynamic) { |
| - return js.call('dart.dynamic'); |
| + if (dynamicIsBottom) return js.call('dart.bottom'); |
| + return _emitTypeName(types.objectType); |
| } else if (type.isBottom) { |
| return js.call('dart.bottom'); |
| } |