Skip to content

Commit 924f2f9

Browse files
author
John Messerly
committed
clean up generic methods in resolution
Introduces MethodInvocation.staticInvokeType to track the type of this invocation. This provides a natural place to store the instantiated generic function type. We then use this type when we are computing corresponding parameters or return types. As a result we do not need FunctionMember, and some of the code around generics becomes simpler/more uniform. This approach should be a straightforward way to add support for generics in FunctionExpressionInvocation, in a follow up (see issue #25175). Also renames "boundTypeParameters" to "typeFormals". "formals" and "actuals" is a pretty common way to describe these, I'm not sure why I didn't think of that better name originally. :) Also removes broken ParameterMember.== that I had added in a previous CL. And the broken FunctionTypeImpl.originalFunction/instantiatedTypeArguments getters. Finally, this fixes #23252 in the process of adding this. The return type of a "call" method was not being statically analyzed if the target was a VariableElement. [email protected], [email protected] Review URL: https://codereview.chromium.org/1568643002 .
1 parent acc709b commit 924f2f9

File tree

12 files changed

+422
-426
lines changed

12 files changed

+422
-426
lines changed

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,20 @@ abstract class DartType {
131131
*/
132132
abstract class FunctionType implements ParameterizedType {
133133
/**
134-
* The type parameters of this generic function. For example `<T> T -> T`.
134+
* Deprecated: use [typeFormals].
135+
*/
136+
@deprecated
137+
List<TypeParameterElement> get boundTypeParameters;
138+
139+
/**
140+
* The formal type parameters of this generic function.
141+
* For example `<T> T -> T`.
135142
*
136143
* These are distinct from the [typeParameters] list, which contains type
137144
* parameters from surrounding contexts, and thus are free type variables from
138145
* the perspective of this function type.
139146
*/
140-
List<TypeParameterElement> get boundTypeParameters;
147+
List<TypeParameterElement> get typeFormals;
141148

142149
/**
143150
* Return a map from the names of named parameters to the types of the named
@@ -569,7 +576,7 @@ abstract class InterfaceType implements ParameterizedType {
569576
*/
570577
// TODO(jmesserly): introduce a new "instantiate" and deprecate this.
571578
// The new "instantiate" should work similar to FunctionType.instantiate,
572-
// which uses [boundTypeParameters] to model type parameters that haven't been
579+
// which uses [typeFormals] to model type parameters that haven't been
573580
// filled in yet. Those are kept separate from already-substituted type
574581
// parameters or free variables from the enclosing scopes, which allows nested
575582
// generics to work, such as a generic method in a generic class.
@@ -590,7 +597,16 @@ abstract class InterfaceType implements ParameterizedType {
590597
}
591598

592599
/**
593-
* A type with type parameters, such as a class or function type alias.
600+
* A type that can track substituted type parameters, either for itself after
601+
* instantiation, or from a surrounding context.
602+
*
603+
* For example, given a class `Foo<T>`, after instantiation with S for T, it
604+
* will track the substitution `{S/T}`.
605+
*
606+
* This substitution will be propagated to its members. For example, say our
607+
* `Foo<T>` class has a field `T bar;`. When we look up this field, we will get
608+
* back a [FieldElement] that tracks the substituted type as `{S/T}T`, so when
609+
* we ask for the field type we will get`S`.
594610
*
595611
* Clients may not extend, implement or mix-in this class.
596612
*/

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -339,15 +339,21 @@ class FieldMember extends VariableMember implements FieldElement {
339339
}
340340

341341
/**
342+
* Deprecated: this type is no longer used. Use
343+
* [MethodInvocation.staticInvokeType] to get the instantiated type of a generic
344+
* method invocation.
345+
*
342346
* An element of a generic function, where the type parameters are known.
343347
*/
344348
// TODO(jmesserly): the term "function member" is a bit weird, but it allows
345349
// a certain consistency.
350+
@deprecated
346351
class FunctionMember extends ExecutableMember implements FunctionElement {
347352
/**
348353
* Initialize a newly created element to represent a function, based on the
349354
* [baseElement], with the corresponding function [type].
350355
*/
356+
@deprecated
351357
FunctionMember(FunctionElement baseElement, [DartType type])
352358
: super(baseElement, null, type);
353359

@@ -674,12 +680,6 @@ class ParameterMember extends VariableMember
674680
@override
675681
SourceRange get visibleRange => baseElement.visibleRange;
676682

677-
// TODO(jmesserly): this equality is broken. It should consider the defining
678-
// type as well, otherwise we're dropping the substitution.
679-
@override
680-
bool operator ==(Object object) =>
681-
object is ParameterMember && baseElement == object.baseElement;
682-
683683
@override
684684
accept(ElementVisitor visitor) => visitor.visitParameterElement(this);
685685

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

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
177177
/**
178178
* True if this type is the result of instantiating type parameters (and thus
179179
* any type parameters bound by the typedef should be considered part of
180-
* [typeParameters] rather than [boundTypeParameters]).
180+
* [typeParameters] rather than [typeFormals]).
181181
*/
182182
final bool _isInstantiated;
183183

@@ -243,8 +243,12 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
243243
*/
244244
DartType get baseReturnType => element.returnType;
245245

246+
@deprecated
246247
@override
247-
List<TypeParameterElement> get boundTypeParameters {
248+
List<TypeParameterElement> get boundTypeParameters => typeFormals;
249+
250+
@override
251+
List<TypeParameterElement> get typeFormals {
248252
if (_isInstantiated) {
249253
return TypeParameterElement.EMPTY_LIST;
250254
} else {
@@ -349,26 +353,6 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
349353
return code;
350354
}
351355

352-
/**
353-
* The type arguments that were used to instantiate this function type, if
354-
* any, otherwise this will return an empty list.
355-
*
356-
* Given a function type `f`:
357-
*
358-
* f == f.originalFunction.instantiate(f.instantiatedTypeArguments)
359-
*
360-
* Will always hold.
361-
*/
362-
List<DartType> get instantiatedTypeArguments {
363-
int typeParameterCount = element.type.boundTypeParameters.length;
364-
if (typeParameterCount == 0) {
365-
return DartType.EMPTY_LIST;
366-
}
367-
// The substituted types at the end should be our bound type parameters.
368-
int skipCount = typeArguments.length - typeParameterCount;
369-
return new List<DartType>.from(typeArguments.skip(skipCount));
370-
}
371-
372356
/**
373357
* Return `true` if this type is the result of instantiating type parameters.
374358
*/
@@ -471,20 +455,6 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
471455
return types;
472456
}
473457

474-
/**
475-
* If this is an instantiation of a generic function type, this will get
476-
* the original function from which it was instantiated.
477-
*
478-
* Otherwise, this will return `this`.
479-
*/
480-
FunctionTypeImpl get originalFunction {
481-
if (element.type.boundTypeParameters.isEmpty) {
482-
return this;
483-
}
484-
return (element.type as FunctionTypeImpl).substitute2(typeArguments,
485-
TypeParameterTypeImpl.getTypes(typeParameters), prunedTypedefs);
486-
}
487-
488458
@override
489459
List<ParameterElement> get parameters {
490460
List<ParameterElement> baseParameters = this.baseParameters;
@@ -558,19 +528,19 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
558528
return false;
559529
}
560530
FunctionTypeImpl otherType = object as FunctionTypeImpl;
561-
if (boundTypeParameters.length != otherType.boundTypeParameters.length) {
531+
if (typeFormals.length != otherType.typeFormals.length) {
562532
return false;
563533
}
564534
// `<T>T -> T` should be equal to `<U>U -> U`
565535
// To test this, we instantiate both types with the same (unique) type
566536
// variables, and see if the result is equal.
567-
if (boundTypeParameters.isNotEmpty) {
537+
if (typeFormals.isNotEmpty) {
568538
List<DartType> instantiateTypeArgs = new List<DartType>();
569539
List<DartType> variablesThis = new List<DartType>();
570540
List<DartType> variablesOther = new List<DartType>();
571-
for (int i = 0; i < boundTypeParameters.length; i++) {
572-
TypeParameterElement pThis = boundTypeParameters[i];
573-
TypeParameterElement pOther = otherType.boundTypeParameters[i];
541+
for (int i = 0; i < typeFormals.length; i++) {
542+
TypeParameterElement pThis = typeFormals[i];
543+
TypeParameterElement pOther = otherType.typeFormals[i];
574544
TypeParameterTypeImpl pFresh = new TypeParameterTypeImpl(
575545
new TypeParameterElementImpl(pThis.name, -1));
576546
instantiateTypeArgs.add(pFresh);
@@ -583,7 +553,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
583553
return false;
584554
}
585555
}
586-
// After instantiation, they will no longer have boundTypeParameters,
556+
// After instantiation, they will no longer have typeFormals,
587557
// so we will continue below.
588558
return this.instantiate(instantiateTypeArgs) ==
589559
otherType.instantiate(instantiateTypeArgs);
@@ -599,7 +569,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
599569

600570
@override
601571
void appendTo(StringBuffer buffer) {
602-
if (boundTypeParameters.isNotEmpty) {
572+
if (typeFormals.isNotEmpty) {
603573
// To print a type with type variables, first make sure we have unique
604574
// variable names to print.
605575
Set<TypeParameterType> freeVariables = new HashSet<TypeParameterType>();
@@ -615,8 +585,8 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
615585
List<DartType> instantiateTypeArgs = new List<DartType>();
616586
List<DartType> variables = new List<DartType>();
617587
buffer.write("<");
618-
for (TypeParameterElement e in boundTypeParameters) {
619-
if (e != boundTypeParameters[0]) {
588+
for (TypeParameterElement e in typeFormals) {
589+
if (e != typeFormals[0]) {
620590
buffer.write(",");
621591
}
622592
String name = e.name;
@@ -645,7 +615,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
645615
buffer.write(">");
646616

647617
// Instantiate it and print the resulting type. After instantiation, it
648-
// will no longer have boundTypeParameters, so we will continue below.
618+
// will no longer have typeFormals, so we will continue below.
649619
this.instantiate(instantiateTypeArgs).appendTo(buffer);
650620
return;
651621
}
@@ -713,10 +683,10 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
713683

714684
@override
715685
FunctionTypeImpl instantiate(List<DartType> argumentTypes) {
716-
if (argumentTypes.length != boundTypeParameters.length) {
686+
if (argumentTypes.length != typeFormals.length) {
717687
throw new IllegalArgumentException(
718688
"argumentTypes.length (${argumentTypes.length}) != "
719-
"boundTypeParameters.length (${boundTypeParameters.length})");
689+
"typeFormals.length (${typeFormals.length})");
720690
}
721691
if (argumentTypes.isEmpty) {
722692
return this;
@@ -725,7 +695,7 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
725695
// Given:
726696
// {U/T} <S> T -> S
727697
// Where {U/T} represents the typeArguments (U) and typeParameters (T) list,
728-
// and <S> represents the boundTypeParameters.
698+
// and <S> represents the typeFormals.
729699
//
730700
// Now instantiate([V]), and the result should be:
731701
// {U/T, V/S} T -> S.
@@ -1024,8 +994,8 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
1024994
FunctionType type, Set<TypeParameterType> free) {
1025995
// Make some fresh variables to avoid capture.
1026996
List<DartType> typeArgs = DartType.EMPTY_LIST;
1027-
if (type.boundTypeParameters.isNotEmpty) {
1028-
typeArgs = new List<DartType>.from(type.boundTypeParameters.map((e) =>
997+
if (type.typeFormals.isNotEmpty) {
998+
typeArgs = new List<DartType>.from(type.typeFormals.map((e) =>
1029999
new TypeParameterTypeImpl(new TypeParameterElementImpl(e.name, -1))));
10301000

10311001
type = type.instantiate(typeArgs);

pkg/analyzer/lib/src/generated/ast.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8087,6 +8087,21 @@ class MethodInvocation extends Expression {
80878087
*/
80888088
ArgumentList _argumentList;
80898089

8090+
/**
8091+
* The function type of the method invocation, or `null` if the AST
8092+
* structure has not been resolved, or if the invoke could not be resolved.
8093+
*
8094+
* This will usually be a [FunctionType], but it can also be an
8095+
* [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
8096+
* interface type that implements `Function`.
8097+
*/
8098+
DartType staticInvokeType;
8099+
8100+
/**
8101+
* Like [staticInvokeType], but reflects propagated type information.
8102+
*/
8103+
DartType propagatedInvokeType;
8104+
80908105
/**
80918106
* Initialize a newly created method invocation. The [target] and [operator]
80928107
* can be `null` if there is no target.

0 commit comments

Comments
 (0)