Skip to content

Commit 2145850

Browse files
Dmitry Stefantsovcommit-bot@chromium.org
Dmitry Stefantsov
authored andcommitted
[cfe] Check bounds for mutual subtyping in generic method overrides
Closes #40479 Bug: http://dartbug.com/40479 Change-Id: Ie98c4d316caa14ab51d838a05b1a2167024ce372 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/135061 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Dmitry Stefantsov <[email protected]>
1 parent 76b18c4 commit 2145850

9 files changed

+180
-1
lines changed

pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,9 @@ class ClassHierarchyNodeBuilder {
678678
for (int i = 0; i < typeParameterCount; i++) {
679679
DartType aBound = aTypeParameters[i].bound;
680680
DartType bBound = substitution.substituteType(bTypeParameters[i].bound);
681-
if (aBound != bBound) {
681+
if (!hierarchy.types
682+
.isSameTypeKernel(aBound, bBound)
683+
.isSubtypeWhenUsingNullabilities()) {
682684
debug?.log("Giving up 3");
683685
return false;
684686
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// @dart = 2.6
6+
7+
// This test checks that when a generic method from an opted-in library is
8+
// overridden by a method from an opted-out library, the bounds are checked to
9+
// be mutual subtypes, and not for equality. Otherwise, it would be impossible
10+
// to override a generic method with a default bound with another generic method
11+
// with a default bound.
12+
13+
import './mixed_mode_hierarchy_generic_methods_lib.dart';
14+
import "dart:async";
15+
16+
class B implements A<int> {
17+
then<B>() => Future<B>.value();
18+
}
19+
20+
main() {}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "mixed_mode_hierarchy_generic_methods_lib.dart" as mix;
5+
import "dart:async" as asy;
6+
7+
import "org-dartlang-testcase:///mixed_mode_hierarchy_generic_methods_lib.dart";
8+
import "dart:async";
9+
10+
class B extends core::Object implements mix::A<core::int*> {
11+
synthetic constructor •() → self::B*
12+
;
13+
method then<B extends core::Object* = dynamic>() → asy::Future<self::B::then::B%>
14+
;
15+
}
16+
static method main() → dynamic
17+
;
18+
19+
library /*isNonNullableByDefault*/;
20+
import self as mix;
21+
import "dart:core" as core;
22+
import "dart:async" as asy;
23+
24+
class A<R extends core::Object? = dynamic> extends core::Object {
25+
synthetic constructor •() → mix::A<mix::A::R%>
26+
;
27+
method then<T extends core::Object? = dynamic>() → asy::Future<mix::A::then::T%>
28+
;
29+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "mixed_mode_hierarchy_generic_methods_lib.dart" as mix;
5+
import "dart:async" as asy;
6+
7+
import "org-dartlang-testcase:///mixed_mode_hierarchy_generic_methods_lib.dart";
8+
import "dart:async";
9+
10+
class B extends core::Object implements mix::A<core::int*> {
11+
synthetic constructor •() → self::B*
12+
: super core::Object::•()
13+
;
14+
method then<B extends core::Object* = dynamic>() → asy::Future<self::B::then::B%>
15+
return asy::Future::value<self::B::then::B*>();
16+
}
17+
static method main() → dynamic {}
18+
19+
library /*isNonNullableByDefault*/;
20+
import self as mix;
21+
import "dart:core" as core;
22+
import "dart:async" as asy;
23+
24+
class A<R extends core::Object? = dynamic> extends core::Object {
25+
synthetic constructor •() → mix::A<mix::A::R%>
26+
: super core::Object::•()
27+
;
28+
method then<T extends core::Object? = dynamic>() → asy::Future<mix::A::then::T%>
29+
return asy::Future::value<mix::A::then::T%>();
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "mixed_mode_hierarchy_generic_methods_lib.dart" as mix;
5+
import "dart:async" as asy;
6+
7+
import "org-dartlang-testcase:///mixed_mode_hierarchy_generic_methods_lib.dart";
8+
import "dart:async";
9+
10+
class B extends core::Object implements mix::A<core::int*> {
11+
synthetic constructor •() → self::B*
12+
: super core::Object::•()
13+
;
14+
method then<B extends core::Object* = dynamic>() → asy::Future<self::B::then::B%>
15+
return asy::Future::value<self::B::then::B*>();
16+
}
17+
static method main() → dynamic {}
18+
19+
library /*isNonNullableByDefault*/;
20+
import self as mix;
21+
import "dart:core" as core;
22+
import "dart:async" as asy;
23+
24+
class A<R extends core::Object? = dynamic> extends core::Object {
25+
synthetic constructor •() → mix::A<mix::A::R%>
26+
: super core::Object::•()
27+
;
28+
method then<T extends core::Object? = dynamic>() → asy::Future<mix::A::then::T%>
29+
return asy::Future::value<mix::A::then::T%>();
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "mixed_mode_hierarchy_generic_methods_lib.dart" as mix;
5+
import "dart:async" as asy;
6+
7+
import "org-dartlang-testcase:///mixed_mode_hierarchy_generic_methods_lib.dart";
8+
import "dart:async";
9+
10+
class B extends core::Object implements mix::A<core::int*> {
11+
synthetic constructor •() → self::B*
12+
: super core::Object::•()
13+
;
14+
method then<B extends core::Object* = dynamic>() → asy::Future<self::B::then::B%>
15+
return asy::Future::value<self::B::then::B*>();
16+
}
17+
static method main() → dynamic {}
18+
19+
library /*isNonNullableByDefault*/;
20+
import self as mix;
21+
import "dart:core" as core;
22+
import "dart:async" as asy;
23+
24+
class A<R extends core::Object? = dynamic> extends core::Object {
25+
synthetic constructor •() → mix::A<mix::A::R%>
26+
: super core::Object::•()
27+
;
28+
method then<T extends core::Object? = dynamic>() → asy::Future<mix::A::then::T%>
29+
return asy::Future::value<mix::A::then::T%>();
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "mixed_mode_hierarchy_generic_methods_lib.dart" as mix;
5+
import "dart:async" as asy;
6+
7+
import "org-dartlang-testcase:///mixed_mode_hierarchy_generic_methods_lib.dart";
8+
import "dart:async";
9+
10+
class B extends core::Object implements mix::A<core::int*> {
11+
synthetic constructor •() → self::B*
12+
: super core::Object::•()
13+
;
14+
method then<B extends core::Object* = dynamic>() → asy::Future<self::B::then::B%>
15+
return asy::Future::value<self::B::then::B*>();
16+
}
17+
static method main() → dynamic {}
18+
19+
library /*isNonNullableByDefault*/;
20+
import self as mix;
21+
import "dart:core" as core;
22+
import "dart:async" as asy;
23+
24+
class A<R extends core::Object? = dynamic> extends core::Object {
25+
synthetic constructor •() → mix::A<mix::A::R%>
26+
: super core::Object::•()
27+
;
28+
method then<T extends core::Object? = dynamic>() → asy::Future<mix::A::then::T%>
29+
return asy::Future::value<mix::A::then::T%>();
30+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
class A<R> {
6+
Future<T> then<T>() => Future<T>.value();
7+
}

pkg/front_end/testcases/text_serialization.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,7 @@ nnbd/member_inheritance_from_opt_out: TextSerializationFailure
12431243
nnbd/messages_with_types_opt_in: TypeCheckError
12441244
nnbd/messages_with_types_opt_out: TypeCheckError
12451245
nnbd/missing_required_named_parameter: TextSerializationFailure
1246+
nnbd/mixed_mode_hierarchy_generic_methods: TextSerializationFailure
12461247
nnbd/mixin_from_opt_in: TextSerializationFailure
12471248
nnbd/mixin_from_opt_out: TextSerializationFailure
12481249
nnbd/never_opt_out: TypeCheckError

0 commit comments

Comments
 (0)