blob: 714c4257b110496523556f8c1feb0962878bb3da [file] [log] [blame]
// 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/common/elements.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/js_backend/runtime_types_resolution.dart';
import 'package:compiler/src/js_emitter/model.dart';
import 'package:compiler/src/js_model/js_strategy.dart';
import 'package:compiler/src/js/js.dart' as js;
import 'package:compiler/src/world.dart';
import 'package:expect/expect.dart';
import '../helpers/program_lookup.dart';
import '../helpers/memory_compiler.dart';
const String code = '''
class A<T> {
final field;
@pragma('dart2js:noInline')
factory A.fact(t) => new A(t);
@pragma('dart2js:noInline')
A(t) : field = t is T;
}
// A call to A.fact.
@pragma('dart2js:noInline')
callAfact() => new A<int>.fact(0).runtimeType;
main() {
callAfact();
}
''';
main() {
asyncTest(() async {
CompilationResult result =
await runCompiler(memorySourceFiles: {'main.dart': code});
Expect.isTrue(result.isSuccess);
Compiler compiler = result.compiler;
JsBackendStrategy backendStrategy = compiler.backendStrategy;
JClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
RuntimeTypesNeed rtiNeed = closedWorld.rtiNeed;
ElementEnvironment elementEnvironment = closedWorld.elementEnvironment;
ProgramLookup programLookup = new ProgramLookup(backendStrategy);
js.Name getName(String name) {
return backendStrategy.namerForTesting
.globalPropertyNameForMember(lookupMember(elementEnvironment, name));
}
void checkParameters(String name,
{int expectedParameterCount, bool needsTypeArguments}) {
FunctionEntity function = lookupMember(elementEnvironment, name);
Expect.equals(
needsTypeArguments,
rtiNeed.methodNeedsTypeArguments(function),
"Unexpected type argument need for $function.");
Method method = programLookup.getMethod(function);
Expect.isNotNull(method, "No method found for $function");
js.Fun fun = method.code;
Expect.equals(expectedParameterCount, fun.params.length,
"Unexpected parameter count on $function: ${js.nodeToString(fun)}");
}
// The declarations should have type parameters only when needed.
checkParameters('A.fact',
expectedParameterCount: 2, needsTypeArguments: false);
checkParameters('A.', expectedParameterCount: 2, needsTypeArguments: false);
checkArguments(String name, String targetName,
{int expectedTypeArguments}) {
FunctionEntity function = lookupMember(elementEnvironment, name);
Method method = programLookup.getMethod(function);
js.Fun fun = method.code;
js.Name selector = getName(targetName);
bool callFound = false;
forEachNode(fun, onCall: (js.Call node) {
js.Expression target = js.undefer(node.target);
if (target is js.PropertyAccess) {
js.Node targetSelector = js.undefer(target.selector);
if (targetSelector is js.Name && targetSelector.key == selector.key) {
callFound = true;
Expect.equals(
expectedTypeArguments,
node.arguments.length,
"Unexpected argument count in $function call to $targetName: "
"${js.nodeToString(fun)}");
}
}
});
Expect.isTrue(
callFound,
"No call to $targetName in $function found: "
"${js.nodeToString(fun)}");
}
// The declarations should have type parameters only when needed by the
// selector.
checkArguments('callAfact', 'A.fact', expectedTypeArguments: 2);
});
}