| // Copyright (c) 2014, 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. |
| |
| library members_test; |
| |
| import 'package:expect/expect.dart'; |
| import "package:async_helper/async_helper.dart"; |
| import 'type_test_helper.dart'; |
| import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart'; |
| import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart" |
| show Element, ClassElement, MemberSignature, Name, PublicName; |
| import "../../../sdk/lib/_internal/compiler/implementation/resolution/class_members.dart" |
| show SyntheticMember, ErroneousMember; |
| |
| void main() { |
| testClassMembers(); |
| testInterfaceMembers(); |
| testClassVsInterfaceMembers(); |
| testMixinMembers(); |
| } |
| |
| MemberSignature getMember(InterfaceType cls, String name, |
| {bool isSetter: false, |
| int checkType: CHECK_INTERFACE}) { |
| Name memberName = |
| new Name(name, cls.element.getLibrary(), isSetter: isSetter); |
| MemberSignature member = checkType == CHECK_CLASS |
| ? cls.element.lookupClassMember(memberName) |
| : cls.element.lookupInterfaceMember(memberName); |
| if (member != null) { |
| Expect.equals(memberName, member.name); |
| } |
| return member; |
| } |
| |
| /// Check interface member only. |
| const int CHECK_INTERFACE = 0; |
| /// Check class member only. |
| const int CHECK_CLASS = 1; |
| /// Check that there is no class member for the interface member. |
| const int NO_CLASS_MEMBER = 2; |
| /// Check that the interface member is also a class member. |
| const int ALSO_CLASS_MEMBER = 3; |
| |
| /** |
| * Checks [member] or interface member [name] of the declaration of [cls]. |
| * |
| * If [inheritFrom] is set, the member from [cls] must be identical to the |
| * member from [inheritedFrom]. |
| * |
| * Otherwise, the properties of member are checked against the values of |
| * [isStatic], [isSetter], [isGetter], [declarer], [type] and |
| * [functionType]. |
| * |
| * If [synthesizedFrom] or [erroneousFrom] is not `null`, the member is checked |
| * to be synthesized for the corresponding members found on the type is |
| * [synthesizedFrom] or or [erroneousFrom], respectively. |
| * Otherwise, if [declarer] is `null`, the declarer is checked to be [cls], and |
| * if [declarer] is not `null`, the declarer is checked to be [declarer]. |
| * If [type] is `null` it is checked that the type of the member is also the |
| * member type, otherwise the type is checked to be [type]. |
| * |
| * If [isClassMember] is `true` it is checked that the member is also a class |
| * member. |
| */ |
| MemberSignature checkMember(InterfaceType cls, |
| String name, |
| {bool isStatic: false, |
| bool isSetter: false, |
| bool isGetter: false, |
| InterfaceType declarer, |
| DartType type, |
| FunctionType functionType, |
| InterfaceType inheritedFrom, |
| List<InterfaceType> synthesizedFrom, |
| List<InterfaceType> erroneousFrom, |
| int checkType: ALSO_CLASS_MEMBER}) { |
| String memberKind = checkType == CHECK_CLASS ? 'class' : 'interface'; |
| MemberSignature member = |
| getMember(cls, name, isSetter: isSetter, checkType: checkType); |
| Expect.isNotNull(member, "No $memberKind member '$name' in $cls."); |
| Name memberName = member.name; |
| if (checkType == ALSO_CLASS_MEMBER) { |
| MemberSignature classMember = cls.element.lookupClassMember(memberName); |
| Expect.isNotNull(classMember, "No class member '$memberName' in $cls."); |
| Expect.equals(member, classMember); |
| } else if (checkType == NO_CLASS_MEMBER) { |
| Expect.isNull(cls.element.lookupClassMember(memberName)); |
| } |
| |
| if (inheritedFrom != null) { |
| MemberSignature inherited = checkType == CHECK_CLASS |
| ? inheritedFrom.element.lookupClassMember(memberName) |
| : inheritedFrom.element.lookupInterfaceMember(memberName); |
| Expect.isNotNull(inherited, |
| "No $memberKind member '$memberName' in $inheritedFrom."); |
| Expect.equals(inherited.inheritFrom(inheritedFrom), member); |
| } else { |
| if (erroneousFrom != null || synthesizedFrom != null) { |
| Expect.notEquals(checkType, CHECK_CLASS, |
| "Arguments 'erroneousFrom' and 'synthesizedFrom' only apply " |
| "to interface members."); |
| if (synthesizedFrom != null) { |
| Expect.isTrue(member is SyntheticMember, |
| "Member '$member' is not synthesized."); |
| } else { |
| Expect.isTrue(member is ErroneousMember, |
| "Member '$member' is not erroneous."); |
| } |
| Set<MemberSignature> members = new Set<MemberSignature>(); |
| List from = synthesizedFrom != null ? synthesizedFrom : erroneousFrom; |
| for (InterfaceType type in from) { |
| MemberSignature inheritedMember = |
| type.element.lookupInterfaceMember(memberName); |
| Expect.isNotNull(inheritedMember); |
| members.add(inheritedMember.inheritFrom(type)); |
| } |
| Expect.setEquals(members, member.declarations); |
| } else if (declarer != null) { |
| Expect.equals(declarer, member.declarer, |
| "Unexpected declarer '${member.declarer}' of $memberKind member " |
| "'$member'. Expected '${declarer}'."); |
| } else { |
| Expect.equals(cls.element, member.element.getEnclosingClass()); |
| Expect.equals(cls, member.declarer); |
| } |
| Expect.equals(isSetter, member.isSetter); |
| Expect.equals(isGetter, member.isGetter); |
| if (type != null) { |
| Expect.equals(type, member.type, |
| "Unexpected type of $memberKind member '$member'."); |
| } |
| if (functionType != null) { |
| if (type == null) { |
| Expect.equals(member.type, member.functionType, |
| "Unexpected type of $memberKind member '$member'."); |
| } |
| Expect.equals(functionType, member.functionType, |
| "Unexpected member type of $memberKind member '$member'."); |
| } |
| } |
| return member; |
| } |
| |
| void checkMemberCount(InterfaceType cls, int expectedCount, |
| {bool interfaceMembers: true}) { |
| int count = 0; |
| if (interfaceMembers) { |
| cls.element.forEachInterfaceMember((_) => count++); |
| } else { |
| cls.element.forEachClassMember((_) => count++); |
| } |
| Expect.equals(expectedCount, count); |
| } |
| |
| void testClassMembers() { |
| asyncTest(() => TypeEnvironment.create(r""" |
| abstract class A { |
| int field; |
| final finalField = 0; |
| static var staticField; |
| |
| int get getter => 0; |
| get abstractGetter; |
| void set setter(int _) {} |
| set abstractSetter(_); |
| |
| method() {} |
| abstractMethod(); |
| static staticMethod() {} |
| } |
| class B<T> { |
| T field; |
| void method(T t) {} |
| static staticMethod() {} |
| toString([T t]) {} |
| } |
| class C<S> extends B<S> {} |
| class D extends C<int> {} |
| class E extends D {} |
| """, useMockCompiler: false).then((env) { |
| |
| InterfaceType bool_ = env['bool']; |
| InterfaceType String_ = env['String']; |
| InterfaceType num_ = env['num']; |
| InterfaceType int_ = env['int']; |
| InterfaceType dynamic_ = env['dynamic']; |
| VoidType void_ = env['void']; |
| InterfaceType Type_ = env['Type']; |
| InterfaceType Invocation_ = env['Invocation']; |
| |
| InterfaceType Object_ = env['Object']; |
| checkMemberCount(Object_, 5 /*declared*/, interfaceMembers: true); |
| checkMemberCount(Object_, 5 /*declared*/, interfaceMembers: false); |
| |
| checkMember(Object_, '==', |
| functionType: env.functionType(bool_, [dynamic_])); |
| checkMember(Object_, 'hashCode', |
| isGetter: true, |
| type: int_, functionType: env.functionType(int_, [])); |
| checkMember(Object_, 'noSuchMethod', |
| functionType: env.functionType(dynamic_, [Invocation_])); |
| checkMember(Object_, 'runtimeType', |
| isGetter: true, |
| type: Type_, functionType: env.functionType(Type_, [])); |
| checkMember(Object_, 'toString', |
| functionType: env.functionType(String_, [])); |
| |
| InterfaceType A = env['A']; |
| checkMemberCount(A, 5 /*inherited*/ + 9 /*non-static declared*/, |
| interfaceMembers: true); |
| checkMemberCount(A, 5 /*inherited*/ + 9 /*non-abstract declared*/, |
| interfaceMembers: false); |
| |
| checkMember(A, '==', inheritedFrom: Object_); |
| checkMember(A, 'hashCode', inheritedFrom: Object_); |
| checkMember(A, 'noSuchMethod', inheritedFrom: Object_); |
| checkMember(A, 'runtimeType', inheritedFrom: Object_); |
| checkMember(A, 'toString', inheritedFrom: Object_); |
| |
| checkMember(A, 'field', isGetter: true, |
| type: int_, functionType: env.functionType(int_, [])); |
| checkMember(A, 'field', isSetter: true, |
| type: int_, functionType: env.functionType(void_, [int_])); |
| checkMember(A, 'finalField', isGetter: true, |
| type: dynamic_, functionType: env.functionType(dynamic_, [])); |
| checkMember(A, 'staticField', isGetter: true, isStatic: true, |
| checkType: CHECK_CLASS, |
| type: dynamic_, functionType: env.functionType(dynamic_, [])); |
| checkMember(A, 'staticField', isSetter: true, isStatic: true, |
| checkType: CHECK_CLASS, type: dynamic_, |
| functionType: env.functionType(void_, [dynamic_])); |
| |
| checkMember(A, 'getter', isGetter: true, |
| type: int_, functionType: env.functionType(int_, [])); |
| checkMember(A, 'abstractGetter', isGetter: true, |
| checkType: NO_CLASS_MEMBER, |
| type: dynamic_, functionType: env.functionType(dynamic_, [])); |
| checkMember(A, 'setter', isSetter: true, |
| type: int_, functionType: env.functionType(void_, [int_])); |
| checkMember(A, 'abstractSetter', isSetter: true, |
| checkType: NO_CLASS_MEMBER, type: dynamic_, |
| functionType: env.functionType(dynamic_, [dynamic_])); |
| |
| checkMember(A, 'method', functionType: env.functionType(dynamic_, [])); |
| checkMember(A, 'abstractMethod', |
| checkType: NO_CLASS_MEMBER, |
| functionType: env.functionType(dynamic_, [])); |
| checkMember(A, 'staticMethod', |
| checkType: CHECK_CLASS, |
| isStatic: true, functionType: env.functionType(dynamic_, [])); |
| |
| ClassElement B = env.getElement('B'); |
| InterfaceType B_this = B.thisType; |
| TypeVariableType B_T = B_this.typeArguments.head; |
| checkMemberCount(B_this, 4 /*inherited*/ + 4 /*non-static declared*/, |
| interfaceMembers: true); |
| checkMemberCount(B_this, 4 /*inherited*/ + 5 /*declared*/, |
| interfaceMembers: false); |
| |
| checkMember(B_this, '==', inheritedFrom: Object_); |
| checkMember(B_this, 'hashCode', inheritedFrom: Object_); |
| checkMember(B_this, 'noSuchMethod', inheritedFrom: Object_); |
| checkMember(B_this, 'runtimeType', inheritedFrom: Object_); |
| |
| checkMember(B_this, 'field', isGetter: true, |
| type: B_T, functionType: env.functionType(B_T, [])); |
| checkMember(B_this, 'field', isSetter: true, |
| type: B_T, functionType: env.functionType(void_, [B_T])); |
| checkMember(B_this, 'method', functionType: env.functionType(void_, [B_T])); |
| checkMember(B_this, 'staticMethod', |
| checkType: CHECK_CLASS, |
| isStatic: true, functionType: env.functionType(dynamic_, [])); |
| checkMember(B_this, 'toString', |
| functionType: env.functionType(dynamic_, [], |
| optionalParameters: [B_T])); |
| |
| ClassElement C = env.getElement('C'); |
| InterfaceType C_this = C.thisType; |
| TypeVariableType C_S = C_this.typeArguments.head; |
| checkMemberCount(C_this, 8 /*inherited*/, interfaceMembers: true); |
| checkMemberCount(C_this, 8 /*inherited*/, interfaceMembers: false); |
| InterfaceType B_S = instantiate(B, [C_S]); |
| |
| checkMember(C_this, '==', inheritedFrom: Object_); |
| checkMember(C_this, 'hashCode', inheritedFrom: Object_); |
| checkMember(C_this, 'noSuchMethod', inheritedFrom: Object_); |
| checkMember(C_this, 'runtimeType', inheritedFrom: Object_); |
| |
| checkMember(C_this, 'field', isGetter: true, |
| declarer: B_S, |
| type: C_S, functionType: env.functionType(C_S, [])); |
| checkMember(C_this, 'field', isSetter: true, |
| declarer: B_S, |
| type: C_S, functionType: env.functionType(void_, [C_S])); |
| checkMember(C_this, 'method', |
| declarer: B_S, |
| functionType: env.functionType(void_, [C_S])); |
| checkMember(C_this, 'toString', |
| declarer: B_S, |
| functionType: env.functionType(dynamic_, [], |
| optionalParameters: [C_S])); |
| |
| InterfaceType D = env['D']; |
| checkMemberCount(D, 8 /*inherited*/, interfaceMembers: true); |
| checkMemberCount(D, 8 /*inherited*/, interfaceMembers: false); |
| InterfaceType B_int = instantiate(B, [int_]); |
| |
| checkMember(D, '==', inheritedFrom: Object_); |
| checkMember(D, 'hashCode', inheritedFrom: Object_); |
| checkMember(D, 'noSuchMethod', inheritedFrom: Object_); |
| checkMember(D, 'runtimeType', inheritedFrom: Object_); |
| |
| checkMember(D, 'field', isGetter: true, |
| declarer: B_int, |
| type: int_, functionType: env.functionType(int_, [])); |
| checkMember(D, 'field', isSetter: true, |
| declarer: B_int, |
| type: int_, functionType: env.functionType(void_, [int_])); |
| checkMember(D, 'method', |
| declarer: B_int, |
| functionType: env.functionType(void_, [int_])); |
| checkMember(D, 'toString', |
| declarer: B_int, |
| functionType: env.functionType(dynamic_, [], |
| optionalParameters: [int_])); |
| |
| InterfaceType E = env['E']; |
| checkMemberCount(E, 8 /*inherited*/, interfaceMembers: true); |
| checkMemberCount(E, 8 /*inherited*/, interfaceMembers: false); |
| |
| checkMember(E, '==', inheritedFrom: Object_); |
| checkMember(E, 'hashCode', inheritedFrom: Object_); |
| checkMember(E, 'noSuchMethod', inheritedFrom: Object_); |
| checkMember(E, 'runtimeType', inheritedFrom: Object_); |
| |
| checkMember(E, 'field', isGetter: true, |
| declarer: B_int, |
| type: int_, functionType: env.functionType(int_, [])); |
| checkMember(E, 'field', isSetter: true, |
| declarer: B_int, |
| type: int_, functionType: env.functionType(void_, [int_])); |
| checkMember(E, 'method', |
| declarer: B_int, |
| functionType: env.functionType(void_, [int_])); |
| checkMember(E, 'toString', |
| declarer: B_int, |
| functionType: env.functionType(dynamic_, [], |
| optionalParameters: [int_])); |
| })); |
| } |
| |
| void testInterfaceMembers() { |
| asyncTest(() => TypeEnvironment.create(r""" |
| abstract class A { |
| num method1(); |
| void method2(); |
| void method3(); |
| void method4(); |
| method5(a); |
| method6(a); |
| method7(a); |
| method8(a, b); |
| method9(a, b, c); |
| method10(a, {b, c}); |
| method11(a, {b, c}); |
| num get getter1; |
| num get getter2; |
| void set setter1(num _); |
| void set setter2(num _); |
| void set setter3(num _); |
| get getterAndMethod; |
| } |
| abstract class B { |
| int method1(); |
| int method2(); |
| num method3(); |
| num method4(); |
| method5([a]); |
| method6([a, b]); |
| method7(a, [b]); |
| method8([a]); |
| method9(a, [b]); |
| method10(a, {c, d}); |
| method11(a, b, {c, d}); |
| num get getter1; |
| int get getter2; |
| void set setter1(num _); |
| set setter2(num _); |
| void set setter3(int _); |
| getterAndMethod(); |
| } |
| abstract class C { |
| int method3(); |
| num method4(); |
| } |
| abstract class D implements A, B, C {} |
| """).then((env) { |
| |
| InterfaceType dynamic_ = env['dynamic']; |
| VoidType void_ = env['void']; |
| InterfaceType num_ = env['num']; |
| InterfaceType int_ = env['int']; |
| |
| InterfaceType A = env['A']; |
| InterfaceType B = env['B']; |
| InterfaceType C = env['C']; |
| InterfaceType D = env['D']; |
| |
| // A: num method1() |
| // B: int method1() |
| // D: dynamic method1() -- synthesized from A and B. |
| checkMember(D, 'method1', |
| synthesizedFrom: [A, B], |
| functionType: env.functionType(dynamic_ , []), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: void method2() |
| // B: int method2() |
| // D: int method2() -- inherited from B |
| checkMember(D, 'method2', inheritedFrom: B, checkType: NO_CLASS_MEMBER); |
| |
| // A: void method3() |
| // B: num method3() |
| // C: int method3() |
| // D: dynamic method3() -- synthesized from A, B, and C. |
| checkMember(D, 'method3', |
| synthesizedFrom: [A, B, C], |
| functionType: env.functionType(dynamic_ , []), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: void method4() |
| // B: num method4() |
| // C: num method4() |
| // D: num method4() -- synthesized from B and C. |
| checkMember(D, 'method4', |
| synthesizedFrom: [B, C], |
| functionType: env.functionType(num_, []), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: method5(a) |
| // B: method5([a]) |
| // D: method5([a]) -- inherited from B |
| checkMember(D, 'method5', inheritedFrom: B, checkType: NO_CLASS_MEMBER); |
| |
| // A: method6(a) |
| // B: method6([a, b]) |
| // D: method6([a, b]) -- inherited from B |
| checkMember(D, 'method6', inheritedFrom: B, checkType: NO_CLASS_MEMBER); |
| |
| // A: method7(a) |
| // B: method7(a, [b]) |
| // D: method7(a, [b]) -- inherited from B |
| checkMember(D, 'method7', inheritedFrom: B, checkType: NO_CLASS_MEMBER); |
| |
| // A: method8(a, b) |
| // B: method8([a]) |
| // D: method8([a, b]) -- synthesized from A and B. |
| checkMember(D, 'method8', |
| synthesizedFrom: [A, B], |
| functionType: env.functionType( |
| dynamic_, [], optionalParameters: [dynamic_, dynamic_]), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: method9(a, b, c) |
| // B: method9(a, [b]) |
| // D: method9(a, [b, c]) -- synthesized from A and B. |
| checkMember(D, 'method9', |
| synthesizedFrom: [A, B], |
| functionType: env.functionType( |
| dynamic_, [dynamic_], optionalParameters: [dynamic_, dynamic_]), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: method10(a, {b, c}) |
| // B: method10(a, {c, d}) |
| // D: method10(a, {b, c, d}) -- synthesized from A and B. |
| checkMember(D, 'method10', |
| synthesizedFrom: [A, B], |
| functionType: env.functionType(dynamic_, [dynamic_], |
| namedParameters: {'b': dynamic_, |
| 'c': dynamic_, |
| 'd': dynamic_}), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: method11(a, {b, c}) |
| // B: method11(a, b, {c, d}) |
| // D: method11(a, [b], {c, d}) -- synthesized from A and B. |
| // TODO(johnniwinther): Change to check synthesized member when function |
| // types with both optional and named parameters are supported. |
| Expect.isNull(getMember(D, 'method11')); |
| /*checkMember(D, 'method11', |
| synthesizedFrom: [A, B], |
| functionType: env.functionType(dynamic_, [dynamic_], |
| optionalParameters: [dynamic_], |
| namedParameters: {'c': dynamic_, |
| 'd': dynamic_,}), |
| checkType: NO_CLASS_MEMBER);*/ |
| |
| // A: num get getter1 |
| // B: num get getter1 |
| // D: num get getter1 -- synthesized from A and B. |
| checkMember(D, 'getter1', |
| isGetter: true, |
| synthesizedFrom: [A, B], type: num_, |
| functionType: env.functionType(num_ , []), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: num get getter2 |
| // B: int get getter2 |
| // D: dynamic get getter2 -- synthesized from A and B. |
| checkMember(D, 'getter2', |
| isGetter: true, |
| synthesizedFrom: [A, B], type: dynamic_, |
| functionType: env.functionType(dynamic_ , []), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: void set setter1(num _) |
| // B: void set setter1(num _) |
| // D: void set setter1(num _) -- synthesized from A and B. |
| checkMember(D, 'setter1', |
| isSetter: true, |
| synthesizedFrom: [A, B], type: num_, |
| functionType: env.functionType(void_ , [num_]), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: void set setter2(num _) |
| // B: set setter2(num _) |
| // D: dynamic set setter2(dynamic _) -- synthesized from A and B. |
| checkMember(D, 'setter2', |
| isSetter: true, |
| synthesizedFrom: [A, B], type: dynamic_, |
| functionType: env.functionType(dynamic_ , [dynamic_]), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: void set setter3(num _) |
| // B: void set setter3(int _) |
| // D: dynamic set setter3(dynamic _) -- synthesized from A and B. |
| checkMember(D, 'setter3', |
| isSetter: true, |
| synthesizedFrom: [A, B], type: dynamic_, |
| functionType: env.functionType(dynamic_ , [dynamic_]), |
| checkType: NO_CLASS_MEMBER); |
| |
| // A: get getterAndMethod |
| // B: getterAndMethod() |
| // D: nothing inherited |
| checkMember(D, 'getterAndMethod', |
| erroneousFrom: [A, B], |
| checkType: NO_CLASS_MEMBER); |
| })); |
| } |
| |
| void testClassVsInterfaceMembers() { |
| asyncTest(() => TypeEnvironment.create(r""" |
| class A { |
| method1() {} |
| method2() {} |
| } |
| abstract class B { |
| method1(); |
| method2(a); |
| } |
| abstract class C extends A implements B {} |
| """).then((env) { |
| |
| InterfaceType dynamic_ = env['dynamic']; |
| VoidType void_ = env['void']; |
| InterfaceType num_ = env['num']; |
| InterfaceType int_ = env['int']; |
| |
| InterfaceType A = env['A']; |
| InterfaceType B = env['B']; |
| InterfaceType C = env['C']; |
| |
| // A: method1() |
| // B: method1() |
| // C class: method1() -- inherited from A. |
| // C interface: dynamic method1() -- synthesized from A and B. |
| MemberSignature interfaceMember = |
| checkMember(C, 'method1', checkType: CHECK_INTERFACE, |
| synthesizedFrom: [A, B], |
| functionType: env.functionType(dynamic_ , [])); |
| MemberSignature classMember = |
| checkMember(C, 'method1', checkType: CHECK_CLASS, inheritedFrom: A); |
| Expect.notEquals(interfaceMember, classMember); |
| |
| // A: method2() |
| // B: method2(a) |
| // C class: method2() -- inherited from A. |
| // C interface: dynamic method2([a]) -- synthesized from A and B. |
| interfaceMember = |
| checkMember(C, 'method2', checkType: CHECK_INTERFACE, |
| synthesizedFrom: [A, B], |
| functionType: env.functionType(dynamic_ , [], |
| optionalParameters: [dynamic_])); |
| classMember = |
| checkMember(C, 'method2', checkType: CHECK_CLASS, inheritedFrom: A); |
| Expect.notEquals(interfaceMember, classMember); |
| })); |
| } |
| |
| |
| void testMixinMembers() { |
| asyncTest(() => TypeEnvironment.create(r""" |
| class A<T> { |
| method1() {} |
| method2() {} |
| method3(T a) {} |
| method4(T a) {} |
| } |
| abstract class B<S> { |
| method1(); |
| method2(a); |
| method3(S a) {} |
| } |
| abstract class C<U, V> extends Object with A<U> implements B<V> {} |
| """).then((env) { |
| |
| InterfaceType dynamic_ = env['dynamic']; |
| VoidType void_ = env['void']; |
| InterfaceType num_ = env['num']; |
| InterfaceType int_ = env['int']; |
| |
| ClassElement A = env.getElement('A'); |
| ClassElement B = env.getElement('B'); |
| ClassElement C = env.getElement('C'); |
| InterfaceType C_this = C.thisType; |
| TypeVariableType C_U = C_this.typeArguments.head; |
| TypeVariableType C_V = C_this.typeArguments.tail.head; |
| InterfaceType A_U = instantiate(A, [C_U]); |
| InterfaceType B_V = instantiate(B, [C_V]); |
| |
| // A: method1() |
| // B: method1() |
| // C class: method1() -- inherited from A. |
| // C interface: dynamic method1() -- synthesized from A and B. |
| MemberSignature interfaceMember = |
| checkMember(C_this, 'method1', checkType: CHECK_INTERFACE, |
| synthesizedFrom: [A_U, B_V], |
| functionType: env.functionType(dynamic_ , [])); |
| MemberSignature classMember = |
| checkMember(C_this, 'method1', checkType: CHECK_CLASS, |
| inheritedFrom: A_U); |
| Expect.notEquals(interfaceMember, classMember); |
| |
| // A: method2() |
| // B: method2(a) |
| // C class: method2() -- inherited from A. |
| // C interface: dynamic method2([a]) -- synthesized from A and B. |
| interfaceMember = |
| checkMember(C_this, 'method2', checkType: CHECK_INTERFACE, |
| synthesizedFrom: [A_U, B_V], |
| functionType: env.functionType(dynamic_ , [], |
| optionalParameters: [dynamic_])); |
| classMember = |
| checkMember(C_this, 'method2', checkType: CHECK_CLASS, |
| inheritedFrom: A_U); |
| Expect.notEquals(interfaceMember, classMember); |
| |
| // A: method3(U a) |
| // B: method3(V a) |
| // C class: method3(U a) -- inherited from A. |
| // C interface: dynamic method3(a) -- synthesized from A and B. |
| interfaceMember = |
| checkMember(C_this, 'method3', checkType: CHECK_INTERFACE, |
| synthesizedFrom: [A_U, B_V], |
| functionType: env.functionType(dynamic_ , [dynamic_])); |
| classMember = |
| checkMember(C_this, 'method3', checkType: CHECK_CLASS, |
| inheritedFrom: A_U); |
| Expect.notEquals(interfaceMember, classMember); |
| |
| // A: method4(U a) |
| // B: -- |
| // C class: method4(U a) -- inherited from A. |
| // C interface: method4(U a) -- inherited from A. |
| checkMember(C_this, 'method4', checkType: ALSO_CLASS_MEMBER, |
| inheritedFrom: A_U); |
| })); |
| } |