Skip to content

Commit

Permalink
[analyzer] Fix type of transformedParameters when inheriting covariance
Browse files Browse the repository at this point in the history
In `InheritanceManager3._inheritCovariance`, if the original
`ExecutableElement` is in fact an `ExecutableMember`, then its
parameters will be `ParameterMember`s. These `ParameterMember`s need
to be converted to `ParameterElementImpl`s in order to be safely
stored in the synthetic `ExecutableElementImpl` that
`_inheritCovariance` returns.

I will follow up with a fix that changes the type accepted by
`ExecutableElementImpl.parameters=` in order to prevent similar
problems happening in the future.

Fixes #59849.

Bug: #59849
Change-Id: I636fd8cca0411745aedb3cd834354b4dcc0aadc1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/403322
Commit-Queue: Paul Berry <[email protected]>
Reviewed-by: Konstantin Shcheglov <[email protected]>
  • Loading branch information
stereotype441 authored and Commit Queue committed Jan 8, 2025
1 parent 3a73f32 commit e4e42f7
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 3 deletions.
7 changes: 6 additions & 1 deletion pkg/analyzer/lib/src/dart/element/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ extension LibraryExtension2 on LibraryElement2? {

extension ParameterElementExtensions on ParameterElement {
/// Return [ParameterElement] with the specified properties replaced.
ParameterElement copyWith({
ParameterElementImpl copyWith({
DartType? type,
ParameterKind? kind,
bool? isCovariant,
Expand All @@ -217,6 +217,11 @@ extension ParameterElementExtensions on ParameterElement {
kind ?? parameterKind,
)..isExplicitlyCovariant = isCovariant ?? this.isCovariant;
}

/// Returns `this`, converted to a [ParameterElementImpl] if it isn't one
/// already.
ParameterElementImpl toImpl() =>
switch (this) { ParameterElementImpl p => p, _ => copyWith() };
}

extension RecordTypeExtension on RecordType {
Expand Down
6 changes: 4 additions & 2 deletions pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1042,14 +1042,16 @@ class InheritanceManager3 {
}

// Update covariance of the parameters of the chosen executable.
List<ParameterElement>? transformedParameters;
List<ParameterElementImpl>? transformedParameters;
for (var index = 0; index < parameters.length; index++) {
var parameter = parameters[index];
var shouldBeCovariant = covariantParameters.contains(
_ParameterDesc(index, parameter),
);
if (parameter.isCovariant != shouldBeCovariant) {
transformedParameters ??= parameters.toList();
transformedParameters ??= [
for (var parameter in parameters) parameter.toImpl()
];
transformedParameters[index] = parameter.copyWith(
isCovariant: shouldBeCovariant,
);
Expand Down
22 changes: 22 additions & 0 deletions pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2400,6 +2400,28 @@ abstract class B extends A {}
expect(returnType.element, same(T));
}

test_getMember_method_covariantAfterSubstitutedParameter_merged() async {
await resolveTestCode(r'''
class A<T> {
void foo<U>(covariant Object a, U b, int c) {}
}
class B extends A<int> implements C {}
class C {
void foo<U>(Object a, U b, covariant Object c) {}
}
''');
var member = manager.getMember2(
findElement.classOrMixin('B'),
Name(null, 'foo'),
concrete: true,
)!;
expect(member.parameters[0].isCovariant, isTrue);
expect(member.parameters[1].isCovariant, isFalse);
expect(member.parameters[2].isCovariant, isTrue);
}

test_getMember_method_covariantByDeclaration_inherited() async {
await resolveTestCode('''
abstract class A {
Expand Down

0 comments on commit e4e42f7

Please sign in to comment.