Index: lib/src/compiler/code_generator.dart |
diff --git a/lib/src/compiler/code_generator.dart b/lib/src/compiler/code_generator.dart |
index b41844e62c8a963be1b1f0aae0e0f2e9d5d10ebc..1276c85eaeaeed3e9b6f4a7bbe8d4cff67e002fc 100644 |
--- a/lib/src/compiler/code_generator.dart |
+++ b/lib/src/compiler/code_generator.dart |
@@ -475,7 +475,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) { |
@@ -1479,7 +1483,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); |
} |
} |
@@ -1542,7 +1546,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) { |
@@ -1978,10 +1982,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( |
@@ -2334,8 +2346,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]); |
} |
@@ -2367,7 +2379,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]); |
} |
@@ -2385,12 +2398,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 && |
@@ -2398,6 +2412,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); |
} |
return null; |
} |
@@ -3365,7 +3385,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); |
} |
} |
@@ -3374,7 +3394,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) { |
@@ -3451,8 +3471,9 @@ 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) { |
+ Element member = memberId.staticElement; |
if (member is PropertyAccessorElement) { |
member = (member as PropertyAccessorElement).variable; |
} |
@@ -3463,30 +3484,49 @@ 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) { |
+ 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. |