Perform substitution on type argument/parameter bounds.
Fixes regression #34528. Introduces a new test to mitigate future
regressions.
Closes #34528.
Change-Id: Iaf0a8f44db2a8b4a8151c391ddb8dff69910fe3a
Reviewed-on: https://dart-review.googlesource.com/75840
Commit-Queue: Daniel Hillerström <hillerstrom@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Erik Ernst <eernst@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 71abcf1..ba3dc08 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -6399,29 +6399,25 @@
r"""Try removing the body, or not making this a redirecting constructor.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<
- Message Function(
- String name,
- DartType _type,
- DartType
- _type2)> templateRedirectingFactoryIncompatibleBounds = const Template<
- Message Function(String name, DartType _type, DartType _type2)>(
- messageTemplate:
- r"""The type variable '#name' has bound '#type' but the context expects a type variable with bound '#type2'.""",
- tipTemplate: r"""Try redirecting to a different constructor.""",
- withArguments: _withArgumentsRedirectingFactoryIncompatibleBounds);
+const Template<Message Function(DartType _type, DartType _type2)>
+ templateRedirectingFactoryIncompatibleTypeArgument =
+ const Template<Message Function(DartType _type, DartType _type2)>(
+ messageTemplate: r"""The type '#type' doesn't extend '#type2'.""",
+ tipTemplate: r"""Try using a different type as argument.""",
+ withArguments:
+ _withArgumentsRedirectingFactoryIncompatibleTypeArgument);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name, DartType _type, DartType _type2)>
- codeRedirectingFactoryIncompatibleBounds =
- const Code<Message Function(String name, DartType _type, DartType _type2)>(
- "RedirectingFactoryIncompatibleBounds",
- templateRedirectingFactoryIncompatibleBounds,
- analyzerCode: "REDIRECT_TO_INVALID_RETURN_TYPE");
+const Code<Message Function(DartType _type, DartType _type2)>
+ codeRedirectingFactoryIncompatibleTypeArgument =
+ const Code<Message Function(DartType _type, DartType _type2)>(
+ "RedirectingFactoryIncompatibleTypeArgument",
+ templateRedirectingFactoryIncompatibleTypeArgument,
+ analyzerCode: "TYPE_ARGUMENT_NOT_MATCHING_BOUNDS");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsRedirectingFactoryIncompatibleBounds(
- String name, DartType _type, DartType _type2) {
+Message _withArgumentsRedirectingFactoryIncompatibleTypeArgument(
+ DartType _type, DartType _type2) {
NameSystem nameSystem = new NameSystem();
StringBuffer buffer;
buffer = new StringBuffer();
@@ -6432,11 +6428,10 @@
new Printer(buffer, syntheticNames: nameSystem).writeNode(_type2);
String type2 = '$buffer';
- return new Message(codeRedirectingFactoryIncompatibleBounds,
- message:
- """The type variable '${name}' has bound '${type}' but the context expects a type variable with bound '${type2}'.""",
- tip: """Try redirecting to a different constructor.""",
- arguments: {'name': name, 'type': _type, 'type2': _type2});
+ return new Message(codeRedirectingFactoryIncompatibleTypeArgument,
+ message: """The type '${type}' doesn't extend '${type2}'.""",
+ tip: """Try using a different type as argument.""",
+ arguments: {'type': _type, 'type2': _type2});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
index cbb9b93..3ad8c9c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
@@ -70,7 +70,7 @@
templateOverrideTypeMismatchParameter,
templateOverrideTypeMismatchReturnType,
templateOverrideTypeVariablesMismatch,
- templateRedirectingFactoryIncompatibleBounds,
+ templateRedirectingFactoryIncompatibleTypeArgument,
templateRedirectingFactoryInvalidNamedParameterType,
templateRedirectingFactoryInvalidPositionalParameterType,
templateRedirectingFactoryMissingNamedParameter,
@@ -103,7 +103,8 @@
Scope,
TypeVariableBuilder;
-import 'redirecting_factory_body.dart' show RedirectingFactoryBody;
+import 'redirecting_factory_body.dart'
+ show getRedirectingFactoryBody, RedirectingFactoryBody;
import 'kernel_target.dart' show KernelTarget;
@@ -1190,9 +1191,9 @@
// Computes the function type of a given redirection target. Returns [null] if
// the type of actual target could not be computed.
- FunctionType computeRedirecteeType(
- ConstructorReferenceBuilder redirectionTarget,
+ FunctionType computeRedirecteeType(KernelRedirectingFactoryBuilder factory,
TypeEnvironment typeEnvironment) {
+ ConstructorReferenceBuilder redirectionTarget = factory.redirectionTarget;
FunctionNode target;
bool isConstructor = false;
Class targetClass; // Used when the redirection target is a constructor.
@@ -1225,51 +1226,43 @@
return null;
}
- FunctionType inferredType = target.functionType;
- if (redirectionTarget.typeArguments != null &&
- inferredType.typeParameters.length !=
- redirectionTarget.typeArguments.length) {
+ List<DartType> typeArguments =
+ getRedirectingFactoryBody(factory.target).typeArguments;
+ FunctionType targetFunctionType = target.functionType;
+ if (typeArguments != null &&
+ targetFunctionType.typeParameters.length != typeArguments.length) {
addProblem(
templateTypeArgumentMismatch
- .withArguments(inferredType.typeParameters.length),
+ .withArguments(targetFunctionType.typeParameters.length),
redirectionTarget.charOffset,
noLength);
return null;
}
// Compute the substitution of the target class type parameters if
- // [redirectionTarget] has any type arguments. Any built type arguments are
- // stored in [typeArguments] for later use.
+ // [redirectionTarget] has any type arguments.
Substitution substitution;
- List<DartType> typeArguments;
- if (redirectionTarget.typeArguments != null &&
- redirectionTarget.typeArguments.length > 0) {
- typeArguments = new List<DartType>();
- for (var i = 0; i < inferredType.typeParameters.length; i++) {
- var typeParameter = inferredType.typeParameters[i];
- var typeArgument = redirectionTarget.typeArguments[i].build(library);
+ bool hasProblem = false;
+ if (typeArguments != null && typeArguments.length > 0) {
+ substitution = Substitution.fromPairs(
+ targetFunctionType.typeParameters, typeArguments);
+ for (int i = 0; i < targetFunctionType.typeParameters.length; i++) {
+ TypeParameter typeParameter = targetFunctionType.typeParameters[i];
+ DartType typeParameterBound =
+ substitution.substituteType(typeParameter.bound);
+ DartType typeArgument = typeArguments[i];
// Check whether the [typeArgument] respects the bounds of [typeParameter].
- if (typeArgument is TypeParameterType) {
- if (!typeEnvironment.isSubtypeOf(
- typeArgument.bound, typeParameter.bound)) {
- // TODO(hillerstrom): Use dmitrays' error message once his "bounds
- // checking" CL has landed.
- addProblem(
- templateRedirectingFactoryIncompatibleBounds.withArguments(
- typeArgument.parameter.name,
- typeArgument.bound,
- typeParameter.bound),
- redirectionTarget.charOffset,
- noLength);
- return null;
- }
+ if (!typeEnvironment.isSubtypeOf(typeArgument, typeParameterBound)) {
+ addProblem(
+ templateRedirectingFactoryIncompatibleTypeArgument.withArguments(
+ typeArgument, typeParameterBound),
+ redirectionTarget.charOffset,
+ noLength);
+ hasProblem = true;
}
- typeArguments.add(typeArgument);
}
- substitution =
- Substitution.fromPairs(inferredType.typeParameters, typeArguments);
- } else if (redirectionTarget.typeArguments == null &&
- inferredType.typeParameters.length > 0) {
+ } else if (typeArguments == null &&
+ targetFunctionType.typeParameters.length > 0) {
// TODO(hillerstrom): In this case, we need to perform type inference on
// the redirectee to obtain actual type arguments which would allow the
// following program to type check:
@@ -1286,21 +1279,21 @@
FunctionType redirecteeType;
// If the target is a constructor then we need to patch the return type of
- // the inferred type, because the type inferrer always infers the return
- // type to be "void", whereas the inferred return type of a factory is its
- // enclosing class. TODO(hillerstrom): It may be worthwhile to change the
- // typing of constructors such that the return type is its enclosing class.
+ // [targetFunctionType], because constructors always have return type to be
+ // "void", whereas the return type of a factory is its enclosing
+ // class. TODO(hillerstrom): It may be worthwhile to change the typing of
+ // constructors such that the return type is its enclosing class.
if (isConstructor) {
DartType returnType =
new InterfaceType(targetClass, typeArguments ?? const <DartType>[]);
redirecteeType = new FunctionType(
- inferredType.positionalParameters, returnType,
- namedParameters: inferredType.namedParameters,
- typeParameters: inferredType.typeParameters,
- requiredParameterCount: inferredType.requiredParameterCount);
+ targetFunctionType.positionalParameters, returnType,
+ namedParameters: targetFunctionType.namedParameters,
+ typeParameters: targetFunctionType.typeParameters,
+ requiredParameterCount: targetFunctionType.requiredParameterCount);
} else {
- redirecteeType = inferredType;
+ redirecteeType = targetFunctionType;
}
// Substitute if necessary.
@@ -1309,7 +1302,7 @@
: (substitution.substituteType(redirecteeType.withoutTypeParameters)
as FunctionType);
- return redirecteeType;
+ return hasProblem ? null : redirecteeType;
}
String computeRedirecteeName(ConstructorReferenceBuilder redirectionTarget) {
@@ -1329,7 +1322,7 @@
FunctionType factoryType =
factory.procedure.function.functionType.withoutTypeParameters;
FunctionType redirecteeType =
- computeRedirecteeType(factory.redirectionTarget, typeEnvironment);
+ computeRedirecteeType(factory, typeEnvironment);
// TODO(hillerstrom): It would be preferable to know whether a failure
// happened during [_computeRedirecteeType].
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 9f85ec7..2c8472f 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -2978,15 +2978,13 @@
A.g(int x, int y) {}
}
-RedirectingFactoryIncompatibleBounds:
- template: "The type variable '#name' has bound '#type' but the context expects a type variable with bound '#type2'."
- tip: "Try redirecting to a different constructor."
- analyzerCode: REDIRECT_TO_INVALID_RETURN_TYPE
+RedirectingFactoryIncompatibleTypeArgument:
+ template: "The type '#type' doesn't extend '#type2'."
+ tip: "Try using a different type as argument."
+ analyzerCode: TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
script:
- >-
class A<T extends int> {
- factory A() = B<T>;
+ factory A() = B<T, int>;
}
- class B<S extends String> implements A<int> {
- B();
- }
+ class B<T extends int, S extends String> implements A<T> {}
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index e276dd0..5ee4078 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -62,6 +62,7 @@
Language/Classes/Constructors/Constant_Constructors/initializer_not_a_constant_t01: MissingCompileTimeError
Language/Classes/Constructors/Constant_Constructors/initializer_not_a_constant_t02: MissingCompileTimeError
Language/Classes/Constructors/Constant_Constructors/invalid_constant_initializer_t02: MissingCompileTimeError
+Language/Classes/Constructors/Factories/arguments_type_t01: CompileTimeError # Expects a warning, but this is an error in Dart 2
Language/Classes/Constructors/Factories/function_type_t01: CompileTimeError # Expects a warning but this is an error in Dart 2
Language/Classes/Constructors/Generative_Constructors/static_type_t01: CompileTimeError
Language/Classes/Constructors/name_t01: MissingCompileTimeError
@@ -557,6 +558,7 @@
Language/Expressions/Instance_Creation/New/execution_t13: CompileTimeError
Language/Expressions/Instance_Creation/New/named_constructor_t01: CompileTimeError
Language/Expressions/Instance_Creation/New/named_constructor_t02: CompileTimeError
+Language/Expressions/Instance_Creation/New/redirecting_factory_constructor_t01: CompileTimeError # Issue 33308
Language/Expressions/Instance_Creation/New/redirecting_factory_constructor_t02: CompileTimeError
Language/Expressions/Instance_Creation/New/type_argument_t01: CompileTimeError
Language/Expressions/Instance_Creation/New/type_t01: CompileTimeError
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index a7fe5f7..7c11557 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -14,7 +14,6 @@
Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t05: MissingCompileTimeError # Legal, see #33235
Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t06: MissingCompileTimeError # Legal, see #33235
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/Generative_Constructors/final_variables_t01: CompileTimeError # Expects a warning, but this is an error in Dart 2
Language/Classes/Constructors/Generative_Constructors/initializers_t15: CompileTimeError
Language/Classes/Constructors/name_t01: MissingCompileTimeError # Legal, see #33235
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index 06730ab..8d5af69 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -237,7 +237,6 @@
duplicate_export_collision_test/01: MissingCompileTimeError # Issue 12916
f_bounded_quantification_test/01: MissingCompileTimeError # Issue 33308
f_bounded_quantification_test/02: MissingCompileTimeError # Issue 33308
-factory4_test/00: MissingCompileTimeError # Issue 31590
generic_methods_bounds_test/01: MissingCompileTimeError # Issue 33308
generic_methods_recursive_bound_test/02: MissingCompileTimeError # Issue 33308
issue31596_super_test/02: MissingCompileTimeError # Issue 31596
@@ -1289,6 +1288,7 @@
[ $fasta && $strong ]
issue18628_2_test/01: MissingCompileTimeError
+redirecting_factory_bounds_test/02: MissingCompileTimeError # Related to issue 33308
type_promotion_logical_and_test/01: MissingCompileTimeError
[ $fasta && !$strong ]
diff --git a/tests/language_2/redirecting_factory_bounds_test.dart b/tests/language_2/redirecting_factory_bounds_test.dart
new file mode 100644
index 0000000..e8dbabf
--- /dev/null
+++ b/tests/language_2/redirecting_factory_bounds_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Bounds checking on redirecting factories.
+
+class Foo<T> {}
+
+class Baz<T> {}
+
+class Foobar<T> implements Foo<T> {}
+
+class Bar<
+ T // A comment to prevent dartfmt from joining the lines.
+ extends Foo<T> //# 00: ok
+ extends Baz<Foo<T>> //# 01: compile-time error
+ extends Foobar<T> //# 02: compile-time error
+ > {
+ Bar.named();
+ factory Bar() = Qux<T>;
+}
+
+class Qux<
+ T // A comment to prevent dartfmt from joining the lines.
+ extends Foo<T> //# 00: continued
+ extends Foo<T> //# 01: continued
+ extends Foo<T> //# 02: continued
+ > extends Bar<T> {
+ Qux() : super.named();
+}
+
+
+
+class A<T extends int> {
+ factory A() = B<
+ T // A comment to prevent dartfmt from joining the lines.
+ , int //# 03: compile-time error
+ , String //# 04: ok
+ >;
+}
+
+class B<T extends int
+ , S extends String //# 03: continued
+ , S extends String //# 04: continued
+ > implements A<T> {}
+
+void main() {
+ new Bar<Null>();
+ new A<int>();
+}
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index 72e6ad5..f39040a 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -35,6 +35,8 @@
mirrors/generic_interface_test/01: MissingCompileTimeError
mirrors/metadata_allowed_values_test/13: MissingCompileTimeError
mirrors/metadata_allowed_values_test/14: MissingCompileTimeError
+mirrors/redirecting_factory_test/01: CompileTimeError # Issue 33308
+mirrors/redirecting_factory_test/none: CompileTimeError # Issue 33308
[ $arch == simarm64 && $strong && ($compiler == dartk || $compiler == dartkb) ]
isolate/mint_maker_test: Timeout # Please triage.