Skip to content

Commit c66faf9

Browse files
scheglovCommit Bot
authored andcommitted
RecordElement.instantiate(), substitution, type alias.
Change-Id: Icd0e234e57d17a1c86140ed58fc9732da31bf1b3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/254942 Reviewed-by: Samuel Rawlins <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 9a3bcbc commit c66faf9

File tree

7 files changed

+154
-22
lines changed

7 files changed

+154
-22
lines changed

pkg/analyzer/lib/dart/element/element.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,6 +2261,11 @@ abstract class RecordElement implements _ExistingElement {
22612261

22622262
/// The positional fields (might be empty).
22632263
List<RecordPositionalFieldElement> get positionalFields;
2264+
2265+
/// Returns [RecordType] with [nullabilitySuffix] and declared field types.
2266+
RecordType instantiate({
2267+
required NullabilitySuffix nullabilitySuffix,
2268+
});
22642269
}
22652270

22662271
/// A field in a [RecordElement].

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,22 +178,21 @@ class ElementDisplayStringBuilder {
178178
final fieldCount = positionalFields.length + namedFields.length;
179179
_write('(');
180180

181-
for (var i = 0; i < positionalFields.length; i++) {
182-
final field = positionalFields[i];
181+
var index = 0;
182+
for (final field in positionalFields) {
183183
_writeType(field.type);
184-
if (i < fieldCount - 1) {
184+
if (index++ < fieldCount - 1) {
185185
_write(', ');
186186
}
187187
}
188188

189189
if (namedFields.isNotEmpty) {
190190
_write('{');
191-
for (var i = 0; i < namedFields.length; i++) {
192-
final field = namedFields[i];
191+
for (final field in namedFields) {
193192
_writeType(field.type);
194193
_write(' ');
195194
_write(field.name);
196-
if (i < fieldCount - 1) {
195+
if (index++ < fieldCount - 1) {
197196
_write(', ');
198197
}
199198
}

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6219,6 +6219,20 @@ class RecordElementImpl extends _ExistingElementImpl implements RecordElement {
62196219
throw UnimplementedError();
62206220
}
62216221

6222+
@override
6223+
RecordTypeImpl instantiate({
6224+
required NullabilitySuffix nullabilitySuffix,
6225+
}) {
6226+
return RecordTypeImpl(
6227+
element2: this,
6228+
fieldTypes: [
6229+
...positionalFields.map((field) => field.type),
6230+
...namedFieldsSorted.map((field) => field.type),
6231+
],
6232+
nullabilitySuffix: nullabilitySuffix,
6233+
);
6234+
}
6235+
62226236
/// Returns [fields], if already sorted, or the sorted copy.
62236237
static List<RecordNamedFieldElementImpl> _sortNamedFields(
62246238
List<RecordNamedFieldElementImpl> fields,
@@ -6597,6 +6611,16 @@ class TypeAliasElementImpl extends _ExistingElementImpl
65976611
typeArguments: typeArguments,
65986612
),
65996613
);
6614+
} else if (type is RecordTypeImpl) {
6615+
return RecordTypeImpl(
6616+
element2: type.element2,
6617+
fieldTypes: type.fieldTypes,
6618+
nullabilitySuffix: resultNullability,
6619+
alias: InstantiatedTypeAliasElementImpl(
6620+
element: this,
6621+
typeArguments: typeArguments,
6622+
),
6623+
);
66006624
} else if (type is TypeParameterType) {
66016625
return TypeParameterTypeImpl(
66026626
element: type.element2,

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import 'package:analyzer/src/dart/element/type_algebra.dart';
1616
import 'package:analyzer/src/dart/element/type_system.dart';
1717
import 'package:analyzer/src/generated/element_type_provider.dart';
1818
import 'package:analyzer/src/generated/utilities_dart.dart';
19+
import 'package:collection/collection.dart';
1920

2021
/// The [Type] representing the type `dynamic`.
2122
class DynamicTypeImpl extends TypeImpl implements DynamicType {
@@ -995,16 +996,18 @@ class RecordTypeImpl extends TypeImpl implements RecordType {
995996
@override
996997
final RecordElementImpl element2;
997998

998-
final Substitution substitution;
999+
/// The types of all fields, first positional, then named.
1000+
final List<DartType> fieldTypes;
9991001

10001002
@override
10011003
final NullabilitySuffix nullabilitySuffix;
10021004

10031005
RecordTypeImpl({
10041006
required this.element2,
1005-
required this.substitution,
1007+
required this.fieldTypes,
10061008
required this.nullabilitySuffix,
1007-
}) : super(element2);
1009+
InstantiatedTypeAliasElement? alias,
1010+
}) : super(element2, alias: alias);
10081011

10091012
@override
10101013
RecordElementImpl get element => element2;
@@ -1015,23 +1018,22 @@ class RecordTypeImpl extends TypeImpl implements RecordType {
10151018

10161019
@override
10171020
List<RecordTypeNamedField> get namedFields {
1018-
return element.namedFieldsSorted.map((field) {
1019-
final type = substitution.substituteType(field.type);
1021+
final baseIndex = element.positionalFields.length;
1022+
return element.namedFieldsSorted.mapIndexed((index, field) {
10201023
return RecordTypeNamedFieldImpl(
10211024
element: field,
10221025
name: field.name,
1023-
type: type,
1026+
type: fieldTypes[baseIndex + index],
10241027
);
10251028
}).toList();
10261029
}
10271030

10281031
@override
10291032
List<RecordTypePositionalField> get positionalFields {
1030-
return element.positionalFields.map((field) {
1031-
final type = substitution.substituteType(field.type);
1033+
return element.positionalFields.mapIndexed((index, field) {
10321034
return RecordTypePositionalFieldImpl(
10331035
element: field,
1034-
type: type,
1036+
type: fieldTypes[index],
10351037
);
10361038
}).toList();
10371039
}

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -546,9 +546,20 @@ abstract class _TypeSubstitutor
546546
DartType visitNeverType(NeverType type) => type;
547547

548548
@override
549-
DartType visitRecordType(RecordType type) {
550-
// TODO: implement visitRecordType
551-
throw UnimplementedError();
549+
DartType visitRecordType(covariant RecordTypeImpl type) {
550+
final before = useCounter;
551+
final fieldTypes = _mapList(type.fieldTypes);
552+
final alias = _mapAlias(type.alias);
553+
if (useCounter == before) {
554+
return type;
555+
}
556+
557+
return RecordTypeImpl(
558+
element2: type.element2,
559+
fieldTypes: fieldTypes,
560+
nullabilitySuffix: type.nullabilitySuffix,
561+
alias: alias,
562+
);
552563
}
553564

554565
@override

pkg/analyzer/test/generated/elements_types_mixin.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import 'package:analyzer/dart/element/type_provider.dart';
1010
import 'package:analyzer/src/dart/analysis/session.dart';
1111
import 'package:analyzer/src/dart/element/element.dart';
1212
import 'package:analyzer/src/dart/element/type.dart';
13-
import 'package:analyzer/src/dart/element/type_algebra.dart';
1413
import 'package:analyzer/src/dart/element/type_system.dart';
1514
import 'package:analyzer/src/dart/resolver/variance.dart';
1615
import 'package:analyzer/src/generated/engine.dart';
@@ -592,10 +591,8 @@ mixin ElementsTypesMixin {
592591
RecordTypeImpl recordTypeNone({
593592
required RecordElementImpl element,
594593
}) {
595-
return RecordTypeImpl(
596-
element2: element,
594+
return element.instantiate(
597595
nullabilitySuffix: NullabilitySuffix.none,
598-
substitution: Substitution.empty,
599596
);
600597
}
601598

pkg/analyzer/test/src/dart/element/type_algebra_test.dart

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,100 @@ class SubstituteTest extends _Base {
377377
_assertIdenticalType(type, {T: intNone});
378378
}
379379

380+
test_record_doesNotUseTypeParameter() async {
381+
final T = typeParameter('T');
382+
383+
final type = recordTypeNone(
384+
element: recordElement(
385+
positionalFields: [
386+
recordPositionalField(type: intNone),
387+
],
388+
),
389+
);
390+
391+
assertType(type, '(int)');
392+
_assertIdenticalType(type, {T: intNone});
393+
}
394+
395+
test_record_fromAlias() async {
396+
// typedef Alias<T> = (int, String);
397+
final T = typeParameter('T');
398+
final Alias = typeAlias(
399+
name: 'Alias',
400+
typeParameters: [T],
401+
aliasedType: recordTypeNone(
402+
element: recordElement(
403+
positionalFields: [
404+
recordPositionalField(type: intNone),
405+
recordPositionalField(type: stringNone),
406+
],
407+
),
408+
),
409+
);
410+
411+
final U = typeParameter('U');
412+
final type = typeAliasTypeNone(Alias, typeArguments: [
413+
typeParameterTypeNone(U),
414+
]);
415+
assertType(type, '(int, String) via Alias<U>');
416+
_assertSubstitution(type, {U: intNone}, '(int, String) via Alias<int>');
417+
}
418+
419+
test_record_fromAlias2() async {
420+
// typedef Alias<T> = (T, List<T>);
421+
final T = typeParameter('T');
422+
final T_none = typeParameterTypeNone(T);
423+
final Alias = typeAlias(
424+
name: 'Alias',
425+
typeParameters: [T],
426+
aliasedType: recordTypeNone(
427+
element: recordElement(
428+
positionalFields: [
429+
recordPositionalField(type: T_none),
430+
recordPositionalField(type: listNone(T_none)),
431+
],
432+
),
433+
),
434+
);
435+
436+
final type = typeAliasTypeNone(Alias, typeArguments: [intNone]);
437+
assertType(type, '(int, List<int>) via Alias<int>');
438+
}
439+
440+
test_record_named() async {
441+
final T = typeParameter('T');
442+
final T_none = typeParameterTypeNone(T);
443+
444+
final type = recordTypeNone(
445+
element: recordElement(
446+
namedFields: [
447+
recordNamedField(name: 'f1', type: T_none),
448+
recordNamedField(name: 'f2', type: listNone(T_none)),
449+
],
450+
),
451+
);
452+
453+
assertType(type, '({T f1, List<T> f2})');
454+
_assertSubstitution(type, {T: intNone}, '({int f1, List<int> f2})');
455+
}
456+
457+
test_record_positional() async {
458+
final T = typeParameter('T');
459+
final T_none = typeParameterTypeNone(T);
460+
461+
final type = recordTypeNone(
462+
element: recordElement(
463+
positionalFields: [
464+
recordPositionalField(type: T_none),
465+
recordPositionalField(type: listNone(T_none)),
466+
],
467+
),
468+
);
469+
470+
assertType(type, '(T, List<T>)');
471+
_assertSubstitution(type, {T: intNone}, '(int, List<int>)');
472+
}
473+
380474
test_typeParameter_nullability() async {
381475
var tElement = typeParameter('T');
382476

0 commit comments

Comments
 (0)