blob: 1574ab99de2444339b05b80eb8bdd4d31b2a9dc0 [file] [log] [blame]
// Copyright (c) 2017, 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:async_helper/async_helper.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/common_elements.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/js/js.dart' as js;
import 'package:compiler/src/world.dart';
import 'package:expect/expect.dart';
import '../kernel/compiler_helper.dart';
const String SOURCE = r'''
import 'package:meta/dart2js.dart';
@noInline
method1<T>(T t) {
print('method1:');
print('$t is $T = ${t is T}');
print('"foo" is $T = ${"foo" is T}');
print('');
}
@noInline
method2<T, S>(S s, T t) {
print('method2:');
print('$t is $T = ${t is T}');
print('$s is $T = ${s is T}');
print('$t is $S = ${t is S}');
print('$s is $S = ${s is S}');
print('');
}
@tryInline
method3<T, S>(T t, S s) {
print('method3:');
print('$t is $T = ${t is T}');
print('$s is $T = ${s is T}');
print('$t is $S = ${t is S}');
print('$s is $S = ${s is S}');
print('');
}
class Class1<T> {
final int index;
Class1(this.index);
String toString() => 'c$index';
}
method4<T>(int index) => new Class1<T>(index);
testMethod4() {
print('method4:');
var c1 = method4<int>(1);
var c2 = method4<String>(2);
print('$c1 is Class1<int> = ${c1 is Class1<int>}');
print('$c2 is Class1<int> = ${c2 is Class1<int>}');
print('$c1 is Class1<String> = ${c1 is Class1<String>}');
print('$c2 is Class1<String> = ${c2 is Class1<String>}');
print('');
}
class Class2 {
@tryInline
method5<T>(T t) {
print('Class2.method5:');
print('$t is $T = ${t is T}');
print('"foo" is $T = ${"foo" is T}');
print('');
}
@noInline
method6(o) {
print('Class2.method6:');
print('$o is int = ${o is int}');
print('$o is String = ${o is String}');
print('');
}
}
class Class3 {
@noInline
method6<T>(T t) {
print('Class3.method6:');
print('$t is $T = ${t is T}');
print('"foo" is $T = ${"foo" is T}');
print('');
}
}
class Class4<T> {
Function method7<Q>() {
foo(T t, Q q) => '';
return foo;
}
}
// Nested generic local function.
outside<T>() {
nested<T>(T t) => '';
return nested;
}
main(args) {
method1<int>(0);
method2<String, double>(0.5, 'foo');
method3<double, String>(1.5, 'bar');
testMethod4();
new Class2().method5<int>(0);
new Class3().method6<int>(0);
dynamic c3 = args != null ? new Class3() : new Class2();
c3.method6(0); // Missing type arguments.
try {
dynamic c2 = args == null ? new Class3() : new Class2();
c2.method6(0); // Valid call.
c2.method6<int>(0); // Extra type arguments.
} catch (e) {
print('noSuchMethod: Class2.method6<int>');
print('');
}
var c = new Class4<bool>();
print((c.method7<int>()).runtimeType);
outside();
}
''';
const String OUTPUT = r'''
method1:
0 is int = true
"foo" is int = false
method2:
foo is String = true
0.5 is String = false
foo is double = false
0.5 is double = true
method3:
1.5 is double = true
bar is double = false
1.5 is String = false
bar is String = true
method4:
c1 is Class1<int> = true
c2 is Class1<int> = false
c1 is Class1<String> = false
c2 is Class1<String> = true
Class2.method5:
0 is int = true
"foo" is int = false
Class3.method6:
0 is int = true
"foo" is int = false
Class3.method6:
0 is dynamic = true
"foo" is dynamic = true
Class2.method6:
0 is int = true
0 is String = false
noSuchMethod: Class2.method6<int>
(bool, int) => String
''';
main(List<String> args) {
asyncTest(() async {
Compiler compiler = await runWithD8(memorySourceFiles: {
'main.dart': SOURCE
}, options: [
Flags.strongMode,
Flags.disableRtiOptimization,
], expectedOutput: OUTPUT, printJs: args.contains('-v'));
ClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
ElementEnvironment elementEnvironment = closedWorld.elementEnvironment;
void checkMethod(String methodName,
{String className, int expectedParameterCount}) {
FunctionEntity method;
if (className != null) {
ClassEntity cls = elementEnvironment.lookupClass(
elementEnvironment.mainLibrary, className);
Expect.isNotNull(cls, "Class '$className' not found.");
method = elementEnvironment.lookupClassMember(cls, methodName);
Expect.isNotNull(method, "Method '$methodName' not found in $cls.");
} else {
method = elementEnvironment.lookupLibraryMember(
elementEnvironment.mainLibrary, methodName);
Expect.isNotNull(method, "Method '$methodName' not found.");
}
js.Fun fun = compiler.backend.generatedCode[method];
Expect.equals(expectedParameterCount, fun.params.length,
"Unexpected parameter count for $method:\n${js.nodeToString(fun)}");
}
checkMethod('method1', expectedParameterCount: 2);
checkMethod('method2', expectedParameterCount: 4);
checkMethod('method6', className: 'Class2', expectedParameterCount: 1);
checkMethod('method6', className: 'Class3', expectedParameterCount: 2);
});
}