Skip to content

Commit 097d0a3

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[analyzer][cfe] Add isDartCoreRecord to the shared methods
This is done by analogy with `isDartCoreFunction` and is used similarly in the type constraint generation methods. Part of #54902 Change-Id: Ied3a4e5ee55846c9c0f7e68dbcdff87548b94787 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/394100 Commit-Queue: Chloe Stefantsova <[email protected]> Reviewed-by: Paul Berry <[email protected]>
1 parent 1640ca7 commit 097d0a3

File tree

8 files changed

+85
-5
lines changed

8 files changed

+85
-5
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,13 @@ abstract interface class TypeAnalyzerOperations<
174174
SharedTypeView<TypeStructure> toType);
175175

176176
/// Returns `true` if [type] is `Function` from `dart:core`. The method
177-
/// returns `false` for `Object?` and `Object*`.
177+
/// returns `false` for `Function?` and `Function*`.
178178
bool isDartCoreFunction(SharedTypeView<TypeStructure> type);
179179

180+
/// Returns `true` if [type] is `Record` from `dart:core`. The method
181+
/// returns `false` for `Record?` and `Record*`.
182+
bool isDartCoreRecord(SharedTypeView<TypeStructure> type);
183+
180184
/// Returns `true` if [type] is `E<T1, ..., Tn>`, `E<T1, ..., Tn>?`, or
181185
/// `E<T1, ..., Tn>*` for some extension type declaration E, some
182186
/// non-negative n, and some types T1, ..., Tn.

pkg/_fe_analyzer_shared/test/mini_ast.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2959,6 +2959,15 @@ class MiniAstOperations
29592959
unwrappedType.args.isEmpty;
29602960
}
29612961

2962+
@override
2963+
bool isDartCoreRecord(SharedTypeView<Type> type) {
2964+
Type unwrappedType = type.unwrapTypeView();
2965+
return unwrappedType is PrimaryType &&
2966+
unwrappedType.nullabilitySuffix == NullabilitySuffix.none &&
2967+
unwrappedType.name == 'Record' &&
2968+
unwrappedType.args.isEmpty;
2969+
}
2970+
29622971
@override
29632972
bool isExtensionType(SharedTypeView<Type> type) {
29642973
// TODO(cstefantsova): Add the support for extension types in the mini ast

pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,34 @@ main() {
538538
.isFalse();
539539
check(tcg._constraints).isEmpty();
540540
});
541+
542+
test('Nullable does not match non-nullable', () {
543+
// `(int, T)? <# (int, String)` does not match
544+
var tcg = _TypeConstraintGatherer({'T'});
545+
check(tcg.performSubtypeConstraintGenerationForLeftNullableType(
546+
Type('(int, T)?'), Type('(int, String)'),
547+
leftSchema: false, astNodeForTesting: Node.placeholder()))
548+
.isFalse();
549+
check(tcg._constraints).isEmpty();
550+
});
551+
552+
test('Both LHS and RHS nullable, matching', () {
553+
var tcg = _TypeConstraintGatherer({'T'});
554+
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
555+
Type('T?'), Type('int?'),
556+
leftSchema: false, astNodeForTesting: Node.placeholder()))
557+
.isTrue();
558+
check(tcg._constraints).deepEquals(['T <: int']);
559+
});
560+
561+
test('Both LHS and RHS nullable, not matching', () {
562+
var tcg = _TypeConstraintGatherer({'T'});
563+
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
564+
Type('(T, int)?'), Type('(int, String)?'),
565+
leftSchema: false, astNodeForTesting: Node.placeholder()))
566+
.isFalse();
567+
check(tcg._constraints).isEmpty();
568+
});
541569
});
542570

543571
group('performSubtypeConstraintGenerationForRightNullableType:', () {
@@ -583,6 +611,33 @@ main() {
583611
.isTrue();
584612
check(tcg._constraints).isEmpty();
585613
});
614+
615+
test('Dynamic matches Object?', () {
616+
var tcg = _TypeConstraintGatherer({});
617+
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
618+
Type('dynamic'), Type('Object?'),
619+
leftSchema: false, astNodeForTesting: Node.placeholder()))
620+
.isTrue();
621+
check(tcg._constraints).isEmpty();
622+
});
623+
624+
test('void matches Object?', () {
625+
var tcg = _TypeConstraintGatherer({});
626+
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
627+
Type('void'), Type('Object?'),
628+
leftSchema: false, astNodeForTesting: Node.placeholder()))
629+
.isTrue();
630+
check(tcg._constraints).isEmpty();
631+
});
632+
633+
test('LHS not nullable, matches with no constraints', () {
634+
var tcg = _TypeConstraintGatherer({});
635+
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
636+
Type('int'), Type('int?'),
637+
leftSchema: false, astNodeForTesting: Node.placeholder()))
638+
.isTrue();
639+
check(tcg._constraints).isEmpty();
640+
});
586641
});
587642

588643
group('performSubtypeConstraintGenerationForTypeDeclarationTypes', () {

pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
368368
// A type `P` is a subtype match for `Record` with respect to `L` under no
369369
// constraints:
370370
// If `P` is a record type or `Record`.
371-
if (Q_nullability == NullabilitySuffix.none && Q.isDartCoreRecord) {
371+
if (_typeSystemOperations.isDartCoreRecord(SharedTypeView(Q))) {
372372
if (P is SharedRecordTypeStructure<DartType>) {
373373
return true;
374374
}

pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,12 @@ class TypeSystemOperations
543543
type.unwrapTypeView().isDartCoreFunction;
544544
}
545545

546+
@override
547+
bool isDartCoreRecord(SharedTypeView<DartType> type) {
548+
return type.nullabilitySuffix == NullabilitySuffix.none &&
549+
type.unwrapTypeView().isDartCoreRecord;
550+
}
551+
546552
@override
547553
bool isExtensionType(SharedTypeView<DartType> type) {
548554
DartType unwrappedType = type.unwrapTypeView();

pkg/front_end/lib/src/type_inference/type_constraint_gatherer.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
480480
// constraints:
481481
//
482482
// If P is a record type or Record.
483-
if (q == _environment.coreTypes.recordNonNullableRawType &&
483+
if (typeOperations.isDartCoreRecord(new SharedTypeView(q)) &&
484484
p is RecordType) {
485485
return true;
486486
}

pkg/front_end/lib/src/type_inference/type_inference_engine.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,12 @@ class OperationsCfe
986986
typeEnvironment.coreTypes.functionNonNullableRawType;
987987
}
988988

989+
@override
990+
bool isDartCoreRecord(SharedTypeView<DartType> type) {
991+
return type.unwrapTypeView() ==
992+
typeEnvironment.coreTypes.recordNonNullableRawType;
993+
}
994+
989995
@override
990996
DartType greatestClosureOfTypeInternal(DartType type,
991997
List<SharedTypeParameterStructure<DartType>> typeParametersToEliminate) {

pkg/front_end/test/coverage_suite_expected.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,7 +1036,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
10361036
),
10371037
// 100.0%.
10381038
"package:front_end/src/type_inference/type_constraint_gatherer.dart": (
1039-
hitCount: 189,
1039+
hitCount: 188,
10401040
missCount: 0,
10411041
),
10421042
// 100.0%.
@@ -1046,7 +1046,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
10461046
),
10471047
// 100.0%.
10481048
"package:front_end/src/type_inference/type_inference_engine.dart": (
1049-
hitCount: 530,
1049+
hitCount: 536,
10501050
missCount: 0,
10511051
),
10521052
// 100.0%.

0 commit comments

Comments
 (0)