Skip to content

Commit 28606d0

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
[cfe] Recompute type parameter type nullability after substitution
Closes #41697 Change-Id: Ib4977aa3f8d97defa7884036a0f561d6ecb4c3ee Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/149587 Commit-Queue: Johnni Winther <[email protected]> Reviewed-by: Dmitry Stefantsov <[email protected]> Reviewed-by: Erik Ernst <[email protected]>
1 parent 929d5e4 commit 28606d0

22 files changed

+650
-29
lines changed

pkg/front_end/testcases/inference/refine_binary_expression_type_type_parameter_t_double.dart.strong.transformed.expect

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ class C<T extends core::num* = core::num*> extends core::Object {
88
: super core::Object::•()
99
;
1010
method op(core::double* b) → void {
11-
core::double* r1 = this.{self::C::a}.{core::num::+}(b) as{TypeError} core::double*;
12-
core::double* r2 = this.{self::C::a}.{core::num::-}(b) as{TypeError} core::double*;
13-
core::double* r3 = this.{self::C::a}.{core::num::*}(b) as{TypeError} core::double*;
11+
core::double* r1 = this.{self::C::a}.{core::num::+}(b);
12+
core::double* r2 = this.{self::C::a}.{core::num::-}(b);
13+
core::double* r3 = this.{self::C::a}.{core::num::*}(b);
1414
core::double* r4 = this.{self::C::a}.{core::num::/}(b);
1515
}
1616
abstract member-signature get _identityHashCode() → core::int*;

pkg/front_end/testcases/inference/refine_binary_expression_type_type_parameter_t_t.dart.strong.transformed.expect

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ class C<T extends core::num* = core::num*> extends core::Object {
88
: super core::Object::•()
99
;
1010
method op(generic-covariant-impl self::C::T* b) → void {
11-
self::C::T* r1 = this.{self::C::a}.{core::num::+}(b);
12-
self::C::T* r2 = this.{self::C::a}.{core::num::-}(b);
13-
self::C::T* r3 = this.{self::C::a}.{core::num::*}(b);
11+
self::C::T* r1 = this.{self::C::a}.{core::num::+}(b) as{TypeError} self::C::T*;
12+
self::C::T* r2 = this.{self::C::a}.{core::num::-}(b) as{TypeError} self::C::T*;
13+
self::C::T* r3 = this.{self::C::a}.{core::num::*}(b) as{TypeError} self::C::T*;
1414
}
1515
method opEq(generic-covariant-impl self::C::T* b) → void {
16-
this.{self::C::a} = this.{self::C::a}.{core::num::+}(b);
17-
this.{self::C::a} = this.{self::C::a}.{core::num::-}(b);
18-
this.{self::C::a} = this.{self::C::a}.{core::num::*}(b);
16+
this.{self::C::a} = this.{self::C::a}.{core::num::+}(b) as{TypeError} self::C::T*;
17+
this.{self::C::a} = this.{self::C::a}.{core::num::-}(b) as{TypeError} self::C::T*;
18+
this.{self::C::a} = this.{self::C::a}.{core::num::*}(b) as{TypeError} self::C::T*;
1919
}
2020
abstract member-signature get _identityHashCode() → core::int*;
2121
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
import 'dart:async';
6+
7+
typedef G<T> = void Function<S extends T>(S);
8+
typedef H<T> = void Function<S extends FutureOr<T>>(S, FutureOr<T>);
9+
// TODO(johnniwinther): Enable and use these when #41951 is fixed to test that
10+
// updating self referencing type parameters works.
11+
//typedef I<T> = void Function<S extends FutureOr<S>>(S, T);
12+
//typedef J<T> = void Function<S extends FutureOr<S>?>(S, T);
13+
//typedef K<T> = void Function<S extends FutureOr<S?>>(S, T);
14+
15+
class C<T> {
16+
G<T> field1;
17+
H<T> field2;
18+
19+
C(this.field1, this.field2);
20+
}
21+
22+
test1(C<num> c) {
23+
var f1 = c.field1 = <S extends num>(S s) {
24+
return s + 1; // ok
25+
};
26+
var f2 = c.field2 = <S extends FutureOr<num>>(S s, FutureOr<num> t) async {
27+
return (await t) + 1; // ok
28+
};
29+
}
30+
31+
test2(C<num?> c) {
32+
var f1 = c.field1 = <S extends num?>(S s) {
33+
return s + 1; // error
34+
};
35+
var f2 = c.field2 = <S extends FutureOr<num?>>(S s, FutureOr<num?> t) async {
36+
return (await t) + 1; // error
37+
};
38+
}
39+
40+
test3<S extends num?>(S s) => s + 1; // error
41+
42+
main() {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "dart:async" as asy;
5+
6+
import "dart:async";
7+
8+
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → void;
9+
typedef H<invariant T extends core::Object? = dynamic> = <S extends asy::FutureOr<T%> = dynamic>(S, asy::FutureOr<T%>) → void;
10+
class C<T extends core::Object? = dynamic> extends core::Object {
11+
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → void field1;
12+
generic-covariant-impl field <S extends asy::FutureOr<self::C::T%> = dynamic>(S, asy::FutureOr<self::C::T%>) → void field2;
13+
constructor •(<S extends self::C::T% = dynamic>(S%) → void field1, <S extends asy::FutureOr<self::C::T%> = dynamic>(S, asy::FutureOr<self::C::T%>) → void field2) → self::C<self::C::T%>
14+
;
15+
}
16+
static method test1(self::C<core::num> c) → dynamic
17+
;
18+
static method test2(self::C<core::num?> c) → dynamic
19+
;
20+
static method test3<S extends core::num? = core::num?>(self::test3::S% s) → dynamic
21+
;
22+
static method main() → dynamic
23+
;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/nnbd/issue41697.dart:33:14: Error: Operator '+' cannot be called on 'S' because it is potentially null.
6+
// return s + 1; // error
7+
// ^
8+
//
9+
// pkg/front_end/testcases/nnbd/issue41697.dart:36:22: Error: Operator '+' cannot be called on 'num?' because it is potentially null.
10+
// return (await t) + 1; // error
11+
// ^
12+
//
13+
// pkg/front_end/testcases/nnbd/issue41697.dart:40:33: Error: Operator '+' cannot be called on 'S' because it is potentially null.
14+
// test3<S extends num?>(S s) => s + 1; // error
15+
// ^
16+
//
17+
import self as self;
18+
import "dart:core" as core;
19+
import "dart:async" as asy;
20+
21+
import "dart:async";
22+
23+
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → void;
24+
typedef H<invariant T extends core::Object? = dynamic> = <S extends asy::FutureOr<T%> = dynamic>(S, asy::FutureOr<T%>) → void;
25+
class C<T extends core::Object? = dynamic> extends core::Object {
26+
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → void field1;
27+
generic-covariant-impl field <S extends asy::FutureOr<self::C::T%> = dynamic>(S, asy::FutureOr<self::C::T%>) → void field2;
28+
constructor •(<S extends self::C::T% = dynamic>(S%) → void field1, <S extends asy::FutureOr<self::C::T%> = dynamic>(S, asy::FutureOr<self::C::T%>) → void field2) → self::C<self::C::T%>
29+
: self::C::field1 = field1, self::C::field2 = field2, super core::Object::•()
30+
;
31+
}
32+
static method test1(self::C<core::num> c) → dynamic {
33+
<S extends core::num = core::num>(S) → core::num f1 = c.{self::C::field1} = <S extends core::num = core::num>(S s) → core::num {
34+
return s.{core::num::+}(1);
35+
};
36+
<S extends asy::FutureOr<core::num> = asy::FutureOr<core::num>>(S, asy::FutureOr<core::num>) → asy::Future<core::num> f2 = c.{self::C::field2} = <S extends asy::FutureOr<core::num> = asy::FutureOr<core::num>>(S s, asy::FutureOr<core::num> t) → asy::Future<core::num> async {
37+
return (await t).{core::num::+}(1);
38+
};
39+
}
40+
static method test2(self::C<core::num?> c) → dynamic {
41+
<S extends core::num? = core::num?>(S%) → core::num f1 = c.{self::C::field1} = <S extends core::num? = core::num?>(S% s) → core::num {
42+
return let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41697.dart:33:14: Error: Operator '+' cannot be called on 'S' because it is potentially null.
43+
return s + 1; // error
44+
^" in s.{core::num::+}(1);
45+
};
46+
<S extends asy::FutureOr<core::num?> = asy::FutureOr<core::num?>>(S, asy::FutureOr<core::num?>) → asy::Future<core::num> f2 = c.{self::C::field2} = <S extends asy::FutureOr<core::num?> = asy::FutureOr<core::num?>>(S s, asy::FutureOr<core::num?> t) → asy::Future<core::num> async {
47+
return let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue41697.dart:36:22: Error: Operator '+' cannot be called on 'num?' because it is potentially null.
48+
return (await t) + 1; // error
49+
^" in (await t).{core::num::+}(1);
50+
};
51+
}
52+
static method test3<S extends core::num? = core::num?>(self::test3::S% s) → dynamic
53+
return let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue41697.dart:40:33: Error: Operator '+' cannot be called on 'S' because it is potentially null.
54+
test3<S extends num?>(S s) => s + 1; // error
55+
^" in s.{core::num::+}(1);
56+
static method main() → dynamic {}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/nnbd/issue41697.dart:33:14: Error: Operator '+' cannot be called on 'S' because it is potentially null.
6+
// return s + 1; // error
7+
// ^
8+
//
9+
// pkg/front_end/testcases/nnbd/issue41697.dart:36:22: Error: Operator '+' cannot be called on 'num?' because it is potentially null.
10+
// return (await t) + 1; // error
11+
// ^
12+
//
13+
// pkg/front_end/testcases/nnbd/issue41697.dart:40:33: Error: Operator '+' cannot be called on 'S' because it is potentially null.
14+
// test3<S extends num?>(S s) => s + 1; // error
15+
// ^
16+
//
17+
import self as self;
18+
import "dart:core" as core;
19+
import "dart:async" as asy;
20+
import "dart:_internal" as _in;
21+
22+
import "dart:async";
23+
24+
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → void;
25+
typedef H<invariant T extends core::Object? = dynamic> = <S extends asy::FutureOr<T%> = dynamic>(S, asy::FutureOr<T%>) → void;
26+
class C<T extends core::Object? = dynamic> extends core::Object {
27+
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → void field1;
28+
generic-covariant-impl field <S extends asy::FutureOr<self::C::T%> = dynamic>(S, asy::FutureOr<self::C::T%>) → void field2;
29+
constructor •(<S extends self::C::T% = dynamic>(S%) → void field1, <S extends asy::FutureOr<self::C::T%> = dynamic>(S, asy::FutureOr<self::C::T%>) → void field2) → self::C<self::C::T%>
30+
: self::C::field1 = field1, self::C::field2 = field2, super core::Object::•()
31+
;
32+
}
33+
static method test1(self::C<core::num> c) → dynamic {
34+
<S extends core::num = core::num>(S) → core::num f1 = c.{self::C::field1} = <S extends core::num = core::num>(S s) → core::num {
35+
return s.{core::num::+}(1);
36+
};
37+
<S extends asy::FutureOr<core::num> = asy::FutureOr<core::num>>(S, asy::FutureOr<core::num>) → asy::Future<core::num> f2 = c.{self::C::field2} = <S extends asy::FutureOr<core::num> = asy::FutureOr<core::num>>(S s, asy::FutureOr<core::num> t) → asy::Future<core::num> /* originally async */ {
38+
final asy::_AsyncAwaitCompleter<core::num> :async_completer = new asy::_AsyncAwaitCompleter::•<core::num>();
39+
asy::FutureOr<core::num>? :return_value;
40+
dynamic :async_stack_trace;
41+
(dynamic) → dynamic :async_op_then;
42+
(core::Object, core::StackTrace) → dynamic :async_op_error;
43+
core::int :await_jump_var = 0;
44+
dynamic :await_ctx_var;
45+
dynamic :saved_try_context_var0;
46+
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
47+
try {
48+
#L1:
49+
{
50+
[yield] let dynamic #t1 = asy::_awaitHelper(t, :async_op_then, :async_op_error, :async_op) in null;
51+
:return_value = _in::unsafeCast<core::num>(:result).{core::num::+}(1);
52+
break #L1;
53+
}
54+
asy::_completeOnAsyncReturn(:async_completer, :return_value);
55+
return;
56+
}
57+
on dynamic catch(dynamic exception, core::StackTrace stack_trace) {
58+
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
59+
}
60+
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
61+
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
62+
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
63+
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
64+
return :async_completer.{asy::Completer::future};
65+
};
66+
}
67+
static method test2(self::C<core::num?> c) → dynamic {
68+
<S extends core::num? = core::num?>(S%) → core::num f1 = c.{self::C::field1} = <S extends core::num? = core::num?>(S% s) → core::num {
69+
return let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue41697.dart:33:14: Error: Operator '+' cannot be called on 'S' because it is potentially null.
70+
return s + 1; // error
71+
^" in s.{core::num::+}(1);
72+
};
73+
<S extends asy::FutureOr<core::num?> = asy::FutureOr<core::num?>>(S, asy::FutureOr<core::num?>) → asy::Future<core::num> f2 = c.{self::C::field2} = <S extends asy::FutureOr<core::num?> = asy::FutureOr<core::num?>>(S s, asy::FutureOr<core::num?> t) → asy::Future<core::num> /* originally async */ {
74+
final asy::_AsyncAwaitCompleter<core::num> :async_completer = new asy::_AsyncAwaitCompleter::•<core::num>();
75+
asy::FutureOr<core::num>? :return_value;
76+
dynamic :async_stack_trace;
77+
(dynamic) → dynamic :async_op_then;
78+
(core::Object, core::StackTrace) → dynamic :async_op_error;
79+
core::int :await_jump_var = 0;
80+
dynamic :await_ctx_var;
81+
dynamic :saved_try_context_var0;
82+
function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
83+
try {
84+
#L2:
85+
{
86+
final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue41697.dart:36:22: Error: Operator '+' cannot be called on 'num?' because it is potentially null.
87+
return (await t) + 1; // error
88+
^";
89+
[yield] let dynamic #t4 = asy::_awaitHelper(t, :async_op_then, :async_op_error, :async_op) in null;
90+
:return_value = _in::unsafeCast<core::num?>(:result).{core::num::+}(1);
91+
break #L2;
92+
}
93+
asy::_completeOnAsyncReturn(:async_completer, :return_value);
94+
return;
95+
}
96+
on dynamic catch(dynamic exception, core::StackTrace stack_trace) {
97+
:async_completer.{asy::Completer::completeError}(exception, stack_trace);
98+
}
99+
:async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
100+
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
101+
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
102+
:async_completer.{asy::_AsyncAwaitCompleter::start}(:async_op);
103+
return :async_completer.{asy::Completer::future};
104+
};
105+
}
106+
static method test3<S extends core::num? = core::num?>(self::test3::S% s) → dynamic
107+
return let final<BottomType> #t5 = invalid-expression "pkg/front_end/testcases/nnbd/issue41697.dart:40:33: Error: Operator '+' cannot be called on 'S' because it is potentially null.
108+
test3<S extends num?>(S s) => s + 1; // error
109+
^" in s.{core::num::+}(1);
110+
static method main() → dynamic {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import 'dart:async';
2+
3+
typedef G<T> = void Function<S extends T>(S);
4+
typedef H<T> = void Function<S extends FutureOr<T>>(S, FutureOr<T>);
5+
6+
class C<T> {
7+
G<T> field1;
8+
H<T> field2;
9+
C(this.field1, this.field2);
10+
}
11+
12+
test1(C<num> c) {}
13+
test2(C<num?> c) {}
14+
test3<S extends num?>(S s) => s + 1;
15+
main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import 'dart:async';
2+
3+
class C<T> {
4+
C(this.field1, this.field2);
5+
G<T> field1;
6+
H<T> field2;
7+
}
8+
9+
main() {}
10+
test1(C<num> c) {}
11+
test2(C<num?> c) {}
12+
test3<S extends num?>(S s) => s + 1;
13+
typedef G<T> = void Function<S extends T>(S);
14+
typedef H<T> = void Function<S extends FutureOr<T>>(S, FutureOr<T>);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/nnbd/issue41697.dart:33:14: Error: Operator '+' cannot be called on 'S' because it is potentially null.
6+
// return s + 1; // error
7+
// ^
8+
//
9+
// pkg/front_end/testcases/nnbd/issue41697.dart:36:22: Error: Operator '+' cannot be called on 'num?' because it is potentially null.
10+
// return (await t) + 1; // error
11+
// ^
12+
//
13+
// pkg/front_end/testcases/nnbd/issue41697.dart:40:33: Error: Operator '+' cannot be called on 'S' because it is potentially null.
14+
// test3<S extends num?>(S s) => s + 1; // error
15+
// ^
16+
//
17+
import self as self;
18+
import "dart:core" as core;
19+
import "dart:async" as asy;
20+
21+
import "dart:async";
22+
23+
typedef G<invariant T extends core::Object? = dynamic> = <S extends T% = dynamic>(S%) → void;
24+
typedef H<invariant T extends core::Object? = dynamic> = <S extends asy::FutureOr<T%> = dynamic>(S, asy::FutureOr<T%>) → void;
25+
class C<T extends core::Object? = dynamic> extends core::Object {
26+
generic-covariant-impl field <S extends self::C::T% = dynamic>(S%) → void field1;
27+
generic-covariant-impl field <S extends asy::FutureOr<self::C::T%> = dynamic>(S, asy::FutureOr<self::C::T%>) → void field2;
28+
constructor •(<S extends self::C::T% = dynamic>(S%) → void field1, <S extends asy::FutureOr<self::C::T%> = dynamic>(S, asy::FutureOr<self::C::T%>) → void field2) → self::C<self::C::T%>
29+
: self::C::field1 = field1, self::C::field2 = field2, super core::Object::•()
30+
;
31+
}
32+
static method test1(self::C<core::num> c) → dynamic {
33+
<S extends core::num = core::num>(S) → core::num f1 = c.{self::C::field1} = <S extends core::num = core::num>(S s) → core::num {
34+
return s.{core::num::+}(1);
35+
};
36+
<S extends asy::FutureOr<core::num> = asy::FutureOr<core::num>>(S, asy::FutureOr<core::num>) → asy::Future<core::num> f2 = c.{self::C::field2} = <S extends asy::FutureOr<core::num> = asy::FutureOr<core::num>>(S s, asy::FutureOr<core::num> t) → asy::Future<core::num> async {
37+
return (await t).{core::num::+}(1);
38+
};
39+
}
40+
static method test2(self::C<core::num?> c) → dynamic {
41+
<S extends core::num? = core::num?>(S%) → core::num f1 = c.{self::C::field1} = <S extends core::num? = core::num?>(S% s) → core::num {
42+
return let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41697.dart:33:14: Error: Operator '+' cannot be called on 'S' because it is potentially null.
43+
return s + 1; // error
44+
^" in s.{core::num::+}(1);
45+
};
46+
<S extends asy::FutureOr<core::num?> = asy::FutureOr<core::num?>>(S, asy::FutureOr<core::num?>) → asy::Future<core::num> f2 = c.{self::C::field2} = <S extends asy::FutureOr<core::num?> = asy::FutureOr<core::num?>>(S s, asy::FutureOr<core::num?> t) → asy::Future<core::num> async {
47+
return let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue41697.dart:36:22: Error: Operator '+' cannot be called on 'num?' because it is potentially null.
48+
return (await t) + 1; // error
49+
^" in (await t).{core::num::+}(1);
50+
};
51+
}
52+
static method test3<S extends core::num? = core::num?>(self::test3::S% s) → dynamic
53+
return let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue41697.dart:40:33: Error: Operator '+' cannot be called on 'S' because it is potentially null.
54+
test3<S extends num?>(S s) => s + 1; // error
55+
^" in s.{core::num::+}(1);
56+
static method main() → dynamic {}

0 commit comments

Comments
 (0)