Change in dart/sdk[master]: Issue 41371. Report an error for covariant parameter in the interface...

5 views
Skip to first unread message

Konstantin Shcheglov (Gerrit)

unread,
May 3, 2020, 10:35:17 PM5/3/20
to rev...@dartlang.org, Brian Wilkerson, Erik Ernst, commi...@chromium.org

View Change

    To view, visit change 146120. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Ife57b54c1f2609ef1202ccc6c918cf85bb8c0df7
    Gerrit-Change-Number: 146120
    Gerrit-PatchSet: 4
    Gerrit-Owner: Konstantin Shcheglov <sche...@google.com>
    Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
    Gerrit-Reviewer: Erik Ernst <eer...@google.com>
    Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
    Gerrit-Comment-Date: Mon, 04 May 2020 02:35:14 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Konstantin Shcheglov (Gerrit)

    unread,
    May 3, 2020, 10:35:17 PM5/3/20
    to Erik Ernst, Brian Wilkerson, rev...@dartlang.org

    Konstantin Shcheglov would like Erik Ernst and Brian Wilkerson to review this change.

    View Change

    Issue 41371. Report an error for covariant parameter in the interface, but not in the implementation.

    Bug: https://github.com/dart-lang/sdk/issues/41371
    Change-Id: Ife57b54c1f2609ef1202ccc6c918cf85bb8c0df7
    ---
    M pkg/analyzer/lib/error/error.dart
    M pkg/analyzer/lib/src/error/codes.dart
    M pkg/analyzer/lib/src/error/correct_override.dart
    M pkg/analyzer/lib/src/error/inheritance_override.dart
    A pkg/analyzer/test/src/diagnostics/covariant_interface_parameter_with_non_covariant_implementation_test.dart
    M pkg/analyzer/test/src/diagnostics/test_all.dart
    M tests/language/covariant_override/tear_off_type_test.dart
    M tests/language_2/covariant_override/tear_off_type_test.dart
    M tests/language_2/regress/regress31596_covariant_declaration_test.dart
    9 files changed, 179 insertions(+), 4 deletions(-)

    diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
    index 1ecfb41..65f6f71 100644
    --- a/pkg/analyzer/lib/error/error.dart
    +++ b/pkg/analyzer/lib/error/error.dart
    @@ -126,6 +126,8 @@
    CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR,
    CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
    CompileTimeErrorCode.CONTINUE_LABEL_ON_SWITCH,
    + CompileTimeErrorCode
    + .COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION,
    CompileTimeErrorCode.DEFAULT_LIST_CONSTRUCTOR,
    CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPED_PARAMETER,
    CompileTimeErrorCode.DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR,
    diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
    index 3a45736..09e9b27 100644
    --- a/pkg/analyzer/lib/src/error/codes.dart
    +++ b/pkg/analyzer/lib/src/error/codes.dart
    @@ -1468,6 +1468,22 @@
    "A continue label resolves to switch, must be loop or switch member");

    /**
    + * Parameters:
    + * 0: the name of the formal parameter.
    + * 1: the name of the member.
    + * 2: the name of the class with the implementation of the member.
    + */
    + static const CompileTimeErrorCode
    + COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION =
    + CompileTimeErrorCode(
    + 'COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION',
    + "The parameter '{0}' of '{1}' is covariant in the interface of the class, "
    + "but is not covariant in the implementation '{2}.{1}'.",
    + correction: "Try removing the covariant modifier in the interface, "
    + "or overriding the method in the class and calling super.",
    + );
    +
    + /**
    * No parameters.
    */
    // #### Description
    diff --git a/pkg/analyzer/lib/src/error/correct_override.dart b/pkg/analyzer/lib/src/error/correct_override.dart
    index 7d67e40..7ff8919 100644
    --- a/pkg/analyzer/lib/src/error/correct_override.dart
    +++ b/pkg/analyzer/lib/src/error/correct_override.dart
    @@ -9,6 +9,7 @@
    import 'package:analyzer/error/listener.dart';
    import 'package:analyzer/src/dart/analysis/session.dart';
    import 'package:analyzer/src/dart/element/element.dart';
    +import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
    import 'package:analyzer/src/dart/element/type.dart';
    import 'package:analyzer/src/dart/element/type_algebra.dart';
    import 'package:analyzer/src/error/codes.dart';
    @@ -16,6 +17,49 @@
    import 'package:analyzer/src/generated/type_system.dart';
    import 'package:meta/meta.dart';

    +/// It is an error if a formal parameter is covariant in the interface, but
    +/// the corresponding formal parameter in the concrete declaration is not
    +/// covariant.
    +///
    +/// This happens when the concrete declaration is inherited, not when it
    +/// is declared in the class being verified, otherwise it would inherit
    +/// the covariant-by-declaration flag.
    +void verifyConcreteForCovariantInterface({
    + @required InheritanceManager3 inheritance,
    + @required Name name,
    + @required ExecutableElement concreteMember,
    + @required List<InterfaceType> directInterfaces,
    + @required ErrorReporter errorReporter,
    + @required AstNode errorNode,
    +}) {
    + for (var directInterface in directInterfaces) {
    + var interfaceMember = inheritance.getMember(directInterface, name);
    + if (interfaceMember == null) continue;
    +
    + var interfaceParameters = interfaceMember.parameters;
    + for (var i = 0; i < interfaceParameters.length; i++) {
    + var interfaceParameter = interfaceParameters[i];
    + if (interfaceParameter.isCovariant) {
    + var concreteParameter =
    + CovariantParametersVerifier._correspondingParameter(
    + concreteMember.parameters, interfaceParameter, i);
    + if (concreteParameter != null && !concreteParameter.isCovariant) {
    + errorReporter.reportErrorForNode(
    + CompileTimeErrorCode
    + .COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION,
    + errorNode,
    + [
    + interfaceParameter.name,
    + interfaceMember.displayName,
    + concreteMember.enclosingElement.displayName,
    + ],
    + );
    + }
    + }
    + }
    + }
    +}
    +
    class CorrectOverrideHelper {
    final LibraryElementImpl _library;
    final TypeSystemImpl _typeSystem;
    diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart
    index 7d6fc78..00e6fa3 100644
    --- a/pkg/analyzer/lib/src/error/inheritance_override.dart
    +++ b/pkg/analyzer/lib/src/error/inheritance_override.dart
    @@ -237,6 +237,19 @@
    }

    _reportInheritedAbstractMembers(inheritedAbstract);
    +
    + for (var entry in interface.implemented.entries) {
    + var name = entry.key;
    + var concreteElement = entry.value;
    + verifyConcreteForCovariantInterface(
    + inheritance: inheritance,
    + name: name,
    + concreteMember: concreteElement,
    + directInterfaces: directSuperInterfaces,
    + errorReporter: reporter,
    + errorNode: classNameNode,
    + );
    + }
    }
    }

    diff --git a/pkg/analyzer/test/src/diagnostics/covariant_interface_parameter_with_non_covariant_implementation_test.dart b/pkg/analyzer/test/src/diagnostics/covariant_interface_parameter_with_non_covariant_implementation_test.dart
    new file mode 100644
    index 0000000..3a51587
    --- /dev/null
    +++ b/pkg/analyzer/test/src/diagnostics/covariant_interface_parameter_with_non_covariant_implementation_test.dart
    @@ -0,0 +1,67 @@
    +// Copyright (c) 2020, 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.
    +
    +import 'package:analyzer/src/error/codes.dart';
    +import 'package:test_reflective_loader/test_reflective_loader.dart';
    +
    +import '../dart/resolution/driver_resolution.dart';
    +
    +main() {
    + defineReflectiveSuite(() {
    + defineReflectiveTests(
    + CovariantInterfaceParameterWithNonCovariantImplementationTest);
    + });
    +}
    +
    +@reflectiveTest
    +class CovariantInterfaceParameterWithNonCovariantImplementationTest
    + extends DriverResolutionTest {
    + test_method_covariantBoth() async {
    + await assertNoErrorsInCode(r'''
    +class C {
    + void foo(covariant int x) {}
    +}
    +
    +abstract class I {
    + void foo(covariant int x);
    +}
    +
    +class D extends C implements I {}
    +''');
    + }
    +
    + test_method_covariantImplementation() async {
    + await assertNoErrorsInCode(r'''
    +class C {
    + void foo(covariant int x) {}
    +}
    +
    +abstract class I {
    + void foo(int x);
    +}
    +
    +class D extends C implements I {}
    +''');
    + }
    +
    + test_method_covariantInterface() async {
    + await assertErrorsInCode(r'''
    +class C {
    + void foo(int x) {}
    +}
    +
    +abstract class I {
    + void foo(covariant int x);
    +}
    +
    +class D extends C implements I {}
    +''', [
    + error(
    + CompileTimeErrorCode
    + .COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION,
    + 91,
    + 1),
    + ]);
    + }
    +}
    diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
    index 76664cc..6955167 100644
    --- a/pkg/analyzer/test/src/diagnostics/test_all.dart
    +++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
    @@ -56,6 +56,8 @@
    import 'const_spread_expected_list_or_set_test.dart'
    as const_spread_expected_list_or_set;
    import 'const_spread_expected_map_test.dart' as const_spread_expected_map;
    +import 'covariant_interface_parameter_with_non_covariant_implementation_test.dart'
    + as covariant_interface_parameter_with_non_covariant_implementation;
    import 'dead_code_test.dart' as dead_code;
    import 'dead_null_aware_expression_test.dart' as dead_null_aware_expression;
    import 'default_list_constructor_test.dart' as default_list_constructor;
    @@ -545,6 +547,7 @@
    const_set_element_type_implements_equals.main();
    const_spread_expected_list_or_set.main();
    const_spread_expected_map.main();
    + covariant_interface_parameter_with_non_covariant_implementation.main();
    dead_code.main();
    dead_null_aware_expression.main();
    default_list_constructor.main();
    diff --git a/tests/language/covariant_override/tear_off_type_test.dart b/tests/language/covariant_override/tear_off_type_test.dart
    index 732aaf6..3e911a7 100644
    --- a/tests/language/covariant_override/tear_off_type_test.dart
    +++ b/tests/language/covariant_override/tear_off_type_test.dart
    @@ -26,6 +26,8 @@
    }

    class C extends Object with M1, M2 {}
    +// ^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION

    class Direct {
    void positional(covariant int a, int b, covariant int c, int d, int e) {}
    @@ -96,8 +98,20 @@
    }

    class Mixed extends Superclass
    - with Mixin1, Mixin2
    - implements Interface1, Interface2 {}
    +// ^^^^^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION
    +// ^^^^^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION
    +// ^^^^^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION
    +// ^^^^^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION
    + with
    + Mixin1,
    + Mixin2
    + implements
    + Interface1,
    + Interface2 {}

    void main() {
    testDirect();
    diff --git a/tests/language_2/covariant_override/tear_off_type_test.dart b/tests/language_2/covariant_override/tear_off_type_test.dart
    index 59991b8..cfb1f48 100644
    --- a/tests/language_2/covariant_override/tear_off_type_test.dart
    +++ b/tests/language_2/covariant_override/tear_off_type_test.dart
    @@ -26,6 +26,8 @@
    }

    class C extends Object with M1, M2 {}
    +// ^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION

    class Direct {
    void positional(covariant int a, int b, covariant int c, int d, int e) {}
    @@ -94,8 +96,20 @@
    }

    class Mixed extends Superclass
    - with Mixin1, Mixin2
    - implements Interface1, Interface2 {}
    +// ^^^^^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION
    +// ^^^^^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION
    +// ^^^^^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION
    +// ^^^^^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION
    + with
    + Mixin1,
    + Mixin2
    + implements
    + Interface1,
    + Interface2 {}

    void main() {
    testDirect();
    diff --git a/tests/language_2/regress/regress31596_covariant_declaration_test.dart b/tests/language_2/regress/regress31596_covariant_declaration_test.dart
    index 20defe2..f3cfe46 100644
    --- a/tests/language_2/regress/regress31596_covariant_declaration_test.dart
    +++ b/tests/language_2/regress/regress31596_covariant_declaration_test.dart
    @@ -20,5 +20,7 @@
    // ^
    // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE
    // [cfe] unspecified
    +// ^
    +// [analyzer] COMPILE_TIME_ERROR.COVARIANT_INTERFACE_PARAMETER_WITH_NON_COVARIANT_IMPLEMENTATION

    main() {}

    To view, visit change 146120. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Ife57b54c1f2609ef1202ccc6c918cf85bb8c0df7
    Gerrit-Change-Number: 146120
    Gerrit-PatchSet: 4
    Gerrit-Owner: Konstantin Shcheglov <sche...@google.com>
    Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
    Gerrit-Reviewer: Erik Ernst <eer...@google.com>
    Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
    Gerrit-MessageType: newchange

    Erik Ernst (Gerrit)

    unread,
    May 4, 2020, 9:33:41 AM5/4/20
    to Konstantin Shcheglov, rev...@dartlang.org, Brian Wilkerson, commi...@chromium.org

    LGTM!

    One thing noted in comments: The error arises when a dynamic type check on an actual argument is absent in the inherited implementation, but required due to a formal parameter which is covariant-by-declaration in the class interface. This means that it is enough for the inherited implementation to have the check due to the parameter being covariant-by-class or -by-declaration. I believe the implementation and comments below omit the -by-class case.

    Patch set 4:Code-Review +1

    View Change

    7 comments:

    To view, visit change 146120. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Ife57b54c1f2609ef1202ccc6c918cf85bb8c0df7
    Gerrit-Change-Number: 146120
    Gerrit-PatchSet: 4
    Gerrit-Owner: Konstantin Shcheglov <sche...@google.com>
    Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
    Gerrit-Reviewer: Erik Ernst <eer...@google.com>
    Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
    Gerrit-Comment-Date: Mon, 04 May 2020 13:33:38 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes
    Gerrit-MessageType: comment

    Brian Wilkerson (Gerrit)

    unread,
    May 4, 2020, 10:39:38 AM5/4/20
    to Konstantin Shcheglov, rev...@dartlang.org, Erik Ernst, commi...@chromium.org

    Patch set 4:Code-Review +1

    View Change

    2 comments:

    To view, visit change 146120. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Ife57b54c1f2609ef1202ccc6c918cf85bb8c0df7
    Gerrit-Change-Number: 146120
    Gerrit-PatchSet: 4
    Gerrit-Owner: Konstantin Shcheglov <sche...@google.com>
    Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
    Gerrit-Reviewer: Erik Ernst <eer...@google.com>
    Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
    Gerrit-Comment-Date: Mon, 04 May 2020 14:39:34 +0000

    Konstantin Shcheglov (Gerrit)

    unread,
    Oct 1, 2021, 3:44:36 PM10/1/21
    to rev...@dartlang.org, Brian Wilkerson, Erik Ernst, commi...@chromium.org

    Konstantin Shcheglov abandoned this change.

    View Change

    Abandoned The issue was reverted to https://github.com/dart-lang/sdk/issues/47072

    To view, visit change 146120. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: main
    Gerrit-Change-Id: Ife57b54c1f2609ef1202ccc6c918cf85bb8c0df7
    Gerrit-Change-Number: 146120
    Gerrit-PatchSet: 4
    Gerrit-Owner: Konstantin Shcheglov <sche...@google.com>
    Gerrit-Reviewer: Brian Wilkerson <brianwi...@google.com>
    Gerrit-Reviewer: Erik Ernst <eer...@google.com>
    Gerrit-Reviewer: Konstantin Shcheglov <sche...@google.com>
    Gerrit-MessageType: abandon
    Reply all
    Reply to author
    Forward
    0 new messages