Skip to content

Commit 095232c

Browse files
solves the generic function type scoping problem (fixes the test). Includes further failures documented here: #31804 with @failingTests. These do seem to fail today as is, so it should be safe to land. Bug: Change-Id: Ice384b6fee35f1b1c4235bb0e4de7a90e2379937 Reviewed-on: https://dart-review.googlesource.com/33582 Commit-Queue: Mike Fairhurst <[email protected]> Reviewed-by: Paul Berry <[email protected]>
1 parent 279cc08 commit 095232c

File tree

9 files changed

+130
-65
lines changed

9 files changed

+130
-65
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,14 +418,17 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
418418
* Initialize a newly created function type that is semantically the same as
419419
* [original], but which has been syntactically renamed with fresh type
420420
* parameters at its outer binding site (if any).
421+
*
422+
* If type formals is empty, this returns the original unless [force] is set
423+
* to [true].
421424
*/
422-
factory FunctionTypeImpl.fresh(FunctionType original) {
425+
factory FunctionTypeImpl.fresh(FunctionType original, {bool force = false}) {
423426
// We build up a substitution for the type parameters,
424427
// {variablesFresh/variables} then apply it.
425428

426429
var originalFormals = original.typeFormals;
427430
var formalCount = originalFormals.length;
428-
if (formalCount == 0) return original;
431+
if (formalCount == 0 && !force) return original;
429432

430433
// Allocate fresh type variables
431434
var typeVars = <DartType>[];

pkg/analyzer/lib/src/summary/format.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,12 @@ class EntityRefBuilder extends Object
23072307
_implicitFunctionTypeIndices ??= <int>[];
23082308

23092309
/**
2310+
* Notice: This will be deprecated. However, its not deprecated yet, as we're
2311+
* keeping it for backwards compatibilty, and marking it deprecated makes it
2312+
* unreadable.
2313+
*
2314+
* TODO(mfairhurst) mark this deprecated, and remove its logic.
2315+
*
23102316
* If this is a reference to a function type implicitly defined by a
23112317
* function-typed parameter, a list of zero-based indices indicating the path
23122318
* from the entity referred to by [reference] to the appropriate type

pkg/analyzer/lib/src/summary/format.fbs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,12 @@ table EntityRef {
12151215
entityKind:EntityRefKind (id: 8);
12161216

12171217
/**
1218+
* Notice: This will be deprecated. However, its not deprecated yet, as we're
1219+
* keeping it for backwards compatibilty, and marking it deprecated makes it
1220+
* unreadable.
1221+
*
1222+
* TODO(mfairhurst) mark this deprecated, and remove its logic.
1223+
*
12181224
* If this is a reference to a function type implicitly defined by a
12191225
* function-typed parameter, a list of zero-based indices indicating the path
12201226
* from the entity referred to by [reference] to the appropriate type

pkg/analyzer/lib/src/summary/idl.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,12 @@ abstract class EntityRef extends base.SummaryClass {
405405
EntityRefKind get entityKind;
406406

407407
/**
408+
* Notice: This will be deprecated. However, its not deprecated yet, as we're
409+
* keeping it for backwards compatibilty, and marking it deprecated makes it
410+
* unreadable.
411+
*
412+
* TODO(mfairhurst) mark this deprecated, and remove its logic.
413+
*
408414
* If this is a reference to a function type implicitly defined by a
409415
* function-typed parameter, a list of zero-based indices indicating the path
410416
* from the entity referred to by [reference] to the appropriate type

pkg/analyzer/lib/src/summary/link.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,8 @@ EntityRefBuilder _createLinkedType(
230230
return result;
231231
}
232232
if (element is GenericFunctionTypeElementForLink) {
233-
// TODO(mfairhurst) update the typeParameterContext to be the current
234-
// element. See test_constExpr_makeTypedList_functionType. This causes
235-
// serious breakages elsewhere.
233+
// Function types are their own type parameter context
234+
typeParameterContext = element;
236235
result.entityKind = EntityRefKind.genericFunctionType;
237236
result.syntheticReturnType = _createLinkedType(
238237
type.returnType, compilationUnit, typeParameterContext);
@@ -4325,6 +4324,9 @@ class ParameterElementForLink implements ParameterElementImpl {
43254324
DartType _declaredType;
43264325
bool _inheritsCovariant = false;
43274326

4327+
@override
4328+
String get identifier => name;
4329+
43284330
ParameterElementForLink(this.enclosingElement, this._unlinkedParam,
43294331
this._typeParameterContext, this.compilationUnit, this._parameterIndex) {
43304332
if (_unlinkedParam.initializer?.bodyExpr != null) {

pkg/analyzer/lib/src/task/strong_mode.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,18 @@ class InstanceMemberInferrer {
169169
parameter, index, overriddenTypes[i].parameters);
170170
DartType type = matchingParameter?.type ?? typeProvider.dynamicType;
171171
if (parameterType == null) {
172-
parameterType = type;
172+
if (type is FunctionType &&
173+
type.element is! TypeDefiningElement &&
174+
type.element.enclosingElement is! TypeDefiningElement) {
175+
// The resulting parameter's type element has an `enclosingElement` of
176+
// the overridden parameter. Change it to the overriding parameter.
177+
parameterType = new FunctionTypeImpl.fresh(type, force: true);
178+
(parameterType.element as ElementImpl).enclosingElement = parameter;
179+
// TODO(mfairhurst) handle cases where non-functions contain functions
180+
// See test_inferredType_parameter_genericFunctionType_asTypeArgument
181+
} else {
182+
parameterType = type;
183+
}
173184
} else if (parameterType != type) {
174185
if (parameter is ParameterElementForLink) {
175186
parameter.setInferenceError(new TopLevelInferenceErrorBuilder(

pkg/analyzer/test/generated/strong_mode_test.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4312,4 +4312,26 @@ int x = 3;
43124312
assertPropagatedAssignedType(code, unit, typeProvider.intType, null);
43134313
assertTypeOfMarkedExpression(code, unit, typeProvider.intType, null);
43144314
}
4315+
4316+
test_inconsistentMethodInheritance_inferFunctionTypeFromTypedef() async {
4317+
Source source = addSource(r'''
4318+
typedef bool F<E>(E argument);
4319+
4320+
abstract class Base {
4321+
f<E extends int>(F<int> x);
4322+
}
4323+
4324+
abstract class BaseCopy extends Base {
4325+
}
4326+
4327+
abstract class Override implements Base, BaseCopy {
4328+
f<E>(x) => null;
4329+
}
4330+
4331+
class C extends Override implements Base {}
4332+
''');
4333+
await computeAnalysisResult(source);
4334+
assertNoErrors(source);
4335+
verify([source]);
4336+
}
43154337
}

pkg/analyzer/test/src/summary/linker_test.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,33 @@ class C extends A<int> {
467467
expect(fType.parameters[0].type.toString(), 'int');
468468
}
469469

470+
@failingTest
471+
void test_inferredType_parameter_genericFunctionType_asTypeArgument() {
472+
var bundle = createPackageBundle('''
473+
class A<T> {
474+
A<R> map<R>(List<R Function(T)> fs) => null;
475+
}
476+
''', path: '/a.dart');
477+
addBundle('/a.ds', bundle);
478+
createLinker('''
479+
import 'a.dart';
480+
class C extends A<int> {
481+
map<R2>(fs) => null;
482+
}
483+
''');
484+
LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
485+
library.libraryCycleForLink.ensureLinked();
486+
ClassElementForLink_Class c = library.getContainedName('C');
487+
expect(c.methods, hasLength(1));
488+
MethodElementForLink map = c.methods[0];
489+
expect(map.parameters, hasLength(1));
490+
InterfaceType iType = map.parameters[0].type;
491+
expect(iType.typeArguments, hasLength(1));
492+
FunctionType fType = iType.typeArguments[0];
493+
expect(fType.returnType.toString(), 'R2');
494+
expect(fType.parameters[0].type.toString(), 'int');
495+
}
496+
470497
void test_inferredType_staticField_dynamic() {
471498
createLinker('''
472499
dynamic x = null;

pkg/analyzer/test/src/summary/summary_common.dart

Lines changed: 41 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ abstract class SummaryTest {
549549
List<_PrefixExpectation> prefixExpectations,
550550
int numTypeArguments: 0,
551551
ReferenceKind expectedKind: ReferenceKind.classOrEnum,
552+
EntityRefKind entityKind: null,
552553
int expectedTargetUnit: 0,
553554
LinkedUnit linkedSourceUnit,
554555
UnlinkedUnit unlinkedSourceUnit,
@@ -559,6 +560,12 @@ abstract class SummaryTest {
559560
expect(typeRef.paramReference, 0);
560561
int index = typeRef.reference;
561562
expect(typeRef.typeArguments, hasLength(numTypeArguments));
563+
564+
if (entityKind == EntityRefKind.genericFunctionType) {
565+
// [GenericFunctionType]s don't have references to check.
566+
return;
567+
}
568+
562569
UnlinkedReference reference = checkReferenceIndex(
563570
index, absoluteUri, expectedName,
564571
expectedKind: expectedKind,
@@ -2663,7 +2670,6 @@ const int v = p.a.length;
26632670
]);
26642671
}
26652672

2666-
@failingTest
26672673
test_constExpr_makeTypedList_functionType_withTypeParameters() {
26682674
UnlinkedVariable variable = serializeVariableText(
26692675
'final v = <void Function<T>(Function<Q>(T, Q))>[];');
@@ -2682,13 +2688,13 @@ const int v = p.a.length;
26822688
expect(param.type.entityKind, EntityRefKind.genericFunctionType);
26832689
expect(param.type.syntheticParams, hasLength(2));
26842690
{
2685-
final subparam = reference.syntheticParams[0];
2691+
final subparam = param.type.syntheticParams[0];
26862692
expect(subparam.name, ''); // no name for generic type parameters
26872693
expect(subparam.type, new isInstanceOf<EntityRef>());
26882694
expect(subparam.type.paramReference, 2);
26892695
}
26902696
{
2691-
final subparam = reference.syntheticParams[1];
2697+
final subparam = param.type.syntheticParams[1];
26922698
expect(subparam.name, ''); // no name for generic type parameters
26932699
expect(subparam.type, new isInstanceOf<EntityRef>());
26942700
expect(subparam.type.paramReference, 1);
@@ -7989,10 +7995,6 @@ import "${'a'}.dart";
79897995
if (!strongMode || skipFullyLinkedData) {
79907996
return;
79917997
}
7992-
// The type that is inferred for C.f's parameter g is "() -> void".
7993-
// Since the associated element for that function type is B.f's parameter g,
7994-
// and B has a type parameter, the inferred type will record a type
7995-
// parameter.
79967998
UnlinkedClass c = serializeClassText('''
79977999
abstract class B<T> {
79988000
void f(void g());
@@ -8007,9 +8009,14 @@ class C<T> extends B<T> {
80078009
UnlinkedParam g = f.parameters[0];
80088010
expect(g.name, 'g');
80098011
EntityRef typeRef = getTypeRefForSlot(g.inferredTypeSlot);
8010-
checkLinkedTypeRef(typeRef, null, 'f',
8011-
expectedKind: ReferenceKind.method, numTypeArguments: 1);
8012-
checkParamTypeRef(typeRef.typeArguments[0], 1);
8012+
8013+
// The type that is inferred for C.f's parameter g is "() -> void".
8014+
// Therefore it has no type arguments. However, the associated element for
8015+
// that function type is B.f's parameter g, and B has a type parameter, so
8016+
// the inferred type *may* safely record that T as a type parameter, in
8017+
// which case this assertion can be altered accordingly.
8018+
checkTypeRef(typeRef, null, 'f',
8019+
numTypeArguments: 0, entityKind: EntityRefKind.genericFunctionType);
80138020
}
80148021

80158022
test_inferred_type_keeps_leading_dynamic() {
@@ -8071,7 +8078,7 @@ var v = h((y) {});
80718078
expect(y.name, 'y');
80728079
EntityRef typeRef = getTypeRefForSlot(y.inferredTypeSlot);
80738080
checkLinkedTypeRef(typeRef, null, 'F', expectedKind: ReferenceKind.typedef);
8074-
expect(typeRef.implicitFunctionTypeIndices, [0]);
8081+
expect(typeRef.implicitFunctionTypeIndices, isEmpty);
80758082
}
80768083

80778084
test_inferred_type_refers_to_function_typed_parameter_type_generic_class() {
@@ -8086,24 +8093,15 @@ var v = h((y) {});
80868093
getTypeRefForSlot(cls.executables[0].parameters[1].inferredTypeSlot);
80878094
// Check that parameter g's inferred type is the type implied by D.f's 1st
80888095
// (zero-based) parameter.
8089-
expect(type.implicitFunctionTypeIndices, [1]);
8096+
expect(type.implicitFunctionTypeIndices, isEmpty);
80908097
expect(type.paramReference, 0);
8091-
expect(type.typeArguments, hasLength(2));
8092-
checkParamTypeRef(type.typeArguments[0], 1);
8093-
checkTypeRef(type.typeArguments[1], 'dart:core', 'int');
8094-
expect(type.reference,
8095-
greaterThanOrEqualTo(unlinkedUnits[0].references.length));
8096-
LinkedReference linkedReference =
8097-
linked.units[0].references[type.reference];
8098-
expect(linkedReference.dependency, 0);
8099-
expect(linkedReference.kind, ReferenceKind.method);
8100-
expect(linkedReference.name, 'f');
8101-
expect(linkedReference.numTypeParameters, 0);
8102-
expect(linkedReference.unit, 0);
8103-
expect(linkedReference.containingReference, isNot(0));
8104-
expect(linkedReference.containingReference, lessThan(type.reference));
8105-
checkReferenceIndex(linkedReference.containingReference, null, 'D',
8106-
numTypeParameters: 2);
8098+
// Note: this *may* legally have two type arguments (V, W), but for the
8099+
// moment does not in practice, so we assert isEmpty.
8100+
expect(type.typeArguments, isEmpty);
8101+
expect(type.entityKind, EntityRefKind.syntheticFunction);
8102+
expect(type.syntheticParams, hasLength(1));
8103+
checkParamTypeRef(type.syntheticParams[0].type, 1);
8104+
checkLinkedTypeRef(type.syntheticReturnType, 'dart:core', 'int');
81078105
}
81088106

81098107
test_inferred_type_refers_to_function_typed_parameter_type_other_lib() {
@@ -8117,24 +8115,15 @@ var v = h((y) {});
81178115
'import "a.dart"; class C extends D { void f(int x, g) {} }');
81188116
EntityRef type =
81198117
getTypeRefForSlot(cls.executables[0].parameters[1].inferredTypeSlot);
8120-
// Check that parameter g's inferred type is the type implied by D.f's 1st
8121-
// (zero-based) parameter.
8122-
expect(type.implicitFunctionTypeIndices, [1]);
8118+
expect(type.implicitFunctionTypeIndices, isEmpty);
81238119
expect(type.paramReference, 0);
8120+
// Note: this *may* legally have two type arguments (V, W), but for the
8121+
// moment does not in practice, so we assert isEmpty.
81248122
expect(type.typeArguments, isEmpty);
8125-
expect(type.reference,
8126-
greaterThanOrEqualTo(unlinkedUnits[0].references.length));
8127-
LinkedReference linkedReference =
8128-
linked.units[0].references[type.reference];
8129-
expect(linkedReference.dependency, 0);
8130-
expect(linkedReference.kind, ReferenceKind.method);
8131-
expect(linkedReference.name, 'f');
8132-
expect(linkedReference.numTypeParameters, 0);
8133-
expect(linkedReference.unit, 0);
8134-
expect(linkedReference.containingReference, isNot(0));
8135-
expect(linkedReference.containingReference, lessThan(type.reference));
8136-
checkReferenceIndex(
8137-
linkedReference.containingReference, absUri('/b.dart'), 'E');
8123+
expect(type.entityKind, EntityRefKind.syntheticFunction);
8124+
expect(type.syntheticParams, hasLength(1));
8125+
checkLinkedTypeRef(type.syntheticReturnType, 'dart:core', 'int');
8126+
checkLinkedTypeRef(type.syntheticParams[0].type, 'dart:core', 'String');
81388127
}
81398128

81408129
test_inferred_type_refers_to_method_function_typed_parameter_type() {
@@ -8147,23 +8136,16 @@ var v = h((y) {});
81478136
className: 'C');
81488137
EntityRef type =
81498138
getTypeRefForSlot(cls.executables[0].parameters[1].inferredTypeSlot);
8150-
// Check that parameter g's inferred type is the type implied by D.f's 1st
8151-
// (zero-based) parameter.
8152-
expect(type.implicitFunctionTypeIndices, [1]);
8139+
8140+
expect(type.implicitFunctionTypeIndices, isEmpty);
81538141
expect(type.paramReference, 0);
8142+
// Note: this *may* legally have two type arguments (V, W), but for the
8143+
// moment does not in practice, so we assert isEmpty.
81548144
expect(type.typeArguments, isEmpty);
8155-
expect(type.reference,
8156-
greaterThanOrEqualTo(unlinkedUnits[0].references.length));
8157-
LinkedReference linkedReference =
8158-
linked.units[0].references[type.reference];
8159-
expect(linkedReference.dependency, 0);
8160-
expect(linkedReference.kind, ReferenceKind.method);
8161-
expect(linkedReference.name, 'f');
8162-
expect(linkedReference.numTypeParameters, 0);
8163-
expect(linkedReference.unit, 0);
8164-
expect(linkedReference.containingReference, isNot(0));
8165-
expect(linkedReference.containingReference, lessThan(type.reference));
8166-
checkReferenceIndex(linkedReference.containingReference, null, 'D');
8145+
expect(type.entityKind, EntityRefKind.syntheticFunction);
8146+
expect(type.syntheticParams, hasLength(1));
8147+
checkLinkedTypeRef(type.syntheticReturnType, 'dart:core', 'int');
8148+
checkLinkedTypeRef(type.syntheticParams[0].type, 'dart:core', 'String');
81678149
}
81688150

81698151
test_inferred_type_refers_to_nested_function_typed_param() {

0 commit comments

Comments
 (0)