Index: pkg/compiler/lib/src/js_emitter/metadata_collector.dart |
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart |
index 009df8c3bd687d0717db95b7d82963b746803ae3..fdea7ff9b0872066437aea7c0cd3d859516f98e1 100644 |
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart |
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart |
@@ -178,12 +178,42 @@ class MetadataCollector implements jsAst.TokenFinalizer { |
} |
List<jsAst.DeferredNumber> reifyDefaultArguments(FunctionElement function) { |
+ function = function.implementation; |
FunctionSignature signature = function.functionSignature; |
if (signature.optionalParameterCount == 0) return const []; |
+ |
+ // Optional parameters of redirecting factory constructors take their |
+ // defaults from the corresponding parameters of the redirection target. |
+ Map<ParameterElement, ParameterElement> targetParameterMap; |
+ if (function is ConstructorElement) { |
+ // TODO(sra): dart2js generates a redirecting factory constructor body |
+ // that has the signature of the redirecting constructor that calls the |
+ // redirection target. This is wrong - it should have the signature of the |
+ // target. This would make the reified default arguments trivial. |
+ |
+ ConstructorElement constructor = function; |
+ while (constructor.isRedirectingFactory && |
+ !constructor.isCyclicRedirection) { |
+ // TODO(sra): Remove the loop once effectiveTarget forwards to patches. |
+ constructor = constructor.effectiveTarget.implementation; |
+ } |
+ |
+ if (constructor != function) { |
+ if (signature.hasOptionalParameters) { |
+ targetParameterMap = |
+ mapRedirectingFactoryConstructorOptionalParameters( |
+ signature, constructor.functionSignature); |
+ } |
+ } |
+ } |
+ |
List<jsAst.DeferredNumber> defaultValues = <jsAst.DeferredNumber>[]; |
for (ParameterElement element in signature.optionalParameters) { |
- ConstantValue constant = |
- _backend.constants.getConstantValueForVariable(element); |
+ ParameterElement parameter = |
+ (targetParameterMap == null) ? element : targetParameterMap[element]; |
+ ConstantValue constant = (parameter == null) |
+ ? null |
+ : _backend.constants.getConstantValueForVariable(parameter); |
jsAst.Expression expression = (constant == null) |
? new jsAst.LiteralNull() |
: _emitter.constantReference(constant); |
@@ -192,6 +222,40 @@ class MetadataCollector implements jsAst.TokenFinalizer { |
return defaultValues; |
} |
+ Map<ParameterElement, ParameterElement> |
+ mapRedirectingFactoryConstructorOptionalParameters( |
+ FunctionSignature source, FunctionSignature target) { |
+ var map = <ParameterElement, ParameterElement>{}; |
+ |
+ if (source.optionalParametersAreNamed != |
+ target.optionalParametersAreNamed) { |
+ // No legal optional arguments due to mismatch between named vs positional |
+ // optional arguments. |
+ return map; |
+ } |
+ |
+ if (source.optionalParametersAreNamed) { |
+ for (ParameterElement element in source.optionalParameters) { |
+ for (ParameterElement redirectedElement in target.optionalParameters) { |
+ if (element.name == redirectedElement.name) { |
+ map[element] = redirectedElement; |
+ break; |
+ } |
+ } |
+ } |
+ } else { |
+ int i = source.requiredParameterCount; |
+ for (ParameterElement element in source.orderedOptionalParameters) { |
+ if (i >= target.requiredParameterCount && i < target.parameterCount) { |
+ map[element] = |
+ target.orderedOptionalParameters[i - target.requiredParameterCount]; |
+ } |
+ ++i; |
+ } |
+ } |
+ return map; |
+ } |
+ |
jsAst.Expression reifyMetadata(MetadataAnnotation annotation) { |
ConstantValue constant = |
_backend.constants.getConstantValueForMetadata(annotation); |
@@ -365,4 +429,4 @@ class UnBoundDebugger extends jsAst.BaseVisitor { |
node.accept(this); |
return _foundUnboundToken; |
} |
-} |
+} |