Disallow default values in redirecting factory constructors.

Closes https://github.com/dart-lang/sdk/issues/34160

Change-Id: Idf6ee172b5fe81aa17920d12b68525a37a3c2231
Reviewed-on: https://dart-review.googlesource.com/72660
Commit-Queue: Daniel Hillerström <hillerstrom@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index 705d94e..b04f0f2 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -1709,6 +1709,33 @@
         message: r"""This is the inherited member.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name)>
+    templateDefaultValueInRedirectingFactoryConstructor =
+    const Template<Message Function(String name)>(
+        messageTemplate:
+            r"""Can't have a default value here because any default values of '#name' would be used instead.""",
+        tipTemplate: r"""Try removing the default value.""",
+        withArguments:
+            _withArgumentsDefaultValueInRedirectingFactoryConstructor);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)>
+    codeDefaultValueInRedirectingFactoryConstructor =
+    const Code<Message Function(String name)>(
+        "DefaultValueInRedirectingFactoryConstructor",
+        templateDefaultValueInRedirectingFactoryConstructor,
+        analyzerCode: "DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsDefaultValueInRedirectingFactoryConstructor(String name) {
+  return new Message(codeDefaultValueInRedirectingFactoryConstructor,
+      message:
+          """Can't have a default value here because any default values of '${name}' would be used instead.""",
+      tip: """Try removing the default value.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeDeferredAfterPrefix = messageDeferredAfterPrefix;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index b6bd338..60fb6cc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -2480,7 +2480,17 @@
             member.fileUri);
       } else {
         variable = formal.build(library);
-        variable.initializer = name.initializer;
+        if (member is KernelRedirectingFactoryBuilder &&
+            name.initializer != null) {
+          KernelRedirectingFactoryBuilder factory = member;
+          addCompileTimeError(
+              fasta.templateDefaultValueInRedirectingFactoryConstructor
+                  .withArguments(factory.redirectionTarget.fullNameForErrors),
+              name.initializer.fileOffset,
+              noLength);
+        } else {
+          variable.initializer = name.initializer;
+        }
       }
     } else {
       variable = new VariableDeclarationJudgment(
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index fcab286..1a218f2 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -42,9 +42,6 @@
 import '../kernel/kernel_function_type_alias_builder.dart'
     show KernelFunctionTypeAliasBuilder;
 
-import '../kernel/kernel_procedure_builder.dart'
-    show KernelRedirectingFactoryBuilder;
-
 import '../parser.dart' show Assert, MemberKind, Parser, optional;
 
 import '../problems.dart' show DebugAbort, internalProblem, unexpected;
@@ -282,8 +279,9 @@
     String name = pop();
     Token metadata = pop();
     checkEmpty(beginToken.charOffset);
-    buildFunctionBody(bodyToken, lookupBuilder(beginToken, getOrSet, name),
-        MemberKind.TopLevelMethod, metadata);
+    final StackListener listener =
+        createFunctionListener(lookupBuilder(beginToken, getOrSet, name));
+    buildFunctionBody(listener, bodyToken, metadata, MemberKind.TopLevelMethod);
   }
 
   @override
@@ -492,37 +490,16 @@
     Object name = pop();
     Token metadata = pop();
     checkEmpty(beginToken.charOffset);
-    if (bodyToken == null || optional("=", bodyToken.endGroup.next)) {
-      // TODO(dmitryas): Consider building redirecting factory bodies here.
-      KernelRedirectingFactoryBuilder factory =
-          lookupConstructor(beginToken, name);
-      parseMetadata(factory, metadata, factory.target);
 
-      if (factory.formals != null) {
-        List<int> metadataOffsets = new List<int>(factory.formals.length);
-        for (int i = 0; i < factory.formals.length; ++i) {
-          List<MetadataBuilder> metadata = factory.formals[i].metadata;
-          if (metadata != null && metadata.length > 0) {
-            // [parseMetadata] is using [Parser.parseMetadataStar] under the
-            // hood, so we only need the offset of the first annotation.
-            metadataOffsets[i] = metadata[0].charOffset;
-          } else {
-            metadataOffsets[i] = -1;
-          }
-        }
-        List<Token> metadataTokens =
-            tokensForOffsets(beginToken, endToken, metadataOffsets);
-        for (int i = 0; i < factory.formals.length; ++i) {
-          Token metadata = metadataTokens[i];
-          if (metadata == null) continue;
-          parseMetadata(
-              factory.formals[i], metadata, factory.formals[i].target);
-        }
-      }
-      return;
+    ProcedureBuilder builder = lookupConstructor(beginToken, name);
+    if (bodyToken == null || optional("=", bodyToken.endGroup.next)) {
+      parseMetadata(builder, metadata, builder.target);
+      buildRedirectingFactoryMethod(
+          bodyToken, builder, MemberKind.Factory, metadata);
+    } else {
+      buildFunctionBody(createFunctionListener(builder), bodyToken, metadata,
+          MemberKind.Factory);
     }
-    buildFunctionBody(bodyToken, lookupConstructor(beginToken, name),
-        MemberKind.Factory, metadata);
   }
 
   @override
@@ -569,10 +546,12 @@
       builder = lookupBuilder(beginToken, getOrSet, name);
     }
     buildFunctionBody(
+        createFunctionListener(builder),
         beginParam,
-        builder,
-        builder.isStatic ? MemberKind.StaticMethod : MemberKind.NonStaticMethod,
-        metadata);
+        metadata,
+        builder.isStatic
+            ? MemberKind.StaticMethod
+            : MemberKind.NonStaticMethod);
   }
 
   StackListener createListener(
@@ -604,19 +583,40 @@
       ..constantContext = constantContext;
   }
 
-  void buildFunctionBody(
-      Token token, ProcedureBuilder builder, MemberKind kind, Token metadata) {
-    Scope typeParameterScope = builder.computeTypeParameterScope(memberScope);
-    Scope formalParameterScope =
+  StackListener createFunctionListener(ProcedureBuilder builder) {
+    final Scope typeParameterScope =
+        builder.computeTypeParameterScope(memberScope);
+    final Scope formalParameterScope =
         builder.computeFormalParameterScope(typeParameterScope);
     assert(typeParameterScope != null);
     assert(formalParameterScope != null);
-    parseFunctionBody(
-        createListener(builder, typeParameterScope, builder.isInstanceMember,
-            formalParameterScope),
-        token,
-        metadata,
-        kind);
+    return createListener(builder, typeParameterScope, builder.isInstanceMember,
+        formalParameterScope);
+  }
+
+  void buildRedirectingFactoryMethod(
+      Token token, ProcedureBuilder builder, MemberKind kind, Token metadata) {
+    final StackListener listener = createFunctionListener(builder);
+    try {
+      Parser parser = new Parser(listener);
+
+      if (metadata != null) {
+        parser.parseMetadataStar(parser.syntheticPreviousToken(metadata));
+        listener.pop();
+      }
+
+      token = parser.parseFormalParametersOpt(
+          parser.syntheticPreviousToken(token), MemberKind.Factory);
+
+      listener.pop();
+      listener.checkEmpty(token.next.charOffset);
+    } on DebugAbort {
+      rethrow;
+    } on deprecated_InputError {
+      rethrow;
+    } catch (e, s) {
+      throw new Crash(uri, token.charOffset, e, s);
+    }
   }
 
   void buildFields(int count, Token token, bool isTopLevel) {
@@ -745,7 +745,7 @@
     listener.finishFields();
   }
 
-  void parseFunctionBody(StackListener listener, Token startToken,
+  void buildFunctionBody(StackListener listener, Token startToken,
       Token metadata, MemberKind kind) {
     Token token = startToken;
     try {
@@ -817,14 +817,11 @@
   Declaration lookupConstructor(Token token, Object nameOrQualified) {
     assert(currentClass != null);
     Declaration declaration;
-    String name;
     String suffix;
     if (nameOrQualified is QualifiedName) {
-      name = nameOrQualified.prefix;
       suffix = nameOrQualified.suffix;
     } else {
-      name = nameOrQualified;
-      suffix = name == currentClass.name ? "" : name;
+      suffix = nameOrQualified == currentClass.name ? "" : nameOrQualified;
     }
     declaration = currentClass.constructors.local[suffix];
     checkBuilder(token, declaration, nameOrQualified);
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 013e5f6..a61d019 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -2740,3 +2740,14 @@
   analyzerCode: CONST_INSTANCE_FIELD
   script:
     - "class C { const field = 0; }"
+
+DefaultValueInRedirectingFactoryConstructor:
+  template: "Can't have a default value here because any default values of '#name' would be used instead."
+  tip: "Try removing the default value."
+  analyzerCode: DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR
+  script:
+    - >-
+      class A {
+        factory A.f({int x = 42}) = A.g;
+        A.g() {}
+      }
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index e53e8f7..70c8436 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -159,8 +159,6 @@
 Language/Classes/Constructors/Factories/accessible_class_t03/01: CompileTimeError
 Language/Classes/Constructors/Factories/accessible_class_t04/01: CompileTimeError
 Language/Classes/Constructors/Factories/accessible_class_t04/02: CompileTimeError
-Language/Classes/Constructors/Factories/default_value_t01: MissingCompileTimeError
-Language/Classes/Constructors/Factories/default_value_t02: MissingCompileTimeError
 Language/Classes/Constructors/Factories/function_type_t02: CompileTimeError
 Language/Classes/Constructors/Factories/redirecting_constructor_call_t01: CompileTimeError
 Language/Classes/Constructors/Factories/redirecting_constructor_call_t02: CompileTimeError
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index 1fdcfee1..82afac9 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -19,8 +19,6 @@
 Language/Classes/Constructors/Constant_Constructors/invalid_constant_initializer_t02: MissingCompileTimeError # Issue 34192
 Language/Classes/Constructors/Constant_Constructors/potentially_constant_expression_t01: MissingCompileTimeError # Issue 34192
 Language/Classes/Constructors/Factories/arguments_type_t01: MissingCompileTimeError # Issue 33308
-Language/Classes/Constructors/Factories/default_value_t01: MissingCompileTimeError # Issue 34160
-Language/Classes/Constructors/Factories/default_value_t02: MissingCompileTimeError # Issue 34160
 Language/Classes/Constructors/Factories/function_type_t01: MissingCompileTimeError # Issue 31590
 Language/Classes/Constructors/Factories/function_type_t02: MissingCompileTimeError # Issue 31590
 Language/Classes/Constructors/Generative_Constructors/final_variables_t01: CompileTimeError # Expects a warning, but this is an error in Dart 2
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index b65a22f..c6a6d0e 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -269,9 +269,6 @@
 mixin_invalid_bound_test/10: MissingCompileTimeError # Issue 33308
 mixin_super_bound_test/01: MissingCompileTimeError # Issue 33308
 mixin_super_bound_test/02: MissingCompileTimeError # Issue 33308
-named_parameters_default_eq_test/02: MissingCompileTimeError # Issue 34160
-redirecting_factory_default_values_test/01: MissingCompileTimeError # Issue 34160
-redirecting_factory_default_values_test/02: MissingCompileTimeError # Issue 34160
 regress_22976_test/*: CompileTimeError # Issue 31935
 syntax_test/28: MissingCompileTimeError # Issue 29763 - low priority
 syntax_test/29: MissingCompileTimeError # Issue 29763 - low priority