Chromium Code Reviews| Index: pkg/compiler/lib/src/elements/elements.dart |
| diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart |
| index 8267b1f5dcb2067e39bf8d1379955c69f83840a7..2784eee422e2f66a87e3ba6d7aa6650dccda18fa 100644 |
| --- a/pkg/compiler/lib/src/elements/elements.dart |
| +++ b/pkg/compiler/lib/src/elements/elements.dart |
| @@ -17,6 +17,7 @@ import '../script.dart'; |
| import '../tokens/token.dart' |
| show Token, isUserDefinableOperator, isMinusOperator; |
| import '../tree/tree.dart'; |
| +import '../universe/call_structure.dart'; |
| import '../util/characters.dart' show $_; |
| import '../util/util.dart'; |
| import '../world.dart' show ClosedWorld; |
| @@ -819,6 +820,131 @@ class Elements { |
| // label is also always unused. |
| return element == null || element.statement != body; |
| } |
| + |
| + /** |
| + * Returns a `List` with the evaluated arguments in the normalized order. |
| + * |
| + * [compileDefaultValue] is a function that returns a compiled constant |
| + * of an optional argument that is not in [compiledArguments]. |
| + * |
| + * Precondition: `this.applies(element, world)`. |
|
Siggi Cherem (dart-lang)
2017/01/13 17:11:07
what is `this` in this static context?
Johnni Winther
2017/01/18 11:02:51
Old invariant. Changed to `callStructure.signature
|
| + * |
| + * Invariant: [element] must be the implementation element. |
| + */ |
| + static List<T> makeArgumentsList<T>( |
| + CallStructure callStructure, |
| + Link<Node> arguments, |
| + FunctionElement element, |
| + T compileArgument(Node argument), |
| + T compileDefaultValue(ParameterElement element)) { |
| + assert(invariant(element, element.isImplementation)); |
| + List<T> result = <T>[]; |
| + |
| + FunctionSignature parameters = element.functionSignature; |
| + parameters.forEachRequiredParameter((ParameterElement element) { |
| + result.add(compileArgument(arguments.head)); |
| + arguments = arguments.tail; |
| + }); |
| + |
| + if (!parameters.optionalParametersAreNamed) { |
| + parameters.forEachOptionalParameter((ParameterElement element) { |
| + if (!arguments.isEmpty) { |
| + result.add(compileArgument(arguments.head)); |
| + arguments = arguments.tail; |
| + } else { |
| + result.add(compileDefaultValue(element)); |
| + } |
| + }); |
| + } else { |
| + // Visit named arguments and add them into a temporary list. |
| + List compiledNamedArguments = []; |
| + for (; !arguments.isEmpty; arguments = arguments.tail) { |
| + NamedArgument namedArgument = arguments.head; |
| + compiledNamedArguments.add(compileArgument(namedArgument.expression)); |
| + } |
| + // 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. |
| + parameters.orderedOptionalParameters.forEach((ParameterElement element) { |
| + int foundIndex = callStructure.namedArguments.indexOf(element.name); |
| + if (foundIndex != -1) { |
| + result.add(compiledNamedArguments[foundIndex]); |
| + } else { |
| + result.add(compileDefaultValue(element)); |
| + } |
| + }); |
| + } |
| + return result; |
| + } |
| + |
| + /** |
| + * Fills [list] with the arguments in the order expected by |
| + * [callee], and where [caller] is a synthesized element |
| + * |
| + * [compileArgument] is a function that returns a compiled version |
| + * of a parameter of [callee]. |
| + * |
| + * [compileConstant] is a function that returns a compiled constant |
| + * of an optional argument that is not in the parameters of [callee]. |
| + * |
| + * Returns [:true:] if the signature of the [caller] matches the |
| + * signature of the [callee], [:false:] otherwise. |
| + */ |
| + static bool addForwardingElementArgumentsToList<T>( |
| + ConstructorElement caller, |
| + List<T> list, |
| + ConstructorElement callee, |
| + T compileArgument(ParameterElement element), |
| + T compileConstant(ParameterElement element)) { |
| + assert(invariant(caller, !callee.isMalformed, |
| + message: "Cannot compute arguments to malformed constructor: " |
| + "$caller calling $callee.")); |
| + |
| + FunctionSignature signature = caller.functionSignature; |
| + Map<Node, ParameterElement> mapping = <Node, ParameterElement>{}; |
| + |
| + // TODO(ngeoffray): This is a hack that fakes up AST nodes, so |
| + // that we can call [addArgumentsToList]. |
| + Link<Node> computeCallNodesFromParameters() { |
| + LinkBuilder<Node> builder = new LinkBuilder<Node>(); |
| + signature.forEachRequiredParameter((ParameterElement element) { |
| + Node node = element.node; |
| + mapping[node] = element; |
| + builder.addLast(node); |
| + }); |
| + if (signature.optionalParametersAreNamed) { |
| + signature.forEachOptionalParameter((ParameterElement element) { |
| + mapping[element.initializer] = element; |
| + builder.addLast(new NamedArgument(null, null, element.initializer)); |
| + }); |
| + } else { |
| + signature.forEachOptionalParameter((ParameterElement element) { |
| + Node node = element.node; |
| + mapping[node] = element; |
| + builder.addLast(node); |
| + }); |
| + } |
| + return builder.toLink(); |
| + } |
| + |
| + /*T*/ internalCompileArgument(Node node) { |
| + return compileArgument(mapping[node]); |
| + } |
| + |
| + Link<Node> nodes = computeCallNodesFromParameters(); |
| + |
| + // Synthesize a structure for the call. |
| + // TODO(ngeoffray): Should the resolver do it instead? |
| + CallStructure callStructure = new CallStructure( |
| + signature.parameterCount, signature.type.namedParameters); |
| + if (!callStructure.signatureApplies(signature.type)) { |
| + return false; |
| + } |
| + list.addAll(makeArgumentsList<T>(callStructure, nodes, callee, |
| + internalCompileArgument, compileConstant)); |
| + |
| + return true; |
| + } |
| } |
| /// An element representing an erroneous resolution. |