Skip to content

Commit

Permalink
[analyzer][cfe] Add isDartCoreRecord to the shared methods
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
chloestefantsova authored and Commit Queue committed Nov 13, 2024
1 parent 1640ca7 commit 097d0a3
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,13 @@ abstract interface class TypeAnalyzerOperations<
SharedTypeView<TypeStructure> toType);

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

/// Returns `true` if [type] is `Record` from `dart:core`. The method
/// returns `false` for `Record?` and `Record*`.
bool isDartCoreRecord(SharedTypeView<TypeStructure> type);

/// Returns `true` if [type] is `E<T1, ..., Tn>`, `E<T1, ..., Tn>?`, or
/// `E<T1, ..., Tn>*` for some extension type declaration E, some
/// non-negative n, and some types T1, ..., Tn.
Expand Down
9 changes: 9 additions & 0 deletions pkg/_fe_analyzer_shared/test/mini_ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2959,6 +2959,15 @@ class MiniAstOperations
unwrappedType.args.isEmpty;
}

@override
bool isDartCoreRecord(SharedTypeView<Type> type) {
Type unwrappedType = type.unwrapTypeView();
return unwrappedType is PrimaryType &&
unwrappedType.nullabilitySuffix == NullabilitySuffix.none &&
unwrappedType.name == 'Record' &&
unwrappedType.args.isEmpty;
}

@override
bool isExtensionType(SharedTypeView<Type> type) {
// TODO(cstefantsova): Add the support for extension types in the mini ast
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,34 @@ main() {
.isFalse();
check(tcg._constraints).isEmpty();
});

test('Nullable does not match non-nullable', () {
// `(int, T)? <# (int, String)` does not match
var tcg = _TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForLeftNullableType(
Type('(int, T)?'), Type('(int, String)'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
.isFalse();
check(tcg._constraints).isEmpty();
});

test('Both LHS and RHS nullable, matching', () {
var tcg = _TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('T?'), Type('int?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
.isTrue();
check(tcg._constraints).deepEquals(['T <: int']);
});

test('Both LHS and RHS nullable, not matching', () {
var tcg = _TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('(T, int)?'), Type('(int, String)?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
.isFalse();
check(tcg._constraints).isEmpty();
});
});

group('performSubtypeConstraintGenerationForRightNullableType:', () {
Expand Down Expand Up @@ -583,6 +611,33 @@ main() {
.isTrue();
check(tcg._constraints).isEmpty();
});

test('Dynamic matches Object?', () {
var tcg = _TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('dynamic'), Type('Object?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
.isTrue();
check(tcg._constraints).isEmpty();
});

test('void matches Object?', () {
var tcg = _TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('void'), Type('Object?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
.isTrue();
check(tcg._constraints).isEmpty();
});

test('LHS not nullable, matches with no constraints', () {
var tcg = _TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('int'), Type('int?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
.isTrue();
check(tcg._constraints).isEmpty();
});
});

group('performSubtypeConstraintGenerationForTypeDeclarationTypes', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
// A type `P` is a subtype match for `Record` with respect to `L` under no
// constraints:
// If `P` is a record type or `Record`.
if (Q_nullability == NullabilitySuffix.none && Q.isDartCoreRecord) {
if (_typeSystemOperations.isDartCoreRecord(SharedTypeView(Q))) {
if (P is SharedRecordTypeStructure<DartType>) {
return true;
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,12 @@ class TypeSystemOperations
type.unwrapTypeView().isDartCoreFunction;
}

@override
bool isDartCoreRecord(SharedTypeView<DartType> type) {
return type.nullabilitySuffix == NullabilitySuffix.none &&
type.unwrapTypeView().isDartCoreRecord;
}

@override
bool isExtensionType(SharedTypeView<DartType> type) {
DartType unwrappedType = type.unwrapTypeView();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
// constraints:
//
// If P is a record type or Record.
if (q == _environment.coreTypes.recordNonNullableRawType &&
if (typeOperations.isDartCoreRecord(new SharedTypeView(q)) &&
p is RecordType) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,12 @@ class OperationsCfe
typeEnvironment.coreTypes.functionNonNullableRawType;
}

@override
bool isDartCoreRecord(SharedTypeView<DartType> type) {
return type.unwrapTypeView() ==
typeEnvironment.coreTypes.recordNonNullableRawType;
}

@override
DartType greatestClosureOfTypeInternal(DartType type,
List<SharedTypeParameterStructure<DartType>> typeParametersToEliminate) {
Expand Down
4 changes: 2 additions & 2 deletions pkg/front_end/test/coverage_suite_expected.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
),
// 100.0%.
"package:front_end/src/type_inference/type_constraint_gatherer.dart": (
hitCount: 189,
hitCount: 188,
missCount: 0,
),
// 100.0%.
Expand All @@ -1046,7 +1046,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
),
// 100.0%.
"package:front_end/src/type_inference/type_inference_engine.dart": (
hitCount: 530,
hitCount: 536,
missCount: 0,
),
// 100.0%.
Expand Down

0 comments on commit 097d0a3

Please sign in to comment.