Skip to content

Commit 251c3d7

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
[cfe] Allow nullable arguments to super==
Closes #42603 Change-Id: I52261ccb7c1d88a7469a72e244466b193777fe38 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155330 Reviewed-by: Dmitry Stefantsov <[email protected]> Commit-Queue: Johnni Winther <[email protected]>
1 parent 125f9e3 commit 251c3d7

11 files changed

+291
-1
lines changed

pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3031,7 +3031,15 @@ class TypeInferrerImpl implements TypeInferrer {
30313031
isSpecialCasedBinaryOperatorForReceiverType(target, receiverType);
30323032
DartType calleeType = getGetterType(target, receiverType);
30333033
FunctionType functionType = getFunctionType(target, receiverType);
3034-
3034+
if (isNonNullableByDefault &&
3035+
expression.name == equalsName &&
3036+
functionType.positionalParameters.length == 1) {
3037+
// operator == always allows nullable arguments.
3038+
functionType = new FunctionType([
3039+
functionType.positionalParameters.single
3040+
.withDeclaredNullability(library.nullable)
3041+
], functionType.returnType, functionType.declaredNullability);
3042+
}
30353043
InvocationInferenceResult result = inferInvocation(
30363044
typeContext, fileOffset, functionType, arguments,
30373045
isSpecialCasedBinaryOperator: isSpecialCasedBinaryOperator,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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 C {
6+
bool operator ==(Object other) => true;
7+
}
8+
9+
class D extends C {
10+
bool operator ==(Object? other) => super == other;
11+
12+
bool method1(dynamic o) => super == o;
13+
14+
bool method2(Null o) => super == o;
15+
}
16+
17+
class E {
18+
bool operator ==() => true;
19+
}
20+
21+
class F extends E {
22+
bool operator ==(Object? other) => super == other;
23+
}
24+
25+
main() {
26+
expect(true, D() == D());
27+
expect(false, D().method1(null));
28+
expect(false, D().method2(null));
29+
}
30+
31+
expect(expected, actual) {
32+
if (expected != actual) throw 'Expected $expected, actual $actual';
33+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: Operator '==' should have exactly one parameter.
6+
// bool operator ==() => true;
7+
// ^^
8+
//
9+
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
10+
// bool operator ==() => true;
11+
// ^
12+
// sdk/lib/_internal/vm/lib/object_patch.dart:18:17: Context: This is the overridden method ('==').
13+
// bool operator ==(Object other) native "Object_equals";
14+
// ^
15+
//
16+
// pkg/front_end/testcases/nnbd/issue42603.dart:22:17: Error: The method 'F.==' has more required arguments than those of overridden method 'E.=='.
17+
// bool operator ==(Object? other) => super == other;
18+
// ^
19+
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Context: This is the overridden method ('==').
20+
// bool operator ==() => true;
21+
// ^
22+
//
23+
import self as self;
24+
import "dart:core" as core;
25+
26+
class C extends core::Object {
27+
synthetic constructor •() → self::C
28+
;
29+
operator ==(core::Object other) → core::bool
30+
;
31+
}
32+
class D extends self::C {
33+
synthetic constructor •() → self::D
34+
;
35+
operator ==(core::Object? other) → core::bool
36+
;
37+
method method1(dynamic o) → core::bool
38+
;
39+
method method2(core::Null? o) → core::bool
40+
;
41+
}
42+
class E extends core::Object {
43+
synthetic constructor •() → self::E
44+
;
45+
operator ==() → core::bool
46+
;
47+
}
48+
class F extends self::E {
49+
synthetic constructor •() → self::F
50+
;
51+
operator ==(core::Object? other) → core::bool
52+
;
53+
}
54+
static method main() → dynamic
55+
;
56+
static method expect(dynamic expected, dynamic actual) → dynamic
57+
;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: Operator '==' should have exactly one parameter.
6+
// bool operator ==() => true;
7+
// ^^
8+
//
9+
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
10+
// bool operator ==() => true;
11+
// ^
12+
// sdk/lib/_internal/vm/lib/object_patch.dart:18:17: Context: This is the overridden method ('==').
13+
// bool operator ==(Object other) native "Object_equals";
14+
// ^
15+
//
16+
// pkg/front_end/testcases/nnbd/issue42603.dart:22:17: Error: The method 'F.==' has more required arguments than those of overridden method 'E.=='.
17+
// bool operator ==(Object? other) => super == other;
18+
// ^
19+
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Context: This is the overridden method ('==').
20+
// bool operator ==() => true;
21+
// ^
22+
//
23+
// pkg/front_end/testcases/nnbd/issue42603.dart:22:44: Error: Too many positional arguments: 0 allowed, but 1 found.
24+
// Try removing the extra positional arguments.
25+
// bool operator ==(Object? other) => super == other;
26+
// ^
27+
//
28+
import self as self;
29+
import "dart:core" as core;
30+
31+
class C extends core::Object {
32+
synthetic constructor •() → self::C
33+
: super core::Object::•()
34+
;
35+
operator ==(core::Object other) → core::bool
36+
return true;
37+
}
38+
class D extends self::C {
39+
synthetic constructor •() → self::D
40+
: super self::C::•()
41+
;
42+
operator ==(core::Object? other) → core::bool
43+
return super.{self::C::==}(other);
44+
method method1(dynamic o) → core::bool
45+
return super.{self::C::==}(o);
46+
method method2(core::Null? o) → core::bool
47+
return super.{self::C::==}(o);
48+
}
49+
class E extends core::Object {
50+
synthetic constructor •() → self::E
51+
: super core::Object::•()
52+
;
53+
operator ==() → core::bool
54+
return true;
55+
}
56+
class F extends self::E {
57+
synthetic constructor •() → self::F
58+
: super self::E::•()
59+
;
60+
operator ==(core::Object? other) → core::bool
61+
return let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42603.dart:22:44: Error: Too many positional arguments: 0 allowed, but 1 found.
62+
Try removing the extra positional arguments.
63+
bool operator ==(Object? other) => super == other;
64+
^" in super.{self::E::==}(other);
65+
}
66+
static method main() → dynamic {
67+
self::expect(true, new self::D::•().{self::D::==}(new self::D::•()));
68+
self::expect(false, new self::D::•().{self::D::method1}(null));
69+
self::expect(false, new self::D::•().{self::D::method2}(null));
70+
}
71+
static method expect(dynamic expected, dynamic actual) → dynamic {
72+
if(!expected.{core::Object::==}(actual))
73+
throw "Expected ${expected}, actual ${actual}";
74+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class C {
2+
bool operator ==(Object other) => true;
3+
}
4+
5+
class D extends C {
6+
bool operator ==(Object? other) => super == other;
7+
bool method1(dynamic o) => super == o;
8+
bool method2(Null o) => super == o;
9+
}
10+
11+
class E {
12+
bool operator ==() => true;
13+
}
14+
15+
class F extends E {
16+
bool operator ==(Object? other) => super == other;
17+
}
18+
19+
main() {}
20+
expect(expected, actual) {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class C {
2+
bool operator ==(Object other) => true;
3+
}
4+
5+
class D extends C {
6+
bool method1(dynamic o) => super == o;
7+
bool method2(Null o) => super == o;
8+
bool operator ==(Object? other) => super == other;
9+
}
10+
11+
class E {
12+
bool operator ==() => true;
13+
}
14+
15+
class F extends E {
16+
bool operator ==(Object? other) => super == other;
17+
}
18+
19+
expect(expected, actual) {}
20+
main() {}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: Operator '==' should have exactly one parameter.
6+
// bool operator ==() => true;
7+
// ^^
8+
//
9+
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Error: The method 'E.==' has fewer positional arguments than those of overridden method 'Object.=='.
10+
// bool operator ==() => true;
11+
// ^
12+
// sdk/lib/_internal/vm/lib/object_patch.dart:18:17: Context: This is the overridden method ('==').
13+
// bool operator ==(Object other) native "Object_equals";
14+
// ^
15+
//
16+
// pkg/front_end/testcases/nnbd/issue42603.dart:22:17: Error: The method 'F.==' has more required arguments than those of overridden method 'E.=='.
17+
// bool operator ==(Object? other) => super == other;
18+
// ^
19+
// pkg/front_end/testcases/nnbd/issue42603.dart:18:17: Context: This is the overridden method ('==').
20+
// bool operator ==() => true;
21+
// ^
22+
//
23+
// pkg/front_end/testcases/nnbd/issue42603.dart:22:44: Error: Too many positional arguments: 0 allowed, but 1 found.
24+
// Try removing the extra positional arguments.
25+
// bool operator ==(Object? other) => super == other;
26+
// ^
27+
//
28+
import self as self;
29+
import "dart:core" as core;
30+
31+
class C extends core::Object {
32+
synthetic constructor •() → self::C
33+
: super core::Object::•()
34+
;
35+
operator ==(core::Object other) → core::bool
36+
return true;
37+
}
38+
class D extends self::C {
39+
synthetic constructor •() → self::D
40+
: super self::C::•()
41+
;
42+
operator ==(core::Object? other) → core::bool
43+
return super.{self::C::==}(other);
44+
method method1(dynamic o) → core::bool
45+
return super.{self::C::==}(o);
46+
method method2(core::Null? o) → core::bool
47+
return super.{self::C::==}(o);
48+
}
49+
class E extends core::Object {
50+
synthetic constructor •() → self::E
51+
: super core::Object::•()
52+
;
53+
operator ==() → core::bool
54+
return true;
55+
}
56+
class F extends self::E {
57+
synthetic constructor •() → self::F
58+
: super self::E::•()
59+
;
60+
operator ==(core::Object? other) → core::bool
61+
return let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42603.dart:22:44: Error: Too many positional arguments: 0 allowed, but 1 found.
62+
Try removing the extra positional arguments.
63+
bool operator ==(Object? other) => super == other;
64+
^" in super.{self::E::==}(other);
65+
}
66+
static method main() → dynamic {
67+
self::expect(true, new self::D::•().{self::D::==}(new self::D::•()));
68+
self::expect(false, new self::D::•().{self::D::method1}(null));
69+
self::expect(false, new self::D::•().{self::D::method2}(null));
70+
}
71+
static method expect(dynamic expected, dynamic actual) → dynamic {
72+
if(!expected.{core::Object::==}(actual))
73+
throw "Expected ${expected}, actual ${actual}";
74+
}

pkg/front_end/testcases/outline.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ inference/mixin_inference_unification_1: TypeCheckError
4343
inference/mixin_inference_unification_2: TypeCheckError
4444
late_lowering/covariant_late_field: TypeCheckError
4545
nnbd/covariant_late_field: TypeCheckError
46+
nnbd/issue42603: TypeCheckError
4647
rasta/native_is_illegal: Pass # Issue 29763
4748
runtime_checks_new/mixin_forwarding_stub_field: TypeCheckError
4849
runtime_checks_new/mixin_forwarding_stub_setter: TypeCheckError

pkg/front_end/testcases/strong.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ late_lowering/covariant_late_field: TypeCheckError
173173
nnbd/covariant_late_field: TypeCheckError
174174
nnbd/issue41180: RuntimeError # Strong mode runtime checking fails due to mixed strong mode.
175175
nnbd/issue42546: TypeCheckError
176+
nnbd/issue42603: TypeCheckError
176177
nnbd/nullable_object_access: TypeCheckError
177178
nnbd/nullable_receiver: TypeCheckError
178179
nnbd/potentially_nullable_access: TypeCheckError

pkg/front_end/testcases/text_serialization.status

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ late_lowering/covariant_late_field: TypeCheckError
171171
nnbd/covariant_late_field: TypeCheckError
172172
nnbd/issue41180: RuntimeError
173173
nnbd/issue42546: TypeCheckError
174+
nnbd/issue42603: TypeCheckError
174175
nnbd/nullable_object_access: TypeCheckError
175176
nnbd/nullable_receiver: TypeCheckError
176177
nnbd/potentially_nullable_access: TypeCheckError

0 commit comments

Comments
 (0)