Chromium Code Reviews| Index: lib/src/compiler/code_generator.dart |
| diff --git a/lib/src/compiler/code_generator.dart b/lib/src/compiler/code_generator.dart |
| index 5ca2eeefe15d6b64e5bf03ca98029a01ce338fd9..468d4ebd43b08b9f98e34d224846c63351749d7e 100644 |
| --- a/lib/src/compiler/code_generator.dart |
| +++ b/lib/src/compiler/code_generator.dart |
| @@ -474,7 +474,11 @@ class CodeGenerator extends GeneralizingAstVisitor |
| } |
| @override |
| - JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type); |
| + JS.Expression visitTypeName(TypeName node) { |
| + // TODO(jmesserly): should only happen for erroneous code. |
| + if (node.type == null) return js.call('dart.dynamic'); |
| + return _emitTypeName(node.type); |
| + } |
| @override |
| JS.Statement visitClassTypeAlias(ClassTypeAlias node) { |
| @@ -1478,7 +1482,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| for (var p in ctor.parameters.parameters) { |
| var element = p.element; |
| if (element is FieldFormalParameterElement) { |
| - fields[element.field] = visitSimpleIdentifier(p.identifier); |
| + fields[element.field] = _emitSimpleIdentifier(p.identifier); |
| } |
| } |
| @@ -1541,7 +1545,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| var body = <JS.Statement>[]; |
| for (var param in parameters.parameters) { |
| - var jsParam = visitSimpleIdentifier(param.identifier); |
| + var jsParam = _emitSimpleIdentifier(param.identifier); |
| if (!options.destructureNamedParams) { |
| if (param.kind == ParameterKind.NAMED) { |
| @@ -1976,10 +1980,18 @@ class CodeGenerator extends GeneralizingAstVisitor |
| ]); |
| } |
| - /// Writes a simple identifier. This can handle implicit `this` as well as |
| - /// going through the qualified library name if necessary. |
| + /// Emits a simple identifier, including handling an inferred generic |
| + /// function instantiation. |
| @override |
| JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { |
| + return _applyFunctionTypeArguments( |
| + _emitSimpleIdentifier(node), node.staticElement, node.staticType); |
| + } |
| + |
| + /// Emits a simple identifier, handling implicit `this` as well as |
| + /// going through the qualified library name if necessary, but *not* handling |
| + /// inferred generic function instantiation. |
| + JS.Expression _emitSimpleIdentifier(SimpleIdentifier node) { |
| var accessor = node.staticElement; |
| if (accessor == null) { |
| return js.commentExpression( |
| @@ -2332,8 +2344,8 @@ class CodeGenerator extends GeneralizingAstVisitor |
| List<JS.Expression> args = _visit(node.argumentList); |
| if (DynamicInvoke.get(target)) { |
| if (typeArgs != null) { |
| - return js.call('dart.dgsend(#, [#], #, #)', |
| - [jsTarget, typeArgs, memberName, args]); |
| + return js.call('dart.dgsend(#, #, #, #)', |
| + [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]); |
| } else { |
| return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]); |
| } |
| @@ -2365,7 +2377,8 @@ class CodeGenerator extends GeneralizingAstVisitor |
| if (DynamicInvoke.get(node.function)) { |
| var typeArgs = _emitInvokeTypeArguments(node); |
| if (typeArgs != null) { |
| - return js.call('dart.dgcall(#, [#], #)', [fn, typeArgs, args]); |
| + return js.call('dart.dgcall(#, #, #)', |
| + [fn, new JS.ArrayInitializer(typeArgs), args]); |
| } else { |
| return js.call('dart.dcall(#, #)', [fn, args]); |
| } |
| @@ -2383,12 +2396,13 @@ class CodeGenerator extends GeneralizingAstVisitor |
| List<JS.Expression> _emitInvokeTypeArguments(InvocationExpression node) { |
| return _emitFunctionTypeArguments( |
| - node.function.staticType, node.staticInvokeType); |
| + node.function.staticType, node.staticInvokeType, node.typeArguments); |
| } |
| /// If `g` is a generic function type, and `f` is an instantiation of it, |
| /// then this will return the type arguments to apply, otherwise null. |
| - List<JS.Expression> _emitFunctionTypeArguments(DartType g, DartType f) { |
| + List<JS.Expression> _emitFunctionTypeArguments(DartType g, DartType f, |
| + [TypeArgumentList typeArgs]) { |
| if (g is FunctionType && |
| g.typeFormals.isNotEmpty && |
| f is FunctionType && |
| @@ -2396,6 +2410,12 @@ class CodeGenerator extends GeneralizingAstVisitor |
| return _recoverTypeArguments(g, f) |
| .map(_emitTypeName) |
| .toList(growable: false); |
| + } else if (typeArgs != null) { |
| + // Dynamic calls may have type arguments, even though the function types |
| + // are not known. |
| + // TODO(jmesserly): seems to be mostly broken in Analyzer at the moment: |
| + // https://github.com/dart-lang/sdk/issues/26368 |
| + return typeArgs.arguments.map(visitTypeName).toList(growable: false); |
|
Harry Terkelsen
2016/04/29 23:04:11
why visitTypeName here and _emitTypeName above? Is
Jennifer Messerly
2016/04/29 23:08:14
_emitTypeName ... probably should be renamed _emit
|
| } |
| return null; |
| } |
| @@ -3237,7 +3257,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| if (isLibraryPrefix(node.prefix)) { |
| return _visit(node.identifier); |
| } else { |
| - return _emitAccess(node.prefix, node.identifier); |
| + return _emitAccess(node.prefix, node.identifier, node.staticType); |
| } |
| } |
| @@ -3246,7 +3266,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| if (node.operator.lexeme == '?.') { |
| return _emitNullSafe(node); |
| } |
| - return _emitAccess(_getTarget(node), node.propertyName); |
| + return _emitAccess(_getTarget(node), node.propertyName, node.staticType); |
| } |
| JS.Expression _emitNullSafe(Expression node) { |
| @@ -3323,8 +3343,8 @@ class CodeGenerator extends GeneralizingAstVisitor |
| } |
| /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. |
| - JS.Expression _emitAccess(Expression target, SimpleIdentifier memberId) { |
| - var member = memberId.staticElement; |
| + JS.Expression _emitAccess(Expression target, SimpleIdentifier memberId, DartType resultType) { |
|
Harry Terkelsen
2016/04/29 23:04:11
long line
Jennifer Messerly
2016/04/29 23:08:14
huh, format must've not run, I'll see about that.
|
| + Element member = memberId.staticElement; |
| if (member is PropertyAccessorElement) { |
| member = (member as PropertyAccessorElement).variable; |
| } |
| @@ -3335,30 +3355,51 @@ class CodeGenerator extends GeneralizingAstVisitor |
| return js.call('dart.dload(#, #)', [_visit(target), name]); |
| } |
| - if (target is SuperExpression && |
| - member is FieldElement && |
| - !member.isSynthetic) { |
| + var jsTarget = _visit(target); |
| + bool isSuper = jsTarget is JS.Super; |
| + |
| + if (isSuper && member is FieldElement && !member.isSynthetic) { |
| // If super.x is actually a field, then x is an instance property since |
| // subclasses cannot override x. |
| - return js.call('this.#', [name]); |
| + jsTarget = new JS.This(); |
| } |
| - String code; |
| + JS.Expression result; |
| if (member != null && member is MethodElement && !isStatic) { |
| // Tear-off methods: explicitly bind it. |
| - if (target is SuperExpression) { |
| - return js.call('dart.bind(this, #, #.#)', [name, _visit(target), name]); |
| + if (isSuper) { |
| + result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]); |
| } else if (_isObjectMemberCall(target, memberId.name)) { |
| - return js.call('dart.bind(#, #, dart.#)', [_visit(target), name, name]); |
| + result = js.call('dart.bind(#, #, dart.#)', [jsTarget, name, name]); |
| + } else { |
| + result = js.call('dart.bind(#, #)', [jsTarget, name]); |
| } |
| - code = 'dart.bind(#, #)'; |
| } else if (_isObjectMemberCall(target, memberId.name)) { |
| - return js.call('dart.#(#)', [name, _visit(target)]); |
| + result = js.call('dart.#(#)', [name, jsTarget]); |
| } else { |
| - code = '#.#'; |
| + result = js.call('#.#', [jsTarget, name]); |
| + } |
| + return _applyFunctionTypeArguments(result, member, resultType); |
| + } |
| + |
| + /// If this is an inferred instantiation of a generic function/method, this |
| + /// will add the inferred type arguments. |
| + JS.Expression _applyFunctionTypeArguments( |
| + JS.Expression result, Element member, DartType instantiated) { |
| + |
|
Harry Terkelsen
2016/04/29 23:04:11
unnecessary blank lines
|
| + |
| + DartType type; |
| + if (member is ExecutableElement) { |
| + type = member.type; |
| + } else if (member is VariableElement) { |
| + type = member.type; |
| } |
| - return js.call(code, [_visit(target), name]); |
| + // TODO(jmesserly): handle explicitly passed type args. |
| + if (type == null) return result; |
| + var typeArgs = _emitFunctionTypeArguments(type, instantiated); |
| + if (typeArgs == null) return result; |
| + return js.call('dart.gbind(#, #)', [result, typeArgs]); |
| } |
| /// Emits a generic send, like an operator method. |