Skip to content

Commit 04484a2

Browse files
scheglovCommit Queue
authored andcommitted
Elements. Migrate ExtensionMemberResolver.
Change-Id: I0a9f008d900a478200bbdac898fe58c61e825391 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/406082 Reviewed-by: Phil Quitslund <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 193f8a2 commit 04484a2

File tree

3 files changed

+149
-28
lines changed

3 files changed

+149
-28
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,8 @@ class LibraryFragmentScope implements Scope {
445445
);
446446
}
447447

448-
void notifyExtensionUsed(ExtensionElement element) {
449-
_importsTracking?.notifyExtensionUsed(element);
448+
void notifyExtensionUsed(ExtensionElement2 element) {
449+
_importsTracking?.notifyExtensionUsed(element.asElement);
450450
}
451451

452452
PrefixScope? _getParentPrefixScope(PrefixElementImpl prefix) {

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

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,54 @@ class TypeSystemImpl implements TypeSystem {
607607
return parameters;
608608
}
609609

610+
/// Computes the set of free type parameters appearing in [rootType].
611+
///
612+
/// If a non-null [candidates] set is given, then only type parameters
613+
/// appearing in it are considered; otherwise all type parameters are
614+
/// considered.
615+
List<TypeParameterElement2>? getFreeParameters2(DartType rootType,
616+
{Set<TypeParameterElement2>? candidates}) {
617+
List<TypeParameterElement2>? parameters;
618+
Set<DartType> visitedTypes = HashSet<DartType>();
619+
Set<TypeParameterElement2> boundTypeParameters =
620+
HashSet<TypeParameterElement2>();
621+
622+
void appendParameters(DartType? type) {
623+
if (type == null) {
624+
return;
625+
}
626+
if (visitedTypes.contains(type)) {
627+
return;
628+
}
629+
visitedTypes.add(type);
630+
if (type is TypeParameterType) {
631+
var element = type.element3;
632+
if ((candidates == null || candidates.contains(element)) &&
633+
!boundTypeParameters.contains(element)) {
634+
parameters ??= <TypeParameterElement2>[];
635+
parameters!.add(element);
636+
}
637+
} else if (type is FunctionType) {
638+
assert(
639+
!type.typeParameters.any((t) => boundTypeParameters.contains(t)));
640+
boundTypeParameters.addAll(type.typeParameters);
641+
appendParameters(type.returnType);
642+
type.parameters.map((p) => p.type).forEach(appendParameters);
643+
// TODO(scheglov): https://github.com/dart-lang/sdk/issues/44218
644+
type.alias?.typeArguments.forEach(appendParameters);
645+
boundTypeParameters.removeAll(type.typeParameters);
646+
} else if (type is InterfaceType) {
647+
type.typeArguments.forEach(appendParameters);
648+
} else if (type is RecordType) {
649+
type.positionalFields.map((f) => f.type).forEach(appendParameters);
650+
type.namedFields.map((f) => f.type).forEach(appendParameters);
651+
}
652+
}
653+
654+
appendParameters(rootType);
655+
return parameters;
656+
}
657+
610658
/// Returns the greatest closure of [type] with respect to [typeParameters].
611659
///
612660
/// https://github.com/dart-lang/language
@@ -837,6 +885,83 @@ class TypeSystemImpl implements TypeSystem {
837885
return orderedArguments;
838886
}
839887

888+
/// Given uninstantiated [typeFormals], instantiate them to their bounds.
889+
/// See the issue for the algorithm description.
890+
///
891+
/// https://github.com/dart-lang/sdk/issues/27526#issuecomment-260021397
892+
List<TypeImpl> instantiateTypeFormalsToBounds2(
893+
List<TypeParameterElementImpl2> typeFormals,
894+
{List<bool>? hasError,
895+
Map<TypeParameterElement2, TypeImpl>? knownTypes}) {
896+
int count = typeFormals.length;
897+
if (count == 0) {
898+
return const <TypeImpl>[];
899+
}
900+
901+
Set<TypeParameterElement2> all = <TypeParameterElement2>{};
902+
// all ground
903+
Map<TypeParameterElement2, TypeImpl> defaults = knownTypes ?? {};
904+
// not ground
905+
Map<TypeParameterElement2, TypeImpl> partials = {};
906+
907+
for (var typeParameter in typeFormals) {
908+
all.add(typeParameter);
909+
if (!defaults.containsKey(typeParameter)) {
910+
var bound = typeParameter.bound ?? DynamicTypeImpl.instance;
911+
partials[typeParameter] = bound;
912+
}
913+
}
914+
915+
bool hasProgress = true;
916+
while (hasProgress) {
917+
hasProgress = false;
918+
for (TypeParameterElement2 parameter in partials.keys) {
919+
var value = partials[parameter]!;
920+
var freeParameters = getFreeParameters2(value, candidates: all);
921+
if (freeParameters == null) {
922+
defaults[parameter] = value;
923+
partials.remove(parameter);
924+
hasProgress = true;
925+
break;
926+
} else if (freeParameters.every(defaults.containsKey)) {
927+
defaults[parameter] =
928+
Substitution.fromMap2(defaults).substituteType(value);
929+
partials.remove(parameter);
930+
hasProgress = true;
931+
break;
932+
}
933+
}
934+
}
935+
936+
// If we stopped making progress, and not all types are ground,
937+
// then the whole type is malbounded and an error should be reported
938+
// if errors are requested, and a partially completed type should
939+
// be returned.
940+
if (partials.isNotEmpty) {
941+
if (hasError != null) {
942+
hasError[0] = true;
943+
}
944+
var domain = defaults.keys.toList();
945+
var range = defaults.values.toList();
946+
// Build a substitution Phi mapping each uncompleted type variable to
947+
// dynamic, and each completed type variable to its default.
948+
for (TypeParameterElement2 parameter in partials.keys) {
949+
domain.add(parameter);
950+
range.add(DynamicTypeImpl.instance);
951+
}
952+
// Set the default for an uncompleted type variable (T extends B)
953+
// to be Phi(B)
954+
for (TypeParameterElement2 parameter in partials.keys) {
955+
defaults[parameter] = Substitution.fromPairs2(domain, range)
956+
.substituteType(partials[parameter]!);
957+
}
958+
}
959+
960+
List<TypeImpl> orderedArguments =
961+
typeFormals.map((p) => defaults[p]!).toFixedList();
962+
return orderedArguments;
963+
}
964+
840965
/// https://github.com/dart-lang/language
841966
/// accepted/future-releases/0546-patterns/feature-specification.md#exhaustiveness-and-reachability
842967
bool isAlwaysExhaustive(DartType type) {

pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
// ignore_for_file: analyzer_use_new_elements
6-
75
import 'package:analyzer/dart/analysis/features.dart';
86
import 'package:analyzer/dart/ast/syntactic_entity.dart';
9-
import 'package:analyzer/dart/element/element.dart';
107
import 'package:analyzer/dart/element/element2.dart';
118
import 'package:analyzer/dart/element/type.dart';
129
import 'package:analyzer/dart/element/type_provider.dart';
@@ -27,7 +24,6 @@ import 'package:analyzer/src/dart/resolver/resolution_result.dart';
2724
import 'package:analyzer/src/error/codes.dart';
2825
import 'package:analyzer/src/generated/inference_log.dart';
2926
import 'package:analyzer/src/generated/resolver.dart';
30-
import 'package:analyzer/src/utilities/extensions/element.dart';
3127
import 'package:analyzer/src/utilities/extensions/string.dart';
3228

3329
class ExtensionMemberResolver {
@@ -106,7 +102,7 @@ class ExtensionMemberResolver {
106102
if (extensions.length == 1) {
107103
var instantiated = extensions[0];
108104
_resolver.libraryFragment.scope.notifyExtensionUsed(
109-
instantiated.extension.asElement,
105+
instantiated.extension,
110106
);
111107
return instantiated.asResolutionResult;
112108
}
@@ -115,7 +111,7 @@ class ExtensionMemberResolver {
115111
if (mostSpecific.length == 1) {
116112
var instantiated = mostSpecific.first;
117113
_resolver.libraryFragment.scope.notifyExtensionUsed(
118-
instantiated.extension.asElement,
114+
instantiated.extension,
119115
);
120116
return instantiated.asResolutionResult;
121117
}
@@ -157,35 +153,35 @@ class ExtensionMemberResolver {
157153
/// The [node] is fully resolved, and its type arguments are set.
158154
ExtensionResolutionResult getOverrideMember(
159155
ExtensionOverride node, String name) {
160-
var element = node.element;
156+
var element = node.element2;
161157

162-
ExecutableElement? getter;
163-
ExecutableElement? setter;
158+
ExecutableElement2? getter;
159+
ExecutableElement2? setter;
164160
if (name == '[]') {
165-
getter = element.getMethod('[]');
166-
setter = element.getMethod('[]=');
161+
getter = element.getMethod2('[]');
162+
setter = element.getMethod2('[]=');
167163
} else {
168-
getter = element.getGetter(name) ?? element.getMethod(name);
169-
setter = element.getSetter(name);
164+
getter = element.getGetter2(name) ?? element.getMethod2(name);
165+
setter = element.getSetter2(name);
170166
}
171167

172168
if (getter == null && setter == null) {
173169
return ExtensionResolutionError.none;
174170
}
175171

176-
var substitution = Substitution.fromPairs(
177-
element.typeParameters,
172+
var substitution = Substitution.fromPairs2(
173+
element.typeParameters2,
178174
node.typeArgumentTypes!,
179175
);
180176

181177
var getterMember =
182-
getter != null ? ExecutableMember.from2(getter, substitution) : null;
178+
getter != null ? ExecutableMember.from(getter, substitution) : null;
183179
var setterMember =
184-
setter != null ? ExecutableMember.from2(setter, substitution) : null;
180+
setter != null ? ExecutableMember.from(setter, substitution) : null;
185181

186182
return SingleExtensionResolutionResult(
187-
getter2: getterMember?.asElement2,
188-
setter2: setterMember?.asElement2,
183+
getter2: getterMember,
184+
setter2: setterMember,
189185
);
190186
}
191187

@@ -394,12 +390,12 @@ class ExtensionMemberResolver {
394390

395391
/// Instantiate the extended type of the [extension] to the bounds of the
396392
/// type formals of the extension.
397-
DartType _instantiateToBounds(ExtensionElement extension) {
398-
extension as ExtensionElementImpl;
399-
var typeParameters = extension.typeParameters;
400-
return Substitution.fromPairs(
393+
DartType _instantiateToBounds(ExtensionElement2 extension) {
394+
extension as ExtensionElementImpl2;
395+
var typeParameters = extension.typeParameters2;
396+
return Substitution.fromPairs2(
401397
typeParameters,
402-
_typeSystem.instantiateTypeFormalsToBounds(typeParameters),
398+
_typeSystem.instantiateTypeFormalsToBounds2(typeParameters),
403399
).substituteType(extension.extendedType);
404400
}
405401

@@ -438,8 +434,8 @@ class ExtensionMemberResolver {
438434
// 5. ...the instantiate-to-bounds type of T1 is a subtype of the
439435
// instantiate-to-bounds type of T2 and not vice versa.
440436
// TODO(scheglov): store instantiated types
441-
var extendedTypeBound1 = _instantiateToBounds(e1.extension.asElement);
442-
var extendedTypeBound2 = _instantiateToBounds(e2.extension.asElement);
437+
var extendedTypeBound1 = _instantiateToBounds(e1.extension);
438+
var extendedTypeBound2 = _instantiateToBounds(e2.extension);
443439
return _isSubtypeOf(extendedTypeBound1, extendedTypeBound2) &&
444440
!_isSubtypeOf(extendedTypeBound2, extendedTypeBound1);
445441
}

0 commit comments

Comments
 (0)