mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:09:49 +00:00
[cfe] Infer Object from constraints similar to T? = dynamic
Closes #43163. Bug: https://github.com/dart-lang/sdk/issues/43163 Change-Id: I55f51eee097a320dcc38cf54a41c9f6684b5dd59 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/162505 Commit-Queue: Dmitry Stefantsov <dmitryas@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
This commit is contained in:
parent
52c3d94863
commit
e119ccad2a
|
@ -511,11 +511,28 @@ abstract class TypeConstraintGatherer {
|
|||
|
||||
// If Q is a legacy type Q0* then the match holds under constraint set C:
|
||||
//
|
||||
// Only if P is a subtype match for Q? under constraint set C.
|
||||
// If P is dynamic or void and P is a subtype match for Q0 under constraint
|
||||
// set C.
|
||||
// Or if P is not dynamic or void and P is a subtype match for Q0? under
|
||||
// constraint set C.
|
||||
if (_isLegacyTypeConstructorApplication(q)) {
|
||||
return _isNullabilityAwareSubtypeMatch(
|
||||
p, q.withDeclaredNullability(Nullability.nullable),
|
||||
constrainSupertype: constrainSupertype);
|
||||
final int baseConstraintCount = _protoConstraints.length;
|
||||
|
||||
if ((p is DynamicType || p is VoidType) &&
|
||||
_isNullabilityAwareSubtypeMatch(p, _computeRawType(q),
|
||||
constrainSupertype: constrainSupertype)) {
|
||||
return true;
|
||||
}
|
||||
_protoConstraints.length = baseConstraintCount;
|
||||
|
||||
if (p is! DynamicType &&
|
||||
p is! VoidType &&
|
||||
_isNullabilityAwareSubtypeMatch(
|
||||
p, q.withDeclaredNullability(Nullability.nullable),
|
||||
constrainSupertype: constrainSupertype)) {
|
||||
return true;
|
||||
}
|
||||
_protoConstraints.length = baseConstraintCount;
|
||||
}
|
||||
|
||||
// If Q is FutureOr<Q0> the match holds under constraint set C:
|
||||
|
@ -560,6 +577,8 @@ abstract class TypeConstraintGatherer {
|
|||
// If Q is Q0? the match holds under constraint set C:
|
||||
//
|
||||
// If P is P0? and P0 is a subtype match for Q0 under constraint set C.
|
||||
// Or if P is dynamic or void and Object is a subtype match for Q0 under
|
||||
// constraint set C.
|
||||
// Or if P is a subtype match for Q0 under non-empty constraint set C.
|
||||
// Or if P is a subtype match for Null under constraint set C.
|
||||
// Or if P is a subtype match for Q0 under empty constraint set C.
|
||||
|
@ -575,6 +594,14 @@ abstract class TypeConstraintGatherer {
|
|||
}
|
||||
_protoConstraints.length = baseConstraintCount;
|
||||
|
||||
if ((p is DynamicType || p is VoidType) &&
|
||||
_isNullabilityAwareSubtypeMatch(
|
||||
coreTypes.objectNonNullableRawType, rawQ,
|
||||
constrainSupertype: constrainSupertype)) {
|
||||
return true;
|
||||
}
|
||||
_protoConstraints.length = baseConstraintCount;
|
||||
|
||||
bool isMatchWithRawQ = _isNullabilityAwareSubtypeMatch(p, rawQ,
|
||||
constrainSupertype: constrainSupertype);
|
||||
bool matchWithRawQAddsConstraints =
|
||||
|
|
|
@ -429,6 +429,7 @@ numerator
|
|||
observable
|
||||
oh
|
||||
okay
|
||||
onull
|
||||
ooo
|
||||
operate
|
||||
ops
|
||||
|
@ -535,6 +536,7 @@ signalled
|
|||
sigwinch
|
||||
slight
|
||||
smoke
|
||||
snull
|
||||
somehow
|
||||
spans
|
||||
spawn
|
||||
|
|
34
pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart
Normal file
34
pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
// 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.
|
||||
|
||||
T f<T>(T t) => t;
|
||||
|
||||
T g<T>(T? t) => t!;
|
||||
|
||||
T h<T extends Object>(T? t) => t!;
|
||||
|
||||
foo(dynamic d, void v, Object? onull, Object o, String? snull, String s) {
|
||||
f(d);
|
||||
f(v);
|
||||
f(onull);
|
||||
f(o);
|
||||
f(snull);
|
||||
f(s);
|
||||
|
||||
g(d);
|
||||
g(v);
|
||||
g(onull);
|
||||
g(o);
|
||||
g(snull);
|
||||
g(s);
|
||||
|
||||
h(d);
|
||||
h(v);
|
||||
h(onull);
|
||||
h(o);
|
||||
h(snull);
|
||||
h(s);
|
||||
}
|
||||
|
||||
main() {}
|
|
@ -0,0 +1,14 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method f<T extends core::Object? = dynamic>(self::f::T% t) → self::f::T%
|
||||
;
|
||||
static method g<T extends core::Object? = dynamic>(self::g::T? t) → self::g::T%
|
||||
;
|
||||
static method h<T extends core::Object = core::Object>(self::h::T? t) → self::h::T
|
||||
;
|
||||
static method foo(dynamic d, void v, core::Object? onull, core::Object o, core::String? snull, core::String s) → dynamic
|
||||
;
|
||||
static method main() → dynamic
|
||||
;
|
|
@ -0,0 +1,46 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:20:5: Error: This expression has type 'void' and can't be used.
|
||||
// g(v);
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:27:5: Error: This expression has type 'void' and can't be used.
|
||||
// h(v);
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method f<T extends core::Object? = dynamic>(self::f::T% t) → self::f::T%
|
||||
return t;
|
||||
static method g<T extends core::Object? = dynamic>(self::g::T? t) → self::g::T%
|
||||
return t!;
|
||||
static method h<T extends core::Object = core::Object>(self::h::T? t) → self::h::T
|
||||
return t!;
|
||||
static method foo(dynamic d, void v, core::Object? onull, core::Object o, core::String? snull, core::String s) → dynamic {
|
||||
self::f<dynamic>(d);
|
||||
self::f<void>(v);
|
||||
self::f<core::Object?>(onull);
|
||||
self::f<core::Object>(o);
|
||||
self::f<core::String?>(snull);
|
||||
self::f<core::String>(s);
|
||||
self::g<core::Object>(d);
|
||||
self::g<core::Object>(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:20:5: Error: This expression has type 'void' and can't be used.
|
||||
g(v);
|
||||
^" in v);
|
||||
self::g<core::Object>(onull);
|
||||
self::g<core::Object>(o);
|
||||
self::g<core::String>(snull);
|
||||
self::g<core::String>(s);
|
||||
self::h<core::Object>(d);
|
||||
self::h<core::Object>(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:27:5: Error: This expression has type 'void' and can't be used.
|
||||
h(v);
|
||||
^" in v);
|
||||
self::h<core::Object>(onull);
|
||||
self::h<core::Object>(o);
|
||||
self::h<core::String>(snull);
|
||||
self::h<core::String>(s);
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,46 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:20:5: Error: This expression has type 'void' and can't be used.
|
||||
// g(v);
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:27:5: Error: This expression has type 'void' and can't be used.
|
||||
// h(v);
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method f<T extends core::Object? = dynamic>(self::f::T% t) → self::f::T%
|
||||
return t;
|
||||
static method g<T extends core::Object? = dynamic>(self::g::T? t) → self::g::T%
|
||||
return t!;
|
||||
static method h<T extends core::Object = core::Object>(self::h::T? t) → self::h::T
|
||||
return t!;
|
||||
static method foo(dynamic d, void v, core::Object? onull, core::Object o, core::String? snull, core::String s) → dynamic {
|
||||
self::f<dynamic>(d);
|
||||
self::f<void>(v);
|
||||
self::f<core::Object?>(onull);
|
||||
self::f<core::Object>(o);
|
||||
self::f<core::String?>(snull);
|
||||
self::f<core::String>(s);
|
||||
self::g<core::Object>(d);
|
||||
self::g<core::Object>(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:20:5: Error: This expression has type 'void' and can't be used.
|
||||
g(v);
|
||||
^" in v);
|
||||
self::g<core::Object>(onull);
|
||||
self::g<core::Object>(o);
|
||||
self::g<core::String>(snull);
|
||||
self::g<core::String>(s);
|
||||
self::h<core::Object>(d);
|
||||
self::h<core::Object>(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:27:5: Error: This expression has type 'void' and can't be used.
|
||||
h(v);
|
||||
^" in v);
|
||||
self::h<core::Object>(onull);
|
||||
self::h<core::Object>(o);
|
||||
self::h<core::String>(snull);
|
||||
self::h<core::String>(s);
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,5 @@
|
|||
T f<T>(T t) => t;
|
||||
T g<T>(T? t) => t!;
|
||||
T h<T extends Object>(T? t) => t!;
|
||||
foo(dynamic d, void v, Object? onull, Object o, String? snull, String s) {}
|
||||
main() {}
|
|
@ -0,0 +1,5 @@
|
|||
T f<T>(T t) => t;
|
||||
T g<T>(T? t) => t!;
|
||||
T h<T extends Object>(T? t) => t!;
|
||||
foo(dynamic d, void v, Object? onull, Object o, String? snull, String s) {}
|
||||
main() {}
|
|
@ -0,0 +1,46 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:20:5: Error: This expression has type 'void' and can't be used.
|
||||
// g(v);
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:27:5: Error: This expression has type 'void' and can't be used.
|
||||
// h(v);
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method f<T extends core::Object? = dynamic>(self::f::T% t) → self::f::T%
|
||||
return t;
|
||||
static method g<T extends core::Object? = dynamic>(self::g::T? t) → self::g::T%
|
||||
return t!;
|
||||
static method h<T extends core::Object = core::Object>(self::h::T? t) → self::h::T
|
||||
return t!;
|
||||
static method foo(dynamic d, void v, core::Object? onull, core::Object o, core::String? snull, core::String s) → dynamic {
|
||||
self::f<dynamic>(d);
|
||||
self::f<void>(v);
|
||||
self::f<core::Object?>(onull);
|
||||
self::f<core::Object>(o);
|
||||
self::f<core::String?>(snull);
|
||||
self::f<core::String>(s);
|
||||
self::g<core::Object>(d);
|
||||
self::g<core::Object>(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:20:5: Error: This expression has type 'void' and can't be used.
|
||||
g(v);
|
||||
^" in v);
|
||||
self::g<core::Object>(onull);
|
||||
self::g<core::Object>(o);
|
||||
self::g<core::String>(snull);
|
||||
self::g<core::String>(s);
|
||||
self::h<core::Object>(d);
|
||||
self::h<core::Object>(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:27:5: Error: This expression has type 'void' and can't be used.
|
||||
h(v);
|
||||
^" in v);
|
||||
self::h<core::Object>(onull);
|
||||
self::h<core::Object>(o);
|
||||
self::h<core::String>(snull);
|
||||
self::h<core::String>(s);
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,46 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:20:5: Error: This expression has type 'void' and can't be used.
|
||||
// g(v);
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:27:5: Error: This expression has type 'void' and can't be used.
|
||||
// h(v);
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method f<T extends core::Object? = dynamic>(self::f::T% t) → self::f::T%
|
||||
return t;
|
||||
static method g<T extends core::Object? = dynamic>(self::g::T? t) → self::g::T%
|
||||
return t!;
|
||||
static method h<T extends core::Object = core::Object>(self::h::T? t) → self::h::T
|
||||
return t!;
|
||||
static method foo(dynamic d, void v, core::Object? onull, core::Object o, core::String? snull, core::String s) → dynamic {
|
||||
self::f<dynamic>(d);
|
||||
self::f<void>(v);
|
||||
self::f<core::Object?>(onull);
|
||||
self::f<core::Object>(o);
|
||||
self::f<core::String?>(snull);
|
||||
self::f<core::String>(s);
|
||||
self::g<core::Object>(d);
|
||||
self::g<core::Object>(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:20:5: Error: This expression has type 'void' and can't be used.
|
||||
g(v);
|
||||
^" in v);
|
||||
self::g<core::Object>(onull);
|
||||
self::g<core::Object>(o);
|
||||
self::g<core::String>(snull);
|
||||
self::g<core::String>(s);
|
||||
self::h<core::Object>(d);
|
||||
self::h<core::Object>(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/infer_object_from_dynamic.dart:27:5: Error: This expression has type 'void' and can't be used.
|
||||
h(v);
|
||||
^" in v);
|
||||
self::h<core::Object>(onull);
|
||||
self::h<core::Object>(o);
|
||||
self::h<core::String>(snull);
|
||||
self::h<core::String>(s);
|
||||
}
|
||||
static method main() → dynamic {}
|
|
@ -0,0 +1,16 @@
|
|||
// 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 './opt_out_lib.dart';
|
||||
|
||||
foo(dynamic d, void v, Object? onull, Object o, String? snull, String s) {
|
||||
f(d);
|
||||
f(v);
|
||||
f(onull);
|
||||
f(o);
|
||||
f(snull);
|
||||
f(s);
|
||||
}
|
||||
|
||||
main() {}
|
|
@ -0,0 +1,4 @@
|
|||
import './opt_out_lib.dart';
|
||||
|
||||
foo(dynamic d, void v, Object? onull, Object o, String? snull, String s) {}
|
||||
main() {}
|
|
@ -0,0 +1,4 @@
|
|||
import './opt_out_lib.dart';
|
||||
|
||||
foo(dynamic d, void v, Object? onull, Object o, String? snull, String s) {}
|
||||
main() {}
|
|
@ -0,0 +1,23 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "opt_out_lib.dart" as opt;
|
||||
|
||||
import "org-dartlang-testcase:///opt_out_lib.dart";
|
||||
|
||||
static method foo(dynamic d, void v, core::Object? onull, core::Object o, core::String? snull, core::String s) → dynamic {
|
||||
opt::f<dynamic>(d);
|
||||
opt::f<void>(v);
|
||||
opt::f<core::Object?>(onull);
|
||||
opt::f<core::Object>(o);
|
||||
opt::f<core::String?>(snull);
|
||||
opt::f<core::String>(s);
|
||||
}
|
||||
static method main() → dynamic {}
|
||||
|
||||
library;
|
||||
import self as opt;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method f<T extends core::Object* = dynamic>(opt::f::T* a) → opt::f::T*
|
||||
return a;
|
|
@ -0,0 +1,23 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "opt_out_lib.dart" as opt;
|
||||
|
||||
import "org-dartlang-testcase:///opt_out_lib.dart";
|
||||
|
||||
static method foo(dynamic d, void v, core::Object? onull, core::Object o, core::String? snull, core::String s) → dynamic {
|
||||
opt::f<dynamic>(d);
|
||||
opt::f<void>(v);
|
||||
opt::f<core::Object?>(onull);
|
||||
opt::f<core::Object>(o);
|
||||
opt::f<core::String?>(snull);
|
||||
opt::f<core::String>(s);
|
||||
}
|
||||
static method main() → dynamic {}
|
||||
|
||||
library;
|
||||
import self as opt;
|
||||
import "dart:core" as core;
|
||||
|
||||
static method f<T extends core::Object* = dynamic>(opt::f::T* a) → opt::f::T*
|
||||
return a;
|
|
@ -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.8
|
||||
|
||||
T f<T>(T a) => a;
|
|
@ -35,7 +35,7 @@ check(expected, actual) {
|
|||
}
|
||||
|
||||
main() {
|
||||
check([dynamic, 1, 2, 3, null, null], staticFn(1 as dynamic, 2, 3));
|
||||
check([Object, 1, 2, 3, null, null], staticFn(1 as dynamic, 2, 3));
|
||||
|
||||
check([Object, 'Z', 2, 4, null, null], staticFn('Z', 2, 4));
|
||||
|
||||
|
@ -53,13 +53,13 @@ main() {
|
|||
|
||||
var c = new C();
|
||||
|
||||
check([dynamic, 8, 2, 3, null, null], c.memberFn(8 as dynamic, 2, 3));
|
||||
check([Object, 8, 2, 3, null, null], c.memberFn(8 as dynamic, 2, 3));
|
||||
|
||||
check([Object, 'A', 2, 3, null, null], c.memberFn('A', 2, 3));
|
||||
|
||||
check([int, 9, 2, 3, null, null], c.memberFn<int>(9, 2, 3));
|
||||
|
||||
check([dynamic, 10, 2, 3, null, null], c.map(10 as dynamic, 2, 3));
|
||||
check([Object, 10, 2, 3, null, null], c.map(10 as dynamic, 2, 3));
|
||||
|
||||
check([Object, 'B', 2, 3, null, null], c.map('B', 2, 3));
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ main() {
|
|||
|
||||
var c = C.list(o);
|
||||
var f = bar(o);
|
||||
var l = o.whereNotNull;
|
||||
var l = o.whereNotNull();
|
||||
|
||||
c.expectStaticType<Exactly<C<Object>>>();
|
||||
Expect.type<C<Object>>(c); // Run-time type is subtype of C<Object>.
|
||||
|
|
Loading…
Reference in a new issue