Skip to content

Commit c67a80f

Browse files
stereotype441Commit Queue
authored andcommitted
Stop using NullabilitySuffix in fe/analyzer shared code.
The getter `SharedType.nullabilitySuffix` is replaced by `SharedType.isQuestionType`, which returns a boolean. The method `TypeAnalyzerOperations.withNullabilitySuffixInternal` is replaced by `SharedType.setNullabilitySuffix`, which accepts a boolean. Support for `*` types has been removed from `mini_types.dart`. A few test cases in `flow_analysis_test.dart` previously used `*` types as a way of exercising corner cases involving types that were mutual subtypes of each other. These tests have been changed to take advantage of the fact that `dynamic` and `Object?` are mutual subtypes. Change-Id: Id9904f9570fc738b388192db8536848204af03e9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/414581 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent 9d3a550 commit c67a80f

File tree

11 files changed

+227
-420
lines changed

11 files changed

+227
-420
lines changed

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import '../flow_analysis/flow_analysis_operations.dart';
66
import '../types/shared_type.dart';
7-
import 'nullability_suffix.dart';
87
import 'type_constraint.dart';
98

109
/// Callback API used by the shared type analyzer to query and manipulate the
@@ -692,10 +691,6 @@ abstract interface class TypeAnalyzerOperations<Variable extends Object,
692691

693692
/// Converts a type into a corresponding type schema.
694693
SharedTypeSchemaView typeToSchema(SharedTypeView type);
695-
696-
/// Returns [type] suffixed with the [suffix].
697-
SharedType withNullabilitySuffixInternal(
698-
covariant SharedType type, NullabilitySuffix suffix);
699694
}
700695

701696
mixin TypeAnalyzerOperationsMixin<Variable extends Object,
@@ -965,7 +960,7 @@ abstract class TypeConstraintGenerator<
965960
/// be rolled back to a state via [restoreState].
966961
TypeConstraintGeneratorState get currentState;
967962

968-
/// True if FutureOr types are required to have the empty [NullabilitySuffix]
963+
/// True if FutureOr types are required to have `isQuestionType == false`
969964
/// when they are matched.
970965
///
971966
/// For more information about the discrepancy between the Analyzer and the
@@ -1073,9 +1068,8 @@ abstract class TypeConstraintGenerator<
10731068
SharedType p, SharedType q,
10741069
{required bool leftSchema, required AstNode? astNodeForTesting}) {
10751070
// If `P` is `FutureOr<P0>` the match holds under constraint set `C1 + C2`:
1076-
NullabilitySuffix pNullability = p.nullabilitySuffix;
10771071
if (typeAnalyzerOperations.matchFutureOrInternal(p) case var p0?
1078-
when pNullability == NullabilitySuffix.none) {
1072+
when !p.isQuestionType) {
10791073
final TypeConstraintGeneratorState state = currentState;
10801074

10811075
// If `Future<P0>` is a subtype match for `Q` under constraint set `C1`.
@@ -1110,10 +1104,8 @@ abstract class TypeConstraintGenerator<
11101104
SharedType p, SharedType q,
11111105
{required bool leftSchema, required AstNode? astNodeForTesting}) {
11121106
// If `P` is `P0?` the match holds under constraint set `C1 + C2`:
1113-
NullabilitySuffix pNullability = p.nullabilitySuffix;
1114-
if (pNullability == NullabilitySuffix.question) {
1115-
SharedType p0 = typeAnalyzerOperations.withNullabilitySuffixInternal(
1116-
p, NullabilitySuffix.none);
1107+
if (p.isQuestionType) {
1108+
SharedType p0 = p.asQuestionType(false);
11171109
final TypeConstraintGeneratorState state = currentState;
11181110

11191111
// If `P0` is a subtype match for `Q` under constraint set `C1`.
@@ -1204,14 +1196,14 @@ abstract class TypeConstraintGenerator<
12041196
// If `Q` is `FutureOr<Q0>` the match holds under constraint set `C`:
12051197
if (typeAnalyzerOperations.matchFutureOrInternal(q) case SharedType q0?
12061198
when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
1207-
q.nullabilitySuffix == NullabilitySuffix.none) {
1199+
!q.isQuestionType) {
12081200
final TypeConstraintGeneratorState state = currentState;
12091201

12101202
// If `P` is `FutureOr<P0>` and `P0` is a subtype match for `Q0` under
12111203
// constraint set `C`.
12121204
if (typeAnalyzerOperations.matchFutureOrInternal(p) case SharedType p0?
12131205
when enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr ||
1214-
p.nullabilitySuffix == NullabilitySuffix.none) {
1206+
!p.isQuestionType) {
12151207
if (performSubtypeConstraintGenerationInternal(p0, q0,
12161208
leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
12171209
return true;
@@ -1260,18 +1252,14 @@ abstract class TypeConstraintGenerator<
12601252
SharedType p, SharedType q,
12611253
{required bool leftSchema, required AstNode? astNodeForTesting}) {
12621254
// If `Q` is `Q0?` the match holds under constraint set `C`:
1263-
NullabilitySuffix qNullability = q.nullabilitySuffix;
1264-
if (qNullability == NullabilitySuffix.question) {
1265-
SharedType q0 = typeAnalyzerOperations.withNullabilitySuffixInternal(
1266-
q, NullabilitySuffix.none);
1255+
if (q.isQuestionType) {
1256+
SharedType q0 = q.asQuestionType(false);
12671257
final TypeConstraintGeneratorState state = currentState;
12681258

12691259
// If `P` is `P0?` and `P0` is a subtype match for `Q0` under
12701260
// constraint set `C`.
1271-
NullabilitySuffix pNullability = p.nullabilitySuffix;
1272-
if (pNullability == NullabilitySuffix.question) {
1273-
SharedType p0 = typeAnalyzerOperations.withNullabilitySuffixInternal(
1274-
p, NullabilitySuffix.none);
1261+
if (p.isQuestionType) {
1262+
SharedType p0 = p.asQuestionType(false);
12751263
if (performSubtypeConstraintGenerationInternal(p0, q0,
12761264
leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
12771265
return true;
@@ -1409,10 +1397,9 @@ abstract class TypeConstraintGenerator<
14091397

14101398
// If `P` is a type variable `X` in `L`, then the match holds:
14111399
// Under constraint `_ <: X <: Q`.
1412-
NullabilitySuffix pNullability = p.nullabilitySuffix;
14131400
if (typeAnalyzerOperations.matchInferableParameterInternal(p)
14141401
case var pParameter?
1415-
when pNullability == NullabilitySuffix.none &&
1402+
when !p.isQuestionType &&
14161403
typeParametersToConstrain.contains(pParameter)) {
14171404
addUpperConstraintForParameter(pParameter, q,
14181405
astNodeForTesting: astNodeForTesting);
@@ -1421,10 +1408,9 @@ abstract class TypeConstraintGenerator<
14211408

14221409
// If `Q` is a type variable `X` in `L`, then the match holds:
14231410
// Under constraint `P <: X <: _`.
1424-
NullabilitySuffix qNullability = q.nullabilitySuffix;
14251411
if (typeAnalyzerOperations.matchInferableParameterInternal(q)
14261412
case var qParameter?
1427-
when qNullability == NullabilitySuffix.none &&
1413+
when !q.isQuestionType &&
14281414
typeParametersToConstrain.contains(qParameter) &&
14291415
(!inferenceUsingBoundsIsEnabled ||
14301416
(qParameter.boundShared == null ||
@@ -1832,11 +1818,11 @@ abstract class TypeConstraintGenerator<
18321818
/// and `false` is returned.
18331819
bool _interfaceTypes(SharedType p, SharedType q, bool leftSchema,
18341820
{required AstNode? astNodeForTesting}) {
1835-
if (p.nullabilitySuffix != NullabilitySuffix.none) {
1821+
if (p.isQuestionType) {
18361822
return false;
18371823
}
18381824

1839-
if (q.nullabilitySuffix != NullabilitySuffix.none) {
1825+
if (q.isQuestionType) {
18401826
return false;
18411827
}
18421828

pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import '../type_inference/nullability_suffix.dart';
6-
75
/// Common interface for data structures used by the implementations to
86
/// represent the type `dynamic`.
97
abstract interface class SharedDynamicType implements SharedType {}
@@ -73,9 +71,19 @@ abstract interface class SharedRecordType implements SharedType {
7371
/// Common interface for data structures used by the implementations to
7472
/// represent a type.
7573
abstract interface class SharedType {
76-
/// If this type ends in a suffix (`?` or `*`), the suffix it ends with;
77-
/// otherwise [NullabilitySuffix.none].
78-
NullabilitySuffix get nullabilitySuffix;
74+
/// Whether this type ends in a `?` suffix.
75+
///
76+
/// Note that some types are nullable even though they do not end in a `?`
77+
/// suffix (for example, `Null`, `dynamic`, and `FutureOr<int?>`). These types
78+
/// all respond to this query with `false`.
79+
bool get isQuestionType;
80+
81+
/// Returns a modified version of this type, with the nullability suffix
82+
/// changed to [isQuestionType].
83+
///
84+
/// For types that don't accept a nullability suffix (`dynamic`, InvalidType,
85+
/// `Null`, `_`, and `void`), the type is returned unchanged.
86+
SharedType asQuestionType(bool isQuestionType);
7987

8088
/// Return the presentation of this type as it should appear when presented
8189
/// to users in contexts such as error messages.
@@ -163,7 +171,7 @@ extension type SharedTypeParameterView(SharedTypeParameter _typeParameter)
163171

164172
extension type SharedTypeSchemaView(SharedType _typeStructure)
165173
implements Object {
166-
NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix;
174+
bool get isQuestionType => _typeStructure.isQuestionType;
167175

168176
String getDisplayString() => _typeStructure.getDisplayString();
169177

@@ -175,7 +183,7 @@ extension type SharedTypeSchemaView(SharedType _typeStructure)
175183
}
176184

177185
extension type SharedTypeView(SharedType _typeStructure) implements Object {
178-
NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix;
186+
bool get isQuestionType => _typeStructure.isQuestionType;
179187

180188
String getDisplayString() => _typeStructure.getDisplayString();
181189

pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4207,27 +4207,29 @@ main() {
42074207
test('; no promotion', () {
42084208
var s1 = FlowModel<SharedTypeView>(Reachability.initial)
42094209
._declare(h, objectQVar, true)
4210-
._tryPromoteForTypeCheck(h, objectQVar, 'num?')
4210+
._tryPromoteForTypeCheck(h, objectQVar, 'List<Object?>')
42114211
.ifFalse
4212-
._tryPromoteForTypeCheck(h, objectQVar, 'num*')
4212+
._tryPromoteForTypeCheck(h, objectQVar, 'List<dynamic>')
42134213
.ifFalse;
42144214
expect(s1.promotionInfo.unwrap(h), {
42154215
h.promotionKeyStore.keyForVariable(objectQVar):
42164216
_matchVariableModel(
4217-
chain: ['Object'],
4218-
ofInterest: ['num?', 'num*'],
4217+
ofInterest: ['List<Object?>', 'List<dynamic>'],
42194218
),
42204219
});
4221-
var s2 = s1._write(h, null, objectQVar, SharedTypeView(Type('int')),
4220+
var s2 = s1._write(
4221+
h,
4222+
null,
4223+
objectQVar,
4224+
SharedTypeView(Type('List<int>')),
42224225
new SsaNode<SharedTypeView>(null));
4223-
// It's ambiguous whether to promote to num? or num*, so we don't
4224-
// promote.
4226+
// It's ambiguous whether to promote to List<Object?> or
4227+
// List<dynamic>, so we don't promote.
42254228
expect(s2, isNot(same(s1)));
42264229
expect(s2.promotionInfo.unwrap(h), {
42274230
h.promotionKeyStore.keyForVariable(objectQVar):
42284231
_matchVariableModel(
4229-
chain: ['Object'],
4230-
ofInterest: ['num?', 'num*'],
4232+
ofInterest: ['List<Object?>', 'List<dynamic>'],
42314233
),
42324234
});
42334235
});
@@ -4236,24 +4238,28 @@ main() {
42364238
test('exact match', () {
42374239
var s1 = FlowModel<SharedTypeView>(Reachability.initial)
42384240
._declare(h, objectQVar, true)
4239-
._tryPromoteForTypeCheck(h, objectQVar, 'num?')
4241+
._tryPromoteForTypeCheck(h, objectQVar, 'List<Object?>')
42404242
.ifFalse
4241-
._tryPromoteForTypeCheck(h, objectQVar, 'num*')
4243+
._tryPromoteForTypeCheck(h, objectQVar, 'List<dynamic>')
42424244
.ifFalse;
42434245
expect(s1.promotionInfo.unwrap(h), {
42444246
h.promotionKeyStore.keyForVariable(objectQVar): _matchVariableModel(
4245-
chain: ['Object'],
4246-
ofInterest: ['num?', 'num*'],
4247+
ofInterest: ['List<Object?>', 'List<dynamic>'],
42474248
),
42484249
});
4249-
var s2 = s1._write(h, _MockNonPromotionReason(), objectQVar,
4250-
SharedTypeView(Type('num?')), new SsaNode<SharedTypeView>(null));
4251-
// It's ambiguous whether to promote to num? or num*, but since the
4252-
// written type is exactly num?, we use that.
4250+
var s2 = s1._write(
4251+
h,
4252+
_MockNonPromotionReason(),
4253+
objectQVar,
4254+
SharedTypeView(Type('List<Object?>')),
4255+
new SsaNode<SharedTypeView>(null));
4256+
// It's ambiguous whether to promote to List<Object?> or
4257+
// List<dynamic>, but since the written type is exactly List<Object?>,
4258+
// we use that.
42534259
expect(s2.promotionInfo.unwrap(h), {
42544260
h.promotionKeyStore.keyForVariable(objectQVar): _matchVariableModel(
4255-
chain: ['num?'],
4256-
ofInterest: ['num?', 'num*'],
4261+
chain: ['List<Object?>'],
4262+
ofInterest: ['List<Object?>', 'List<dynamic>'],
42574263
),
42584264
});
42594265
});

0 commit comments

Comments
 (0)