| // 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. |
| |
| // @dart = 2.7 |
| |
| import 'package:async_helper/async_helper.dart'; |
| import 'package:compiler/src/compiler.dart'; |
| import 'package:compiler/src/universe/call_structure.dart'; |
| import 'package:compiler/src/universe/codegen_world_builder.dart'; |
| import 'package:expect/expect.dart'; |
| |
| import '../helpers/memory_compiler.dart'; |
| |
| const String code = r''' |
| class Class1 { |
| @pragma('dart2js:noInline') |
| method1<T>() {} |
| |
| @pragma('dart2js:noInline') |
| method2<T>() => T; |
| |
| @pragma('dart2js:noInline') |
| method3<T>() => T; |
| |
| @pragma('dart2js:noInline') |
| method4<T>() => T; |
| |
| @pragma('dart2js:noInline') |
| method5<T>() => T; |
| |
| @pragma('dart2js:noInline') |
| method6<T>() {} |
| } |
| |
| class Class2 {} |
| |
| class Class3 implements Class1 { |
| @pragma('dart2js:noInline') |
| method1<T>() {} |
| |
| @pragma('dart2js:noInline') |
| method2<T>() {} |
| |
| @pragma('dart2js:noInline') |
| method3<T>() {} |
| |
| @pragma('dart2js:noInline') |
| method4<T>() {} |
| |
| @pragma('dart2js:noInline') |
| method5<T>() {} |
| |
| @pragma('dart2js:noInline') |
| method6<T>() {} |
| } |
| |
| main(args) { |
| dynamic c1 = args != null ? new Class1() : new Class2(); |
| c1.method1(); // No type arguments are inferred here. |
| |
| dynamic c2 = args != null ? new Class1() : new Class2(); |
| c2.method2<int>(); |
| |
| var c3 = args != null ? new Class1() : new Class3(); |
| c3.method3(); // Type arguments are inferred here. |
| |
| var c4 = args != null ? new Class1() : new Class3(); |
| c4.method4<int>(); |
| |
| dynamic c5 = args != null ? new Class1() : new Class2(); |
| c5.method5(); // No type arguments are inferred here. |
| |
| var c6 = args != null ? new Class1() : new Class3(); |
| c6.method5(); // Type arguments are inferred here. |
| |
| dynamic c7 = args != null ? new Class1() : new Class2(); |
| c7.method6<int>(); // Type arguments are not needed. |
| |
| var c8 = args != null ? new Class1() : new Class3(); |
| c8.method6(); // Type arguments are inferred here but not needed. |
| } |
| '''; |
| |
| main() { |
| asyncTest(() async { |
| CompilationResult result = |
| await runCompiler(memorySourceFiles: {'main.dart': code}); |
| Expect.isTrue(result.isSuccess); |
| Compiler compiler = result.compiler; |
| CodegenWorld codegenWorld = compiler.codegenWorldForTesting; |
| |
| CallStructure noTypeArguments = new CallStructure(0, [], 0); |
| CallStructure oneTypeArgument = new CallStructure(0, [], 1); |
| |
| Iterable<CallStructure> getCallStructures(String name) { |
| return codegenWorld |
| .invocationsByName(name) |
| ?.keys |
| ?.map((s) => s.callStructure) ?? |
| []; |
| } |
| |
| void checkInvocationsFor( |
| String methodName, List<CallStructure> expectedCallStructures) { |
| Iterable<CallStructure> actualCallStructures = |
| getCallStructures(methodName); |
| Expect.setEquals( |
| expectedCallStructures, |
| actualCallStructures, |
| "Unexpected call structures for '$methodName'. " |
| "Expected ${expectedCallStructures}, " |
| "actual ${actualCallStructures}."); |
| } |
| |
| checkInvocationsFor('method1', [noTypeArguments]); |
| checkInvocationsFor('method2', [oneTypeArgument]); |
| checkInvocationsFor('method3', [oneTypeArgument]); |
| checkInvocationsFor('method4', [oneTypeArgument]); |
| checkInvocationsFor('method5', [noTypeArguments, oneTypeArgument]); |
| checkInvocationsFor('method6', [noTypeArguments]); |
| }); |
| } |