| Index: pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
|
| diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
|
| index 197c6b12697d772dee680aba353fd0841ccdacea..e859eef61e5b502dd98b18e5233d2ae187b0d791 100644
|
| --- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
|
| +++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
|
| @@ -149,7 +149,27 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
|
| ClosureScope getClosureScopeForNode(ast.Node node);
|
| ClosureEnvironment getClosureEnvironment();
|
|
|
| -
|
| + /// Normalizes the argument list to a static invocation (i.e. where the target
|
| + /// element is known).
|
| + ///
|
| + /// For the JS backend, inserts default arguments and normalizes order of
|
| + /// named arguments.
|
| + ///
|
| + /// For the Dart backend, returns [arguments].
|
| + List<ir.Primitive> normalizeStaticArguments(
|
| + Selector selector,
|
| + FunctionElement target,
|
| + List<ir.Primitive> arguments);
|
| +
|
| + /// Normalizes the argument list of a dynamic invocation (i.e. where the
|
| + /// target element is unknown).
|
| + ///
|
| + /// For the JS backend, normalizes order of named arguments.
|
| + ///
|
| + /// For the Dart backend, returns [arguments].
|
| + List<ir.Primitive> normalizeDynamicArguments(
|
| + Selector selector,
|
| + List<ir.Primitive> arguments);
|
|
|
| ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
|
| ast.FunctionExpression node) {
|
| @@ -554,19 +574,13 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
|
| ir.Primitive visitClosureSend(ast.Send node) {
|
| assert(irBuilder.isOpen);
|
| Element element = elements[node];
|
| - Selector closureSelector = elements.getSelector(node);
|
| - if (element == null) {
|
| - ir.Primitive closureTarget = visit(node.selector);
|
| - List<ir.Primitive> args =
|
| - node.arguments.mapToList(visit, growable:false);
|
| - return irBuilder.buildFunctionExpressionInvocation(
|
| - closureTarget, elements.getSelector(node), args);
|
| - } else {
|
| - List<ir.Primitive> args =
|
| - node.arguments.mapToList(visit, growable:false);
|
| - return irBuilder.buildLocalInvocation(
|
| - element, elements.getSelector(node), args);
|
| - }
|
| + Selector selector = elements.getSelector(node);
|
| + ir.Primitive receiver = (element == null)
|
| + ? visit(node.selector)
|
| + : irBuilder.buildLocalGet(element);
|
| + List<ir.Primitive> arguments = node.arguments.mapToList(visit);
|
| + arguments = normalizeDynamicArguments(selector, arguments);
|
| + return irBuilder.buildCallInvocation(receiver, selector, arguments);
|
| }
|
|
|
| /// If [node] is null, returns this.
|
| @@ -588,10 +602,8 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
|
| assert(irBuilder.isOpen);
|
| Selector selector = elements.getSelector(node);
|
| ir.Primitive receiver = visitReceiver(node.receiver);
|
| - List<ir.Primitive> arguments = new List<ir.Primitive>();
|
| - for (ast.Node n in node.arguments) {
|
| - arguments.add(visit(n));
|
| - }
|
| + List<ir.Primitive> arguments = node.arguments.mapToList(visit);
|
| + arguments = normalizeDynamicArguments(selector, arguments);
|
| return irBuilder.buildDynamicInvocation(receiver, selector, arguments);
|
| }
|
|
|
| @@ -717,10 +729,31 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
|
|
|
| Selector selector = elements.getSelector(node);
|
|
|
| - // TODO(lry): support default arguments, need support for locals.
|
| - List<ir.Primitive> arguments =
|
| - node.arguments.mapToList(visit, growable:false);
|
| - return irBuilder.buildStaticInvocation(element, selector, arguments);
|
| + if (selector.isCall && (element.isGetter || element.isField)) {
|
| + // We are invoking a static field or getter as if it was a method, e.g:
|
| + //
|
| + // get foo => {..}
|
| + // main() { foo(1, 2, 3); }
|
| + //
|
| + // We invoke the getter of 'foo' and then invoke the 'call' method
|
| + // on the result, using the given arguments.
|
| + Selector getter = new Selector.getterFrom(selector);
|
| + Selector call = new Selector.callClosureFrom(selector);
|
| + ir.Primitive receiver = irBuilder.buildStaticGet(element, getter);
|
| + List<ir.Primitive> arguments = node.arguments.mapToList(visit);
|
| + arguments = normalizeDynamicArguments(selector, arguments);
|
| + return irBuilder.buildCallInvocation(receiver, call, arguments);
|
| + } else if (selector.isGetter) {
|
| + // We are reading a static field or invoking a static getter.
|
| + return irBuilder.buildStaticGet(element, selector);
|
| + } else {
|
| + // We are invoking a static method.
|
| + assert(selector.isCall);
|
| + assert(element is FunctionElement);
|
| + List<ir.Primitive> arguments = node.arguments.mapToList(visit);
|
| + arguments = normalizeStaticArguments(selector, element, arguments);
|
| + return irBuilder.buildStaticInvocation(element, selector, arguments);
|
| + }
|
| }
|
|
|
| ir.Primitive visitSuperSend(ast.Send node) {
|
| @@ -730,9 +763,9 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
|
| } else {
|
| Selector selector = elements.getSelector(node);
|
| Element target = elements[node];
|
| - List<ir.Primitive> arguments = new List<ir.Primitive>();
|
| - for (ast.Node n in node.arguments) {
|
| - arguments.add(visit(n));
|
| + List<ir.Primitive> arguments = node.arguments.mapToList(visit);
|
| + if (selector.isCall) {
|
| + arguments = normalizeStaticArguments(selector, target, arguments);
|
| }
|
| return irBuilder.buildSuperInvocation(target, selector, arguments);
|
| }
|
| @@ -866,8 +899,9 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
|
| Selector selector = elements.getSelector(node.send);
|
| DartType type = elements.getType(node);
|
| ast.Node selectorNode = node.send.selector;
|
| - List<ir.Definition> arguments =
|
| + List<ir.Primitive> arguments =
|
| node.send.arguments.mapToList(visit, growable:false);
|
| + arguments = normalizeStaticArguments(selector, element, arguments);
|
| return irBuilder.buildConstructorInvocation(
|
| element, selector, type, arguments);
|
| }
|
| @@ -892,12 +926,9 @@ abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
|
| return irBuilder.buildStringConcatenation(arguments);
|
| }
|
|
|
| - ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) {
|
| + ir.Primitive translateConstant(ast.Node node) {
|
| assert(irBuilder.isOpen);
|
| - if (constant == null) {
|
| - constant = getConstantForNode(node);
|
| - }
|
| - return irBuilder.buildConstantLiteral(constant);
|
| + return irBuilder.buildConstantLiteral(getConstantForNode(node));
|
| }
|
|
|
| ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) {
|
| @@ -1112,6 +1143,19 @@ class DartIrBuilderVisitor extends IrBuilderVisitor {
|
|
|
| return withBuilder(builder, () => _makeFunctionBody(element, node));
|
| }
|
| +
|
| + List<ir.Primitive> normalizeStaticArguments(
|
| + Selector selector,
|
| + FunctionElement target,
|
| + List<ir.Primitive> arguments) {
|
| + return arguments;
|
| + }
|
| +
|
| + List<ir.Primitive> normalizeDynamicArguments(
|
| + Selector selector,
|
| + List<ir.Primitive> arguments) {
|
| + return arguments;
|
| + }
|
| }
|
|
|
| /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder].
|
| @@ -1247,6 +1291,18 @@ class JsIrBuilderVisitor extends IrBuilderVisitor {
|
| return visitor.withBuilder(irBuilder, () => visitor.visit(expression));
|
| }
|
|
|
| + /// Builds the IR for a constant taken from a different [context].
|
| + ///
|
| + /// Such constants need to be compiled with a different [sourceFile] and
|
| + /// [elements] mapping.
|
| + ir.Primitive inlineConstant(AstElement context, ast.Expression exp) {
|
| + JsIrBuilderVisitor visitor = new JsIrBuilderVisitor(
|
| + context.resolvedAst.elements,
|
| + compiler,
|
| + elementSourceFile(context));
|
| + return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp));
|
| + }
|
| +
|
| /// Builds the IR for a given constructor.
|
| ///
|
| /// 1. Evaluates all own or inherited field initializers.
|
| @@ -1551,5 +1607,80 @@ class JsIrBuilderVisitor extends IrBuilderVisitor {
|
| return withBuilder(builder, () => _makeFunctionBody(element, node));
|
| }
|
|
|
| + /// Creates a primitive for the default value of [parameter].
|
| + ir.Primitive translateDefaultValue(ParameterElement parameter) {
|
| + if (parameter.initializer == null) {
|
| + return irBuilder.buildNullLiteral();
|
| + } else {
|
| + return inlineConstant(parameter.executableContext, parameter.initializer);
|
| + }
|
| + }
|
| +
|
| + /// Inserts default arguments and normalizes order of named arguments.
|
| + List<ir.Primitive> normalizeStaticArguments(
|
| + Selector selector,
|
| + FunctionElement target,
|
| + List<ir.Primitive> arguments) {
|
| + target = target.implementation;
|
| + FunctionSignature signature = target.functionSignature;
|
| + if (!signature.optionalParametersAreNamed &&
|
| + signature.parameterCount == arguments.length) {
|
| + // Optimization: don't copy the argument list for trivial cases.
|
| + return arguments;
|
| + }
|
| +
|
| + List<ir.Primitive> result = <ir.Primitive>[];
|
| + int i = 0;
|
| + signature.forEachRequiredParameter((ParameterElement element) {
|
| + result.add(arguments[i]);
|
| + ++i;
|
| + });
|
| +
|
| + if (!signature.optionalParametersAreNamed) {
|
| + signature.forEachOptionalParameter((ParameterElement element) {
|
| + if (i < arguments.length) {
|
| + result.add(arguments[i]);
|
| + ++i;
|
| + } else {
|
| + result.add(translateDefaultValue(element));
|
| + }
|
| + });
|
| + } else {
|
| + int offset = i;
|
| + // Iterate over the optional parameters of the signature, and try to
|
| + // find them in [compiledNamedArguments]. If found, we use the
|
| + // value in the temporary list, otherwise the default value.
|
| + signature.orderedOptionalParameters.forEach((ParameterElement element) {
|
| + int nameIndex = selector.namedArguments.indexOf(element.name);
|
| + if (nameIndex != -1) {
|
| + int translatedIndex = offset + nameIndex;
|
| + result.add(arguments[translatedIndex]);
|
| + } else {
|
| + result.add(translateDefaultValue(element));
|
| + }
|
| + });
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + /// Normalizes order of named arguments.
|
| + List<ir.Primitive> normalizeDynamicArguments(
|
| + Selector selector,
|
| + List<ir.Primitive> arguments) {
|
| + assert(arguments.length == selector.argumentCount);
|
| + // Optimization: don't copy the argument list for trivial cases.
|
| + if (selector.namedArguments.isEmpty) return arguments;
|
| + List<ir.Primitive> result = <ir.Primitive>[];
|
| + for (int i=0; i < selector.positionalArgumentCount; i++) {
|
| + result.add(arguments[i]);
|
| + }
|
| + for (String argName in selector.getOrderedNamedArguments()) {
|
| + int nameIndex = selector.namedArguments.indexOf(argName);
|
| + int translatedIndex = selector.positionalArgumentCount + nameIndex;
|
| + result.add(arguments[translatedIndex]);
|
| + }
|
| + return result;
|
| + }
|
| +
|
| }
|
|
|
|
|