Introduce tests specific to behaviors of FunctionType.
I am about to start embarking on bug fixes and refactors to
FunctionType, so I want a set of tests that I can use to make sure I
don't break any important behaviors. These tests use a mock element
model, so they don't rely on any behaviors outside of FunctionTypeImpl
itself.
Change-Id: I037f6a8cd2ee2a94fba13bb9b6be9e7090e254e8
Reviewed-on: https://dart-review.googlesource.com/57708
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/test/src/dart/element/function_type_test.dart b/pkg/analyzer/test/src/dart/element/function_type_test.dart
new file mode 100644
index 0000000..047473b
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/element/function_type_test.dart
@@ -0,0 +1,1002 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(FunctionTypeTest);
+ });
+}
+
+DynamicTypeImpl get dynamicType => DynamicTypeImpl.instance;
+
+VoidTypeImpl get voidType => VoidTypeImpl.instance;
+
+Element getBaseElement(Element e) {
+ if (e is Member) {
+ return e.baseElement;
+ } else {
+ return e;
+ }
+}
+
+@reflectiveTest
+class FunctionTypeTest {
+ static const bug_33294_fixed = false;
+ static const bug_33300_fixed = false;
+ static const bug_33301_fixed = false;
+ static const bug_33302_fixed = false;
+
+ final objectType = new InterfaceTypeImpl(new MockClassElement('Object'));
+
+ final mapType = _makeMapType();
+
+ final listType = _makeListType();
+
+ void basicChecks(FunctionType f,
+ {element,
+ displayName: '() → dynamic',
+ returnType,
+ namedParameterTypes: isEmpty,
+ normalParameterNames: isEmpty,
+ normalParameterTypes: isEmpty,
+ optionalParameterNames: isEmpty,
+ optionalParameterTypes: isEmpty,
+ parameters: isEmpty,
+ typeFormals: isEmpty,
+ typeArguments: isEmpty,
+ typeParameters: isEmpty,
+ name: isNull}) {
+ // DartType properties
+ expect(f.displayName, displayName, reason: 'displayName');
+ expect(f.element, element);
+ expect(f.name, name, reason: 'name');
+ // ParameterizedType properties
+ expect(f.typeArguments, typeArguments, reason: 'typeArguments');
+ expect(f.typeParameters, typeParameters, reason: 'typeParameters');
+ // FunctionType properties
+ expect(f.namedParameterTypes, namedParameterTypes);
+ expect(f.normalParameterNames, normalParameterNames,
+ reason: 'normalParameterNames');
+ expect(f.normalParameterTypes, normalParameterTypes);
+ expect(f.optionalParameterNames, optionalParameterNames);
+ expect(f.optionalParameterTypes, optionalParameterTypes);
+ expect(f.parameters, parameters);
+ expect(f.returnType, returnType ?? same(dynamicType), reason: 'returnType');
+ expect(f.typeFormals, typeFormals, reason: 'typeFormals');
+ }
+
+ DartType listOf(DartType elementType) => listType.instantiate([elementType]);
+
+ DartType mapOf(DartType keyType, DartType valueType) =>
+ mapType.instantiate([keyType, valueType]);
+
+ test_elementWithNameAndArgs_nonTypedef_noTypeArguments() {
+ var e = new MockFunctionTypedElement();
+ FunctionType f =
+ new FunctionTypeImpl.elementWithNameAndArgs(e, null, [], false);
+ basicChecks(f, element: same(e));
+ }
+
+ test_elementWithNameAndArgs_nonTypedef_withTypeArguments() {
+ var t = new MockTypeParameterElement('T');
+ var c = new MockClassElement('C', typeParameters: [t]);
+ var e = new MockMethodElement(c, returnType: t.type);
+ FunctionType f =
+ new FunctionTypeImpl.elementWithNameAndArgs(e, null, [t.type], false);
+ basicChecks(f,
+ element: same(e),
+ typeArguments: [same(t.type)],
+ typeParameters: [same(t)],
+ displayName: '() → T',
+ returnType: same(t.type));
+ }
+
+ test_elementWithNameAndArgs_typedef_bothTypeParameters() {
+ var t = new MockTypeParameterElement('T');
+ var u = new MockTypeParameterElement('U');
+ var e = new MockGenericTypeAliasElement('F',
+ typeParameters: [t],
+ innerTypeParameters: [u],
+ returnType: mapOf(t.type, u.type));
+ FunctionType f =
+ new FunctionTypeImpl.elementWithNameAndArgs(e, 'F', [objectType], true);
+ basicChecks(f,
+ element: same(e),
+ displayName: 'F<Object>',
+ name: 'F',
+ typeArguments: [same(objectType)],
+ typeParameters: [same(t)],
+ returnType: mapOf(objectType, u.type));
+ }
+
+ test_elementWithNameAndArgs_typedef_innerTypeParameter() {
+ var t = new MockTypeParameterElement('T');
+ var e = new MockGenericTypeAliasElement('F',
+ innerTypeParameters: [t], returnType: t.type);
+ FunctionType f =
+ new FunctionTypeImpl.elementWithNameAndArgs(e, 'F', [], true);
+ basicChecks(f,
+ element: same(e),
+ displayName: 'F',
+ name: 'F',
+ returnType: same(t.type));
+ }
+
+ test_elementWithNameAndArgs_typedef_noTypeParameters() {
+ var e = new MockGenericTypeAliasElement('F');
+ FunctionType f =
+ new FunctionTypeImpl.elementWithNameAndArgs(e, 'F', [], true);
+ basicChecks(f, element: same(e), displayName: 'F', name: 'F');
+ }
+
+ test_elementWithNameAndArgs_typedef_outerTypeParameters() {
+ var t = new MockTypeParameterElement('T');
+ var e = new MockGenericTypeAliasElement('F',
+ typeParameters: [t], returnType: t.type);
+ FunctionType f =
+ new FunctionTypeImpl.elementWithNameAndArgs(e, 'F', [objectType], true);
+ basicChecks(f,
+ element: same(e),
+ displayName: 'F<Object>',
+ name: 'F',
+ typeArguments: [same(objectType)],
+ typeParameters: [same(t)],
+ returnType: same(objectType));
+ }
+
+ test_forTypedef() {
+ var e = new MockGenericTypeAliasElement('F');
+ basicChecks(e.type, element: same(e), displayName: 'F', name: 'F');
+ basicChecks(e.function.type,
+ element: same(e.function), displayName: '() → dynamic');
+ }
+
+ test_forTypedef_innerAndOuterTypeParameter() {
+ // typedef F<T> = T Function<U>(U p);
+ var t = new MockTypeParameterElement('T');
+ var u = new MockTypeParameterElement('U');
+ var p = new MockParameterElement('p', type: u.type);
+ var e = new MockGenericTypeAliasElement('F',
+ typeParameters: [t],
+ innerTypeParameters: [u],
+ returnType: t.type,
+ parameters: [p]);
+ basicChecks(e.type,
+ element: same(e),
+ displayName: 'F',
+ name: 'F',
+ returnType: same(t.type),
+ normalParameterTypes: [same(u.type)],
+ normalParameterNames: ['p'],
+ parameters: [same(p)],
+ typeFormals: [same(t)]);
+ basicChecks(e.function.type,
+ element: same(e.function),
+ displayName: '<U>(U) → T',
+ returnType: same(t.type),
+ typeArguments: [same(t.type)],
+ typeParameters: [same(t)],
+ typeFormals: [same(u)],
+ normalParameterTypes: [same(u.type)],
+ normalParameterNames: ['p'],
+ parameters: [same(p)]);
+ }
+
+ test_forTypedef_innerAndOuterTypeParameter_instantiate() {
+ // typedef F<T> = T Function<U>(U p);
+ var t = new MockTypeParameterElement('T');
+ var u = new MockTypeParameterElement('U');
+ var p = new MockParameterElement('p', type: u.type);
+ var e = new MockGenericTypeAliasElement('F',
+ typeParameters: [t],
+ innerTypeParameters: [u],
+ returnType: t.type,
+ parameters: [p]);
+ var instantiated = e.type.instantiate([objectType]);
+ basicChecks(instantiated,
+ element: same(e),
+ displayName: 'F<Object>',
+ name: 'F',
+ returnType: same(objectType),
+ normalParameterTypes: [same(u.type)],
+ normalParameterNames: ['p'],
+ parameters: [same(p)],
+ typeFormals: isNotNull,
+ typeArguments: [same(objectType)],
+ typeParameters: [same(t)]);
+ if (bug_33294_fixed) {
+ expect(instantiated.typeFormals, [same(u)]);
+ } else {
+ expect(instantiated.typeFormals, isEmpty);
+ }
+ }
+
+ test_forTypedef_innerTypeParameter() {
+ // typedef F = T Function<T>();
+ var t = new MockTypeParameterElement('T');
+ var e = new MockGenericTypeAliasElement('F',
+ innerTypeParameters: [t], returnType: t.type);
+ basicChecks(e.type,
+ element: same(e),
+ displayName: 'F',
+ name: 'F',
+ returnType: same(t.type));
+ basicChecks(e.function.type,
+ element: same(e.function),
+ displayName: '<T>() → T',
+ returnType: same(t.type),
+ typeFormals: [same(t)]);
+ }
+
+ test_forTypedef_normalParameter() {
+ var p = new MockParameterElement('p');
+ var e = new MockGenericTypeAliasElement('F', parameters: [p]);
+ basicChecks(e.type,
+ element: same(e),
+ displayName: 'F',
+ name: 'F',
+ normalParameterNames: ['p'],
+ normalParameterTypes: [same(dynamicType)],
+ parameters: [same(p)]);
+ basicChecks(e.function.type,
+ element: same(e.function),
+ displayName: '(dynamic) → dynamic',
+ normalParameterNames: ['p'],
+ normalParameterTypes: [same(dynamicType)],
+ parameters: [same(p)]);
+ }
+
+ test_forTypedef_recursive_via_interfaceTypes() {
+ // typedef F = List<G> Function();
+ // typedef G = List<F> Function();
+ var f = new MockGenericTypeAliasElement('F');
+ var g = new MockGenericTypeAliasElement('G');
+ f.returnType = listOf(g.function.type);
+ g.returnType = listOf(f.function.type);
+ basicChecks(f.type,
+ element: same(f), displayName: 'F', name: 'F', returnType: isNotNull);
+ var fReturn = f.type.returnType;
+ expect(fReturn.element, same(listType.element));
+ if (bug_33302_fixed) {
+ expect(fReturn.displayName, 'List<G>');
+ } else {
+ expect(fReturn.displayName, 'List<() → List<...>>');
+ }
+ var fReturnArg = (fReturn as InterfaceType).typeArguments[0];
+ expect(fReturnArg.element, same(g.function));
+ var fReturnArgReturn = (fReturnArg as FunctionType).returnType;
+ expect(fReturnArgReturn.element, same(listType.element));
+ expect((fReturnArgReturn as InterfaceType).typeArguments[0],
+ new isInstanceOf<CircularFunctionTypeImpl>());
+ basicChecks(f.function.type,
+ element: same(f.function), displayName: isNotNull, returnType: fReturn);
+ if (bug_33302_fixed) {
+ expect(f.function.type.displayName, '() → List<G>');
+ } else {
+ expect(f.function.type.displayName, '() → List<() → List<...>>');
+ }
+ basicChecks(g.type,
+ element: same(g), displayName: 'G', name: 'G', returnType: isNotNull);
+ var gReturn = g.type.returnType;
+ expect(gReturn.element, same(listType.element));
+ if (bug_33302_fixed) {
+ expect(gReturn.displayName, 'List<F>');
+ } else {
+ expect(gReturn.displayName, 'List<() → List<...>>');
+ }
+ var gReturnArg = (gReturn as InterfaceType).typeArguments[0];
+ expect(gReturnArg.element, same(f.function));
+ var gReturnArgReturn = (gReturnArg as FunctionType).returnType;
+ expect(gReturnArgReturn.element, same(listType.element));
+ expect((gReturnArgReturn as InterfaceType).typeArguments[0],
+ new isInstanceOf<CircularFunctionTypeImpl>());
+ basicChecks(g.function.type,
+ element: same(g.function), displayName: isNotNull, returnType: gReturn);
+ if (bug_33302_fixed) {
+ expect(g.function.type.displayName, '() → F');
+ } else {
+ expect(g.function.type.displayName, '() → List<() → List<...>>');
+ }
+ }
+
+ test_forTypedef_recursive_via_parameterTypes() {
+ // typedef F = void Function(G g);
+ // typedef G = void Function(F f);
+ var f = new MockGenericTypeAliasElement('F', returnType: voidType);
+ var g = new MockGenericTypeAliasElement('G', returnType: voidType);
+ f.parameters = [new MockParameterElement('g', type: g.function.type)];
+ g.parameters = [new MockParameterElement('f', type: f.function.type)];
+ basicChecks(f.type,
+ element: same(f),
+ displayName: 'F',
+ name: 'F',
+ parameters: hasLength(1),
+ normalParameterTypes: hasLength(1),
+ normalParameterNames: ['g'],
+ returnType: same(voidType));
+ var fParamType = f.type.normalParameterTypes[0];
+ expect(fParamType.element, same(g.function));
+ expect((fParamType as FunctionType).normalParameterTypes[0],
+ new isInstanceOf<CircularFunctionTypeImpl>());
+ basicChecks(f.function.type,
+ element: same(f.function),
+ displayName: isNotNull,
+ parameters: hasLength(1),
+ normalParameterTypes: [fParamType],
+ normalParameterNames: ['g'],
+ returnType: same(voidType));
+ if (bug_33302_fixed) {
+ expect(f.function.type.displayName, '(G) → void');
+ } else {
+ expect(f.function.type.displayName, '((...) → void) → void');
+ }
+ basicChecks(g.type,
+ element: same(g),
+ displayName: 'G',
+ name: 'G',
+ parameters: hasLength(1),
+ normalParameterTypes: hasLength(1),
+ normalParameterNames: ['f'],
+ returnType: same(voidType));
+ var gParamType = g.type.normalParameterTypes[0];
+ expect(gParamType.element, same(f.function));
+ expect((gParamType as FunctionType).normalParameterTypes[0],
+ new isInstanceOf<CircularFunctionTypeImpl>());
+ basicChecks(g.function.type,
+ element: same(g.function),
+ displayName: isNotNull,
+ parameters: hasLength(1),
+ normalParameterTypes: [gParamType],
+ normalParameterNames: ['f'],
+ returnType: same(voidType));
+ if (bug_33302_fixed) {
+ expect(g.function.type.displayName, '(F) → void');
+ } else {
+ expect(g.function.type.displayName, '((...) → void) → void');
+ }
+ }
+
+ test_forTypedef_recursive_via_returnTypes() {
+ // typedef F = G Function();
+ // typedef G = F Function();
+ var f = new MockGenericTypeAliasElement('F');
+ var g = new MockGenericTypeAliasElement('G');
+ f.returnType = g.function.type;
+ g.returnType = f.function.type;
+ basicChecks(f.type,
+ element: same(f), displayName: 'F', name: 'F', returnType: isNotNull);
+ var fReturn = f.type.returnType;
+ expect(fReturn.element, same(g.function));
+ expect((fReturn as FunctionType).returnType,
+ new isInstanceOf<CircularFunctionTypeImpl>());
+ basicChecks(f.function.type,
+ element: same(f.function), displayName: isNotNull, returnType: fReturn);
+ if (bug_33302_fixed) {
+ expect(f.function.type.displayName, '() → G');
+ } else {
+ expect(f.function.type.displayName, '() → () → ...');
+ }
+ basicChecks(g.type,
+ element: same(g), displayName: 'G', name: 'G', returnType: isNotNull);
+ var gReturn = g.type.returnType;
+ expect(gReturn.element, same(f.function));
+ expect((gReturn as FunctionType).returnType,
+ new isInstanceOf<CircularFunctionTypeImpl>());
+ basicChecks(g.function.type,
+ element: same(g.function), displayName: isNotNull, returnType: gReturn);
+ if (bug_33302_fixed) {
+ expect(g.function.type.displayName, '() → F');
+ } else {
+ expect(g.function.type.displayName, '() → () → ...');
+ }
+ }
+
+ test_forTypedef_returnType() {
+ var e = new MockGenericTypeAliasElement('F', returnType: objectType);
+ basicChecks(e.type,
+ element: same(e), displayName: 'F', name: 'F', returnType: objectType);
+ basicChecks(e.function.type,
+ element: same(e.function),
+ displayName: '() → Object',
+ returnType: objectType);
+ }
+
+ test_forTypedef_returnType_null() {
+ var e = new MockGenericTypeAliasElement.withNullReturn('F');
+ basicChecks(e.type, element: same(e), displayName: 'F', name: 'F');
+ basicChecks(e.function.type,
+ element: same(e.function), displayName: '() → dynamic');
+ }
+
+ test_forTypedef_typeParameter() {
+ // typedef F<T> = T Function();
+ var t = new MockTypeParameterElement('T');
+ var e = new MockGenericTypeAliasElement('F',
+ typeParameters: [t], returnType: t.type);
+ basicChecks(e.type,
+ element: same(e),
+ displayName: 'F',
+ name: 'F',
+ returnType: same(t.type),
+ typeFormals: [same(t)]);
+ basicChecks(e.function.type,
+ element: same(e.function),
+ displayName: '() → T',
+ returnType: same(t.type),
+ typeArguments: [same(t.type)],
+ typeParameters: [same(t)]);
+ }
+
+ test_unnamedConstructor() {
+ var e = new MockFunctionTypedElement();
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f, element: same(e));
+ }
+
+ test_unnamedConstructor_instantiate_noop() {
+ var t = new MockTypeParameterElement('T');
+ var p = new MockParameterElement('x', type: t.type);
+ var e = new MockFunctionTypedElement(typeParameters: [t], parameters: [p]);
+ FunctionType f = new FunctionTypeImpl(e);
+ var instantiated = f.instantiate([t.type]);
+ basicChecks(instantiated,
+ element: same(e),
+ displayName: '(T) → dynamic',
+ typeArguments: hasLength(1),
+ typeParameters: [same(t)],
+ normalParameterNames: ['x'],
+ normalParameterTypes: [same(t.type)],
+ parameters: [same(p)]);
+ expect(instantiated.typeArguments[0], same(t.type));
+ // TODO(paulberry): test instantiate length mismatch
+ }
+
+ test_unnamedConstructor_instantiate_noTypeParameters() {
+ var e = new MockFunctionTypedElement();
+ FunctionType f = new FunctionTypeImpl(e);
+ expect(f.instantiate([]), same(f));
+ }
+
+ test_unnamedConstructor_instantiate_parameterType_simple() {
+ var t = new MockTypeParameterElement('T');
+ var p = new MockParameterElement('x', type: t.type);
+ var e = new MockFunctionTypedElement(typeParameters: [t], parameters: [p]);
+ FunctionType f = new FunctionTypeImpl(e);
+ var instantiated = f.instantiate([objectType]);
+ basicChecks(instantiated,
+ element: same(e),
+ displayName: '(Object) → dynamic',
+ typeArguments: hasLength(1),
+ typeParameters: [same(t)],
+ normalParameterNames: ['x'],
+ normalParameterTypes: [same(objectType)],
+ parameters: hasLength(1));
+ expect(instantiated.typeArguments[0], same(objectType));
+ expect(instantiated.parameters[0].name, 'x');
+ expect(instantiated.parameters[0].type, same(objectType));
+ }
+
+ test_unnamedConstructor_instantiate_returnType_simple() {
+ var t = new MockTypeParameterElement('T');
+ var e =
+ new MockFunctionTypedElement(typeParameters: [t], returnType: t.type);
+ FunctionType f = new FunctionTypeImpl(e);
+ var instantiated = f.instantiate([objectType]);
+ basicChecks(instantiated,
+ element: same(e),
+ displayName: '() → Object',
+ typeArguments: hasLength(1),
+ typeParameters: [same(t)],
+ returnType: same(objectType));
+ expect(instantiated.typeArguments[0], same(objectType));
+ }
+
+ test_unnamedConstructor_namedParameter() {
+ var p = new MockParameterElement('x', parameterKind: ParameterKind.NAMED);
+ var e = new MockFunctionTypedElement(parameters: [p]);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ displayName: '({x: dynamic}) → dynamic',
+ namedParameterTypes: {'x': same(dynamicType)},
+ parameters: [same(p)]);
+ }
+
+ test_unnamedConstructor_namedParameter_object() {
+ var p = new MockParameterElement('x',
+ parameterKind: ParameterKind.NAMED, type: objectType);
+ var e = new MockFunctionTypedElement(parameters: [p]);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ displayName: '({x: Object}) → dynamic',
+ namedParameterTypes: {'x': same(objectType)},
+ parameters: [same(p)]);
+ }
+
+ test_unnamedConstructor_normalParameter() {
+ var p = new MockParameterElement('x');
+ var e = new MockFunctionTypedElement(parameters: [p]);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ displayName: '(dynamic) → dynamic',
+ normalParameterNames: ['x'],
+ normalParameterTypes: [same(dynamicType)],
+ parameters: [same(p)]);
+ }
+
+ test_unnamedConstructor_normalParameter_object() {
+ var p = new MockParameterElement('x', type: objectType);
+ var e = new MockFunctionTypedElement(parameters: [p]);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ displayName: '(Object) → dynamic',
+ normalParameterNames: ['x'],
+ normalParameterTypes: [same(objectType)],
+ parameters: [same(p)]);
+ }
+
+ test_unnamedConstructor_optionalParameter() {
+ var p =
+ new MockParameterElement('x', parameterKind: ParameterKind.POSITIONAL);
+ var e = new MockFunctionTypedElement(parameters: [p]);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ displayName: '([dynamic]) → dynamic',
+ optionalParameterNames: ['x'],
+ optionalParameterTypes: [same(dynamicType)],
+ parameters: [same(p)]);
+ }
+
+ test_unnamedConstructor_optionalParameter_object() {
+ var p = new MockParameterElement('x',
+ parameterKind: ParameterKind.POSITIONAL, type: objectType);
+ var e = new MockFunctionTypedElement(parameters: [p]);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ displayName: '([Object]) → dynamic',
+ optionalParameterNames: ['x'],
+ optionalParameterTypes: [same(objectType)],
+ parameters: [same(p)]);
+ }
+
+ test_unnamedConstructor_returnType() {
+ var e = new MockFunctionTypedElement(returnType: objectType);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ returnType: same(objectType),
+ displayName: '() → Object');
+ }
+
+ test_unnamedConstructor_returnType_null() {
+ var e = new MockFunctionTypedElement.withNullReturn();
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ returnType: same(dynamicType),
+ displayName: '() → dynamic');
+ }
+
+ test_unnamedConstructor_staticMethod_ignores_enclosing_type_params() {
+ var t = new MockTypeParameterElement('T');
+ var c = new MockClassElement('C', typeParameters: [t]);
+ var e = new MockMethodElement(c, isStatic: true);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f, element: same(e));
+ }
+
+ test_unnamedConstructor_substitute_bound_recursive() {
+ // abstract class C<T> {
+ // Map<S, V> f<S extends T, T extends U, V extends T>();
+ // }
+ var s = new MockTypeParameterElement('S');
+ var t = new MockTypeParameterElement('T');
+ var u = new MockTypeParameterElement('U');
+ var v = new MockTypeParameterElement('V');
+ s.bound = t.type;
+ t.bound = u.type;
+ v.bound = t.type;
+ var c = new MockClassElement('C', typeParameters: [u]);
+ var e = new MockFunctionTypedElement(
+ returnType: mapOf(s.type, v.type),
+ typeParameters: [s, t, v],
+ enclosingElement: c);
+ FunctionType f = new FunctionTypeImpl(e);
+ var substituted = f.substitute2([objectType], [u.type]);
+ basicChecks(substituted,
+ element: same(e),
+ displayName: isNotNull,
+ returnType: isNotNull,
+ typeFormals: hasLength(3),
+ typeParameters: [same(u)],
+ typeArguments: [same(objectType)]);
+ if (bug_33300_fixed) {
+ expect(substituted.displayName,
+ '<S extends T,T extends Object,V extends T>() → Map<S, V>');
+ } else {
+ expect(substituted.displayName,
+ '<S extends T extends Object,T extends Object,V extends T>() → Map<S, V>');
+ }
+ var s2 = substituted.typeFormals[0];
+ var t2 = substituted.typeFormals[1];
+ var v2 = substituted.typeFormals[2];
+ expect(s2.name, 'S');
+ expect(t2.name, 'T');
+ expect(v2.name, 'V');
+ expect(s2.bound, t2.type);
+ expect(t2.bound, same(objectType));
+ expect(v2.bound, t2.type);
+ if (bug_33301_fixed) {
+ expect(substituted.returnType, mapOf(s2.type, v2.type));
+ } else {
+ expect(substituted.returnType, mapOf(s.type, v.type));
+ }
+ }
+
+ test_unnamedConstructor_substitute_bound_simple() {
+ // abstract class C<T> {
+ // U f<U extends T>();
+ // }
+ var t = new MockTypeParameterElement('T');
+ var c = new MockClassElement('C', typeParameters: [t]);
+ var u = new MockTypeParameterElement('U', bound: t.type);
+ var e = new MockFunctionTypedElement(
+ typeParameters: [u], returnType: u.type, enclosingElement: c);
+ FunctionType f = new FunctionTypeImpl(e);
+ var substituted = f.substitute2([objectType], [t.type]);
+ basicChecks(substituted,
+ element: same(e),
+ displayName: '<U extends Object>() → U',
+ typeArguments: [same(objectType)],
+ typeParameters: [same(t)],
+ returnType: isNotNull,
+ typeFormals: hasLength(1));
+ expect(substituted.typeFormals[0].name, 'U');
+ expect(substituted.typeFormals[0].bound, same(objectType));
+ expect((substituted.returnType as TypeParameterTypeImpl).element,
+ same(getBaseElement(substituted.typeFormals[0])));
+ }
+
+ test_unnamedConstructor_substitute_noop() {
+ var t = new MockTypeParameterElement('T');
+ var e = new MockFunctionTypedElement(returnType: t.type);
+ FunctionType f = new FunctionTypeImpl(e);
+ var substituted = f.substitute2([t.type], [t.type]);
+ basicChecks(substituted,
+ element: same(e), displayName: '() → T', returnType: same(t.type));
+ // TODO(paulberry): test substitute length mismatch
+ }
+
+ test_unnamedConstructor_substitute_parameterType_simple() {
+ var t = new MockTypeParameterElement('T');
+ var c = new MockClassElement('C', typeParameters: [t]);
+ var p = new MockParameterElement('x', type: t.type);
+ var e = new MockFunctionTypedElement(parameters: [p], enclosingElement: c);
+ FunctionType f = new FunctionTypeImpl(e);
+ var substituted = f.substitute2([objectType], [t.type]);
+ basicChecks(substituted,
+ element: same(e),
+ displayName: '(Object) → dynamic',
+ normalParameterNames: ['x'],
+ normalParameterTypes: [same(objectType)],
+ parameters: hasLength(1),
+ typeArguments: [same(objectType)],
+ typeParameters: [same(t)]);
+ expect(substituted.parameters[0].name, 'x');
+ expect(substituted.parameters[0].type, same(objectType));
+ }
+
+ test_unnamedConstructor_substitute_returnType_simple() {
+ var t = new MockTypeParameterElement('T');
+ var c = new MockClassElement('C', typeParameters: [t]);
+ var e =
+ new MockFunctionTypedElement(returnType: t.type, enclosingElement: c);
+ FunctionType f = new FunctionTypeImpl(e);
+ var substituted = f.substitute2([objectType], [t.type]);
+ basicChecks(substituted,
+ element: same(e),
+ displayName: '() → Object',
+ returnType: same(objectType),
+ typeArguments: [same(objectType)],
+ typeParameters: [same(t)]);
+ }
+
+ test_unnamedConstructor_typeParameter() {
+ var t = new MockTypeParameterElement('T');
+ var e = new MockFunctionTypedElement(typeParameters: [t]);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ displayName: '<T>() → dynamic',
+ typeFormals: [same(t)]);
+ // TODO(paulberry): test pruning of bounds
+ }
+
+ test_unnamedConstructor_typeParameter_with_bound() {
+ var t = new MockTypeParameterElement('T');
+ var c = new MockClassElement('C', typeParameters: [t]);
+ var u = new MockTypeParameterElement('U', bound: t.type);
+ var e = new MockFunctionTypedElement(
+ typeParameters: [u], returnType: u.type, enclosingElement: c);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ displayName: '<U extends T>() → U',
+ typeArguments: [same(t.type)],
+ typeParameters: [same(t)],
+ returnType: same(u.type),
+ typeFormals: hasLength(1));
+ expect(f.typeFormals[0].name, 'U');
+ expect(f.typeFormals[0].bound, same(t.type));
+ }
+
+ test_unnamedConstructor_with_enclosing_type_parameters() {
+ // Test a weird behavior: substitutions are recorded in typeArguments and
+ // typeParameters.
+ var t = new MockTypeParameterElement('T');
+ var c = new MockClassElement('C', typeParameters: [t]);
+ var e =
+ new MockFunctionTypedElement(returnType: t.type, enclosingElement: c);
+ FunctionType f = new FunctionTypeImpl(e);
+ basicChecks(f,
+ element: same(e),
+ displayName: '() → T',
+ returnType: same(t.type),
+ typeArguments: [same(t.type)],
+ typeParameters: [same(t)]);
+ }
+
+ static InterfaceTypeImpl _makeListType() {
+ var e = new MockTypeParameterElement('E');
+ return new InterfaceTypeImpl.elementWithNameAndArgs(
+ new MockClassElement('List', typeParameters: [e]),
+ 'List',
+ () => [e.type]);
+ }
+
+ static InterfaceTypeImpl _makeMapType() {
+ var k = new MockTypeParameterElement('K');
+ var v = new MockTypeParameterElement('V');
+ return new InterfaceTypeImpl.elementWithNameAndArgs(
+ new MockClassElement('Map', typeParameters: [k, v]),
+ 'Map',
+ () => [k.type, v.type]);
+ }
+}
+
+class MockClassElement implements ClassElement {
+ @override
+ final List<TypeParameterElement> typeParameters;
+
+ @override
+ final String displayName;
+
+ MockClassElement(this.displayName, {this.typeParameters: const []});
+
+ @override
+ get enclosingElement => const MockCompilationUnitElement();
+
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
+
+class MockCompilationUnitElement implements CompilationUnitElement {
+ const MockCompilationUnitElement();
+
+ @override
+ get enclosingElement => const MockLibraryElement();
+
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
+
+class MockElementLocation implements ElementLocation {
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
+
+class MockFunctionTypedElement implements FunctionTypedElement {
+ @override
+ final List<ParameterElement> parameters;
+
+ @override
+ final DartType returnType;
+
+ @override
+ final List<TypeParameterElement> typeParameters;
+
+ @override
+ final Element enclosingElement;
+
+ MockFunctionTypedElement(
+ {this.parameters: const [],
+ DartType returnType,
+ this.typeParameters: const [],
+ this.enclosingElement: const MockCompilationUnitElement()})
+ : returnType = returnType ?? dynamicType;
+
+ MockFunctionTypedElement.withNullReturn(
+ {this.parameters: const [],
+ this.typeParameters: const [],
+ this.enclosingElement: const MockCompilationUnitElement()})
+ : returnType = null;
+
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
+
+class MockGenericFunctionTypeElementImpl
+ implements GenericFunctionTypeElementImpl {
+ @override
+ final MockGenericTypeAliasElement enclosingElement;
+
+ FunctionTypeImpl _type;
+
+ MockGenericFunctionTypeElementImpl(this.enclosingElement);
+
+ @override
+ get parameters => enclosingElement.parameters;
+
+ @override
+ get returnType => enclosingElement.returnType;
+
+ @override
+ get type => _type ??= new FunctionTypeImpl.elementWithNameAndArgs(this, null,
+ enclosingElement.typeParameters.map((e) => e.type).toList(), false);
+
+ @override
+ get typeParameters => enclosingElement.innerTypeParameters;
+
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
+
+class MockGenericTypeAliasElement implements GenericTypeAliasElement {
+ @override
+ final String name;
+
+ @override
+ List<ParameterElement> parameters;
+
+ @override
+ final List<TypeParameterElement> typeParameters;
+
+ @override
+ DartType returnType;
+
+ FunctionType _type;
+
+ MockGenericFunctionTypeElementImpl _function;
+
+ final List<TypeParameterElement> innerTypeParameters;
+
+ MockGenericTypeAliasElement(this.name,
+ {this.parameters: const [],
+ DartType returnType,
+ this.typeParameters: const [],
+ this.innerTypeParameters: const []})
+ : returnType = returnType ?? dynamicType;
+
+ MockGenericTypeAliasElement.withNullReturn(this.name,
+ {this.parameters: const [],
+ this.typeParameters: const [],
+ this.innerTypeParameters: const []})
+ : returnType = null;
+
+ @override
+ get enclosingElement => const MockCompilationUnitElement();
+
+ @override
+ get function => _function ??= new MockGenericFunctionTypeElementImpl(this);
+
+ @override
+ get isSynthetic => false;
+
+ @override
+ get type => _type ??= new FunctionTypeImpl.forTypedef(this);
+
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
+
+class MockLibraryElement implements LibraryElement {
+ const MockLibraryElement();
+
+ @override
+ get enclosingElement => null;
+
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
+
+class MockMethodElement extends MockFunctionTypedElement
+ implements MethodElement {
+ @override
+ final bool isStatic;
+
+ MockMethodElement(MockClassElement enclosingElement,
+ {this.isStatic: false, DartType returnType})
+ : super(enclosingElement: enclosingElement, returnType: returnType);
+
+ @override
+ ClassElement get enclosingElement => super.enclosingElement;
+}
+
+class MockParameterElement implements ParameterElement {
+ @override
+ final String name;
+
+ @override
+ final ParameterKind parameterKind;
+
+ @override
+ final DartType type;
+
+ MockParameterElement(this.name,
+ {this.parameterKind: ParameterKind.REQUIRED, this.type});
+
+ @override
+ get displayName => name;
+
+ @override
+ bool get isNamed => parameterKind == ParameterKind.NAMED;
+
+ @override
+ bool get isNotOptional => parameterKind == ParameterKind.REQUIRED;
+
+ @override
+ bool get isOptionalPositional => parameterKind == ParameterKind.POSITIONAL;
+
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
+
+class MockTypeParameterElement implements TypeParameterElement {
+ @override
+ final String name;
+
+ TypeParameterTypeImpl _type;
+
+ MockElementLocation _location;
+
+ @override
+ DartType bound;
+
+ MockTypeParameterElement(this.name, {this.bound});
+
+ @override
+ get kind => ElementKind.TYPE_PARAMETER;
+
+ @override
+ get location => _location ??= new MockElementLocation();
+
+ @override
+ get type => _type ??= new TypeParameterTypeImpl(this);
+
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/element/test_all.dart b/pkg/analyzer/test/src/dart/element/test_all.dart
index 2577db8..b2a1b2e 100644
--- a/pkg/analyzer/test/src/dart/element/test_all.dart
+++ b/pkg/analyzer/test/src/dart/element/test_all.dart
@@ -7,10 +7,12 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'element_test.dart' as element;
+import 'function_type_test.dart' as function_type;
/// Utility for manually running all tests.
main() {
defineReflectiveSuite(() {
element.main();
+ function_type.main();
}, name: 'element');
}