| // 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); |
| } |
| } |