Skip to content

Commit 2a4ce14

Browse files
stereotype441Commit Queue
authored andcommitted
[mini_types] Introduce _PreType class hierarchy.
The `_PreType` class (and its subclasses) mirrors the `Type` class, except that it represents types in a more raw form, before identifiers have been resolved to their associated meanings. For example, the `_PreType` representing `int` is a `_PrePrimaryType` whose `typeName` field is the string `int`, whereas the `Type` representing `int` is a `PrimaryType` whose `nameInfo` field points to the `TypeNameInfo` object representing the class `int`. Parsing of `Type` objects is now a two-step process: the string is first converted to a `_PreType`, and then the `_PreType` is materialized into a `Type` by looking up each identifier in it in the `TypeRegistry`. This will be needed in a follow-up CL that introduces support for generic function types, to support the possiblity that a generic function type's return type refers to one of its type parameters (e.g. `List<T> Function<T>()`). The reason this is will be needed is because the meaning of the return type (`List<T>`) can't be determined until the `TypeParameter` object representing the type parameter `T` has been created. Change-Id: I9f4a73bdc0f38380518a9c39db8c788234adb806 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/395686 Reviewed-by: Chloe Stefantsova <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent c65057e commit 2a4ce14

File tree

1 file changed

+205
-73
lines changed

1 file changed

+205
-73
lines changed

pkg/_fe_analyzer_shared/test/mini_types.dart

Lines changed: 205 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,181 @@ class VoidType extends _SpecialSimpleType
15671567
Type withNullability(NullabilitySuffix suffix) => this;
15681568
}
15691569

1570+
/// Representation of a [FunctionType] that has been parsed but hasn't had
1571+
/// meaning assigned to its identifiers yet.
1572+
class _PreFunctionType extends _PreType {
1573+
final _PreType returnType;
1574+
final List<_PreType> positionalParameterTypes;
1575+
final int requiredPositionalParameterCount;
1576+
final List<_PreNamedFunctionParameter> namedParameters;
1577+
1578+
_PreFunctionType(
1579+
{required this.returnType,
1580+
required this.positionalParameterTypes,
1581+
required this.requiredPositionalParameterCount,
1582+
required this.namedParameters});
1583+
1584+
@override
1585+
Type materialize() => FunctionType(
1586+
returnType.materialize(),
1587+
[
1588+
for (var positionalParameterType in positionalParameterTypes)
1589+
positionalParameterType.materialize()
1590+
],
1591+
requiredPositionalParameterCount: requiredPositionalParameterCount,
1592+
namedParameters: [
1593+
for (var namedParameter in namedParameters)
1594+
NamedFunctionParameter(
1595+
isRequired: namedParameter.isRequired,
1596+
name: namedParameter.name,
1597+
type: namedParameter.type.materialize())
1598+
]);
1599+
}
1600+
1601+
/// Representation of a named function parameter in a [_PreFunctionType].
1602+
class _PreNamedFunctionParameter {
1603+
final String name;
1604+
final _PreType type;
1605+
final bool isRequired;
1606+
1607+
_PreNamedFunctionParameter(
1608+
{required this.name, required this.type, required this.isRequired});
1609+
}
1610+
1611+
/// Representation of a named component of a [_PreRecordType].
1612+
class _PreNamedType {
1613+
final String name;
1614+
final _PreType type;
1615+
1616+
_PreNamedType({required this.name, required this.type});
1617+
}
1618+
1619+
/// Representation of a [PrimaryType] or [TypeParameterType] that has been
1620+
/// parsed but hasn't had meaning assigned to its identifiers yet.
1621+
class _PrePrimaryType extends _PreType {
1622+
final String typeName;
1623+
final List<_PreType> typeArgs;
1624+
1625+
_PrePrimaryType({required this.typeName, required this.typeArgs});
1626+
1627+
@override
1628+
Type materialize() {
1629+
var nameInfo = TypeRegistry.lookup(typeName);
1630+
switch (nameInfo) {
1631+
case TypeParameter():
1632+
if (typeArgs.isNotEmpty) {
1633+
throw ParseError('Type parameter types do not accept type arguments');
1634+
}
1635+
return TypeParameterType(nameInfo);
1636+
case InterfaceTypeName():
1637+
return PrimaryType(nameInfo,
1638+
args: [for (var typeArg in typeArgs) typeArg.materialize()]);
1639+
case SpecialTypeName():
1640+
if (typeName == 'dynamic') {
1641+
if (typeArgs.isNotEmpty) {
1642+
throw ParseError('`dynamic` does not accept type arguments');
1643+
}
1644+
return DynamicType.instance;
1645+
} else if (typeName == 'error') {
1646+
if (typeArgs.isNotEmpty) {
1647+
throw ParseError('`error` does not accept type arguments');
1648+
}
1649+
return InvalidType.instance;
1650+
} else if (typeName == 'FutureOr') {
1651+
if (typeArgs.length != 1) {
1652+
throw ParseError('`FutureOr` requires exactly one type argument');
1653+
}
1654+
return FutureOrType(typeArgs.single.materialize());
1655+
} else if (typeName == 'Never') {
1656+
if (typeArgs.isNotEmpty) {
1657+
throw ParseError('`Never` does not accept type arguments');
1658+
}
1659+
return NeverType.instance;
1660+
} else if (typeName == 'Null') {
1661+
if (typeArgs.isNotEmpty) {
1662+
throw ParseError('`Null` does not accept type arguments');
1663+
}
1664+
return NullType.instance;
1665+
} else if (typeName == 'void') {
1666+
if (typeArgs.isNotEmpty) {
1667+
throw ParseError('`void` does not accept type arguments');
1668+
}
1669+
return VoidType.instance;
1670+
} else {
1671+
throw UnimplementedError('Unknown special type name: $typeName');
1672+
}
1673+
}
1674+
}
1675+
}
1676+
1677+
/// Representation of a promoted [TypeParameterType] that has been parsed but
1678+
/// hasn't had meaning assigned to its identifiers yet.
1679+
class _PrePromotedType extends _PreType {
1680+
final _PreType inner;
1681+
final _PreType promotion;
1682+
1683+
_PrePromotedType({required this.inner, required this.promotion});
1684+
1685+
@override
1686+
Type materialize() {
1687+
var type = inner.materialize();
1688+
if (type case TypeParameterType(promotion: null)) {
1689+
return TypeParameterType(type.typeParameter,
1690+
promotion: promotion.materialize());
1691+
} else {
1692+
throw ParseError(
1693+
'The type to the left of & must be an unpromoted type parameter');
1694+
}
1695+
}
1696+
}
1697+
1698+
/// Representation of a [RecordType] that has been parsed but hasn't had
1699+
/// meaning assigned to its identifiers yet.
1700+
class _PreRecordType extends _PreType {
1701+
final List<_PreType> positionalTypes;
1702+
final List<_PreNamedType> namedTypes;
1703+
1704+
_PreRecordType({required this.positionalTypes, required this.namedTypes});
1705+
1706+
@override
1707+
Type materialize() => RecordType(positionalTypes: [
1708+
for (var positionalType in positionalTypes) positionalType.materialize()
1709+
], namedTypes: [
1710+
for (var namedType in namedTypes)
1711+
NamedType(name: namedType.name, type: namedType.type.materialize())
1712+
]);
1713+
}
1714+
1715+
/// Representation of a [Type] that has been parsed but hasn't had meaning
1716+
/// assigned to its identifiers yet.
1717+
sealed class _PreType {
1718+
/// Translates `this` into a [Type].
1719+
///
1720+
/// The meaning of identifiers in `this` is determined by looking them up in
1721+
/// the [TypeRegistry].
1722+
Type materialize();
1723+
}
1724+
1725+
/// Representation of a [Type] with a nullability suffix that has been parsed
1726+
/// but hasn't had meaning assigned to its identifiers yet.
1727+
class _PreTypeWithNullability extends _PreType {
1728+
final _PreType inner;
1729+
final NullabilitySuffix nullabilitySuffix;
1730+
1731+
_PreTypeWithNullability(
1732+
{required this.inner, required this.nullabilitySuffix});
1733+
1734+
@override
1735+
Type materialize() => inner.materialize().withNullability(nullabilitySuffix);
1736+
}
1737+
1738+
/// Representation of an [UnknownType] that has been parsed but hasn't had
1739+
/// meaning assigned to its identifiers yet.
1740+
class _PreUnknownType extends _PreType {
1741+
@override
1742+
Type materialize() => const UnknownType();
1743+
}
1744+
15701745
/// Shared implementation of the types `void`, `dynamic`, `null`, `Never`, and
15711746
/// the invalid type.
15721747
///
@@ -1628,10 +1803,10 @@ class _TypeParser {
16281803
'Error parsing type `$_typeStr` at token $_currentToken: $message');
16291804
}
16301805

1631-
List<NamedFunctionParameter> _parseNamedFunctionParameters() {
1806+
List<_PreNamedFunctionParameter> _parseNamedFunctionParameters() {
16321807
assert(_currentToken == '{');
16331808
_next();
1634-
var namedParameters = <NamedFunctionParameter>[];
1809+
var namedParameters = <_PreNamedFunctionParameter>[];
16351810
while (true) {
16361811
var isRequired = _currentToken == 'required';
16371812
if (isRequired) {
@@ -1642,7 +1817,7 @@ class _TypeParser {
16421817
if (_identifierRegexp.matchAsPrefix(name) == null) {
16431818
_parseFailure('Expected an identifier');
16441819
}
1645-
namedParameters.add(NamedFunctionParameter(
1820+
namedParameters.add(_PreNamedFunctionParameter(
16461821
name: name, type: type, isRequired: isRequired));
16471822
_next();
16481823
if (_currentToken == ',') {
@@ -1659,7 +1834,8 @@ class _TypeParser {
16591834
return namedParameters;
16601835
}
16611836

1662-
void _parseOptionalFunctionParameters(List<Type> positionalParameterTypes) {
1837+
void _parseOptionalFunctionParameters(
1838+
List<_PreType> positionalParameterTypes) {
16631839
assert(_currentToken == '[');
16641840
_next();
16651841
while (true) {
@@ -1677,17 +1853,17 @@ class _TypeParser {
16771853
_next();
16781854
}
16791855

1680-
List<NamedType> _parseRecordTypeNamedFields() {
1856+
List<_PreNamedType> _parseRecordTypeNamedFields() {
16811857
assert(_currentToken == '{');
16821858
_next();
1683-
var namedTypes = <NamedType>[];
1859+
var namedTypes = <_PreNamedType>[];
16841860
while (_currentToken != '}') {
16851861
var type = _parseType();
16861862
var name = _currentToken;
16871863
if (_identifierRegexp.matchAsPrefix(name) == null) {
16881864
_parseFailure('Expected an identifier');
16891865
}
1690-
namedTypes.add(NamedType(name: name, type: type));
1866+
namedTypes.add(_PreNamedType(name: name, type: type));
16911867
_next();
16921868
if (_currentToken == ',') {
16931869
_next();
@@ -1706,8 +1882,8 @@ class _TypeParser {
17061882
return namedTypes;
17071883
}
17081884

1709-
Type _parseRecordTypeRest(List<Type> positionalTypes) {
1710-
List<NamedType>? namedTypes;
1885+
_PreRecordType _parseRecordTypeRest(List<_PreType> positionalTypes) {
1886+
List<_PreNamedType>? namedTypes;
17111887
while (_currentToken != ')') {
17121888
if (_currentToken == '{') {
17131889
namedTypes = _parseRecordTypeNamedFields();
@@ -1727,34 +1903,31 @@ class _TypeParser {
17271903
_parseFailure('Expected `)` or `,`');
17281904
}
17291905
_next();
1730-
return RecordType(
1906+
return _PreRecordType(
17311907
positionalTypes: positionalTypes, namedTypes: namedTypes ?? const []);
17321908
}
17331909

1734-
Type? _parseSuffix(Type type) {
1910+
_PreType? _parseSuffix(_PreType type) {
17351911
if (_currentToken == '?') {
17361912
_next();
1737-
return type.withNullability(NullabilitySuffix.question);
1913+
return _PreTypeWithNullability(
1914+
inner: type, nullabilitySuffix: NullabilitySuffix.question);
17381915
} else if (_currentToken == '*') {
17391916
_next();
1740-
return type.withNullability(NullabilitySuffix.star);
1917+
return _PreTypeWithNullability(
1918+
inner: type, nullabilitySuffix: NullabilitySuffix.star);
17411919
} else if (_currentToken == '&') {
1742-
if (type case TypeParameterType(promotion: null)) {
1743-
_next();
1744-
var promotion = _parseUnsuffixedType();
1745-
return TypeParameterType(type.typeParameter, promotion: promotion);
1746-
} else {
1747-
_parseFailure(
1748-
'The type to the left of & must be an unpromoted type parameter');
1749-
}
1920+
_next();
1921+
var promotion = _parseUnsuffixedType();
1922+
return _PrePromotedType(inner: type, promotion: promotion);
17501923
} else if (_currentToken == 'Function') {
17511924
_next();
17521925
if (_currentToken != '(') {
17531926
_parseFailure('Expected `(`');
17541927
}
17551928
_next();
1756-
var positionalParameterTypes = <Type>[];
1757-
List<NamedFunctionParameter>? namedFunctionParameters;
1929+
var positionalParameterTypes = <_PreType>[];
1930+
List<_PreNamedFunctionParameter>? namedFunctionParameters;
17581931
int? requiredPositionalParameterCount;
17591932
if (_currentToken != ')') {
17601933
while (true) {
@@ -1781,7 +1954,9 @@ class _TypeParser {
17811954
}
17821955
}
17831956
_next();
1784-
return FunctionType(type, positionalParameterTypes,
1957+
return _PreFunctionType(
1958+
returnType: type,
1959+
positionalParameterTypes: positionalParameterTypes,
17851960
requiredPositionalParameterCount: requiredPositionalParameterCount ??
17861961
positionalParameterTypes.length,
17871962
namedParameters: namedFunctionParameters ?? const []);
@@ -1790,7 +1965,7 @@ class _TypeParser {
17901965
}
17911966
}
17921967

1793-
Type _parseType() {
1968+
_PreType _parseType() {
17941969
// We currently accept the following grammar for types:
17951970
// type := unsuffixedType nullability suffix*
17961971
// unsuffixedType := identifier typeArgs?
@@ -1825,10 +2000,10 @@ class _TypeParser {
18252000
return result;
18262001
}
18272002

1828-
Type _parseUnsuffixedType() {
2003+
_PreType _parseUnsuffixedType() {
18292004
if (_currentToken == '_') {
18302005
_next();
1831-
return const UnknownType();
2006+
return _PreUnknownType();
18322007
}
18332008
if (_currentToken == '(') {
18342009
_next();
@@ -1851,7 +2026,7 @@ class _TypeParser {
18512026
_parseFailure('Expected an identifier, `_`, or `(`');
18522027
}
18532028
_next();
1854-
List<Type> typeArgs;
2029+
List<_PreType> typeArgs;
18552030
if (_currentToken == '<') {
18562031
_next();
18572032
typeArgs = [];
@@ -1867,50 +2042,7 @@ class _TypeParser {
18672042
} else {
18682043
typeArgs = const [];
18692044
}
1870-
var nameInfo = TypeRegistry.lookup(typeName);
1871-
switch (nameInfo) {
1872-
case TypeParameter():
1873-
if (typeArgs.isNotEmpty) {
1874-
throw ParseError('Type parameter types do not accept type arguments');
1875-
}
1876-
return TypeParameterType(nameInfo);
1877-
case InterfaceTypeName():
1878-
return PrimaryType(nameInfo, args: typeArgs);
1879-
case SpecialTypeName():
1880-
if (typeName == 'dynamic') {
1881-
if (typeArgs.isNotEmpty) {
1882-
throw ParseError('`dynamic` does not accept type arguments');
1883-
}
1884-
return DynamicType.instance;
1885-
} else if (typeName == 'error') {
1886-
if (typeArgs.isNotEmpty) {
1887-
throw ParseError('`error` does not accept type arguments');
1888-
}
1889-
return InvalidType.instance;
1890-
} else if (typeName == 'FutureOr') {
1891-
if (typeArgs.length != 1) {
1892-
throw ParseError('`FutureOr` requires exactly one type argument');
1893-
}
1894-
return FutureOrType(typeArgs.single);
1895-
} else if (typeName == 'Never') {
1896-
if (typeArgs.isNotEmpty) {
1897-
throw ParseError('`Never` does not accept type arguments');
1898-
}
1899-
return NeverType.instance;
1900-
} else if (typeName == 'Null') {
1901-
if (typeArgs.isNotEmpty) {
1902-
throw ParseError('`Null` does not accept type arguments');
1903-
}
1904-
return NullType.instance;
1905-
} else if (typeName == 'void') {
1906-
if (typeArgs.isNotEmpty) {
1907-
throw ParseError('`void` does not accept type arguments');
1908-
}
1909-
return VoidType.instance;
1910-
} else {
1911-
throw UnimplementedError('Unknown special type name: $typeName');
1912-
}
1913-
}
2045+
return _PrePrimaryType(typeName: typeName, typeArgs: typeArgs);
19142046
}
19152047

19162048
static Type parse(String typeStr) {
@@ -1920,7 +2052,7 @@ class _TypeParser {
19202052
throw ParseError('Extra tokens after parsing type `$typeStr`: '
19212053
'${parser._tokens.sublist(parser._i, parser._tokens.length - 1)}');
19222054
}
1923-
return result;
2055+
return result.materialize();
19242056
}
19252057

19262058
static List<String> _tokenizeTypeStr(String typeStr) {

0 commit comments

Comments
 (0)