Skip to content

Commit f5af2d9

Browse files
stereotype441Commit Bot
authored and
Commit Bot
committed
Use ParameterMember when substituting function types.
This ensures that the parameters from the function type still point to the original function declaration (previously, they were synthetic parameters). This should lead to a better user experience in editor integration, by ensuring that the editor can still find the parameter declarations associated with parameters in generic function invocations. Fixes #48500. Change-Id: I10a0dd54e7c70e1d0d05dced37565c35bcaabfd0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243524 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent e593b86 commit f5af2d9

File tree

5 files changed

+122
-34
lines changed

5 files changed

+122
-34
lines changed

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

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class ConstructorMember extends ExecutableMember
2424
/// Initialize a newly created element to represent a constructor, based on
2525
/// the [declaration], and applied [substitution].
2626
ConstructorMember(
27-
TypeProviderImpl typeProvider,
27+
TypeProviderImpl? typeProvider,
2828
ConstructorElement declaration,
2929
MapSubstitution substitution,
3030
bool isLegacy,
@@ -138,7 +138,7 @@ abstract class ExecutableMember extends Member implements ExecutableElement {
138138
/// their bounds. The [substitution] includes replacing [declaration] type
139139
/// parameters with the provided fresh [typeParameters].
140140
ExecutableMember(
141-
TypeProviderImpl typeProvider,
141+
TypeProviderImpl? typeProvider,
142142
ExecutableElement declaration,
143143
MapSubstitution substitution,
144144
bool isLegacy,
@@ -178,6 +178,12 @@ abstract class ExecutableMember extends Member implements ExecutableElement {
178178
@override
179179
bool get isSynchronous => declaration.isSynchronous;
180180

181+
@override
182+
LibraryElement get library => _declaration.library!;
183+
184+
@override
185+
Source get librarySource => _declaration.librarySource!;
186+
181187
@override
182188
List<ParameterElement> get parameters {
183189
return declaration.parameters.map<ParameterElement>((p) {
@@ -220,7 +226,7 @@ abstract class ExecutableMember extends Member implements ExecutableElement {
220226
ExecutableElement element,
221227
MapSubstitution substitution,
222228
) {
223-
TypeProviderImpl typeProvider;
229+
TypeProviderImpl? typeProvider;
224230
var isLegacy = false;
225231
var combined = substitution;
226232
if (element is ExecutableMember) {
@@ -261,7 +267,7 @@ abstract class ExecutableMember extends Member implements ExecutableElement {
261267
class FieldFormalParameterMember extends ParameterMember
262268
implements FieldFormalParameterElement {
263269
factory FieldFormalParameterMember(
264-
TypeProviderImpl typeProvider,
270+
TypeProviderImpl? typeProvider,
265271
FieldFormalParameterElement declaration,
266272
MapSubstitution substitution,
267273
bool isLegacy,
@@ -280,7 +286,7 @@ class FieldFormalParameterMember extends ParameterMember
280286
}
281287

282288
FieldFormalParameterMember._(
283-
TypeProviderImpl typeProvider,
289+
TypeProviderImpl? typeProvider,
284290
FieldFormalParameterElement declaration,
285291
MapSubstitution substitution,
286292
bool isLegacy,
@@ -320,7 +326,7 @@ class FieldMember extends VariableMember implements FieldElement {
320326
/// Initialize a newly created element to represent a field, based on the
321327
/// [declaration], with applied [substitution].
322328
FieldMember(
323-
TypeProviderImpl typeProvider,
329+
TypeProviderImpl? typeProvider,
324330
FieldElement declaration,
325331
MapSubstitution substitution,
326332
bool isLegacy,
@@ -360,6 +366,9 @@ class FieldMember extends VariableMember implements FieldElement {
360366
@override
361367
bool get isExternal => declaration.isExternal;
362368

369+
@override
370+
LibraryElement get library => _declaration.library!;
371+
363372
@override
364373
String get name => declaration.name;
365374

@@ -406,8 +415,8 @@ class FieldMember extends VariableMember implements FieldElement {
406415
}
407416

408417
class FunctionMember extends ExecutableMember implements FunctionElement {
409-
FunctionMember(
410-
TypeProviderImpl typeProvider, FunctionElement declaration, bool isLegacy)
418+
FunctionMember(TypeProviderImpl? typeProvider, FunctionElement declaration,
419+
bool isLegacy)
411420
: super(
412421
typeProvider,
413422
declaration,
@@ -441,7 +450,7 @@ class FunctionMember extends ExecutableMember implements FunctionElement {
441450
/// parameters are known.
442451
abstract class Member implements Element {
443452
/// A type provider (might be legacy, might be null-safe).
444-
final TypeProviderImpl _typeProvider;
453+
final TypeProviderImpl? _typeProvider;
445454

446455
/// The element on which the parameterized element was created.
447456
final Element _declaration;
@@ -459,6 +468,10 @@ abstract class Member implements Element {
459468
if (_declaration is Member) {
460469
throw StateError('Members must be created from a declarations.');
461470
}
471+
if (_typeProvider == null && isLegacy) {
472+
throw StateError(
473+
'A type provider must be supplied for legacy conversion');
474+
}
462475
}
463476

464477
@override
@@ -552,10 +565,10 @@ abstract class Member implements Element {
552565
ElementKind get kind => _declaration.kind;
553566

554567
@override
555-
LibraryElement get library => _declaration.library!;
568+
LibraryElement? get library => _declaration.library;
556569

557570
@override
558-
Source get librarySource => _declaration.librarySource!;
571+
Source? get librarySource => _declaration.librarySource;
559572

560573
@override
561574
ElementLocation get location => _declaration.location!;
@@ -642,7 +655,7 @@ abstract class Member implements Element {
642655
/// Otherwise, return the type unchanged.
643656
DartType _toLegacyType(DartType type) {
644657
if (isLegacy) {
645-
return NullabilityEliminator.perform(_typeProvider, type);
658+
return NullabilityEliminator.perform(_typeProvider!, type);
646659
} else {
647660
return type;
648661
}
@@ -720,7 +733,7 @@ abstract class Member implements Element {
720733
/// type parameters are known.
721734
class MethodMember extends ExecutableMember implements MethodElement {
722735
factory MethodMember(
723-
TypeProviderImpl typeProvider,
736+
TypeProviderImpl? typeProvider,
724737
MethodElement declaration,
725738
MapSubstitution substitution,
726739
bool isLegacy,
@@ -739,7 +752,7 @@ class MethodMember extends ExecutableMember implements MethodElement {
739752
}
740753

741754
MethodMember._(
742-
TypeProviderImpl typeProvider,
755+
TypeProviderImpl? typeProvider,
743756
MethodElement declaration,
744757
MapSubstitution substitution,
745758
bool isLegacy,
@@ -799,7 +812,7 @@ class ParameterMember extends VariableMember
799812
final List<TypeParameterElement> typeParameters;
800813

801814
factory ParameterMember(
802-
TypeProviderImpl typeProvider,
815+
TypeProviderImpl? typeProvider,
803816
ParameterElement declaration,
804817
MapSubstitution substitution,
805818
bool isLegacy,
@@ -820,7 +833,7 @@ class ParameterMember extends VariableMember
820833
/// Initialize a newly created element to represent a parameter, based on the
821834
/// [declaration], with applied [substitution].
822835
ParameterMember._(
823-
TypeProviderImpl typeProvider,
836+
TypeProviderImpl? typeProvider,
824837
ParameterElement declaration,
825838
MapSubstitution substitution,
826839
bool isLegacy,
@@ -887,14 +900,41 @@ class ParameterMember extends VariableMember
887900
super.visitChildren(visitor);
888901
safelyVisitChildren(parameters, visitor);
889902
}
903+
904+
static ParameterElement from(
905+
ParameterElement element, MapSubstitution substitution) {
906+
TypeProviderImpl? typeProvider;
907+
var isLegacy = false;
908+
var combined = substitution;
909+
if (element is ParameterMember) {
910+
var member = element;
911+
element = member.declaration;
912+
typeProvider = member._typeProvider;
913+
914+
isLegacy = member.isLegacy;
915+
916+
var map = <TypeParameterElement, DartType>{};
917+
for (var entry in member._substitution.map.entries) {
918+
map[entry.key] = substitution.substituteType(entry.value);
919+
}
920+
map.addAll(substitution.map);
921+
combined = Substitution.fromMap(map);
922+
}
923+
924+
if (!isLegacy && combined.map.isEmpty) {
925+
return element;
926+
}
927+
928+
return ParameterMember(typeProvider, element, combined, isLegacy);
929+
}
890930
}
891931

892932
/// A property accessor element defined in a parameterized type where the values
893933
/// of the type parameters are known.
894934
class PropertyAccessorMember extends ExecutableMember
895935
implements PropertyAccessorElement {
896936
factory PropertyAccessorMember(
897-
TypeProviderImpl typeProvider,
937+
TypeProviderImpl? typeProvider,
898938
PropertyAccessorElement declaration,
899939
MapSubstitution substitution,
900940
bool isLegacy,
@@ -913,7 +953,7 @@ class PropertyAccessorMember extends ExecutableMember
913953
}
914954

915955
PropertyAccessorMember._(
916-
TypeProviderImpl typeProvider,
956+
TypeProviderImpl? typeProvider,
917957
PropertyAccessorElement declaration,
918958
MapSubstitution substitution,
919959
bool isLegacy,
@@ -1005,7 +1045,7 @@ class PropertyAccessorMember extends ExecutableMember
10051045
class SuperFormalParameterMember extends ParameterMember
10061046
implements SuperFormalParameterElement {
10071047
factory SuperFormalParameterMember(
1008-
TypeProviderImpl typeProvider,
1048+
TypeProviderImpl? typeProvider,
10091049
SuperFormalParameterElement declaration,
10101050
MapSubstitution substitution,
10111051
bool isLegacy,
@@ -1024,7 +1064,7 @@ class SuperFormalParameterMember extends ParameterMember
10241064
}
10251065

10261066
SuperFormalParameterMember._(
1027-
TypeProviderImpl typeProvider,
1067+
TypeProviderImpl? typeProvider,
10281068
SuperFormalParameterElement declaration,
10291069
MapSubstitution substitution,
10301070
bool isLegacy,
@@ -1063,7 +1103,7 @@ class SuperFormalParameterMember extends ParameterMember
10631103
class TopLevelVariableMember extends VariableMember
10641104
implements TopLevelVariableElement {
10651105
TopLevelVariableMember(
1066-
TypeProviderImpl typeProvider,
1106+
TypeProviderImpl? typeProvider,
10671107
VariableElement declaration,
10681108
MapSubstitution substitution,
10691109
bool isLegacy,
@@ -1092,6 +1132,9 @@ class TopLevelVariableMember extends VariableMember
10921132
@override
10931133
bool get isExternal => declaration.isExternal;
10941134

1135+
@override
1136+
LibraryElement get library => _declaration.library!;
1137+
10951138
@override
10961139
String get name => declaration.name;
10971140

@@ -1119,7 +1162,7 @@ abstract class VariableMember extends Member implements VariableElement {
11191162
/// Initialize a newly created element to represent a variable, based on the
11201163
/// [declaration], with applied [substitution].
11211164
VariableMember(
1122-
TypeProviderImpl typeProvider,
1165+
TypeProviderImpl? typeProvider,
11231166
VariableElement declaration,
11241167
MapSubstitution substitution,
11251168
bool isLegacy,

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import 'package:analyzer/dart/element/type_visitor.dart';
1010
import 'package:analyzer/src/dart/analysis/session.dart';
1111
import 'package:analyzer/src/dart/element/display_string_builder.dart';
1212
import 'package:analyzer/src/dart/element/element.dart';
13-
import 'package:analyzer/src/dart/element/extensions.dart';
1413
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
1514
import 'package:analyzer/src/dart/element/member.dart';
1615
import 'package:analyzer/src/dart/element/type_algebra.dart';
@@ -224,9 +223,8 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
224223
return FunctionTypeImpl(
225224
returnType: substitution.substituteType(returnType),
226225
typeFormals: const [],
227-
parameters: parameters
228-
.map((p) => p.copyWith(type: substitution.substituteType(p.type)))
229-
.toList(),
226+
parameters:
227+
parameters.map((p) => ParameterMember.from(p, substitution)).toList(),
230228
nullabilitySuffix: nullabilitySuffix,
231229
);
232230
}

pkg/analyzer/lib/src/test_utilities/mock_sdk.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,9 @@ abstract class Set<E> implements Iterable<E> {
591591
void addAll(Iterable<E> elements);
592592
bool remove(Object? value);
593593
E? lookup(Object? object);
594+
595+
static Set<T> castFrom<S, T>(Set<S> source, {Set<R> Function<R>()? newSet}) =>
596+
throw '';
594597
}
595598
596599
class StackTrace {}

pkg/analyzer/test/generated/non_error_resolver_test.dart

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,10 +1458,8 @@ test(C c) => c.method<bool>(arg: true);
14581458
''');
14591459
var x = findNode.namedExpression('arg: true');
14601460
var y = x.staticParameterElement!;
1461-
// Note: the staticParameterElement is synthetic; see
1462-
// https://github.com/dart-lang/sdk/issues/48500
1463-
expect(y, isNot(TypeMatcher<ParameterMember>()));
1464-
expect(y.enclosingElement, isNull);
1461+
expect(y.enclosingElement, isNotNull);
1462+
expect(y.declaration, findElement.parameter('arg'));
14651463
}
14661464

14671465
test_generic_staticParameterElement_methodCall_implicitTypeArg() async {
@@ -1473,10 +1471,8 @@ bool test(C c) => c.method<bool>(arg: true);
14731471
''');
14741472
var x = findNode.namedExpression('arg: true');
14751473
var y = x.staticParameterElement!;
1476-
// Note: the staticParameterElement is synthetic; see
1477-
// https://github.com/dart-lang/sdk/issues/48500
1478-
expect(y, isNot(TypeMatcher<ParameterMember>()));
1479-
expect(y.enclosingElement, isNull);
1474+
expect(y.enclosingElement, isNotNull);
1475+
expect(y.declaration, findElement.parameter('arg'));
14801476
}
14811477

14821478
test_genericTypeAlias_castsAndTypeChecks_hasTypeParameters() async {
@@ -2258,6 +2254,21 @@ int f(v) {
22582254
''');
22592255
}
22602256

2257+
test_librarySource_of_type_substituted_synthetic_parameter() async {
2258+
await assertErrorsInCode('''
2259+
Map<int, T> f<T>(T t) => throw '';
2260+
Map<double, T> g<T>(T t) => throw '';
2261+
h(bool b) {
2262+
Map<num, String> m = (b ? f : g)('x');
2263+
}
2264+
''', [
2265+
error(HintCode.UNUSED_LOCAL_VARIABLE, 104, 1),
2266+
]);
2267+
var parameter = findNode.stringLiteral("'x'").staticParameterElement;
2268+
expect(parameter!.library, isNull);
2269+
expect(parameter.librarySource, isNull);
2270+
}
2271+
22612272
test_loadLibraryDefined() async {
22622273
newFile('$testPackageLibPath/lib.dart', r'''
22632274
library lib;
@@ -3310,6 +3321,24 @@ core.dynamic dynamicVariable;
33103321
@reflectiveTest
33113322
class NonErrorResolverWithoutNullSafetyTest extends PubPackageResolutionTest
33123323
with WithoutNullSafetyMixin, NonErrorResolverTestCases {
3324+
test_castFrom() async {
3325+
// This test exercises a corner case of legacy erasure: due to the type
3326+
// substitution in the `newSet` parameter of `Set.castFrom`, we wind up with
3327+
// a synthetic `ParameterMember` that belongs to no library. We need to
3328+
// make sure this doesn't lead to a crash.
3329+
await assertErrorsInCode('''
3330+
class C {}
3331+
3332+
void testNewSet(Set<C> setEls) {
3333+
var customNewSet;
3334+
Set.castFrom<C, Object>(setEls,
3335+
newSet: <T>() => customNewSet = new Set<T>());
3336+
}
3337+
''', [
3338+
error(HintCode.UNUSED_LOCAL_VARIABLE, 51, 12),
3339+
]);
3340+
}
3341+
33133342
test_conflictingStaticGetterAndInstanceSetter_thisClass() async {
33143343
await assertNoErrorsInCode(r'''
33153344
class A {

pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,21 @@ ConstructorReference
242242
''');
243243
}
244244

245+
test_alias_generic_with_inferred_type_parameter() async {
246+
await assertErrorsInCode('''
247+
class C<T> {
248+
final T x;
249+
C(this.x);
250+
}
251+
typedef Direct<T> = C<T>;
252+
void main() {
253+
var x = const <C<int> Function(int)>[Direct.new];
254+
}
255+
''', [
256+
error(HintCode.UNUSED_LOCAL_VARIABLE, 87, 1),
257+
]);
258+
}
259+
245260
test_alias_genericWithBound_unnamed() async {
246261
await assertNoErrorsInCode('''
247262
class A<T> {

0 commit comments

Comments
 (0)