From 8f23dad9d5ca0e8886a099b89ce53a99d8a5fe98 Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Mon, 30 Sep 2024 10:23:45 +0000 Subject: [PATCH 1/5] [vm] Remove duplicated `HashMap` test TEST=removing duplicated test Change-Id: I6c0c02166d024d1569ab18cade26de232454395e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/387240 Auto-Submit: Daco Harkes Commit-Queue: Daco Harkes Reviewed-by: Tess Strickland --- runtime/bin/hashmap_test.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/runtime/bin/hashmap_test.cc b/runtime/bin/hashmap_test.cc index 4808073e9bb2..51e970408ae4 100644 --- a/runtime/bin/hashmap_test.cc +++ b/runtime/bin/hashmap_test.cc @@ -74,9 +74,6 @@ static uint32_t CollisionHash2(uint32_t key) { static uint32_t CollisionHash3(uint32_t key) { return kInitialSize - 2; } -static uint32_t CollisionHash4(uint32_t key) { - return kInitialSize - 2; -} void TestSet(IntKeyHash hash, int size) { IntSet set(hash); @@ -174,7 +171,6 @@ VM_UNIT_TEST_CASE(SimpleHashMap_Basic) { TestSet(CollisionHash1, 50); TestSet(CollisionHash2, 50); TestSet(CollisionHash3, 50); - TestSet(CollisionHash4, 50); } } // namespace dart From defce40d9d8caa0b85aa2869d569c92740fa4fe9 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Mon, 30 Sep 2024 12:21:36 +0000 Subject: [PATCH 2/5] Expand mini-ast function type representation. Mini-ast function types now support optional positional parameters and named parameters (both required and optional). This will allow more _fe_analyzer_shared functionality to be unit tested. Change-Id: I3425e0742de2bee511f2f3d303dd3ed6f26c289c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/386729 Reviewed-by: Chloe Stefantsova Commit-Queue: Paul Berry --- pkg/_fe_analyzer_shared/test/mini_ast.dart | 9 + pkg/_fe_analyzer_shared/test/mini_types.dart | 281 ++++++++++++++++-- .../test/mini_types_test.dart | 190 +++++++++++- 3 files changed, 448 insertions(+), 32 deletions(-) diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart index d9a2693ecd5b..f0b34dd909b3 100644 --- a/pkg/_fe_analyzer_shared/test/mini_ast.dart +++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart @@ -5602,6 +5602,15 @@ class _MiniAstTypeAnalyzer var methodType = _handlePropertyTargetAndMemberLookup( null, target, methodName, location: node.location); + if (methodType is FunctionType) { + if (methodType.namedParameters.isNotEmpty) { + throw UnimplementedError('Named parameters are not supported yet'); + } else if (methodType.requiredPositionalParameterCount != + methodType.positionalParameters.length) { + throw UnimplementedError( + 'Optional positional parameters are not supported yet'); + } + } // Recursively analyze each argument. var inputKinds = [Kind.expression]; for (var i = 0; i < arguments.length; i++) { diff --git a/pkg/_fe_analyzer_shared/test/mini_types.dart b/pkg/_fe_analyzer_shared/test/mini_types.dart index 60ff6c5d7029..da069bd86970 100644 --- a/pkg/_fe_analyzer_shared/test/mini_types.dart +++ b/pkg/_fe_analyzer_shared/test/mini_types.dart @@ -29,8 +29,7 @@ class DynamicType extends _SpecialSimpleType /// Representation of a function type suitable for unit testing of code in the /// `_fe_analyzer_shared` package. /// -/// Optional parameters, named parameters, and type parameters are not (yet) -/// supported. +/// Type parameters are not (yet) supported. class FunctionType extends Type { /// The return type. final Type returnType; @@ -38,9 +37,25 @@ class FunctionType extends Type { /// A list of the types of positional parameters. final List positionalParameters; + /// The number of elements of [positionalParameters] that are required + /// parameters. + final int requiredPositionalParameterCount; + + /// A list of the named parameters, sorted by name. + final List namedParameters; + FunctionType(this.returnType, this.positionalParameters, - {super.nullabilitySuffix = NullabilitySuffix.none}) - : super._(); + {int? requiredPositionalParameterCount, + this.namedParameters = const [], + super.nullabilitySuffix = NullabilitySuffix.none}) + : requiredPositionalParameterCount = + requiredPositionalParameterCount ?? positionalParameters.length, + super._() { + for (var i = 1; i < namedParameters.length; i++) { + assert(namedParameters[i - 1].name.compareTo(namedParameters[i].name) < 0, + 'namedParameters not properly sorted'); + } + } @override Type? closureWithRespectToUnknown({required bool covariant}) { @@ -48,11 +63,17 @@ class FunctionType extends Type { returnType.closureWithRespectToUnknown(covariant: covariant); List? newPositionalParameters = positionalParameters.closureWithRespectToUnknown(covariant: !covariant); - if (newReturnType == null && newPositionalParameters == null) { + List? newNamedParameters = + namedParameters.closureWithRespectToUnknown(covariant: !covariant); + if (newReturnType == null && + newPositionalParameters == null && + newNamedParameters == null) { return null; } return FunctionType(newReturnType ?? returnType, newPositionalParameters ?? positionalParameters, + requiredPositionalParameterCount: requiredPositionalParameterCount, + namedParameters: newNamedParameters ?? namedParameters, nullabilitySuffix: nullabilitySuffix); } @@ -61,22 +82,43 @@ class FunctionType extends Type { Type? newReturnType = returnType.recursivelyDemote(covariant: covariant); List? newPositionalParameters = positionalParameters.recursivelyDemote(covariant: !covariant); - if (newReturnType == null && newPositionalParameters == null) { + List? newNamedParameters = + namedParameters.recursivelyDemote(covariant: !covariant); + if (newReturnType == null && + newPositionalParameters == null && + newNamedParameters == null) { return null; } return FunctionType(newReturnType ?? returnType, newPositionalParameters ?? positionalParameters, + requiredPositionalParameterCount: requiredPositionalParameterCount, + namedParameters: newNamedParameters ?? namedParameters, nullabilitySuffix: nullabilitySuffix); } @override Type withNullability(NullabilitySuffix suffix) => - FunctionType(returnType, positionalParameters, nullabilitySuffix: suffix); + FunctionType(returnType, positionalParameters, + requiredPositionalParameterCount: requiredPositionalParameterCount, + namedParameters: namedParameters, + nullabilitySuffix: suffix); @override - String _toStringWithoutSuffix({required bool parenthesizeIfComplex}) => - _parenthesizeIf(parenthesizeIfComplex, - '$returnType Function(${positionalParameters.join(', ')})'); + String _toStringWithoutSuffix({required bool parenthesizeIfComplex}) { + var parameters = [ + ...positionalParameters.sublist(0, requiredPositionalParameterCount) + ]; + if (requiredPositionalParameterCount < positionalParameters.length) { + var optionalPositionalParameters = + positionalParameters.sublist(requiredPositionalParameterCount); + parameters.add('[${optionalPositionalParameters.join(', ')}]'); + } + if (namedParameters.isNotEmpty) { + parameters.add('{${namedParameters.join(', ')}}'); + } + return _parenthesizeIf(parenthesizeIfComplex, + '$returnType Function(${parameters.join(', ')})'); + } } /// Representation of the type `FutureOr` suitable for unit testing of code @@ -120,6 +162,17 @@ class InvalidType extends _SpecialSimpleType Type withNullability(NullabilitySuffix suffix) => this; } +/// A named parameter of a function type. +class NamedFunctionParameter extends NamedType { + final bool isRequired; + + NamedFunctionParameter( + {required this.isRequired, required super.name, required super.type}); + + @override + String toString() => [if (isRequired) 'required', type, name].join(' '); +} + class NamedType implements SharedNamedTypeStructure { @override final String name; @@ -802,16 +855,15 @@ class TypeSystem { bool isPositionalFunctionSubtype() { // Positional Function Types: T0 is U0 Function(V0 x0, ..., Vn xn, [Vn+1 xn+1, ..., Vm xm]) - if (t0 is! FunctionType) return false; - var n = t0.positionalParameters.length; - // (Note: we don't support optional parameters) - var m = n; + if (t0 is! FunctionType || t0.namedParameters.isNotEmpty) return false; + var n = t0.requiredPositionalParameterCount; + var m = t0.positionalParameters.length; // - and T1 is U1 Function(S0 y0, // ..., Sp yp, [Sp+1 yp+1, ..., Sq yq]) - if (t1 is! FunctionType) return false; - var p = t1.positionalParameters.length; - var q = p; + if (t1 is! FunctionType || t1.namedParameters.isNotEmpty) return false; + var p = t1.requiredPositionalParameterCount; + var q = t1.positionalParameters.length; // - and p >= n if (p < n) return false; @@ -847,24 +899,78 @@ class TypeSystem { // Named Function Types: T0 is U0 Function(V0 x0, ..., Vn xn, {r0n+1 Vn+1 xn+1, ..., r0m Vm xm}) where r0j is // empty or required for j in n+1...m - // + if (t0 is! FunctionType) return false; + var n = t0.positionalParameters.length; + if (t0.requiredPositionalParameterCount != n) return false; + // - and T1 is U1 Function(S0 y0, // ..., Sn yn, {r1n+1 Sn+1 yn+1, ..., r1q Sq yq}) where r1j is empty or // required for j in n+1...q + if (t1 is! FunctionType || + t1.positionalParameters.length != n || + t1.requiredPositionalParameterCount != n) { + return false; + } + // - and {yn+1, ... , yq} subsetof {xn+1, ... , xm} + var t1IndexToT0Index = []; + for (var i = 0, j = 0; + i < t0.namedParameters.length || j < t1.namedParameters.length;) { + if (i >= t0.namedParameters.length) break; + if (j >= t1.namedParameters.length) return false; + switch ( + t0.namedParameters[i].name.compareTo(t1.namedParameters[j].name)) { + case < 0: + i++; + case > 0: + return false; + default: // == 0 + t1IndexToT0Index.add(i); + i++; + j++; + } + } + + // (Note: no substitution is needed in the code below; we don't support + // type arguments on function types) + // - and Si[Z0/Y0, ..., Zk/Yk] <: Vi[Z0/X0, ..., Zk/Xk] for i in 0...n + for (var i = 0; i < n; i++) { + if (!isSubtype( + t1.positionalParameters[i], t0.positionalParameters[i])) { + return false; + } + } + // - and Si[Z0/Y0, ..., Zk/Yk] <: Tj[Z0/X0, ..., Zk/Xk] for i in n+1...q, // yj = xi + for (var j = 0; j < t1IndexToT0Index.length; j++) { + var i = t1IndexToT0Index[j]; + if (!isSubtype( + t1.namedParameters[j].type, t0.namedParameters[i].type)) { + return false; + } + } + // - and for each j such that r0j is required, then there exists an i in // n+1...q such that xj = yi, and r1i is required + for (var j = 0; j < t1IndexToT0Index.length; j++) { + var i = t1IndexToT0Index[j]; + if (t1.namedParameters[j].isRequired && + !t0.namedParameters[i].isRequired) { + return false; + } + } + // - and U0[Z0/X0, ..., Zk/Xk] <: U1[Z0/Y0, ..., Zk/Yk] + if (!isSubtype(t0.returnType, t1.returnType)) return false; + // - and B0i[Z0/X0, ..., Zk/Xk] === B1i[Z0/Y0, ..., Zk/Yk] for i in 0...k // - where the Zi are fresh type variables with bounds B0i[Z0/X0, ..., // Zk/Xk] - - // Note: nothing to do here; we don't support named arguments on function - // types. - return false; + // (No check needed here since we don't support type arguments on function + // types) + return true; } if (isNamedFunctionSubtype()) return true; @@ -981,7 +1087,7 @@ abstract class _SpecialSimpleType extends PrimaryType { class _TypeParser { static final _typeTokenizationRegexp = - RegExp(_identifierPattern + r'|\(|\)|<|>|,|\?|\*|&|{|}'); + RegExp(_identifierPattern + r'|\(|\)|<|>|,|\?|\*|&|{|}|\[|\]'); static const _identifierPattern = '[_a-zA-Z][_a-zA-Z0-9]*'; @@ -1006,6 +1112,55 @@ class _TypeParser { 'Error parsing type `$_typeStr` at token $_currentToken: $message'); } + List _parseNamedFunctionParameters() { + assert(_currentToken == '{'); + _next(); + var namedParameters = []; + while (true) { + var isRequired = _currentToken == 'required'; + if (isRequired) { + _next(); + } + var type = _parseType(); + var name = _currentToken; + if (_identifierRegexp.matchAsPrefix(name) == null) { + _parseFailure('Expected an identifier'); + } + namedParameters.add(NamedFunctionParameter( + name: name, type: type, isRequired: isRequired)); + _next(); + if (_currentToken == ',') { + _next(); + continue; + } + if (_currentToken == '}') { + break; + } + _parseFailure('Expected `}` or `,`'); + } + _next(); + namedParameters.sort((a, b) => a.name.compareTo(b.name)); + return namedParameters; + } + + void _parseOptionalFunctionParameters(List positionalParameterTypes) { + assert(_currentToken == '['); + _next(); + while (true) { + var type = _parseType(); + positionalParameterTypes.add(type); + if (_currentToken == ',') { + _next(); + continue; + } + if (_currentToken == ']') { + break; + } + _parseFailure('Expected `]` or `,`'); + } + _next(); + } + List _parseRecordTypeNamedFields() { assert(_currentToken == '{'); _next(); @@ -1076,10 +1231,26 @@ class _TypeParser { _parseFailure('Expected `(`'); } _next(); - var parameterTypes = []; + var positionalParameterTypes = []; + List? namedFunctionParameters; + int? requiredPositionalParameterCount; if (_currentToken != ')') { while (true) { - parameterTypes.add(_parseType()); + if (_currentToken == '{') { + namedFunctionParameters = _parseNamedFunctionParameters(); + if (_currentToken != ')') { + _parseFailure('Expected `)`'); + } + break; + } else if (_currentToken == '[') { + requiredPositionalParameterCount = positionalParameterTypes.length; + _parseOptionalFunctionParameters(positionalParameterTypes); + if (_currentToken != ')') { + _parseFailure('Expected `)`'); + } + break; + } + positionalParameterTypes.add(_parseType()); if (_currentToken == ')') break; if (_currentToken != ',') { _parseFailure('Expected `,` or `)`'); @@ -1088,7 +1259,10 @@ class _TypeParser { } } _next(); - return FunctionType(type, parameterTypes); + return FunctionType(type, positionalParameterTypes, + requiredPositionalParameterCount: requiredPositionalParameterCount ?? + positionalParameterTypes.length, + namedParameters: namedFunctionParameters ?? const []); } else { return null; } @@ -1110,9 +1284,15 @@ class _TypeParser { // typeArgs := `<` type (`,` type)* `>` // nullability := (`?` | `*`)? // suffix := `Function` `(` type (`,` type)* `)` + // | `Function` `(` (type `,`)* namedFunctionParameters `)` + // | `Function` `(` (type `,`)* optionalFunctionParameters `)` // | `?` // | `*` // | `&` unsuffixedType + // namedFunctionParameters := `{` namedFunctionParameter + // (`,` namedFunctionParameter)* `}` + // namedFunctionParameter := `required`? type identifier + // optionalFunctionParameters := `[` type (`,` type)* `]` // TODO(paulberry): support more syntax if needed var result = _parseUnsuffixedType(); while (true) { @@ -1232,6 +1412,55 @@ class _TypeParser { } } +extension on List { + /// Calls [Type.closureWithRespectToUnknown] to translate every list member + /// into a type that doesn't involve the unknown type (`_`). If no type would + /// be changed by this operation, returns `null`. + List? closureWithRespectToUnknown( + {required bool covariant}) { + List? newList; + for (int i = 0; i < length; i++) { + NamedFunctionParameter namedFunctionParameter = this[i]; + Type? newType = namedFunctionParameter.type + .closureWithRespectToUnknown(covariant: covariant); + if (newList == null) { + if (newType == null) continue; + newList = sublist(0, i); + } + newList.add(newType == null + ? namedFunctionParameter + : NamedFunctionParameter( + isRequired: namedFunctionParameter.isRequired, + name: namedFunctionParameter.name, + type: newType)); + } + return newList; + } + + /// Calls [Type.recursivelyDemote] to translate every list member into a type + /// that doesn't involve any type promotion. If no type would be changed by + /// this operation, returns `null`. + List? recursivelyDemote({required bool covariant}) { + List? newList; + for (int i = 0; i < length; i++) { + NamedFunctionParameter namedFunctionParameter = this[i]; + Type? newType = + namedFunctionParameter.type.recursivelyDemote(covariant: covariant); + if (newList == null) { + if (newType == null) continue; + newList = sublist(0, i); + } + newList.add(newType == null + ? namedFunctionParameter + : NamedFunctionParameter( + isRequired: namedFunctionParameter.isRequired, + name: namedFunctionParameter.name, + type: newType)); + } + return newList; + } +} + extension on List { /// Calls [Type.closureWithRespectToUnknown] to translate every list member /// into a type that doesn't involve the unknown type (`_`). If no type would diff --git a/pkg/_fe_analyzer_shared/test/mini_types_test.dart b/pkg/_fe_analyzer_shared/test/mini_types_test.dart index 4dc17bee0fc1..b7cfa2ec0bda 100644 --- a/pkg/_fe_analyzer_shared/test/mini_types_test.dart +++ b/pkg/_fe_analyzer_shared/test/mini_types_test.dart @@ -10,11 +10,54 @@ import 'mini_types.dart'; main() { group('toString:', () { group('FunctionType:', () { - test('basic', () { + group('positional parameters:', () { + test('all required', () { + expect( + FunctionType( + PrimaryType('T'), [PrimaryType('U'), PrimaryType('V')]) + .toString(), + 'T Function(U, V)'); + }); + + test('all optional', () { + expect( + FunctionType( + PrimaryType('T'), [PrimaryType('U'), PrimaryType('V')], + requiredPositionalParameterCount: 0) + .toString(), + 'T Function([U, V])'); + }); + + test('mixed required and optional', () { + expect( + FunctionType( + PrimaryType('T'), [PrimaryType('U'), PrimaryType('V')], + requiredPositionalParameterCount: 1) + .toString(), + 'T Function(U, [V])'); + }); + }); + + test('named parameters', () { expect( - FunctionType(PrimaryType('T'), [PrimaryType('U'), PrimaryType('V')]) - .toString(), - 'T Function(U, V)'); + FunctionType(PrimaryType('T'), [], namedParameters: [ + NamedFunctionParameter( + isRequired: false, type: PrimaryType('U'), name: 'x'), + NamedFunctionParameter( + isRequired: true, type: PrimaryType('V'), name: 'y') + ]).toString(), + 'T Function({U x, required V y})'); + }); + + test('positional and named parameters', () { + expect( + FunctionType(PrimaryType('T'), [ + PrimaryType('U') + ], namedParameters: [ + NamedFunctionParameter( + isRequired: false, type: PrimaryType('V'), name: 'y') + ]).toString(), + 'T Function(U, {V y})'); }); test('needs parentheses', () { @@ -270,21 +313,98 @@ main() { var t = Type('int Function()') as FunctionType; expect(t.returnType.type, 'int'); expect(t.positionalParameters, isEmpty); + expect(t.requiredPositionalParameterCount, 0); + expect(t.namedParameters, isEmpty); }); - test('positional parameter', () { + test('required positional parameter', () { var t = Type('int Function(String)') as FunctionType; expect(t.returnType.type, 'int'); expect(t.positionalParameters, hasLength(1)); expect(t.positionalParameters[0].type, 'String'); + expect(t.requiredPositionalParameterCount, 1); + expect(t.namedParameters, isEmpty); }); - test('positional parameters', () { + test('required positional parameters', () { var t = Type('int Function(String, double)') as FunctionType; expect(t.returnType.type, 'int'); expect(t.positionalParameters, hasLength(2)); expect(t.positionalParameters[0].type, 'String'); expect(t.positionalParameters[1].type, 'double'); + expect(t.requiredPositionalParameterCount, 2); + expect(t.namedParameters, isEmpty); + }); + + test('optional positional parameter', () { + var t = Type('int Function([String])') as FunctionType; + expect(t.returnType.type, 'int'); + expect(t.positionalParameters, hasLength(1)); + expect(t.positionalParameters[0].type, 'String'); + expect(t.requiredPositionalParameterCount, 0); + expect(t.namedParameters, isEmpty); + }); + + test('optional positional parameters', () { + var t = Type('int Function([String, double])') as FunctionType; + expect(t.returnType.type, 'int'); + expect(t.positionalParameters, hasLength(2)); + expect(t.positionalParameters[0].type, 'String'); + expect(t.positionalParameters[1].type, 'double'); + expect(t.requiredPositionalParameterCount, 0); + expect(t.namedParameters, isEmpty); + }); + + group('named parameter:', () { + test('not required', () { + var t = Type('int Function({String x})') as FunctionType; + expect(t.returnType.type, 'int'); + expect(t.positionalParameters, isEmpty); + expect(t.requiredPositionalParameterCount, 0); + expect(t.namedParameters, hasLength(1)); + expect(t.namedParameters[0].isRequired, false); + expect(t.namedParameters[0].type.type, 'String'); + expect(t.namedParameters[0].name, 'x'); + }); + + test('required', () { + var t = Type('int Function({required String x})') as FunctionType; + expect(t.returnType.type, 'int'); + expect(t.positionalParameters, isEmpty); + expect(t.requiredPositionalParameterCount, 0); + expect(t.namedParameters, hasLength(1)); + expect(t.namedParameters[0].isRequired, true); + expect(t.namedParameters[0].type.type, 'String'); + expect(t.namedParameters[0].name, 'x'); + }); + }); + + test('named parameters', () { + var t = Type('int Function({String x, double y})') as FunctionType; + expect(t.returnType.type, 'int'); + expect(t.positionalParameters, isEmpty); + expect(t.requiredPositionalParameterCount, 0); + expect(t.namedParameters, hasLength(2)); + expect(t.namedParameters[0].isRequired, false); + expect(t.namedParameters[0].type.type, 'String'); + expect(t.namedParameters[0].name, 'x'); + expect(t.namedParameters[1].isRequired, false); + expect(t.namedParameters[1].type.type, 'double'); + expect(t.namedParameters[1].name, 'y'); + }); + + test('named parameter sorting', () { + var t = Type('int Function({double y, String x})') as FunctionType; + expect(t.returnType.type, 'int'); + expect(t.positionalParameters, isEmpty); + expect(t.requiredPositionalParameterCount, 0); + expect(t.namedParameters, hasLength(2)); + expect(t.namedParameters[0].isRequired, false); + expect(t.namedParameters[0].type.type, 'String'); + expect(t.namedParameters[0].name, 'x'); + expect(t.namedParameters[1].isRequired, false); + expect(t.namedParameters[1].type.type, 'double'); + expect(t.namedParameters[1].name, 'y'); }); test('invalid parameter separator', () { @@ -454,6 +574,35 @@ main() { 'void Function(T, String)'); }); }); + + group('named parameters:', () { + test('unchanged', () { + expect( + Type('void Function({int x, String y})') + .recursivelyDemote(covariant: true), + isNull); + expect( + Type('void Function({int x, String y})') + .recursivelyDemote(covariant: false), + isNull); + }); + + test('covariant', () { + expect( + Type('void Function({T&int x, String y})') + .recursivelyDemote(covariant: true)! + .type, + 'void Function({Never x, String y})'); + }); + + test('contravariant', () { + expect( + Type('void Function({T&int x, String y})') + .recursivelyDemote(covariant: false)! + .type, + 'void Function({T x, String y})'); + }); + }); }); group('NonFunctionType', () { @@ -641,6 +790,35 @@ main() { 'void Function(Object?, String)'); }); }); + + group('named parameters:', () { + test('unchanged', () { + expect( + Type('void Function({int x, String y})') + .closureWithRespectToUnknown(covariant: true), + isNull); + expect( + Type('void Function({int x, String y})') + .closureWithRespectToUnknown(covariant: false), + isNull); + }); + + test('covariant', () { + expect( + Type('void Function({_ x, String y})') + .closureWithRespectToUnknown(covariant: true)! + .type, + 'void Function({Never x, String y})'); + }); + + test('contravariant', () { + expect( + Type('void Function({_ x, String y})') + .closureWithRespectToUnknown(covariant: false)! + .type, + 'void Function({Object? x, String y})'); + }); + }); }); group('NonFunctionType', () { From fa3dfe924a64e75ef0c94d25bb2f37c079adad85 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Mon, 30 Sep 2024 12:51:22 +0000 Subject: [PATCH 3/5] Sort declarations in _fe_analyzer_shared files. No functional change. Change-Id: I0f98137e9c358e70f7f12124b31c2deeaf569530 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/387342 Commit-Queue: Paul Berry Reviewed-by: Chloe Stefantsova --- .../type_analyzer_operations.dart | 836 +++++++++--------- .../src/type_inference/type_constraint.dart | 80 +- .../lib/src/types/shared_type.dart | 90 +- 3 files changed, 503 insertions(+), 503 deletions(-) diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart index 774c1877df5b..6ef9a1326b74 100644 --- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart +++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart @@ -63,16 +63,6 @@ abstract interface class TypeAnalyzerOperations< SharedTypeView futureType( SharedTypeView argumentType); - /// Returns the type schema `Future` with omitted nullability and type - /// argument [argumentTypeSchema]. - /// - /// The concrete classes implementing [TypeAnalyzerOperations] should mix in - /// [TypeAnalyzerOperationsMixin] and implement [futureTypeInternal] to - /// receive a concrete implementation of [futureTypeSchema] instead of - /// implementing [futureTypeSchema] directly. - SharedTypeSchemaView futureTypeSchema( - SharedTypeSchemaView argumentTypeSchema); - /// [futureTypeInternal] should be implemented by concrete classes /// implementing [TypeAnalyzerOperations]. The implementations of [futureType] /// and [futureTypeSchema] are provided by mixing in @@ -98,6 +88,16 @@ abstract interface class TypeAnalyzerOperations< /// step too. TypeStructure futureTypeInternal(TypeStructure typeStructure); + /// Returns the type schema `Future` with omitted nullability and type + /// argument [argumentTypeSchema]. + /// + /// The concrete classes implementing [TypeAnalyzerOperations] should mix in + /// [TypeAnalyzerOperationsMixin] and implement [futureTypeInternal] to + /// receive a concrete implementation of [futureTypeSchema] instead of + /// implementing [futureTypeSchema] directly. + SharedTypeSchemaView futureTypeSchema( + SharedTypeSchemaView argumentTypeSchema); + /// If [type] was introduced by a class, mixin, enum, or extension type, /// returns a [TypeDeclarationKind] indicating what kind of thing it was /// introduced by. Otherwise, returns `null`. @@ -108,6 +108,8 @@ abstract interface class TypeAnalyzerOperations< TypeDeclarationKind? getTypeDeclarationKind( SharedTypeView type); + TypeDeclarationKind? getTypeDeclarationKindInternal(TypeStructure type); + /// Returns variance for of the type parameter at index [parameterIndex] in /// [typeDeclaration]. Variance getTypeParameterVariance( @@ -125,8 +127,6 @@ abstract interface class TypeAnalyzerOperations< TypeDeclarationKind? getTypeSchemaDeclarationKind( SharedTypeSchemaView typeSchema); - TypeDeclarationKind? getTypeDeclarationKindInternal(TypeStructure type); - /// Computes the greatest lower bound of [type1] and [type2]. /// /// The concrete classes implementing [TypeAnalyzerOperations] should mix in @@ -135,16 +135,6 @@ abstract interface class TypeAnalyzerOperations< SharedTypeView glb( SharedTypeView type1, SharedTypeView type2); - /// Computes the greatest lower bound of [typeSchema1] and [typeSchema2]. - /// - /// The concrete classes implementing [TypeAnalyzerOperations] should mix in - /// [TypeAnalyzerOperationsMixin] and implement [glbInternal] to receive a - /// concrete implementation of [typeSchemaGlb] instead of implementing - /// [typeSchemaGlb] directly. - SharedTypeSchemaView typeSchemaGlb( - SharedTypeSchemaView typeSchema1, - SharedTypeSchemaView typeSchema2); - /// [glbInternal] should be implemented by concrete classes implementing /// [TypeAnalyzerOperations]. The implementations of [glb] and [typeSchemaGlb] /// are provided by mixing in [TypeAnalyzerOperationsMixin], which defines @@ -200,6 +190,9 @@ abstract interface class TypeAnalyzerOperations< /// type `X`. bool isInterfaceType(SharedTypeView type); + @override + bool isNever(SharedTypeView type); + /// Returns `true` if `Null` is not a subtype of all types matching /// [typeSchema]. /// @@ -214,6 +207,16 @@ abstract interface class TypeAnalyzerOperations< /// `false` for `Object?` and `Object*`. bool isObject(SharedTypeView type); + /// The concrete classes implementing [TypeAnalyzerOperations] should + /// implement [isSubtypeOfInternal] in order to receive the implementations of + /// [typeIsSubtypeOfTypeSchema], [typeSchemaIsSubtypeOfType], and + /// [typeSchemaIsSubtypeOfTypeSchema] by mixing in + /// [TypeAnalyzerOperationsMixin]. + bool isSubtypeOfInternal(TypeStructure left, TypeStructure right); + + @override + bool isTypeParameterType(SharedTypeView type); + /// Returns `true` if the type [type] satisfies the type schema [typeSchema]. bool isTypeSchemaSatisfied( {required SharedTypeSchemaView typeSchema, @@ -235,15 +238,6 @@ abstract interface class TypeAnalyzerOperations< SharedTypeView listType( SharedTypeView elementType); - /// Returns the type schema `List`, with type argument [elementTypeSchema]. - /// - /// The concrete classes implementing [TypeAnalyzerOperations] should mix in - /// [TypeAnalyzerOperationsMixin] and implement [listTypeInternal] to receive - /// a concrete implementation of [listTypeSchema] instead of implementing - /// [listTypeSchema] directly. - SharedTypeSchemaView listTypeSchema( - SharedTypeSchemaView elementTypeSchema); - /// [listTypeInternal] should be implemented by concrete classes implementing /// [TypeAnalyzerOperations]. The implementations of [listType] and /// [listTypeSchema] are provided by mixing in [TypeAnalyzerOperationsMixin], @@ -268,6 +262,15 @@ abstract interface class TypeAnalyzerOperations< /// step too. TypeStructure listTypeInternal(TypeStructure elementType); + /// Returns the type schema `List`, with type argument [elementTypeSchema]. + /// + /// The concrete classes implementing [TypeAnalyzerOperations] should mix in + /// [TypeAnalyzerOperationsMixin] and implement [listTypeInternal] to receive + /// a concrete implementation of [listTypeSchema] instead of implementing + /// [listTypeSchema] directly. + SharedTypeSchemaView listTypeSchema( + SharedTypeSchemaView elementTypeSchema); + /// Computes the least upper bound of [type1] and [type2]. /// /// The concrete classes implementing [TypeAnalyzerOperations] should mix in @@ -276,16 +279,6 @@ abstract interface class TypeAnalyzerOperations< SharedTypeView lub( SharedTypeView type1, SharedTypeView type2); - /// Computes the least upper bound of [typeSchema1] and [typeSchema2]. - /// - /// The concrete classes implementing [TypeAnalyzerOperations] should mix in - /// [TypeAnalyzerOperationsMixin] and implement [lubInternal] to receive a - /// concrete implementation of [typeSchemaLub] instead of implementing - /// [typeSchemaLub] directly. - SharedTypeSchemaView typeSchemaLub( - SharedTypeSchemaView typeSchema1, - SharedTypeSchemaView typeSchema2); - /// [lubInternal] should be implemented by concrete classes implementing /// [TypeAnalyzerOperations]. The implementations of [lub] and [typeSchemaLub] /// are provided by mixing in [TypeAnalyzerOperationsMixin], which defines @@ -318,15 +311,6 @@ abstract interface class TypeAnalyzerOperations< SharedTypeView makeNullable( SharedTypeView type); - /// Computes the nullable form of [typeSchema]. - /// - /// The concrete classes implementing [TypeAnalyzerOperations] should mix in - /// [TypeAnalyzerOperationsMixin] and implement [makeNullableInternal] to - /// receive a concrete implementation of [makeTypeSchemaNullable] instead of - /// implementing [makeTypeSchemaNullable] directly. - SharedTypeSchemaView makeTypeSchemaNullable( - SharedTypeSchemaView typeSchema); - /// [makeNullableInternal] should be implemented by concrete classes /// implementing [TypeAnalyzerOperations]. The implementations of /// [makeNullable] and [makeTypeSchemaNullable] are provided by mixing in @@ -352,6 +336,15 @@ abstract interface class TypeAnalyzerOperations< /// step too. TypeStructure makeNullableInternal(TypeStructure type); + /// Computes the nullable form of [typeSchema]. + /// + /// The concrete classes implementing [TypeAnalyzerOperations] should mix in + /// [TypeAnalyzerOperationsMixin] and implement [makeNullableInternal] to + /// receive a concrete implementation of [makeTypeSchemaNullable] instead of + /// implementing [makeTypeSchemaNullable] directly. + SharedTypeSchemaView makeTypeSchemaNullable( + SharedTypeSchemaView typeSchema); + /// Returns the type `Map`, with type arguments. /// /// The concrete classes implementing [TypeAnalyzerOperations] should mix in @@ -363,18 +356,6 @@ abstract interface class TypeAnalyzerOperations< required SharedTypeView valueType, }); - /// Returns the type schema `Map`, with type arguments [keyTypeSchema] and - /// [valueTypeSchema]. - /// - /// The concrete classes implementing [TypeAnalyzerOperations] should mix in - /// [TypeAnalyzerOperationsMixin] and implement [mapTypeInternal] to receive a - /// concrete implementation of [makeTypeSchemaNullable] instead of - /// implementing [makeTypeSchemaNullable] directly. - SharedTypeSchemaView mapTypeSchema({ - required SharedTypeSchemaView keyTypeSchema, - required SharedTypeSchemaView valueTypeSchema, - }); - /// [mapTypeInternal] should be implemented by concrete classes implementing /// [TypeAnalyzerOperations]. The implementations of [mapType] and /// [makeTypeSchemaNullable] are provided by mixing in @@ -403,6 +384,18 @@ abstract interface class TypeAnalyzerOperations< required TypeStructure valueType, }); + /// Returns the type schema `Map`, with type arguments [keyTypeSchema] and + /// [valueTypeSchema]. + /// + /// The concrete classes implementing [TypeAnalyzerOperations] should mix in + /// [TypeAnalyzerOperationsMixin] and implement [mapTypeInternal] to receive a + /// concrete implementation of [makeTypeSchemaNullable] instead of + /// implementing [makeTypeSchemaNullable] directly. + SharedTypeSchemaView mapTypeSchema({ + required SharedTypeSchemaView keyTypeSchema, + required SharedTypeSchemaView valueTypeSchema, + }); + /// If [type] takes the form `FutureOr`, `FutureOr?`, or `FutureOr*` /// for some `T`, returns the type `T`. Otherwise returns `null`. /// @@ -413,17 +406,6 @@ abstract interface class TypeAnalyzerOperations< SharedTypeView? matchFutureOr( SharedTypeView type); - /// If [typeSchema] takes the form `FutureOr`, `FutureOr?`, or - /// `FutureOr*` for some `T`, returns the type schema `T`. Otherwise - /// returns `null`. - /// - /// The concrete classes implementing [TypeAnalyzerOperations] should mix in - /// [TypeAnalyzerOperationsMixin] and implement [matchFutureOrInternal] to - /// receive a concrete implementation of [matchTypeSchemaFutureOr] instead of - /// implementing [matchTypeSchemaFutureOr] directly. - SharedTypeSchemaView? matchTypeSchemaFutureOr( - SharedTypeSchemaView typeSchema); - /// [matchFutureOrInternal] should be implemented by concrete classes /// implementing [TypeAnalyzerOperations]. The implementations of /// [matchFutureOr] and [matchTypeSchemaFutureOr] are provided by mixing in @@ -471,16 +453,6 @@ abstract interface class TypeAnalyzerOperations< SharedTypeView? matchIterableType( SharedTypeView type); - /// If [typeSchema] is the type schema `Iterable?` (or a subtype thereof), - /// for some `T`, returns the type `T`. Otherwise returns `null`. - /// - /// The concrete classes implementing [TypeAnalyzerOperations] should mix in - /// [TypeAnalyzerOperationsMixin] and implement [matchIterableTypeInternal] to - /// receive a concrete implementation of [matchIterableTypeSchema] instead of - /// implementing [matchIterableTypeSchema] directly. - SharedTypeSchemaView? matchIterableTypeSchema( - SharedTypeSchemaView typeSchema); - /// [matchIterableTypeInternal] should be implemented by concrete classes /// implementing [TypeAnalyzerOperations]. The implementations of /// [matchIterableType] and [matchIterableTypeSchema] are provided by mixing @@ -506,6 +478,16 @@ abstract interface class TypeAnalyzerOperations< /// the abstraction step too. TypeStructure? matchIterableTypeInternal(TypeStructure type); + /// If [typeSchema] is the type schema `Iterable?` (or a subtype thereof), + /// for some `T`, returns the type `T`. Otherwise returns `null`. + /// + /// The concrete classes implementing [TypeAnalyzerOperations] should mix in + /// [TypeAnalyzerOperationsMixin] and implement [matchIterableTypeInternal] to + /// receive a concrete implementation of [matchIterableTypeSchema] instead of + /// implementing [matchIterableTypeSchema] directly. + SharedTypeSchemaView? matchIterableTypeSchema( + SharedTypeSchemaView typeSchema); + /// If [type] is a subtype of the type `List?` for some `T`, returns the /// type `T`. Otherwise returns `null`. SharedTypeView? matchListType( @@ -533,11 +515,26 @@ abstract interface class TypeAnalyzerOperations< TypeStructure>? matchTypeDeclarationType(SharedTypeView type); + /// If [typeSchema] takes the form `FutureOr`, `FutureOr?`, or + /// `FutureOr*` for some `T`, returns the type schema `T`. Otherwise + /// returns `null`. + /// + /// The concrete classes implementing [TypeAnalyzerOperations] should mix in + /// [TypeAnalyzerOperationsMixin] and implement [matchFutureOrInternal] to + /// receive a concrete implementation of [matchTypeSchemaFutureOr] instead of + /// implementing [matchTypeSchemaFutureOr] directly. + SharedTypeSchemaView? matchTypeSchemaFutureOr( + SharedTypeSchemaView typeSchema); + /// Computes `NORM` of [type]. /// https://github.com/dart-lang/language /// See `resources/type-system/normalization.md` SharedTypeView normalize(SharedTypeView type); + @override + SharedTypeView promoteToNonNull( + SharedTypeView type); + /// Builds the client specific record type. /// /// The concrete classes implementing [TypeAnalyzerOperations] should mix in @@ -548,16 +545,6 @@ abstract interface class TypeAnalyzerOperations< {required List> positional, required List<(String, SharedTypeView)> named}); - /// Builds the client specific record type schema. - /// - /// The concrete classes implementing [TypeAnalyzerOperations] should mix in - /// [TypeAnalyzerOperationsMixin] and implement [recordTypeInternal] to - /// receive a concrete implementation of [recordTypeSchema] instead of - /// implementing [recordTypeSchema] directly. - SharedTypeSchemaView recordTypeSchema( - {required List> positional, - required List<(String, SharedTypeSchemaView)> named}); - /// [recordTypeInternal] should be implemented by concrete classes /// implementing [TypeAnalyzerOperations]. The implementations of [recordType] /// and [recordTypeSchema] are provided by mixing in @@ -585,10 +572,24 @@ abstract interface class TypeAnalyzerOperations< {required List positional, required List<(String, TypeStructure)> named}); + /// Builds the client specific record type schema. + /// + /// The concrete classes implementing [TypeAnalyzerOperations] should mix in + /// [TypeAnalyzerOperationsMixin] and implement [recordTypeInternal] to + /// receive a concrete implementation of [recordTypeSchema] instead of + /// implementing [recordTypeSchema] directly. + SharedTypeSchemaView recordTypeSchema( + {required List> positional, + required List<(String, SharedTypeSchemaView)> named}); + /// Returns the type schema `Stream`, with type argument [elementTypeSchema]. SharedTypeSchemaView streamTypeSchema( SharedTypeSchemaView elementTypeSchema); + @override + SharedTypeView? tryPromoteToType( + SharedTypeView to, SharedTypeView from); + /// Returns `true` if [leftType] is a subtype of the greatest closure of /// [rightSchema]. /// @@ -605,6 +606,16 @@ abstract interface class TypeAnalyzerOperations< bool typeIsSubtypeOfTypeSchema(SharedTypeView leftType, SharedTypeSchemaView rightSchema); + /// Computes the greatest lower bound of [typeSchema1] and [typeSchema2]. + /// + /// The concrete classes implementing [TypeAnalyzerOperations] should mix in + /// [TypeAnalyzerOperationsMixin] and implement [glbInternal] to receive a + /// concrete implementation of [typeSchemaGlb] instead of implementing + /// [typeSchemaGlb] directly. + SharedTypeSchemaView typeSchemaGlb( + SharedTypeSchemaView typeSchema1, + SharedTypeSchemaView typeSchema2); + /// Returns `true` if the least closure of [leftSchema] is a subtype of /// [rightType]. /// @@ -638,12 +649,15 @@ abstract interface class TypeAnalyzerOperations< SharedTypeSchemaView leftSchema, SharedTypeSchemaView rightSchema); - /// The concrete classes implementing [TypeAnalyzerOperations] should - /// implement [isSubtypeOfInternal] in order to receive the implementations of - /// [typeIsSubtypeOfTypeSchema], [typeSchemaIsSubtypeOfType], and - /// [typeSchemaIsSubtypeOfTypeSchema] by mixing in - /// [TypeAnalyzerOperationsMixin]. - bool isSubtypeOfInternal(TypeStructure left, TypeStructure right); + /// Computes the least upper bound of [typeSchema1] and [typeSchema2]. + /// + /// The concrete classes implementing [TypeAnalyzerOperations] should mix in + /// [TypeAnalyzerOperationsMixin] and implement [lubInternal] to receive a + /// concrete implementation of [typeSchemaLub] instead of implementing + /// [typeSchemaLub] directly. + SharedTypeSchemaView typeSchemaLub( + SharedTypeSchemaView typeSchema1, + SharedTypeSchemaView typeSchema2); /// Converts a type into a corresponding type schema. SharedTypeSchemaView typeToSchema( @@ -652,20 +666,6 @@ abstract interface class TypeAnalyzerOperations< /// Returns [type] suffixed with the [suffix]. SharedTypeView withNullabilitySuffix( SharedTypeView type, NullabilitySuffix suffix); - - @override - bool isNever(SharedTypeView type); - - @override - bool isTypeParameterType(SharedTypeView type); - - @override - SharedTypeView promoteToNonNull( - SharedTypeView type); - - @override - SharedTypeView? tryPromoteToType( - SharedTypeView to, SharedTypeView from); } mixin TypeAnalyzerOperationsMixin< @@ -711,12 +711,10 @@ mixin TypeAnalyzerOperationsMixin< } @override - SharedTypeSchemaView typeSchemaGlb( - SharedTypeSchemaView typeSchema1, - SharedTypeSchemaView typeSchema2) { - return new SharedTypeSchemaView(glbInternal( - typeSchema1.unwrapTypeSchemaView(), - typeSchema2.unwrapTypeSchemaView())); + bool isSubtypeOf(SharedTypeView leftType, + SharedTypeView rightType) { + return isSubtypeOfInternal( + leftType.unwrapTypeView(), rightType.unwrapTypeView()); } @override @@ -739,15 +737,6 @@ mixin TypeAnalyzerOperationsMixin< lubInternal(type1.unwrapTypeView(), type2.unwrapTypeView())); } - @override - SharedTypeSchemaView typeSchemaLub( - SharedTypeSchemaView typeSchema1, - SharedTypeSchemaView typeSchema2) { - return new SharedTypeSchemaView(lubInternal( - typeSchema1.unwrapTypeSchemaView(), - typeSchema2.unwrapTypeSchemaView())); - } - @override SharedTypeView makeNullable( SharedTypeView type) { @@ -786,13 +775,6 @@ mixin TypeAnalyzerOperationsMixin< return matchFutureOrInternal(type.unwrapTypeView())?.wrapSharedTypeView(); } - @override - SharedTypeSchemaView? matchTypeSchemaFutureOr( - SharedTypeSchemaView typeSchema) { - return matchFutureOrInternal(typeSchema.unwrapTypeSchemaView()) - ?.wrapSharedTypeSchemaView(); - } - @override SharedTypeView? matchIterableType( SharedTypeView type) { @@ -808,10 +790,17 @@ mixin TypeAnalyzerOperationsMixin< } @override - SharedTypeView recordType( - {required List> positional, - required List<(String, SharedTypeView)> named}) { - return new SharedTypeView(recordTypeInternal( + SharedTypeSchemaView? matchTypeSchemaFutureOr( + SharedTypeSchemaView typeSchema) { + return matchFutureOrInternal(typeSchema.unwrapTypeSchemaView()) + ?.wrapSharedTypeSchemaView(); + } + + @override + SharedTypeView recordType( + {required List> positional, + required List<(String, SharedTypeView)> named}) { + return new SharedTypeView(recordTypeInternal( positional: positional.cast(), named: named.cast<(String, TypeStructure)>())); } @@ -825,13 +814,6 @@ mixin TypeAnalyzerOperationsMixin< named: named.cast<(String, TypeStructure)>())); } - @override - bool isSubtypeOf(SharedTypeView leftType, - SharedTypeView rightType) { - return isSubtypeOfInternal( - leftType.unwrapTypeView(), rightType.unwrapTypeView()); - } - @override bool typeIsSubtypeOfTypeSchema(SharedTypeView leftType, SharedTypeSchemaView rightSchema) { @@ -839,6 +821,15 @@ mixin TypeAnalyzerOperationsMixin< leftType.unwrapTypeView(), rightSchema.unwrapTypeSchemaView()); } + @override + SharedTypeSchemaView typeSchemaGlb( + SharedTypeSchemaView typeSchema1, + SharedTypeSchemaView typeSchema2) { + return new SharedTypeSchemaView(glbInternal( + typeSchema1.unwrapTypeSchemaView(), + typeSchema2.unwrapTypeSchemaView())); + } + @override bool typeSchemaIsSubtypeOfType(SharedTypeSchemaView leftSchema, SharedTypeView rightType) { @@ -854,6 +845,15 @@ mixin TypeAnalyzerOperationsMixin< leftSchema.unwrapTypeSchemaView(), rightSchema.unwrapTypeSchemaView()); } + @override + SharedTypeSchemaView typeSchemaLub( + SharedTypeSchemaView typeSchema1, + SharedTypeSchemaView typeSchema2) { + return new SharedTypeSchemaView(lubInternal( + typeSchema1.unwrapTypeSchemaView(), + typeSchema2.unwrapTypeSchemaView())); + } + @override SharedTypeSchemaView typeToSchema( SharedTypeView type) { @@ -861,187 +861,6 @@ mixin TypeAnalyzerOperationsMixin< } } -/// Describes all possibility for a type to be derived from a declaration. -/// -/// This enum is intended to exhaustively handle all possibilities for a type to -/// be derived from a type declaration. Currently, there are two such kinds of -/// declarations: declarations inducing interfaces for dynamic dispatch (such as -/// classes, mixins, and enums), and extension types. -enum TypeDeclarationKind { - /// Indication that the type is derived from a declaration inducing interface. - /// - /// An example of such declaration can be a class declaration, a mixin - /// declaration, or an enum declaration. - interfaceDeclaration, - - /// Indication that the type is derived from an extension type declaration. - extensionTypeDeclaration, -} - -/// Describes constituents of a type derived from a declaration. -/// -/// If a type is derived from a declaration, as described in the documentation -/// for [TypeDeclarationKind], objects of [TypeDeclarationMatchResult] describe -/// its components that can be used for the further analysis of the type in the -/// algorithms related to type inference. -class TypeDeclarationMatchResult { - /// The kind of type declaration the matched type is of. - final TypeDeclarationKind typeDeclarationKind; - - /// A more specific subtype of [Type] describing the matched type. - /// - /// This is client-specific is needed to avoid unnecessary downcasts. - final TypeDeclarationType typeDeclarationType; - - /// The type declaration that the matched type is derived from. - /// - /// The type declaration is defined in the documentation for - /// [TypeDeclarationKind] and is a client-specific object representing a - /// class, an enum, a mixin, or an extension type. - final TypeDeclaration typeDeclaration; - - /// Type arguments instantiating [typeDeclaration] to the matched type. - /// - /// If [typeDeclaration] is not generic, [typeArguments] is an empty list. - final List typeArguments; - - TypeDeclarationMatchResult( - {required this.typeDeclarationKind, - required this.typeDeclarationType, - required this.typeDeclaration, - required this.typeArguments}); -} - -/// The variance of a type parameter `X` in a type `T`. -enum Variance { - /// Used when `X` does not occur free in `T`. - unrelated(keyword: ''), - - /// Used when `X` occurs free in `T`, and `U <: V` implies `[U/X]T <: [V/X]T`. - covariant(keyword: 'out'), - - /// Used when `X` occurs free in `T`, and `U <: V` implies `[V/X]T <: [U/X]T`. - contravariant(keyword: 'in'), - - /// Used when there exists a pair `U` and `V` such that `U <: V`, but - /// `[U/X]T` and `[V/X]T` are incomparable. - invariant(keyword: 'inout'); - - final String keyword; - - const Variance({required this.keyword}); - - /// Return the variance with the given [encoding]. - factory Variance.fromEncoding(int encoding) => values[encoding]; - - /// Return the variance associated with the string representation of variance. - factory Variance.fromKeywordString(String keywordString) { - Variance? result; - if (keywordString == "in") { - result = contravariant; - } else if (keywordString == "inout") { - result = invariant; - } else if (keywordString == "out") { - result = covariant; - } else if (keywordString == "unrelated") { - result = unrelated; - } - if (result != null) { - assert(result.keyword == keywordString); - return result; - } else { - throw new ArgumentError( - 'Invalid keyword string for variance: $keywordString'); - } - } - - /// Return `true` if this represents the case when `X` occurs free in `T`, and - /// `U <: V` implies `[V/X]T <: [U/X]T`. - bool get isContravariant => this == contravariant; - - /// Return `true` if this represents the case when `X` occurs free in `T`, and - /// `U <: V` implies `[U/X]T <: [V/X]T`. - bool get isCovariant => this == covariant; - - /// Return `true` if this represents the case when there exists a pair `U` and - /// `V` such that `U <: V`, but `[U/X]T` and `[V/X]T` are incomparable. - bool get isInvariant => this == invariant; - - /// Return `true` if this represents the case when `X` does not occur free in - /// `T`. - bool get isUnrelated => this == unrelated; - - /// Combines variances of `X` in `T` and `Y` in `S` into variance of `X` in - /// `[Y/T]S`. - /// - /// Consider the following examples: - /// - /// * variance of `X` in `Function(X)` is contravariant, variance of `Y` - /// in `List` is covariant, so variance of `X` in `List` is - /// contravariant; - /// - /// * variance of `X` in `List` is covariant, variance of `Y` in - /// `Function(Y)` is contravariant, so variance of `X` in - /// `Function(List)` is contravariant; - /// - /// * variance of `X` in `Function(X)` is contravariant, variance of `Y` in - /// `Function(Y)` is contravariant, so variance of `X` in - /// `Function(Function(X))` is covariant; - /// - /// * let the following be declared: - /// - /// typedef F = Function(); - /// - /// then variance of `X` in `F` is unrelated, variance of `Y` in - /// `List` is covariant, so variance of `X` in `List>` is - /// unrelated; - /// - /// * let the following be declared: - /// - /// typedef G = Z Function(Z); - /// - /// then variance of `X` in `List` is covariant, variance of `Y` in - /// `G` is invariant, so variance of `X` in `G>` is invariant. - Variance combine(Variance other) { - if (isUnrelated || other.isUnrelated) return unrelated; - if (isInvariant || other.isInvariant) return invariant; - return this == other ? covariant : contravariant; - } - - /// Returns true if this variance is greater than (above) or equal to the - /// [other] variance in the partial order induced by the variance lattice. - /// - /// unrelated - /// covariant contravariant - /// invariant - bool greaterThanOrEqual(Variance other) { - if (isUnrelated) { - return true; - } else if (isCovariant) { - return other.isCovariant || other.isInvariant; - } else if (isContravariant) { - return other.isContravariant || other.isInvariant; - } else { - assert(isInvariant); - return other.isInvariant; - } - } - - /// Variance values form a lattice where unrelated is the top, invariant is - /// the bottom, and covariant and contravariant are incomparable. [meet] - /// calculates the meet of two elements of such lattice. It can be used, for - /// example, to calculate the variance of a typedef type parameter if it's - /// encountered on the RHS of the typedef multiple times. - /// - /// unrelated - /// covariant contravariant - /// invariant - Variance meet(Variance other) { - return new Variance.fromEncoding(index | other.index); - } -} - /// Abstract interface of a type constraint generator. abstract class TypeConstraintGenerator< TypeStructure extends SharedTypeStructure, @@ -1057,16 +876,6 @@ abstract class TypeConstraintGenerator< /// be rolled back to a state via [restoreState]. TypeConstraintGeneratorState get currentState; - /// Restores the constraint generator to [state]. - /// - /// The [state] to restore the constraint generator to can be obtained via - /// [currentState]. - void restoreState(TypeConstraintGeneratorState state); - - /// Abstract type operations to be used in the matching methods. - TypeAnalyzerOperations get typeAnalyzerOperations; - /// True if FutureOr types are required to have the empty [NullabilitySuffix] /// when they are matched. /// @@ -1076,60 +885,15 @@ abstract class TypeConstraintGenerator< /// https://github.com/dart-lang/sdk/issues/51156#issuecomment-2158825417. bool get enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr; - /// Matches type [p] against type schema [q] as a subtype against supertype, - /// assuming [p] contains the type parameters to constrain, and [q] is the - /// constraining type schema, and returns true if [p] is a subtype of [q] - /// under some constraints, and false otherwise. - /// - /// As the generator computes the constraints making the relation possible, - /// it changes its internal state. The current state of the generator can be - /// obtained by [currentState], and the generator can be restored to a state - /// via [restoreState]. All of the shared constraint generation methods are - /// supposed to restore the generator to the prior state in case of a - /// mismatch, taking that responsibility away from the caller. - /// - /// The algorithm for subtype constraint generation is described in - /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation - bool performSubtypeConstraintGenerationRightSchema( - SharedTypeView p, SharedTypeSchemaView q, - {required AstNode? astNodeForTesting}); - - /// Matches type schema [p] against type [q] as a subtype against supertype, - /// assuming [p] is the constraining type schema, and [q] contains the type - /// parameters to constrain, and returns true if [p] is a subtype of [q] - /// under some constraints, and false otherwise. - /// - /// As the generator computes the constraints making the relation possible, - /// it changes its internal state. The current state of the generator can be - /// obtained by [currentState], and the generator can be restored to a state - /// via [restoreState]. All of the shared constraint generation methods are - /// supposed to restore the generator to the prior state in case of a - /// mismatch, taking that responsibility away from the caller. - /// - /// The algorithm for subtype constraint generation is described in - /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation - bool performSubtypeConstraintGenerationLeftSchema( - SharedTypeSchemaView p, SharedTypeView q, - {required AstNode? astNodeForTesting}); + /// Abstract type operations to be used in the matching methods. + TypeAnalyzerOperations get typeAnalyzerOperations; - /// [performSubtypeConstraintGenerationInternal] should be implemented by - /// concrete classes implementing [TypeConstraintGenerator]. The - /// implementations of [performSubtypeConstraintGenerationLeftSchema] and - /// [performSubtypeConstraintGenerationRightSchema] are provided by mixing in - /// [TypeConstraintGeneratorMixin], which defines - /// [performSubtypeConstraintGenerationLeftSchema] and - /// [performSubtypeConstraintGenerationRightSchema] in terms of - /// [performSubtypeConstraintGenerationInternal]. - /// - /// The main purpose of this method is to avoid code duplication in the - /// concrete classes implementing [TypeAnalyzerOperations], so they can - /// implement only one member, in this case - /// [performSubtypeConstraintGenerationInternal], and receive the - /// implementation of both [performSubtypeConstraintGenerationLeftSchema] and - /// [performSubtypeConstraintGenerationRightSchema] from the mixin. - bool performSubtypeConstraintGenerationInternal( - TypeStructure p, TypeStructure q, - {required bool leftSchema, required AstNode? astNodeForTesting}); + /// Returns the type arguments of the supertype of [type] that is an + /// instantiation of [typeDeclaration]. If none of the supertypes of [type] + /// are instantiations of [typeDeclaration], returns null. + List? getTypeArgumentsAsInstanceOf( + TypeDeclarationType type, TypeDeclaration typeDeclaration); /// Matches [p] against [q] as a subtype against supertype and returns true if /// [p] and [q] are both FutureOr, with or without nullability suffixes as @@ -1242,18 +1006,79 @@ abstract class TypeConstraintGenerator< pDeclarationObject, pTypeArguments, qTypeArguments, leftSchema, astNodeForTesting: astNodeForTesting); - case (TypeDeclarationMatchResult(), TypeDeclarationMatchResult()): - return _interfaceTypes(p, q, leftSchema, - astNodeForTesting: astNodeForTesting); + case (TypeDeclarationMatchResult(), TypeDeclarationMatchResult()): + return _interfaceTypes(p, q, leftSchema, + astNodeForTesting: astNodeForTesting); + + case ( + TypeDeclarationMatchResult? pMatched, + TypeDeclarationMatchResult? qMatched + ): + assert(pMatched == null || qMatched == null); + return null; + } + } + + /// [performSubtypeConstraintGenerationInternal] should be implemented by + /// concrete classes implementing [TypeConstraintGenerator]. The + /// implementations of [performSubtypeConstraintGenerationLeftSchema] and + /// [performSubtypeConstraintGenerationRightSchema] are provided by mixing in + /// [TypeConstraintGeneratorMixin], which defines + /// [performSubtypeConstraintGenerationLeftSchema] and + /// [performSubtypeConstraintGenerationRightSchema] in terms of + /// [performSubtypeConstraintGenerationInternal]. + /// + /// The main purpose of this method is to avoid code duplication in the + /// concrete classes implementing [TypeAnalyzerOperations], so they can + /// implement only one member, in this case + /// [performSubtypeConstraintGenerationInternal], and receive the + /// implementation of both [performSubtypeConstraintGenerationLeftSchema] and + /// [performSubtypeConstraintGenerationRightSchema] from the mixin. + bool performSubtypeConstraintGenerationInternal( + TypeStructure p, TypeStructure q, + {required bool leftSchema, required AstNode? astNodeForTesting}); + + /// Matches type schema [p] against type [q] as a subtype against supertype, + /// assuming [p] is the constraining type schema, and [q] contains the type + /// parameters to constrain, and returns true if [p] is a subtype of [q] + /// under some constraints, and false otherwise. + /// + /// As the generator computes the constraints making the relation possible, + /// it changes its internal state. The current state of the generator can be + /// obtained by [currentState], and the generator can be restored to a state + /// via [restoreState]. All of the shared constraint generation methods are + /// supposed to restore the generator to the prior state in case of a + /// mismatch, taking that responsibility away from the caller. + /// + /// The algorithm for subtype constraint generation is described in + /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation + bool performSubtypeConstraintGenerationLeftSchema( + SharedTypeSchemaView p, SharedTypeView q, + {required AstNode? astNodeForTesting}); + + /// Matches type [p] against type schema [q] as a subtype against supertype, + /// assuming [p] contains the type parameters to constrain, and [q] is the + /// constraining type schema, and returns true if [p] is a subtype of [q] + /// under some constraints, and false otherwise. + /// + /// As the generator computes the constraints making the relation possible, + /// it changes its internal state. The current state of the generator can be + /// obtained by [currentState], and the generator can be restored to a state + /// via [restoreState]. All of the shared constraint generation methods are + /// supposed to restore the generator to the prior state in case of a + /// mismatch, taking that responsibility away from the caller. + /// + /// The algorithm for subtype constraint generation is described in + /// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#subtype-constraint-generation + bool performSubtypeConstraintGenerationRightSchema( + SharedTypeView p, SharedTypeSchemaView q, + {required AstNode? astNodeForTesting}); - case ( - TypeDeclarationMatchResult? pMatched, - TypeDeclarationMatchResult? qMatched - ): - assert(pMatched == null || qMatched == null); - return null; - } - } + /// Restores the constraint generator to [state]. + /// + /// The [state] to restore the constraint generator to can be obtained via + /// [currentState]. + void restoreState(TypeConstraintGeneratorState state); /// Match arguments [pTypeArguments] of P against arguments [qTypeArguments] /// of Q, taking into account the variance of type variables in [declaration]. @@ -1330,25 +1155,8 @@ abstract class TypeConstraintGenerator< return false; } - - /// Returns the type arguments of the supertype of [type] that is an - /// instantiation of [typeDeclaration]. If none of the supertypes of [type] - /// are instantiations of [typeDeclaration], returns null. - List? getTypeArgumentsAsInstanceOf( - TypeDeclarationType type, TypeDeclaration typeDeclaration); } -/// Representation of the state of [TypeConstraintGenerator]. -/// -/// The state can be obtained via [TypeConstraintGenerator.currentState]. A -/// [TypeConstraintGenerator] can be restored to a state via -/// [TypeConstraintGenerator.restoreState]. -/// -/// In practice, the state is represented as an integer: the count of the -/// constraints generated so far. Since the count only increases as the -/// generator proceeds, restoring to a state means discarding some constraints. -extension type TypeConstraintGeneratorState(int count) {} - mixin TypeConstraintGeneratorMixin< TypeStructure extends SharedTypeStructure, Variable extends Object, @@ -1376,3 +1184,195 @@ mixin TypeConstraintGeneratorMixin< leftSchema: false, astNodeForTesting: astNodeForTesting); } } + +/// Describes all possibility for a type to be derived from a declaration. +/// +/// This enum is intended to exhaustively handle all possibilities for a type to +/// be derived from a type declaration. Currently, there are two such kinds of +/// declarations: declarations inducing interfaces for dynamic dispatch (such as +/// classes, mixins, and enums), and extension types. +enum TypeDeclarationKind { + /// Indication that the type is derived from a declaration inducing interface. + /// + /// An example of such declaration can be a class declaration, a mixin + /// declaration, or an enum declaration. + interfaceDeclaration, + + /// Indication that the type is derived from an extension type declaration. + extensionTypeDeclaration, +} + +/// Describes constituents of a type derived from a declaration. +/// +/// If a type is derived from a declaration, as described in the documentation +/// for [TypeDeclarationKind], objects of [TypeDeclarationMatchResult] describe +/// its components that can be used for the further analysis of the type in the +/// algorithms related to type inference. +class TypeDeclarationMatchResult { + /// The kind of type declaration the matched type is of. + final TypeDeclarationKind typeDeclarationKind; + + /// A more specific subtype of [Type] describing the matched type. + /// + /// This is client-specific is needed to avoid unnecessary downcasts. + final TypeDeclarationType typeDeclarationType; + + /// The type declaration that the matched type is derived from. + /// + /// The type declaration is defined in the documentation for + /// [TypeDeclarationKind] and is a client-specific object representing a + /// class, an enum, a mixin, or an extension type. + final TypeDeclaration typeDeclaration; + + /// Type arguments instantiating [typeDeclaration] to the matched type. + /// + /// If [typeDeclaration] is not generic, [typeArguments] is an empty list. + final List typeArguments; + + TypeDeclarationMatchResult( + {required this.typeDeclarationKind, + required this.typeDeclarationType, + required this.typeDeclaration, + required this.typeArguments}); +} + +/// The variance of a type parameter `X` in a type `T`. +enum Variance { + /// Used when `X` does not occur free in `T`. + unrelated(keyword: ''), + + /// Used when `X` occurs free in `T`, and `U <: V` implies `[U/X]T <: [V/X]T`. + covariant(keyword: 'out'), + + /// Used when `X` occurs free in `T`, and `U <: V` implies `[V/X]T <: [U/X]T`. + contravariant(keyword: 'in'), + + /// Used when there exists a pair `U` and `V` such that `U <: V`, but + /// `[U/X]T` and `[V/X]T` are incomparable. + invariant(keyword: 'inout'); + + final String keyword; + + const Variance({required this.keyword}); + + /// Return the variance with the given [encoding]. + factory Variance.fromEncoding(int encoding) => values[encoding]; + + /// Return the variance associated with the string representation of variance. + factory Variance.fromKeywordString(String keywordString) { + Variance? result; + if (keywordString == "in") { + result = contravariant; + } else if (keywordString == "inout") { + result = invariant; + } else if (keywordString == "out") { + result = covariant; + } else if (keywordString == "unrelated") { + result = unrelated; + } + if (result != null) { + assert(result.keyword == keywordString); + return result; + } else { + throw new ArgumentError( + 'Invalid keyword string for variance: $keywordString'); + } + } + + /// Return `true` if this represents the case when `X` occurs free in `T`, and + /// `U <: V` implies `[V/X]T <: [U/X]T`. + bool get isContravariant => this == contravariant; + + /// Return `true` if this represents the case when `X` occurs free in `T`, and + /// `U <: V` implies `[U/X]T <: [V/X]T`. + bool get isCovariant => this == covariant; + + /// Return `true` if this represents the case when there exists a pair `U` and + /// `V` such that `U <: V`, but `[U/X]T` and `[V/X]T` are incomparable. + bool get isInvariant => this == invariant; + + /// Return `true` if this represents the case when `X` does not occur free in + /// `T`. + bool get isUnrelated => this == unrelated; + + /// Combines variances of `X` in `T` and `Y` in `S` into variance of `X` in + /// `[Y/T]S`. + /// + /// Consider the following examples: + /// + /// * variance of `X` in `Function(X)` is contravariant, variance of `Y` + /// in `List` is covariant, so variance of `X` in `List` is + /// contravariant; + /// + /// * variance of `X` in `List` is covariant, variance of `Y` in + /// `Function(Y)` is contravariant, so variance of `X` in + /// `Function(List)` is contravariant; + /// + /// * variance of `X` in `Function(X)` is contravariant, variance of `Y` in + /// `Function(Y)` is contravariant, so variance of `X` in + /// `Function(Function(X))` is covariant; + /// + /// * let the following be declared: + /// + /// typedef F = Function(); + /// + /// then variance of `X` in `F` is unrelated, variance of `Y` in + /// `List` is covariant, so variance of `X` in `List>` is + /// unrelated; + /// + /// * let the following be declared: + /// + /// typedef G = Z Function(Z); + /// + /// then variance of `X` in `List` is covariant, variance of `Y` in + /// `G` is invariant, so variance of `X` in `G>` is invariant. + Variance combine(Variance other) { + if (isUnrelated || other.isUnrelated) return unrelated; + if (isInvariant || other.isInvariant) return invariant; + return this == other ? covariant : contravariant; + } + + /// Returns true if this variance is greater than (above) or equal to the + /// [other] variance in the partial order induced by the variance lattice. + /// + /// unrelated + /// covariant contravariant + /// invariant + bool greaterThanOrEqual(Variance other) { + if (isUnrelated) { + return true; + } else if (isCovariant) { + return other.isCovariant || other.isInvariant; + } else if (isContravariant) { + return other.isContravariant || other.isInvariant; + } else { + assert(isInvariant); + return other.isInvariant; + } + } + + /// Variance values form a lattice where unrelated is the top, invariant is + /// the bottom, and covariant and contravariant are incomparable. [meet] + /// calculates the meet of two elements of such lattice. It can be used, for + /// example, to calculate the variance of a typedef type parameter if it's + /// encountered on the RHS of the typedef multiple times. + /// + /// unrelated + /// covariant contravariant + /// invariant + Variance meet(Variance other) { + return new Variance.fromEncoding(index | other.index); + } +} + +/// Representation of the state of [TypeConstraintGenerator]. +/// +/// The state can be obtained via [TypeConstraintGenerator.currentState]. A +/// [TypeConstraintGenerator] can be restored to a state via +/// [TypeConstraintGenerator.restoreState]. +/// +/// In practice, the state is represented as an integer: the count of the +/// constraints generated so far. Since the count only increases as the +/// generator proceeds, restoring to a state means discarding some constraints. +extension type TypeConstraintGeneratorState(int count) {} diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart index 32e8e68d1b49..566fb26e59c8 100644 --- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart +++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart @@ -149,20 +149,20 @@ class MergedTypeConstraint< } } - void mergeInTypeSchemaUpper( + void mergeInTypeSchemaLower( SharedTypeSchemaView constraint, TypeAnalyzerOperations typeAnalyzerOperations) { - upper = typeAnalyzerOperations.typeSchemaGlb(upper, constraint); + lower = typeAnalyzerOperations.typeSchemaLub(lower, constraint); } - void mergeInTypeSchemaLower( + void mergeInTypeSchemaUpper( SharedTypeSchemaView constraint, TypeAnalyzerOperations typeAnalyzerOperations) { - lower = typeAnalyzerOperations.typeSchemaLub(lower, constraint); + upper = typeAnalyzerOperations.typeSchemaGlb(upper, constraint); } @override @@ -171,42 +171,6 @@ class MergedTypeConstraint< } } -/// The origin of a type constraint, for the purposes of producing a human -/// readable error message during type inference as well as determining whether -/// the constraint was used to fix the type parameter or not. -abstract class TypeConstraintOrigin< - TypeStructure extends SharedTypeStructure, - Variable extends Object, - TypeParameter extends Object, - TypeDeclarationType extends Object, - TypeDeclaration extends Object> { - const TypeConstraintOrigin(); - - List formatError( - TypeAnalyzerOperations - typeAnalyzerOperations); -} - -class UnknownTypeConstraintOrigin< - TypeStructure extends SharedTypeStructure, - Variable extends Object, - InferableParameter extends Object, - TypeDeclarationType extends Object, - TypeDeclaration extends Object> - extends TypeConstraintOrigin { - const UnknownTypeConstraintOrigin(); - - @override - List formatError( - TypeAnalyzerOperations - typeAnalyzerOperations) { - return []; - } -} - class TypeConstraintFromArgument< TypeStructure extends SharedTypeStructure, Variable extends Object, @@ -355,3 +319,39 @@ class TypeConstraintFromReturnType< ]; } } + +/// The origin of a type constraint, for the purposes of producing a human +/// readable error message during type inference as well as determining whether +/// the constraint was used to fix the type parameter or not. +abstract class TypeConstraintOrigin< + TypeStructure extends SharedTypeStructure, + Variable extends Object, + TypeParameter extends Object, + TypeDeclarationType extends Object, + TypeDeclaration extends Object> { + const TypeConstraintOrigin(); + + List formatError( + TypeAnalyzerOperations + typeAnalyzerOperations); +} + +class UnknownTypeConstraintOrigin< + TypeStructure extends SharedTypeStructure, + Variable extends Object, + InferableParameter extends Object, + TypeDeclarationType extends Object, + TypeDeclaration extends Object> + extends TypeConstraintOrigin { + const UnknownTypeConstraintOrigin(); + + @override + List formatError( + TypeAnalyzerOperations + typeAnalyzerOperations) { + return []; + } +} diff --git a/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart b/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart index c775ee0ba547..48ce2eb1ce0d 100644 --- a/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart +++ b/pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart @@ -71,34 +71,53 @@ abstract interface class SharedVoidTypeStructure< TypeStructure extends SharedTypeStructure> implements SharedTypeStructure {} -extension type SharedTypeView< - TypeStructure extends SharedTypeStructure>( - SharedTypeStructure _typeStructure) implements Object { - TypeStructure unwrapTypeView() => _typeStructure as TypeStructure; - - NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix; - - String getDisplayString() => _typeStructure.getDisplayString(); -} +extension type SharedDynamicTypeSchemaView< + TypeStructure extends SharedTypeStructure>( + SharedDynamicTypeStructure _typeStructure) + implements SharedTypeSchemaView {} extension type SharedDynamicTypeView< TypeStructure extends SharedTypeStructure>( SharedDynamicTypeStructure _typeStructure) implements SharedTypeView {} +extension type SharedInvalidTypeSchemaView< + TypeStructure extends SharedTypeStructure>( + SharedInvalidTypeStructure _typeStructure) + implements SharedTypeSchemaView {} + extension type SharedInvalidTypeView< TypeStructure extends SharedTypeStructure>( SharedInvalidTypeStructure _typeStructure) implements SharedTypeView {} +extension type SharedNamedTypeSchemaView< + TypeStructure extends SharedTypeStructure>( + SharedNamedTypeStructure _typeStructure) implements Object {} + extension type SharedNamedTypeView< TypeStructure extends SharedTypeStructure>( SharedNamedTypeStructure _namedTypeStructure) implements Object { + String get name => _namedTypeStructure.name; + SharedTypeView get type => new SharedTypeView(_namedTypeStructure.type); +} - String get name => _namedTypeStructure.name; +extension type SharedRecordTypeSchemaView< + TypeStructure extends SharedTypeStructure>( + SharedRecordTypeStructure _typeStructure) + implements SharedTypeSchemaView { + List> get namedTypes { + return _typeStructure.namedTypes + as List>; + } + + List> get positionalTypes { + return _typeStructure.positionalTypes + as List>; + } } extension type SharedRecordTypeView< @@ -116,48 +135,24 @@ extension type SharedRecordTypeView< } } -extension type SharedVoidTypeView< - TypeStructure extends SharedTypeStructure>( - SharedVoidTypeStructure _typeStructure) - implements SharedTypeView {} - extension type SharedTypeSchemaView< TypeStructure extends SharedTypeStructure>( SharedTypeStructure _typeStructure) implements Object { - TypeStructure unwrapTypeSchemaView() => _typeStructure as TypeStructure; - NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix; String getDisplayString() => _typeStructure.getDisplayString(); -} - -extension type SharedDynamicTypeSchemaView< - TypeStructure extends SharedTypeStructure>( - SharedDynamicTypeStructure _typeStructure) - implements SharedTypeSchemaView {} -extension type SharedInvalidTypeSchemaView< - TypeStructure extends SharedTypeStructure>( - SharedInvalidTypeStructure _typeStructure) - implements SharedTypeSchemaView {} + TypeStructure unwrapTypeSchemaView() => _typeStructure as TypeStructure; +} -extension type SharedNamedTypeSchemaView< +extension type SharedTypeView< TypeStructure extends SharedTypeStructure>( - SharedNamedTypeStructure _typeStructure) implements Object {} + SharedTypeStructure _typeStructure) implements Object { + NullabilitySuffix get nullabilitySuffix => _typeStructure.nullabilitySuffix; -extension type SharedRecordTypeSchemaView< - TypeStructure extends SharedTypeStructure>( - SharedRecordTypeStructure _typeStructure) - implements SharedTypeSchemaView { - List> get namedTypes { - return _typeStructure.namedTypes - as List>; - } + String getDisplayString() => _typeStructure.getDisplayString(); - List> get positionalTypes { - return _typeStructure.positionalTypes - as List>; - } + TypeStructure unwrapTypeView() => _typeStructure as TypeStructure; } /// Note that there is no `SharedUnknownTypeView`, only @@ -174,6 +169,11 @@ extension type SharedVoidTypeSchemaView< SharedVoidTypeStructure _typeStructure) implements SharedTypeSchemaView {} +extension type SharedVoidTypeView< + TypeStructure extends SharedTypeStructure>( + SharedVoidTypeStructure _typeStructure) + implements SharedTypeView {} + /// Extension methods of [SharedTypeStructureExtension] are intended to avoid /// explicit null-testing on types before wrapping them into [SharedTypeView] or /// [SharedTypeSchemaView]. @@ -193,13 +193,13 @@ extension type SharedVoidTypeSchemaView< extension SharedTypeStructureExtension< TypeStructure extends SharedTypeStructure> on SharedTypeStructure { - SharedTypeView wrapSharedTypeView() { - return new SharedTypeView(this); - } - SharedTypeSchemaView wrapSharedTypeSchemaView() { return new SharedTypeSchemaView(this); } + + SharedTypeView wrapSharedTypeView() { + return new SharedTypeView(this); + } } extension SharedTypeStructureMapEntryExtension< From 3920bba3165bdca424320e693a9606f25ce7eb72 Mon Sep 17 00:00:00 2001 From: Keerti Parthasarathy Date: Mon, 30 Sep 2024 13:57:37 +0000 Subject: [PATCH 4/5] [Element mode] Migrate convert_to_initializing_formal and convert_to_map_literal correction producers Change-Id: I7afd7d49b62cde780e6a3da3231035a323b7a012 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/387324 Reviewed-by: Brian Wilkerson Commit-Queue: Keerti Parthasarathy --- .../dart/convert_to_initializing_formal.dart | 10 +++++----- .../correction/dart/convert_to_map_literal.dart | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_initializing_formal.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_initializing_formal.dart index 462ff3f78a36..60d948010a92 100644 --- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_initializing_formal.dart +++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_initializing_formal.dart @@ -5,7 +5,7 @@ import 'package:analysis_server/src/services/correction/fix.dart'; import 'package:analysis_server_plugin/edit/dart/correction_producer.dart'; import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/element2.dart'; import 'package:analyzer/src/dart/ast/extensions.dart'; import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart'; import 'package:analyzer_plugin/utilities/fixes/fixes.dart'; @@ -77,8 +77,8 @@ class ConvertToInitializingFormal extends ResolvedCorrectionProducer { return; } - var fieldElement = node.fieldName.staticElement; - if (fieldElement is! VariableElement) { + var fieldElement = node.fieldName.element; + if (fieldElement is! VariableElement2) { return; } @@ -107,9 +107,9 @@ class ConvertToInitializingFormal extends ResolvedCorrectionProducer { if (expression is! SimpleIdentifier) { return null; } - var parameterElement = expression.staticElement; + var parameterElement = expression.element; for (var parameter in constructor.parameters.parameters) { - if (parameter.declaredElement == parameterElement) { + if (parameter.declaredFragment?.element == parameterElement) { parameter = parameter.notDefault; return parameter is SimpleFormalParameter ? parameter : null; } diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_map_literal.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_map_literal.dart index 38603bb2d5ee..998710b994ee 100644 --- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_map_literal.dart +++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_map_literal.dart @@ -6,7 +6,7 @@ import 'package:analysis_server/src/services/correction/assist.dart'; import 'package:analysis_server/src/services/correction/fix.dart'; import 'package:analysis_server_plugin/edit/dart/correction_producer.dart'; import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/element2.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer_plugin/utilities/assist/assist.dart'; import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart'; @@ -45,7 +45,7 @@ class ConvertToMapLiteral extends ResolvedCorrectionProducer { creation.constructorName.name != null || creation.argumentList.arguments.isNotEmpty || type is! InterfaceType || - !_isMapClass(type.element)) { + !_isMapClass(type.element3)) { return; } // @@ -83,8 +83,8 @@ class ConvertToMapLiteral extends ResolvedCorrectionProducer { /// Return `true` if the [element] represents either the class `Map` or /// `LinkedHashMap`. - bool _isMapClass(InterfaceElement element) => - element == typeProvider.mapElement || + bool _isMapClass(InterfaceElement2 element) => + element == typeProvider.mapElement2 || (element.name == 'LinkedHashMap' && - element.library.name == 'dart.collection'); + element.library2.name == 'dart.collection'); } From 8a77fa05acdab53bc9f1fd08a4596249062807ef Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Mon, 30 Sep 2024 14:28:29 +0000 Subject: [PATCH 5/5] Elements. Migrate EncapsulateField. Change-Id: I505623f21211f1e529962b563f1898919f080537 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/387401 Reviewed-by: Samuel Rawlins Commit-Queue: Konstantin Shcheglov --- .../analyzer_use_new_elements.txt | 1 + .../correction/dart/encapsulate_field.dart | 27 ++++++++++--------- .../dart/element/inheritance_manager3.dart | 13 +++++++++ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/pkg/analysis_server/analyzer_use_new_elements.txt b/pkg/analysis_server/analyzer_use_new_elements.txt index f6f472e599ab..bf827a5e2aa4 100644 --- a/pkg/analysis_server/analyzer_use_new_elements.txt +++ b/pkg/analysis_server/analyzer_use_new_elements.txt @@ -285,6 +285,7 @@ lib/src/services/correction/dart/create_method_or_function.dart lib/src/services/correction/dart/create_no_such_method.dart lib/src/services/correction/dart/create_parameter.dart lib/src/services/correction/dart/data_driven.dart +lib/src/services/correction/dart/encapsulate_field.dart lib/src/services/correction/dart/exchange_operands.dart lib/src/services/correction/dart/extend_class_for_mixin.dart lib/src/services/correction/dart/flutter_move_down.dart diff --git a/pkg/analysis_server/lib/src/services/correction/dart/encapsulate_field.dart b/pkg/analysis_server/lib/src/services/correction/dart/encapsulate_field.dart index 78fd48658b47..eb9c8271ac90 100644 --- a/pkg/analysis_server/lib/src/services/correction/dart/encapsulate_field.dart +++ b/pkg/analysis_server/lib/src/services/correction/dart/encapsulate_field.dart @@ -5,7 +5,7 @@ import 'package:analysis_server/src/services/correction/assist.dart'; import 'package:analysis_server_plugin/edit/dart/correction_producer.dart'; import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/element2.dart'; import 'package:analyzer/src/dart/element/inheritance_manager3.dart'; import 'package:analyzer_plugin/utilities/assist/assist.dart'; import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart'; @@ -50,7 +50,8 @@ class EncapsulateField extends ResolvedCorrectionProducer { } var field = fields.first; var nameToken = field.name; - var fieldElement = field.declaredElement as FieldElement; + var fieldFragment = field.declaredFragment as FieldFragment; + var fieldElement = fieldFragment.element; // should have a public name var name = nameToken.lexeme; if (Identifier.isPrivateName(name)) { @@ -63,15 +64,15 @@ class EncapsulateField extends ResolvedCorrectionProducer { // Should be in a class or mixin. List classMembers; - InterfaceElement parentElement; + InterfaceElement2 parentElement; var parent = fieldDeclaration.parent; switch (parent) { case ClassDeclaration(): classMembers = parent.members; - parentElement = parent.declaredElement!; + parentElement = parent.declaredFragment!.element; case MixinDeclaration(): classMembers = parent.members; - parentElement = parent.declaredElement!; + parentElement = parent.declaredFragment!.element; default: return; } @@ -129,7 +130,7 @@ class EncapsulateField extends ResolvedCorrectionProducer { } // Write getter. - var overriddenGetters = inheritanceManager.getOverridden2( + var overriddenGetters = inheritanceManager.getOverridden4( parentElement, Name(null, name), ); @@ -137,7 +138,7 @@ class EncapsulateField extends ResolvedCorrectionProducer { builder.write(' ${typeCode}get $name => _$name;'); // Write setter. - var overriddenSetters = inheritanceManager.getOverridden2( + var overriddenSetters = inheritanceManager.getOverridden4( parentElement, Name(null, '$name='), ); @@ -152,15 +153,15 @@ class EncapsulateField extends ResolvedCorrectionProducer { void _updateReferencesInConstructor( DartFileEditBuilder builder, ConstructorDeclaration constructor, - FieldElement fieldElement, + FieldElement2 fieldElement, String name, ) { for (var parameter in constructor.parameters.parameters) { var identifier = parameter.name; - var parameterElement = parameter.declaredElement; + var parameterElement = parameter.declaredFragment?.element; if (identifier != null && - parameterElement is FieldFormalParameterElement && - parameterElement.field == fieldElement) { + parameterElement is FieldFormalParameterElement2 && + parameterElement.field2 == fieldElement) { if (parameter.isNamed && parameter is DefaultFormalParameter) { var normalParam = parameter.parameter; if (normalParam is FieldFormalParameter) { @@ -182,7 +183,7 @@ class EncapsulateField extends ResolvedCorrectionProducer { } for (var initializer in constructor.initializers) { if (initializer is ConstructorFieldInitializer && - initializer.fieldName.staticElement == fieldElement) { + initializer.fieldName.element == fieldElement) { builder.addSimpleReplacement( range.node(initializer.fieldName), '_$name', @@ -194,7 +195,7 @@ class EncapsulateField extends ResolvedCorrectionProducer { void _updateReferencesInConstructors( DartFileEditBuilder builder, List classMembers, - FieldElement fieldElement, + FieldElement2 fieldElement, String name, ) { for (var constructor in classMembers) { diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart index 56f78b7e0363..3e5e2bd5a3e3 100644 --- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart +++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart @@ -11,6 +11,7 @@ import 'package:analyzer/src/dart/element/member.dart'; import 'package:analyzer/src/dart/element/type_algebra.dart'; import 'package:analyzer/src/dart/element/type_system.dart'; import 'package:analyzer/src/utilities/extensions/collection.dart'; +import 'package:analyzer/src/utilities/extensions/element.dart'; import 'package:meta/meta.dart'; /// Failure because of there is no most specific signature in [candidates]. @@ -410,6 +411,18 @@ class InheritanceManager3 { return interface.overridden[name]; } + /// Return all members of mixins, superclasses, and interfaces that a member + /// with the given [name], defined in the [element], would override; or `null` + /// if no members would be overridden. + List? getOverridden4( + InterfaceElement2 element, Name name) { + var interface = getInterface2(element); + var fragments = interface.overridden[name]; + return fragments + ?.map((fragment) => fragment.asElement2 as ExecutableElement2) + .toList(); + } + /// Remove interfaces for classes defined in specified libraries. void removeOfLibraries(Set uriSet) { _interfaces.removeWhere((element, _) {