Skip to content

Commit

Permalink
Elements. Migrate SubtypeHelper.
Browse files Browse the repository at this point in the history
Change-Id: Iced0a394881f82937638caba4011cd8ac09ffa98
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/404280
Reviewed-by: Phil Quitslund <[email protected]>
Commit-Queue: Konstantin Shcheglov <[email protected]>
  • Loading branch information
scheglov authored and Commit Queue committed Jan 14, 2025
1 parent d3c7590 commit 50527da
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 75 deletions.
3 changes: 2 additions & 1 deletion pkg/analyzer/lib/src/dart/element/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11367,7 +11367,8 @@ class TypeParameterElementImpl2 extends TypeDefiningElementImpl2
TypeParameterType instantiate({
required NullabilitySuffix nullabilitySuffix,
}) {
return firstFragment.instantiate(
return TypeParameterTypeImpl.v2(
element: this,
nullabilitySuffix: nullabilitySuffix,
);
}
Expand Down
83 changes: 44 additions & 39 deletions pkg/analyzer/lib/src/dart/element/subtype.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// ignore_for_file: analyzer_use_new_elements

import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
show Variance;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
Expand Down Expand Up @@ -92,7 +90,7 @@ class SubtypeHelper {
T0 is TypeParameterTypeImpl) {
var S = T0.promotedBound;
if (S == null) {
var B = T0.element.bound ?? _objectQuestion;
var B = T0.element3.bound ?? _objectQuestion;
return isSubtypeOf(B, _objectNone);
} else {
return isSubtypeOf(S, _objectNone);
Expand All @@ -115,7 +113,7 @@ class SubtypeHelper {
return false;
}
// Extension types require explicit `Object` implementation.
if (T0 is InterfaceTypeImpl && T0.element is ExtensionTypeElement) {
if (T0 is InterfaceTypeImpl && T0.element3 is ExtensionTypeElement2) {
for (var interface in T0.interfaces) {
if (isSubtypeOf(interface, T1_)) {
return true;
Expand Down Expand Up @@ -179,7 +177,7 @@ class SubtypeHelper {
if (T0 is TypeParameterTypeImpl &&
T1 is TypeParameterTypeImpl &&
T1.promotedBound == null &&
T0.element == T1.element) {
T0.element3 == T1.element3) {
return true;
}

Expand All @@ -188,8 +186,8 @@ class SubtypeHelper {
if (T1 is TypeParameterTypeImpl) {
var T1_promotedBound = T1.promotedBound;
if (T1_promotedBound != null) {
var X1 = TypeParameterTypeImpl(
element: T1.element,
var X1 = TypeParameterTypeImpl.v2(
element: T1.element3,
nullabilitySuffix: T1.nullabilitySuffix,
);
return isSubtypeOf(T0, X1) && isSubtypeOf(T0, T1_promotedBound);
Expand Down Expand Up @@ -221,7 +219,7 @@ class SubtypeHelper {
if (S0 != null && isSubtypeOf(S0, T1)) {
return true;
}
var B0 = T0.element.bound;
var B0 = T0.element3.bound;
if (B0 != null && isSubtypeOf(B0, T1)) {
return true;
}
Expand Down Expand Up @@ -249,7 +247,7 @@ class SubtypeHelper {
if (S0 != null && isSubtypeOf(S0, T1)) {
return true;
}
var B0 = T0.element.bound;
var B0 = T0.element3.bound;
if (B0 != null && isSubtypeOf(B0, T1)) {
return true;
}
Expand All @@ -275,7 +273,7 @@ class SubtypeHelper {
return true;
}

var B0 = T0.element.bound;
var B0 = T0.element3.bound;
if (B0 != null && isSubtypeOf(B0, T1)) {
return true;
}
Expand Down Expand Up @@ -305,19 +303,19 @@ class SubtypeHelper {
}

bool _interfaceArguments(
InterfaceElement element,
InterfaceElement2 element,
InterfaceType subType,
InterfaceType superType,
) {
List<TypeParameterElement> parameters = element.typeParameters;
List<TypeParameterElement2> parameters = element.typeParameters2;
List<DartType> subArguments = subType.typeArguments;
List<DartType> superArguments = superType.typeArguments;

assert(subArguments.length == superArguments.length);
assert(parameters.length == subArguments.length);

for (int i = 0; i < subArguments.length; i++) {
var parameter = parameters[i] as TypeParameterElementImpl;
var parameter = parameters[i] as TypeParameterElementImpl2;
var subArgument = subArguments[i];
var superArgument = superArguments[i];

Expand Down Expand Up @@ -347,7 +345,8 @@ class SubtypeHelper {

/// Check that [f] is a subtype of [g].
bool _isFunctionSubtypeOf(FunctionType f, FunctionType g) {
var fresh = _typeSystem.relateTypeParameters(f.typeFormals, g.typeFormals);
var fresh =
_typeSystem.relateTypeParameters2(f.typeParameters, g.typeParameters);
if (fresh == null) {
return false;
}
Expand All @@ -359,8 +358,8 @@ class SubtypeHelper {
return false;
}

var fParameters = f.parameters;
var gParameters = g.parameters;
var fParameters = f.formalParameters;
var gParameters = g.formalParameters;

var fIndex = 0;
var gIndex = 0;
Expand Down Expand Up @@ -391,27 +390,33 @@ class SubtypeHelper {
}
} else if (fParameter.isNamed) {
if (gParameter.isNamed) {
var compareNames = fParameter.name.compareTo(gParameter.name);
if (compareNames == 0) {
if (fParameter.isRequiredNamed && !gParameter.isRequiredNamed) {
return false;
} else if (isSubtypeOf(gParameter.type, fParameter.type)) {
fIndex++;
gIndex++;
} else {
return false;
}
} else if (compareNames < 0) {
if (fParameter.isRequiredNamed) {
return false;
} else {
fIndex++;
}
} else {
assert(compareNames > 0);
// The subtype must accept all parameters of the supertype.
var fName = fParameter.name3;
var gName = gParameter.name3;
if (fName == null || gName == null) {
return false;
}

var compareNames = fName.compareTo(gName);
switch (compareNames) {
case 0:
if (fParameter.isRequiredNamed && !gParameter.isRequiredNamed) {
return false;
} else if (isSubtypeOf(gParameter.type, fParameter.type)) {
fIndex++;
gIndex++;
} else {
return false;
}
case < 0:
if (fParameter.isRequiredNamed) {
return false;
} else {
fIndex++;
}
default:
// The subtype must accept all parameters of the supertype.
return false;
}
} else {
break;
}
Expand Down Expand Up @@ -448,8 +453,8 @@ class SubtypeHelper {
return false;
}

var subElement = subType.element;
var superElement = superType.element;
var subElement = subType.element3;
var superElement = superType.element3;
if (identical(subElement, superElement)) {
return _interfaceArguments(superElement, subType, superType);
}
Expand All @@ -460,7 +465,7 @@ class SubtypeHelper {
}

for (var interface in subElement.allSupertypes) {
if (identical(interface.element, superElement)) {
if (identical(interface.element3, superElement)) {
var substitution = Substitution.fromInterfaceType(subType);
var substitutedInterface =
substitution.substituteType(interface) as InterfaceType;
Expand Down
11 changes: 3 additions & 8 deletions pkg/analyzer/lib/src/dart/element/type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,9 @@ class FunctionTypeImpl extends TypeImpl
Null get element3 => null;

@override
List<FormalParameterElement> get formalParameters => parameters
.map((parameter) => switch (parameter) {
FormalParameterFragment(:var element) => element,
ParameterMember(:var element) => element,
_ => throw UnsupportedError(
'Unsupported type ${parameter.runtimeType}'),
})
.toList();
List<FormalParameterElement> get formalParameters {
return parameters.map((p) => p.asElement2).toList(growable: false);
}

@Deprecated('Check element, or use getDisplayString()')
@override
Expand Down
75 changes: 75 additions & 0 deletions pkg/analyzer/lib/src/dart/element/type_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import 'package:analyzer/src/dart/element/well_bounded.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/generated/inference_log.dart';
import 'package:analyzer/src/utilities/extensions/collection.dart';
import 'package:analyzer/src/utilities/extensions/element.dart';
import 'package:meta/meta.dart';

class ExtensionTypeErasure extends ReplacementVisitor {
Expand Down Expand Up @@ -78,6 +79,19 @@ class RelatedTypeParameters {
);
}

/// Fresh type parameters created to unify two lists of type parameters.
class RelatedTypeParameters2 {
static final _empty = RelatedTypeParameters2._(const [], const []);

final List<TypeParameterElement2> typeParameters;
final List<TypeParameterType> typeParameterTypes;

RelatedTypeParameters2._(
this.typeParameters,
this.typeParameterTypes,
);
}

/// The [TypeSystem] implementation.
class TypeSystemImpl implements TypeSystem {
/// The provider of types for the system.
Expand Down Expand Up @@ -1622,6 +1636,67 @@ class TypeSystemImpl implements TypeSystem {
);
}

/// Given two lists of type parameters, check that they have the same
/// number of elements, and their bounds are equal.
///
/// The return value will be a new list of fresh type parameters, that can
/// be used to instantiate both function types, allowing further comparison.
RelatedTypeParameters2? relateTypeParameters2(
List<TypeParameterElement2> typeParameters1,
List<TypeParameterElement2> typeParameters2,
) {
if (typeParameters1.length != typeParameters2.length) {
return null;
}
if (typeParameters1.isEmpty) {
return RelatedTypeParameters2._empty;
}

var length = typeParameters1.length;
var freshTypeParameters = List.generate(length, (index) {
return typeParameters1[index].freshCopy();
}, growable: false);

var freshTypeParameterTypes = List.generate(length, (index) {
return freshTypeParameters[index].instantiate(
nullabilitySuffix: NullabilitySuffix.none,
);
}, growable: false);

var substitution1 = Substitution.fromPairs2(
typeParameters1,
freshTypeParameterTypes,
);
var substitution2 = Substitution.fromPairs2(
typeParameters2,
freshTypeParameterTypes,
);

for (var i = 0; i < typeParameters1.length; i++) {
var bound1 = typeParameters1[i].bound;
var bound2 = typeParameters2[i].bound;
if (bound1 == null && bound2 == null) {
continue;
}
bound1 ??= DynamicTypeImpl.instance;
bound2 ??= DynamicTypeImpl.instance;
bound1 = substitution1.substituteType(bound1);
bound2 = substitution2.substituteType(bound2);
if (!isEqualTo(bound1, bound2)) {
return null;
}

if (bound1 is! DynamicType) {
freshTypeParameters[i].bound = bound1;
}
}

return RelatedTypeParameters2._(
freshTypeParameters,
freshTypeParameterTypes,
);
}

/// Replaces all covariant occurrences of `dynamic`, `void`, and `Object` or
/// `Object?` with `Null` or `Never` and all contravariant occurrences of
/// `Null` or `Never` with `Object` or `Object?`.
Expand Down
11 changes: 11 additions & 0 deletions pkg/analyzer/lib/src/utilities/extensions/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,17 @@ extension TypeParameterElement2Extension on TypeParameterElement2 {
TypeParameterElement get asElement {
return firstFragment as TypeParameterElement;
}

TypeParameterElementImpl2 freshCopy() {
return TypeParameterElementImpl2(
firstFragment: TypeParameterElementImpl(
name3 ?? '',
-1,
),
name3: name3,
bound: bound,
);
}
}

extension TypeParameterElementExtension on TypeParameterElement {
Expand Down
Loading

0 comments on commit 50527da

Please sign in to comment.