[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:
Dmitry Stefantsov 2020-09-16 11:36:28 +00:00 committed by commit-bot@chromium.org
parent 52c3d94863
commit e119ccad2a
18 changed files with 356 additions and 8 deletions

View file

@ -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 =

View file

@ -429,6 +429,7 @@ numerator
observable
oh
okay
onull
ooo
operate
ops
@ -535,6 +536,7 @@ signalled
sigwinch
slight
smoke
snull
somehow
spans
spawn

View 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() {}

View file

@ -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
;

View file

@ -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 {}

View file

@ -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 {}

View file

@ -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() {}

View file

@ -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() {}

View file

@ -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 {}

View file

@ -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 {}

View file

@ -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() {}

View file

@ -0,0 +1,4 @@
import './opt_out_lib.dart';
foo(dynamic d, void v, Object? onull, Object o, String? snull, String s) {}
main() {}

View file

@ -0,0 +1,4 @@
import './opt_out_lib.dart';
foo(dynamic d, void v, Object? onull, Object o, String? snull, String s) {}
main() {}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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));

View file

@ -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>.