[Language] Various NNBD Tests.
Add a variety of small nnbd tests covering the specification changes/clarifications landed in https://github.com/dart-lang/language/pull/1003 . Change-Id: I0716f14652128323bf103df154efb5bf978091d0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/150160 Commit-Queue: Leaf Petersen <leafp@google.com> Reviewed-by: Bob Nystrom <rnystrom@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
c48263e901
commit
db36f1190f
@@ -28,4 +28,39 @@ main() {
|
||||
Expect.isTrue(h is int Function(String));
|
||||
Expect.isFalse(h is int Function(Object));
|
||||
Expect.isFalse(h is int Function(Object?));
|
||||
|
||||
int Function(Null) i = (Null x) => 1; // Runtime type is int Function(Null)
|
||||
Expect.isTrue(i is int Function(Null));
|
||||
Expect.isTrue(i is int Function(Never));
|
||||
Expect.isFalse(i is int Function(String));
|
||||
Expect.isFalse(i is int Function(Object));
|
||||
Expect.isFalse(i is int Function(Object?));
|
||||
|
||||
int Function(Never) j = (Never x) => 1; // Runtime type is int Function(Never)
|
||||
Expect.isFalse(j is int Function(Null));
|
||||
Expect.isTrue(j is int Function(Never));
|
||||
Expect.isFalse(j is int Function(String));
|
||||
Expect.isFalse(j is int Function(Object));
|
||||
Expect.isFalse(j is int Function(Object?));
|
||||
|
||||
// Test that the criteria used for weakening the parameter type
|
||||
// is that the downwards context parameter type is a subtype of Null
|
||||
void test<X extends Null, Y extends Never>() {
|
||||
int Function(X) f = (x) => 1; // Runtime type is int Function(Object?)
|
||||
Expect.isTrue(f is int Function(Null));
|
||||
Expect.isTrue(f is int Function(Never));
|
||||
Expect.isTrue(f is int Function(String));
|
||||
Expect.isTrue(f is int Function(Object));
|
||||
Expect.isTrue(f is int Function(Object?));
|
||||
|
||||
int Function(Y) g = (x) => 1; // Runtime type is int Function(Object?)
|
||||
Expect.isTrue(g is int Function(Null));
|
||||
Expect.isTrue(g is int Function(Never));
|
||||
Expect.isTrue(g is int Function(String));
|
||||
Expect.isTrue(g is int Function(Object));
|
||||
Expect.isTrue(g is int Function(Object?));
|
||||
}
|
||||
|
||||
test<Null, Never>();
|
||||
test<Never, Never>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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.
|
||||
|
||||
// Requirements=nnbd-strong
|
||||
|
||||
/// Test instance checks and casts in constants may use potentially constant
|
||||
/// types, and cause compile time errors when the casts fail.
|
||||
|
||||
class C1<T> {
|
||||
final t;
|
||||
|
||||
/// Check casts to T
|
||||
const C1.test(dynamic x) : t = x as T;
|
||||
}
|
||||
|
||||
class C2<T> {
|
||||
final l;
|
||||
|
||||
/// Check casts to List<T>
|
||||
const C2.test(dynamic x) : l = x as List<T>;
|
||||
}
|
||||
|
||||
void main() {
|
||||
const c1 = C1<int>.test("hello");
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] Constant evaluation error:
|
||||
const c2 = C1<int>.test(null);
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
const c3 = C2<int>.test(<num>[0]);
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] Constant evaluation error:
|
||||
const c4 = C2<int>.test("hello");
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] Constant evaluation error:
|
||||
const c5 = C2<int>.test(null);
|
||||
// ^
|
||||
// [analyzer] unspecified
|
||||
// [cfe] unspecified
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// 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.
|
||||
|
||||
// Requirements=nnbd-strong
|
||||
|
||||
/// Test instance checks and casts in constants may use potentially constant
|
||||
/// types, and evaluate appropriately.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
class C<T> {
|
||||
final bool isT;
|
||||
final bool isListT;
|
||||
final T? t;
|
||||
final List<T>? l;
|
||||
|
||||
/// Check instance tests in isolation
|
||||
const C.test1(dynamic x)
|
||||
: isT = x is T,
|
||||
isListT = x is List<T>,
|
||||
t = null,
|
||||
l = null;
|
||||
|
||||
/// Check casts to T in isolation
|
||||
const C.test2(dynamic x)
|
||||
: isT = true,
|
||||
isListT = false,
|
||||
t = x as T,
|
||||
l = null;
|
||||
|
||||
/// Check casts to List<T> in isolation
|
||||
const C.test3(dynamic x)
|
||||
: isT = false,
|
||||
isListT = true,
|
||||
t = null,
|
||||
l = x as List<T>;
|
||||
|
||||
/// Combine instance checks with casts, conditional expressions, promotion
|
||||
const C.test4(dynamic x)
|
||||
: isT = x is T,
|
||||
isListT = x is List<T>,
|
||||
t = (x is T) ? x : null,
|
||||
l = (x is List<T>) ? x : null;
|
||||
}
|
||||
|
||||
void main() {
|
||||
{
|
||||
// Test instance checks of T
|
||||
const c1 = C<int>.test1(0);
|
||||
const c2 = C<int>.test1(0);
|
||||
const c3 = C<int>.test1(1);
|
||||
const c4 = C<int>.test1("hello");
|
||||
const c5 = C<int>.test1(null);
|
||||
Expect.identical(c1, c2);
|
||||
Expect.identical(c1, c3);
|
||||
Expect.notIdentical(c1, c4);
|
||||
Expect.notIdentical(c1, c5);
|
||||
Expect.isTrue(c1.isT);
|
||||
Expect.isTrue(c2.isT);
|
||||
Expect.isTrue(c3.isT);
|
||||
Expect.isFalse(c4.isT);
|
||||
Expect.isFalse(c5.isT);
|
||||
Expect.isFalse(c1.isListT);
|
||||
Expect.isFalse(c2.isListT);
|
||||
Expect.isFalse(c3.isListT);
|
||||
Expect.isFalse(c4.isListT);
|
||||
Expect.isFalse(c5.isListT);
|
||||
}
|
||||
{
|
||||
// Test instance checks of List<T>
|
||||
const c1 = C<int>.test1(<int>[0]);
|
||||
const c2 = C<int>.test1(<int>[0]);
|
||||
const c3 = C<int>.test1(<int>[1]);
|
||||
const c4 = C<int>.test1(<num>[1]);
|
||||
const c5 = C<num>.test1(<int>[1]);
|
||||
Expect.identical(c1, c2);
|
||||
Expect.identical(c1, c3);
|
||||
Expect.notIdentical(c1, c4);
|
||||
Expect.notIdentical(c1, c5);
|
||||
Expect.notIdentical(c4, c5);
|
||||
Expect.isFalse(c1.isT);
|
||||
Expect.isFalse(c2.isT);
|
||||
Expect.isFalse(c3.isT);
|
||||
Expect.isFalse(c4.isT);
|
||||
Expect.isFalse(c5.isT);
|
||||
Expect.isTrue(c1.isListT);
|
||||
Expect.isTrue(c2.isListT);
|
||||
Expect.isTrue(c3.isListT);
|
||||
Expect.isFalse(c4.isListT);
|
||||
Expect.isTrue(c5.isListT);
|
||||
}
|
||||
{
|
||||
// Test casts to T
|
||||
const c1 = C<int>.test2(0);
|
||||
const c2 = C<int>.test2(0);
|
||||
const c3 = C<num>.test2(1);
|
||||
Expect.identical(c1, c2);
|
||||
Expect.notIdentical(c1, c3);
|
||||
}
|
||||
{
|
||||
// Test casts to List<T>
|
||||
const c1 = C<int>.test3(<int>[0]);
|
||||
const c2 = C<int>.test3(<int>[0]);
|
||||
const c3 = C<num>.test3(<int>[0]);
|
||||
Expect.identical(c1, c2);
|
||||
Expect.notIdentical(c1, c3);
|
||||
}
|
||||
|
||||
{
|
||||
// Combined tests
|
||||
const c1 = C<num>.test4(0);
|
||||
const c2 = C<num>.test4("hello");
|
||||
const c3 = C<num>.test4(<int>[0]);
|
||||
const c4 = C<num>.test4(<String>["hello"]);
|
||||
const c5 = C<int>.test4(<num>[0]);
|
||||
|
||||
Expect.isTrue(c1.isT);
|
||||
Expect.isFalse(c1.isListT);
|
||||
Expect.equals(c1.t, 0);
|
||||
Expect.equals(c1.l, null);
|
||||
|
||||
Expect.isFalse(c2.isT);
|
||||
Expect.isFalse(c2.isListT);
|
||||
Expect.equals(c2.t, null);
|
||||
Expect.equals(c2.l, null);
|
||||
|
||||
Expect.isFalse(c3.isT);
|
||||
Expect.isTrue(c3.isListT);
|
||||
Expect.equals(c3.t, null);
|
||||
Expect.identical(c3.l, const <int>[0]);
|
||||
|
||||
Expect.isFalse(c4.isT);
|
||||
Expect.isFalse(c4.isListT);
|
||||
Expect.equals(c4.t, null);
|
||||
Expect.equals(c4.l, null);
|
||||
|
||||
Expect.isFalse(c5.isT);
|
||||
Expect.isFalse(c5.isListT);
|
||||
Expect.equals(c5.t, null);
|
||||
Expect.equals(c5.l, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
// 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.
|
||||
|
||||
// Requirements=nnbd-strong
|
||||
|
||||
/// Test that `Never` has all members, and that as a result no extensions
|
||||
/// apply to it. Also test that `Never` is inferred as the type of a
|
||||
/// throw expression, and as the return type of function literals that
|
||||
/// never return.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
/// A call of the form staticErrorIfNotNever(t) will produce a static error
|
||||
/// unless `t` has type `Never`.
|
||||
void staticErrorIfNotNever<T extends Never>(T t) {}
|
||||
|
||||
void neverHasAllMembers(Never x) {
|
||||
{
|
||||
// getters
|
||||
var t = x.arglebargle;
|
||||
staticErrorIfNotNever(t);
|
||||
}
|
||||
{
|
||||
// setter
|
||||
x.arglebargle = 3;
|
||||
}
|
||||
{
|
||||
// operator[]
|
||||
x[0] = 3;
|
||||
}
|
||||
{
|
||||
// methods
|
||||
var t = x.arglebargle(0);
|
||||
staticErrorIfNotNever(t);
|
||||
}
|
||||
{
|
||||
// methods with named parameters
|
||||
var t = x.arglebargle(foo: 0);
|
||||
staticErrorIfNotNever(t);
|
||||
}
|
||||
{
|
||||
// call method
|
||||
var t = x(3);
|
||||
staticErrorIfNotNever(t);
|
||||
}
|
||||
{
|
||||
// Object members
|
||||
staticErrorIfNotNever(x.toString());
|
||||
staticErrorIfNotNever(x.toString);
|
||||
staticErrorIfNotNever(x.runtimeType);
|
||||
staticErrorIfNotNever(x.noSuchMethod);
|
||||
staticErrorIfNotNever(x.noSuchMethod(x));
|
||||
staticErrorIfNotNever(x.hashCode);
|
||||
staticErrorIfNotNever(x == x);
|
||||
staticErrorIfNotNever(x == 3);
|
||||
staticErrorIfNotNever(3 == x);
|
||||
// ^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
|
||||
// [cfe] Inferred type argument 'bool' doesn't conform to the bound 'Never' of the type variable 'T' on 'staticErrorIfNotNever'.
|
||||
}
|
||||
}
|
||||
|
||||
extension NeverExt on Never {
|
||||
int neverMethod() => 3;
|
||||
}
|
||||
|
||||
extension ObjectExt on Object {
|
||||
int objectMethod() => 3;
|
||||
}
|
||||
|
||||
void extensionsDontApply(Never x) {
|
||||
{
|
||||
var t = x.neverMethod();
|
||||
staticErrorIfNotNever(t);
|
||||
}
|
||||
{
|
||||
var t = x.objectMethod();
|
||||
staticErrorIfNotNever(t);
|
||||
}
|
||||
{
|
||||
var t = NeverExt(x).neverMethod();
|
||||
staticErrorIfNotNever(t);
|
||||
// ^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
|
||||
// [cfe] Inferred type argument 'int' doesn't conform to the bound 'Never' of the type variable 'T' on 'staticErrorIfNotNever'.
|
||||
}
|
||||
{
|
||||
var t = ObjectExt(x).objectMethod();
|
||||
staticErrorIfNotNever(t);
|
||||
// ^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
|
||||
// [cfe] Inferred type argument 'int' doesn't conform to the bound 'Never' of the type variable 'T' on 'staticErrorIfNotNever'.
|
||||
}
|
||||
}
|
||||
|
||||
void throwHasTypeNever() {
|
||||
var t = throw "hello";
|
||||
staticErrorIfNotNever(t);
|
||||
}
|
||||
|
||||
void neverReturns(bool b) {
|
||||
{
|
||||
var f = () => throw "Unreachable";
|
||||
var t = f();
|
||||
staticErrorIfNotNever(t);
|
||||
}
|
||||
{
|
||||
var f = () {
|
||||
if (b) {
|
||||
throw "argle";
|
||||
} else {
|
||||
throw "bargle";
|
||||
}
|
||||
};
|
||||
var t = f();
|
||||
staticErrorIfNotNever(t);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
neverHasAllMembers(throw "Unreachable");
|
||||
extensionsDontApply(throw "Unreachable");
|
||||
throwHasTypeNever();
|
||||
neverReturns(true);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
/// Test that the type of a local function is an error if local function type
|
||||
/// inference requires the type of the function being inferred.
|
||||
|
||||
void main() {
|
||||
f() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
f().arglebargle;
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'int'.
|
||||
f().isEven; // Inferred type is int
|
||||
|
||||
g() {
|
||||
if (f() == 3) {
|
||||
return g();
|
||||
} else {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
// ^
|
||||
// [analyzer] undefined
|
||||
// [cfe] undefined
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
// 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.
|
||||
|
||||
/// Test that downwards inference uses the promoted type of the variable in an
|
||||
/// assignment as the context, but still considers the assignment as a valid
|
||||
/// promotion/demotion point.
|
||||
|
||||
/// A generic class to serve as the base type.
|
||||
class C<S> {
|
||||
S cMethod(S x) => x;
|
||||
}
|
||||
|
||||
/// An inference context C<S> constrains the first type variable of D but not
|
||||
/// the second.
|
||||
class D<S, T> extends C<S> {
|
||||
S dMethod1(S x) => x;
|
||||
T dMethod2(T x) => x;
|
||||
}
|
||||
|
||||
/// Generic function which if inferred in a context C<A> with argument type B,
|
||||
/// should infer to mkD<A, B>
|
||||
D<S, T> mkD<S, T>(T x) => D();
|
||||
|
||||
/// Generic function which if inferred in a context D<S0, S1> with argument type
|
||||
/// D<T0, T1>, should infer to useD<T0>.
|
||||
C<T> useD<T>(D<T, int> d) => d;
|
||||
|
||||
void main() {
|
||||
{
|
||||
C<String> x = C();
|
||||
|
||||
// Inference uses C<String> as a downwards context, constraining S from
|
||||
// mkD<S,T> to String. Upwards inference constrains T to int. D<String,
|
||||
// int> is not a type of interest so no promotion should happen.
|
||||
{
|
||||
// y has the type of the RHS of the assignment
|
||||
var y = x = mkD(3);
|
||||
|
||||
// x still has type C<String>
|
||||
x.dMethod1("hello");
|
||||
//^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
|
||||
// [cfe] The method 'dMethod1' isn't defined for the class 'C<String>'.
|
||||
x.dMethod2(3);
|
||||
//^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
|
||||
// [cfe] The method 'dMethod2' isn't defined for the class 'C<String>'.
|
||||
|
||||
var t0 = x.cMethod("hello");
|
||||
t0.length;
|
||||
t0.arglebargle; // t0 is not dynamic
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
|
||||
|
||||
// y has type D<String, int>
|
||||
var t1 = y.dMethod1("hello");
|
||||
t1.length;
|
||||
t1.arglebargle; // t1 is not dynamic
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
|
||||
var t2 = y.dMethod2(3);
|
||||
t2.isEven;
|
||||
t2.arglebargle; // t2 is not dynamic
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'int'.
|
||||
}
|
||||
|
||||
// Establish D<String, int> as a type of interest
|
||||
if (x is D<String, int>) {}
|
||||
// Inference uses C<String> as a downwards context, constraining S from
|
||||
// mkD<S,T> to String. Upwards inference constrains T to int. D<String,
|
||||
// int> is a type of interest so promotion should happen.
|
||||
{
|
||||
// y has the type of the RHS of the assignment
|
||||
var y = x = mkD(3);
|
||||
|
||||
// x has type D<String, int>
|
||||
var t0 = x.dMethod1("hello");
|
||||
t0.length;
|
||||
t0.arglebargle; // t0 is not dynamic
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
|
||||
var t1 = x.dMethod2(3);
|
||||
t1.isEven;
|
||||
t1.arglebargle; // t1 is not dynamic
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'int'.
|
||||
|
||||
// y has type D<String, int>
|
||||
var t2 = y.dMethod1("hello");
|
||||
t2.length;
|
||||
t2.arglebargle; // t2 is not dynamic
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
|
||||
var t3 = y.dMethod2(3);
|
||||
t3.isEven;
|
||||
t3.arglebargle; // t3 is not dynamic
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'int'.
|
||||
}
|
||||
|
||||
// Inference should use D<String, int> as a downwards context, T from
|
||||
// useD<T> to int. The variable x as an argument has type D<String, int>
|
||||
// which is assignable to D<String, int> so the call should have no error.
|
||||
// C<String> is a type of interest, so x should be demoted after the call.
|
||||
{
|
||||
// y has the type of the RHS of the assignment
|
||||
var y = x = useD(x);
|
||||
|
||||
// x has type C<String>, and not D<String, int>
|
||||
x.dMethod1("hello");
|
||||
//^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
|
||||
// [cfe] The method 'dMethod1' isn't defined for the class 'C<String>'.
|
||||
x.dMethod2(3);
|
||||
//^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
|
||||
// [cfe] The method 'dMethod2' isn't defined for the class 'C<String>'.
|
||||
|
||||
var t0 = x.cMethod("hello");
|
||||
t0.length;
|
||||
t0.arglebargle; // t0 is not dynamic
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
|
||||
|
||||
// C<String>, and not D<String, int>
|
||||
y.dMethod1("hello");
|
||||
//^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
|
||||
// [cfe] The method 'dMethod1' isn't defined for the class 'C<String>'.
|
||||
y.dMethod2(3);
|
||||
//^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
|
||||
// [cfe] The method 'dMethod2' isn't defined for the class 'C<String>'.
|
||||
var t1 = y.cMethod("hello");
|
||||
t1.length;
|
||||
t1.arglebargle; // t0 is not dynamic
|
||||
// ^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// 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.
|
||||
|
||||
// Requirements=nnbd-weak
|
||||
|
||||
/// Test that typedefs imported from opted out libraries are treated as
|
||||
/// non-nullable at the top level, with legacy components.
|
||||
|
||||
import 'typedef_opted_out.dart';
|
||||
|
||||
int? takesNonNullable(int x) {}
|
||||
void main() {
|
||||
F f = null; // typedefs from opted out libraries are treated as non-nullable
|
||||
// ^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
|
||||
// [cfe] A value of type 'Null' can't be assigned to a variable of type 'int Function(int)'.
|
||||
|
||||
f = takesNonNullable; // F is int* Function(int*)
|
||||
f(null); // F is int* Function(int*)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// 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.
|
||||
|
||||
// @dart=2.7
|
||||
|
||||
typedef F = int Function(int);
|
||||
Reference in New Issue
Block a user