mirror of
https://github.com/dart-lang/sdk
synced 2024-09-04 16:03:44 +00:00
RecordElement.instantiate(), substitution, type alias.
Change-Id: Icd0e234e57d17a1c86140ed58fc9732da31bf1b3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/254942 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
9a3bcbcdb0
commit
c66faf9f3a
|
@ -2261,6 +2261,11 @@ abstract class RecordElement implements _ExistingElement {
|
|||
|
||||
/// The positional fields (might be empty).
|
||||
List<RecordPositionalFieldElement> get positionalFields;
|
||||
|
||||
/// Returns [RecordType] with [nullabilitySuffix] and declared field types.
|
||||
RecordType instantiate({
|
||||
required NullabilitySuffix nullabilitySuffix,
|
||||
});
|
||||
}
|
||||
|
||||
/// A field in a [RecordElement].
|
||||
|
|
|
@ -178,22 +178,21 @@ class ElementDisplayStringBuilder {
|
|||
final fieldCount = positionalFields.length + namedFields.length;
|
||||
_write('(');
|
||||
|
||||
for (var i = 0; i < positionalFields.length; i++) {
|
||||
final field = positionalFields[i];
|
||||
var index = 0;
|
||||
for (final field in positionalFields) {
|
||||
_writeType(field.type);
|
||||
if (i < fieldCount - 1) {
|
||||
if (index++ < fieldCount - 1) {
|
||||
_write(', ');
|
||||
}
|
||||
}
|
||||
|
||||
if (namedFields.isNotEmpty) {
|
||||
_write('{');
|
||||
for (var i = 0; i < namedFields.length; i++) {
|
||||
final field = namedFields[i];
|
||||
for (final field in namedFields) {
|
||||
_writeType(field.type);
|
||||
_write(' ');
|
||||
_write(field.name);
|
||||
if (i < fieldCount - 1) {
|
||||
if (index++ < fieldCount - 1) {
|
||||
_write(', ');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6219,6 +6219,20 @@ class RecordElementImpl extends _ExistingElementImpl implements RecordElement {
|
|||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
RecordTypeImpl instantiate({
|
||||
required NullabilitySuffix nullabilitySuffix,
|
||||
}) {
|
||||
return RecordTypeImpl(
|
||||
element2: this,
|
||||
fieldTypes: [
|
||||
...positionalFields.map((field) => field.type),
|
||||
...namedFieldsSorted.map((field) => field.type),
|
||||
],
|
||||
nullabilitySuffix: nullabilitySuffix,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns [fields], if already sorted, or the sorted copy.
|
||||
static List<RecordNamedFieldElementImpl> _sortNamedFields(
|
||||
List<RecordNamedFieldElementImpl> fields,
|
||||
|
@ -6597,6 +6611,16 @@ class TypeAliasElementImpl extends _ExistingElementImpl
|
|||
typeArguments: typeArguments,
|
||||
),
|
||||
);
|
||||
} else if (type is RecordTypeImpl) {
|
||||
return RecordTypeImpl(
|
||||
element2: type.element2,
|
||||
fieldTypes: type.fieldTypes,
|
||||
nullabilitySuffix: resultNullability,
|
||||
alias: InstantiatedTypeAliasElementImpl(
|
||||
element: this,
|
||||
typeArguments: typeArguments,
|
||||
),
|
||||
);
|
||||
} else if (type is TypeParameterType) {
|
||||
return TypeParameterTypeImpl(
|
||||
element: type.element2,
|
||||
|
|
|
@ -16,6 +16,7 @@ import 'package:analyzer/src/dart/element/type_algebra.dart';
|
|||
import 'package:analyzer/src/dart/element/type_system.dart';
|
||||
import 'package:analyzer/src/generated/element_type_provider.dart';
|
||||
import 'package:analyzer/src/generated/utilities_dart.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
/// The [Type] representing the type `dynamic`.
|
||||
class DynamicTypeImpl extends TypeImpl implements DynamicType {
|
||||
|
@ -995,16 +996,18 @@ class RecordTypeImpl extends TypeImpl implements RecordType {
|
|||
@override
|
||||
final RecordElementImpl element2;
|
||||
|
||||
final Substitution substitution;
|
||||
/// The types of all fields, first positional, then named.
|
||||
final List<DartType> fieldTypes;
|
||||
|
||||
@override
|
||||
final NullabilitySuffix nullabilitySuffix;
|
||||
|
||||
RecordTypeImpl({
|
||||
required this.element2,
|
||||
required this.substitution,
|
||||
required this.fieldTypes,
|
||||
required this.nullabilitySuffix,
|
||||
}) : super(element2);
|
||||
InstantiatedTypeAliasElement? alias,
|
||||
}) : super(element2, alias: alias);
|
||||
|
||||
@override
|
||||
RecordElementImpl get element => element2;
|
||||
|
@ -1015,23 +1018,22 @@ class RecordTypeImpl extends TypeImpl implements RecordType {
|
|||
|
||||
@override
|
||||
List<RecordTypeNamedField> get namedFields {
|
||||
return element.namedFieldsSorted.map((field) {
|
||||
final type = substitution.substituteType(field.type);
|
||||
final baseIndex = element.positionalFields.length;
|
||||
return element.namedFieldsSorted.mapIndexed((index, field) {
|
||||
return RecordTypeNamedFieldImpl(
|
||||
element: field,
|
||||
name: field.name,
|
||||
type: type,
|
||||
type: fieldTypes[baseIndex + index],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
List<RecordTypePositionalField> get positionalFields {
|
||||
return element.positionalFields.map((field) {
|
||||
final type = substitution.substituteType(field.type);
|
||||
return element.positionalFields.mapIndexed((index, field) {
|
||||
return RecordTypePositionalFieldImpl(
|
||||
element: field,
|
||||
type: type,
|
||||
type: fieldTypes[index],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
|
|
@ -546,9 +546,20 @@ abstract class _TypeSubstitutor
|
|||
DartType visitNeverType(NeverType type) => type;
|
||||
|
||||
@override
|
||||
DartType visitRecordType(RecordType type) {
|
||||
// TODO: implement visitRecordType
|
||||
throw UnimplementedError();
|
||||
DartType visitRecordType(covariant RecordTypeImpl type) {
|
||||
final before = useCounter;
|
||||
final fieldTypes = _mapList(type.fieldTypes);
|
||||
final alias = _mapAlias(type.alias);
|
||||
if (useCounter == before) {
|
||||
return type;
|
||||
}
|
||||
|
||||
return RecordTypeImpl(
|
||||
element2: type.element2,
|
||||
fieldTypes: fieldTypes,
|
||||
nullabilitySuffix: type.nullabilitySuffix,
|
||||
alias: alias,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -10,7 +10,6 @@ import 'package:analyzer/dart/element/type_provider.dart';
|
|||
import 'package:analyzer/src/dart/analysis/session.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_algebra.dart';
|
||||
import 'package:analyzer/src/dart/element/type_system.dart';
|
||||
import 'package:analyzer/src/dart/resolver/variance.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
|
@ -592,10 +591,8 @@ mixin ElementsTypesMixin {
|
|||
RecordTypeImpl recordTypeNone({
|
||||
required RecordElementImpl element,
|
||||
}) {
|
||||
return RecordTypeImpl(
|
||||
element2: element,
|
||||
return element.instantiate(
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
substitution: Substitution.empty,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -377,6 +377,100 @@ class SubstituteTest extends _Base {
|
|||
_assertIdenticalType(type, {T: intNone});
|
||||
}
|
||||
|
||||
test_record_doesNotUseTypeParameter() async {
|
||||
final T = typeParameter('T');
|
||||
|
||||
final type = recordTypeNone(
|
||||
element: recordElement(
|
||||
positionalFields: [
|
||||
recordPositionalField(type: intNone),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
assertType(type, '(int)');
|
||||
_assertIdenticalType(type, {T: intNone});
|
||||
}
|
||||
|
||||
test_record_fromAlias() async {
|
||||
// typedef Alias<T> = (int, String);
|
||||
final T = typeParameter('T');
|
||||
final Alias = typeAlias(
|
||||
name: 'Alias',
|
||||
typeParameters: [T],
|
||||
aliasedType: recordTypeNone(
|
||||
element: recordElement(
|
||||
positionalFields: [
|
||||
recordPositionalField(type: intNone),
|
||||
recordPositionalField(type: stringNone),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final U = typeParameter('U');
|
||||
final type = typeAliasTypeNone(Alias, typeArguments: [
|
||||
typeParameterTypeNone(U),
|
||||
]);
|
||||
assertType(type, '(int, String) via Alias<U>');
|
||||
_assertSubstitution(type, {U: intNone}, '(int, String) via Alias<int>');
|
||||
}
|
||||
|
||||
test_record_fromAlias2() async {
|
||||
// typedef Alias<T> = (T, List<T>);
|
||||
final T = typeParameter('T');
|
||||
final T_none = typeParameterTypeNone(T);
|
||||
final Alias = typeAlias(
|
||||
name: 'Alias',
|
||||
typeParameters: [T],
|
||||
aliasedType: recordTypeNone(
|
||||
element: recordElement(
|
||||
positionalFields: [
|
||||
recordPositionalField(type: T_none),
|
||||
recordPositionalField(type: listNone(T_none)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final type = typeAliasTypeNone(Alias, typeArguments: [intNone]);
|
||||
assertType(type, '(int, List<int>) via Alias<int>');
|
||||
}
|
||||
|
||||
test_record_named() async {
|
||||
final T = typeParameter('T');
|
||||
final T_none = typeParameterTypeNone(T);
|
||||
|
||||
final type = recordTypeNone(
|
||||
element: recordElement(
|
||||
namedFields: [
|
||||
recordNamedField(name: 'f1', type: T_none),
|
||||
recordNamedField(name: 'f2', type: listNone(T_none)),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
assertType(type, '({T f1, List<T> f2})');
|
||||
_assertSubstitution(type, {T: intNone}, '({int f1, List<int> f2})');
|
||||
}
|
||||
|
||||
test_record_positional() async {
|
||||
final T = typeParameter('T');
|
||||
final T_none = typeParameterTypeNone(T);
|
||||
|
||||
final type = recordTypeNone(
|
||||
element: recordElement(
|
||||
positionalFields: [
|
||||
recordPositionalField(type: T_none),
|
||||
recordPositionalField(type: listNone(T_none)),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
assertType(type, '(T, List<T>)');
|
||||
_assertSubstitution(type, {T: intNone}, '(int, List<int>)');
|
||||
}
|
||||
|
||||
test_typeParameter_nullability() async {
|
||||
var tElement = typeParameter('T');
|
||||
|
||||
|
|
Loading…
Reference in a new issue