From 94fc11388ac753ddb06d9fd10e96728ebb50db62 Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Wed, 17 Jan 2018 10:19:53 +0000 Subject: [PATCH] Port inference tests, #5 of 5 Change-Id: I384056289dfa99991aa42fbe0baadedc6c208b6f Reviewed-on: https://dart-review.googlesource.com/34586 Reviewed-by: Sigmund Cherem --- .../lib/src/inferrer/inferrer_engine.dart | 14 +- .../lib/src/inferrer/type_graph_inferrer.dart | 4 +- .../lib/src/inferrer/type_graph_nodes.dart | 9 +- pkg/compiler/lib/src/use_unused_api.dart | 2 +- .../equivalence/id_equivalence_helper.dart | 21 +- .../dart2js/equivalence/show_helper.dart | 17 +- .../call_site_simple_type_inferer_test.dart | 297 -------- .../inference/callers/field_access.dart | 20 + .../dart2js/inference/callers_test.dart | 145 ++++ .../concrete_type_inference_test.dart | 90 --- .../dart2js/inference/data/call_site.dart | 309 ++++++++ .../inference/data/dictionary_types.dart | 196 +++++ .../inference/data/map_tracer_keys.dart | 189 +++++ .../inference/dictionary_types_test.dart | 173 ----- .../field_type_simple_inferer_test.dart | 689 ------------------ .../inference/list_tracer_length_test.dart | 3 +- .../inference/list_tracer_node_type_test.dart | 3 +- .../dart2js/inference/list_tracer_test.dart | 121 +-- .../inference/map_tracer_keys_test.dart | 80 -- .../dart2js/inference/map_tracer_test.dart | 184 ++--- tests/compiler/dart2js/inference/show.dart | 28 +- .../simple_inferrer_callers_test.dart | 67 -- .../dart2js/inlining/inlining_viewer.dart | 3 +- 23 files changed, 1102 insertions(+), 1562 deletions(-) delete mode 100644 tests/compiler/dart2js/inference/call_site_simple_type_inferer_test.dart create mode 100644 tests/compiler/dart2js/inference/callers/field_access.dart create mode 100644 tests/compiler/dart2js/inference/callers_test.dart delete mode 100644 tests/compiler/dart2js/inference/concrete_type_inference_test.dart create mode 100644 tests/compiler/dart2js/inference/data/call_site.dart create mode 100644 tests/compiler/dart2js/inference/data/dictionary_types.dart create mode 100644 tests/compiler/dart2js/inference/data/map_tracer_keys.dart delete mode 100644 tests/compiler/dart2js/inference/dictionary_types_test.dart delete mode 100644 tests/compiler/dart2js/inference/field_type_simple_inferer_test.dart delete mode 100644 tests/compiler/dart2js/inference/map_tracer_keys_test.dart delete mode 100644 tests/compiler/dart2js/inference/simple_inferrer_callers_test.dart diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart index ac9ae6ede8a..02f075e83d8 100644 --- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart +++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart @@ -115,7 +115,7 @@ abstract class InferrerEngine { void setDefaultTypeOfParameter(Local parameter, TypeInformation type, {bool isInstanceMember}); - Iterable getCallersOf(MemberEntity element); + Iterable getCallersOfForTesting(MemberEntity element); // TODO(johnniwinther): Make this private again. GlobalTypeInferenceElementData dataOfMember(MemberEntity element); @@ -250,6 +250,8 @@ abstract class InferrerEngine { } abstract class InferrerEngineImpl extends InferrerEngine { + static bool retainDataForTesting = false; + final Map defaultTypeOfParameter = new Map(); final WorkQueue workQueue = new WorkQueue(); @@ -1094,7 +1096,11 @@ abstract class InferrerEngineImpl extends InferrerEngine { } void clear() { - void cleanup(TypeInformation info) => info.cleanup(); + void cleanup(TypeInformation info) { + if (!retainDataForTesting) { + info.cleanup(); + } + } types.allocatedCalls.forEach(cleanup); types.allocatedCalls.clear(); @@ -1119,9 +1125,9 @@ abstract class InferrerEngineImpl extends InferrerEngine { types.allocatedLists.values.forEach(cleanup); } - Iterable getCallersOf(MemberEntity element) { + Iterable getCallersOfForTesting(MemberEntity element) { MemberTypeInformation info = types.getInferredTypeOfMember(element); - return info.callers; + return info.callersForTesting; } TypeInformation typeOfMemberWithSelector( diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart index 5df28695e55..19410c09584 100644 --- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart +++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart @@ -140,12 +140,12 @@ abstract class TypeGraphInferrer implements TypesInferrer { return result; } - Iterable getCallersOf(MemberEntity element) { + Iterable getCallersOfForTesting(MemberEntity element) { if (_disableTypeInference) { throw new UnsupportedError( "Cannot query the type inferrer when type inference is disabled."); } - return inferrer.getCallersOf(element); + return inferrer.getCallersOfForTesting(element); } bool isMemberCalledOnce(MemberEntity element) { diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart index 5fcca72cc22..2a74cf9ae99 100644 --- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart +++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart @@ -429,13 +429,8 @@ abstract class MemberTypeInformation extends ElementTypeInformation } } - Iterable get callers { - // TODO(sra): This is called only from an unused API and a test. If it - // becomes used, [cleanup] will need to copy `_caller.keys`. - - // `simple_inferrer_callers_test.dart` ensures that cleanup has not - // happened. - return _callers.keys; + Iterable get callersForTesting { + return _callers?.keys; } bool isCalledOnce() { diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart index 08601ea235c..fa487cb860b 100644 --- a/pkg/compiler/lib/src/use_unused_api.dart +++ b/pkg/compiler/lib/src/use_unused_api.dart @@ -254,7 +254,7 @@ usedByTests() { closedWorld.getClassHierarchyNode(null); closedWorld.getClassSet(null); closedWorld.haveAnyCommonSubtypes(null, null); - typeGraphInferrer.getCallersOf(null); + typeGraphInferrer.getCallersOfForTesting(null); dart_types.Types.sorted(null); new dart_types.Types(null).copy(null); } diff --git a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart index dfe9783b10a..d43c8c0e986 100644 --- a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart +++ b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart @@ -542,6 +542,12 @@ Spannable computeSpannable( if (id is NodeId) { return new SourceSpan(mainUri, id.value, id.value + 1); } else if (id is ElementId) { + String memberName = id.memberName; + bool isSetter = false; + if (memberName != '[]=' && memberName.endsWith('=')) { + isSetter = true; + memberName = memberName.substring(0, memberName.length - 1); + } LibraryEntity library = elementEnvironment.lookupLibrary(mainUri); if (id.className != null) { ClassEntity cls = @@ -549,23 +555,22 @@ Spannable computeSpannable( if (cls == null) { throw new ArgumentError("No class '${id.className}' in $mainUri."); } - MemberEntity member = - elementEnvironment.lookupClassMember(cls, id.memberName); + MemberEntity member = elementEnvironment + .lookupClassMember(cls, memberName, setter: isSetter); if (member == null) { ConstructorEntity constructor = - elementEnvironment.lookupConstructor(cls, id.memberName); + elementEnvironment.lookupConstructor(cls, memberName); if (constructor == null) { - throw new ArgumentError( - "No class member '${id.memberName}' in $cls."); + throw new ArgumentError("No class member '${memberName}' in $cls."); } return constructor; } return member; } else { - MemberEntity member = - elementEnvironment.lookupLibraryMember(library, id.memberName); + MemberEntity member = elementEnvironment + .lookupLibraryMember(library, memberName, setter: isSetter); if (member == null) { - throw new ArgumentError("No member '${id.memberName}' in $mainUri."); + throw new ArgumentError("No member '${memberName}' in $mainUri."); } return member; } diff --git a/tests/compiler/dart2js/equivalence/show_helper.dart b/tests/compiler/dart2js/equivalence/show_helper.dart index d37f502d515..bb72432898e 100644 --- a/tests/compiler/dart2js/equivalence/show_helper.dart +++ b/tests/compiler/dart2js/equivalence/show_helper.dart @@ -8,37 +8,40 @@ import 'dart:io'; import 'package:args/args.dart'; import 'package:compiler/src/commandline_options.dart'; import 'package:compiler/src/filenames.dart'; -import 'package:compiler/src/inferrer/inferrer_engine.dart'; import 'package:compiler/src/io/source_file.dart'; import 'package:compiler/src/source_file_provider.dart'; import '../kernel/test_helpers.dart'; import 'id_equivalence_helper.dart'; -show(List args, ComputeMemberDataFunction computeAstData, - ComputeMemberDataFunction computeKernelData) async { +ArgParser createArgParser() { ArgParser argParser = new ArgParser(allowTrailingOptions: true); argParser.addFlag('verbose', negatable: true, defaultsTo: false); argParser.addFlag('colors', negatable: true); argParser.addFlag('all', negatable: false, defaultsTo: false); argParser.addFlag('use-kernel', negatable: false, defaultsTo: false); - ArgResults argResults = argParser.parse(args); + return argParser; +} + +show(ArgResults argResults, ComputeMemberDataFunction computeAstData, + ComputeMemberDataFunction computeKernelData) async { if (argResults.wasParsed('colors')) { useColors = argResults['colors']; } bool verbose = argResults['verbose']; bool useKernel = argResults['use-kernel']; - InferrerEngineImpl.useSorterForTesting = true; String file = argResults.rest.first; Uri entryPoint = Uri.base.resolve(nativeToUriPath(file)); List show; - if (argResults.rest.length > 1) { + if (argResults['all']) { + show = null; + } else if (argResults.rest.length > 1) { show = argResults.rest.skip(1).toList(); } else { show = [entryPoint.pathSegments.last]; } - List options = []; + List options = [stopAfterTypeInference]; if (useKernel) { options.add(Flags.useKernel); } diff --git a/tests/compiler/dart2js/inference/call_site_simple_type_inferer_test.dart b/tests/compiler/dart2js/inference/call_site_simple_type_inferer_test.dart deleted file mode 100644 index 40476413755..00000000000 --- a/tests/compiler/dart2js/inference/call_site_simple_type_inferer_test.dart +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) 2013, 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. - -/// TODO(johnniwinther): Port this test to use the equivalence framework. -/// Currently it only works with the mock compiler. - -import 'package:async_helper/async_helper.dart'; -import 'package:compiler/src/elements/elements.dart'; -import 'package:compiler/src/types/masks.dart'; -import 'package:expect/expect.dart'; - -import 'type_mask_test_helper.dart'; -import '../compiler_helper.dart'; - -void compileAndFind(String code, String className, String memberName, - bool disableInlining, check(compiler, element)) { - Uri uri = new Uri(scheme: 'source'); - var compiler = mockCompilerFor(code, uri, disableInlining: disableInlining); - asyncTest(() => compiler.run(uri).then((_) { - ClassElement cls = findElement(compiler, className); - var member = cls.lookupLocalMember(memberName); - return check(compiler, member); - })); -} - -const String TEST_1 = r""" - class A { - x(p) => p; - } - main() { new A().x("s"); } -"""; - -const String TEST_2 = r""" - class A { - x(p) => p; - } - main() { new A().x(1); } -"""; - -const String TEST_3 = r""" - class A { - x(p) => x(p - 1); - } - main() { new A().x(1); } -"""; - -const String TEST_4 = r""" - class A { - x(p) => x(p - 1); - } - main() { new A().x(1.5); } -"""; - -const String TEST_5 = r""" - class A { - x(p) => p; - } - main() { - new A().x(1); - new A().x(1.5); - } -"""; - -const String TEST_6 = r""" - class A { - x(p) => p; - } - main() { - new A().x(1.5); - new A().x(1); - } -"""; - -const String TEST_7a = r""" - class A { - x(p) => x("x"); - } - main() { - new A().x(1); - } -"""; - -const String TEST_7b = r""" - class A { - x(p) => x("x"); - } - main() { - new A().x({}); - } -"""; - -const String TEST_8 = r""" - class A { - x(p1, p2, p3) => x(p1, "x", {}); - } - main() { - new A().x(1, 2, 3); - } -"""; - -const String TEST_9 = r""" - class A { - x(p1, p2) => x(p1, p2); - } - main() { - new A().x(1, 2); - } -"""; - -const String TEST_10 = r""" - class A { - x(p1, p2) => x(p1, p2); - } - void f(p) { - p.x("x", "y"); - } - main() { - f(null); - new A().x(1, 2); - } -"""; - -const String TEST_11 = r""" - class A { - x(p1, p2) => x(1, 2); - } - main() { - new A().x("x", "y"); - } -"""; - -const String TEST_12 = r""" - class A { - x(p1, [p2 = 1]) => 1; - } - main() { - new A().x("x", 1); - new A().x("x"); - } -"""; - -const String TEST_13 = r""" - class A { - x(p) => 1; - } - f(p) => p.x(2.2); - main() { - new A().x(1); - f(new A()); - } -"""; - -const String TEST_14 = r""" - class A { - x(p1, [p2 = "s"]) => 1; - } - main() { - new A().x(1); - } -"""; - -const String TEST_15 = r""" - class A { - x(p1, [p2 = true]) => 1; - } - f(p) => p.a("x"); - main() { - new A().x("x"); - new A().x("x", false); - f(null); - } -"""; - -const String TEST_16 = r""" - class A { - x(p1, [p2 = 1, p3 = "s"]) => 1; - } - main() { - new A().x(1); - new A().x(1, 2); - new A().x(1, 2, "x"); - new A().x(1, p2: 2); - new A().x(1, p3: "x"); - new A().x(1, p3: "x", p2: 2); - new A().x(1, p2: 2, p3: "x"); - } -"""; - -const String TEST_17 = r""" - class A { - x(p1, [p2 = 1, p3 = "s"]) => 1; - } - main() { - new A().x(1, true, 1.1); - new A().x(1, false, 2.2); - new A().x(1, p3: 3.3, p2: true); - new A().x(1, p2: false, p3: 4.4); - } -"""; - -const String TEST_18 = r""" - class A { - x(p1, p2) => x(p1, p2); - } - class B extends A { - } - main() { - new B().x("a", "b"); - new A().x(1, 2); - } -"""; - -typedef List TestCallback(CommonMasks masks); - -void doTest(String test, bool enableInlining, TestCallback f) { - compileAndFind(test, 'A', 'x', enableInlining, (compiler, element) { - var inferrer = compiler.globalInference.typesInferrerInternal; - var closedWorld = inferrer.closedWorld; - var expectedTypes = f(closedWorld.commonMasks); - var signature = element.functionSignature; - int index = 0; - signature.forEachParameter((Element element) { - Expect.equals(expectedTypes[index++], - simplify(inferrer.getTypeOfParameter(element), closedWorld), test); - }); - Expect.equals(index, expectedTypes.length); - }); -} - -void runTest(String test, TestCallback f) { - doTest(test, false, f); - doTest(test, true, f); -} - -void test() { - runTest(TEST_1, (commonMasks) => [commonMasks.stringType]); - runTest(TEST_2, (commonMasks) => [commonMasks.uint31Type]); - runTest(TEST_3, (commonMasks) => [commonMasks.intType]); - runTest(TEST_4, (commonMasks) => [commonMasks.numType]); - runTest(TEST_5, (commonMasks) => [commonMasks.numType]); - runTest(TEST_6, (commonMasks) => [commonMasks.numType]); - runTest(TEST_7a, (commonMasks) => [commonMasks.interceptorType]); - runTest(TEST_7b, (commonMasks) => [commonMasks.dynamicType.nonNullable()]); - - runTest( - TEST_8, - (commonMasks) => [ - commonMasks.uint31Type, - commonMasks.interceptorType, - commonMasks.dynamicType.nonNullable() - ]); - runTest(TEST_9, - (commonMasks) => [commonMasks.uint31Type, commonMasks.uint31Type]); - runTest(TEST_10, - (commonMasks) => [commonMasks.uint31Type, commonMasks.uint31Type]); - runTest( - TEST_11, - (commonMasks) => - [commonMasks.interceptorType, commonMasks.interceptorType]); - - runTest(TEST_12, - (commonMasks) => [commonMasks.stringType, commonMasks.uint31Type]); - - runTest(TEST_13, (commonMasks) => [commonMasks.numType]); - - runTest(TEST_14, - (commonMasks) => [commonMasks.uint31Type, commonMasks.stringType]); - - runTest( - TEST_15, (commonMasks) => [commonMasks.stringType, commonMasks.boolType]); - - runTest( - TEST_16, - (commonMasks) => [ - commonMasks.uint31Type, - commonMasks.uint31Type, - commonMasks.stringType - ]); - - runTest( - TEST_17, - (commonMasks) => [ - commonMasks.uint31Type, - commonMasks.boolType, - commonMasks.doubleType - ]); - - runTest( - TEST_18, - (commonMasks) => - [commonMasks.interceptorType, commonMasks.interceptorType]); -} - -void main() { - test(); -} diff --git a/tests/compiler/dart2js/inference/callers/field_access.dart b/tests/compiler/dart2js/inference/callers/field_access.dart new file mode 100644 index 00000000000..71699e9e771 --- /dev/null +++ b/tests/compiler/dart2js/inference/callers/field_access.dart @@ -0,0 +1,20 @@ +// 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. + +/*element: B.:[main]*/ +class A { + /*element: A.field:[main]*/ + var field; +} + +/*element: A.:[main]*/ +class B { + /*element: B.field:[main]*/ + var field; +} + +main() { + new A().field; + new B().field; +} diff --git a/tests/compiler/dart2js/inference/callers_test.dart b/tests/compiler/dart2js/inference/callers_test.dart new file mode 100644 index 00000000000..b88f07fffd3 --- /dev/null +++ b/tests/compiler/dart2js/inference/callers_test.dart @@ -0,0 +1,145 @@ +// 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 'dart:io'; +import 'package:async_helper/async_helper.dart'; +import 'package:compiler/src/closure.dart'; +import 'package:compiler/src/common.dart'; +import 'package:compiler/src/compiler.dart'; +import 'package:compiler/src/diagnostics/diagnostic_listener.dart'; +import 'package:compiler/src/elements/elements.dart'; +import 'package:compiler/src/elements/entities.dart'; +import 'package:compiler/src/inferrer/inferrer_engine.dart'; +import 'package:compiler/src/inferrer/type_graph_inferrer.dart'; +import 'package:compiler/src/kernel/element_map.dart'; +import 'package:compiler/src/kernel/kernel_backend_strategy.dart'; +import 'package:compiler/src/tree/nodes.dart' as ast; +import 'package:kernel/ast.dart' as ir; +import '../equivalence/id_equivalence.dart'; +import '../equivalence/id_equivalence_helper.dart'; + +main(List args) { + InferrerEngineImpl.retainDataForTesting = true; + asyncTest(() async { + Directory dataDir = + new Directory.fromUri(Platform.script.resolve('callers')); + await checkTests(dataDir, computeMemberAstCallers, computeMemberIrCallers, + args: args, options: [stopAfterTypeInference]); + }); +} + +/// Compute callers data for [_member] as a [MemberElement]. +/// +/// Fills [actualMap] with the data. +void computeMemberAstCallers( + Compiler compiler, MemberEntity _member, Map actualMap, + {bool verbose: false}) { + MemberElement member = _member; + ResolvedAst resolvedAst = member.resolvedAst; + compiler.reporter.withCurrentElement(member.implementation, () { + new CallersAstComputer(compiler.reporter, actualMap, resolvedAst, + compiler.globalInference.typesInferrerInternal) + .run(); + }); +} + +abstract class ComputeValueMixin { + TypeGraphInferrer get inferrer; + + String getMemberValue(MemberEntity member) { + Iterable callers = inferrer.getCallersOfForTesting(member); + if (callers != null) { + List names = callers.map((MemberEntity member) { + StringBuffer sb = new StringBuffer(); + if (member.enclosingClass != null) { + sb.write(member.enclosingClass.name); + sb.write('.'); + } + sb.write(member.name); + if (member.isSetter) { + sb.write('='); + } + return sb.toString(); + }).toList() + ..sort(); + return '[${names.join(',')}]'; + } + return null; + } +} + +/// AST visitor for computing side effects data for a member. +class CallersAstComputer extends AstDataExtractor + with ComputeValueMixin { + final TypeGraphInferrer inferrer; + + CallersAstComputer(DiagnosticReporter reporter, Map actualMap, + ResolvedAst resolvedAst, this.inferrer) + : super(reporter, actualMap, resolvedAst); + + @override + String computeElementValue(Id id, AstElement element) { + if (element.isParameter) { + return null; + } else if (element.isLocal && element.isFunction) { + LocalFunctionElement localFunction = element; + return getMemberValue(localFunction.callMethod); + } else { + MemberElement member = element.declaration; + return getMemberValue(member); + } + } + + @override + String computeNodeValue(Id id, ast.Node node, [AstElement element]) { + if (element != null && element.isLocal && element.isFunction) { + return computeElementValue(id, element); + } + return null; + } +} + +/// Compute callers data for [member] from kernel based inference. +/// +/// Fills [actualMap] with the data. +void computeMemberIrCallers( + Compiler compiler, MemberEntity member, Map actualMap, + {bool verbose: false}) { + KernelBackendStrategy backendStrategy = compiler.backendStrategy; + KernelToElementMapForBuilding elementMap = backendStrategy.elementMap; + MemberDefinition definition = elementMap.getMemberDefinition(member); + new CallersIrComputer( + compiler.reporter, + actualMap, + elementMap, + compiler.globalInference.typesInferrerInternal, + backendStrategy.closureDataLookup as ClosureDataLookup) + .run(definition.node); +} + +/// AST visitor for computing side effects data for a member. +class CallersIrComputer extends IrDataExtractor + with ComputeValueMixin { + final TypeGraphInferrer inferrer; + final KernelToElementMapForBuilding _elementMap; + final ClosureDataLookup _closureDataLookup; + + CallersIrComputer(DiagnosticReporter reporter, Map actualMap, + this._elementMap, this.inferrer, this._closureDataLookup) + : super(reporter, actualMap); + + @override + String computeMemberValue(Id id, ir.Member node) { + return getMemberValue(_elementMap.getMember(node)); + } + + @override + String computeNodeValue(Id id, ir.TreeNode node) { + if (node is ir.FunctionExpression || node is ir.FunctionDeclaration) { + ClosureRepresentationInfo info = _closureDataLookup.getClosureInfo(node); + return getMemberValue(info.callMethod); + } + return null; + } +} diff --git a/tests/compiler/dart2js/inference/concrete_type_inference_test.dart b/tests/compiler/dart2js/inference/concrete_type_inference_test.dart deleted file mode 100644 index 4b1b6b515fb..00000000000 --- a/tests/compiler/dart2js/inference/concrete_type_inference_test.dart +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2012, 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. - -/// TODO(johnniwinther): Port this test to use the equivalence framework. - -import 'dart:async'; -import 'package:expect/expect.dart'; -import 'package:async_helper/async_helper.dart'; -import '../compiler_helper.dart'; - -Future compileAndFind(String code, String name, check(compiler, element)) { - Uri uri = new Uri(scheme: 'source'); - var compiler = mockCompilerFor(code, uri); - return compiler.run(uri).then((_) { - var element = findElement(compiler, name); - check(compiler, element); - }); -} - -void checkPrintType(String expression, checkType(closedWorld, type)) { - asyncTest(() => compileAndFind('main() { print($expression); }', 'print', - (compiler, printElement) { - var parameter = printElement.functionSignature.requiredParameters.first; - checkType(compiler.resolutionWorldBuilder.closedWorldForTesting, - _typeOf(compiler, parameter)); - })); - - asyncTest(() => - compileAndFind('main() { var x = print; print($expression); }', 'print', - (compiler, printElement) { - var parameter = printElement.functionSignature.requiredParameters.first; - checkType(compiler.resolutionWorldBuilder.closedWorldForTesting, - _typeOf(compiler, parameter)); - })); - - asyncTest(() => compileAndFind( - 'main() { print($expression); print($expression); }', 'print', - (compiler, printElement) { - var parameter = printElement.functionSignature.requiredParameters.first; - checkType(compiler.resolutionWorldBuilder.closedWorldForTesting, - _typeOf(compiler, parameter)); - })); -} - -void testBasicTypes() { - checkPrintType('true', (closedWorld, type) { - if (type.isForwarding) type = type.forwardTo; - Expect.identical(closedWorld.commonMasks.boolType, type); - }); - checkPrintType('1.5', (closedWorld, type) { - Expect.identical(closedWorld.commonMasks.doubleType, type); - }); - checkPrintType('1', (closedWorld, type) { - Expect.identical(closedWorld.commonMasks.uint31Type, type); - }); - checkPrintType('[]', (closedWorld, type) { - if (type.isForwarding) type = type.forwardTo; - Expect.identical(closedWorld.commonMasks.growableListType, type); - }); - checkPrintType('null', (closedWorld, type) { - Expect.identical(closedWorld.commonMasks.nullType, type); - }); - checkPrintType('"foo"', (closedWorld, type) { - Expect.isTrue( - closedWorld.commonMasks.stringType.containsOnlyString(closedWorld)); - }); -} - -void testOptionalParameters() { - compileAndFind('fisk(a, [b, c]) {} main() { fisk(1); }', 'fisk', - (compiler, fiskElement) { - var firstParameter = fiskElement.functionSignature.requiredParameters[0]; - var secondParameter = fiskElement.functionSignature.optionalParameters[0]; - var thirdParameter = fiskElement.functionSignature.optionalParameters[1]; - var commonMasks = - compiler.resolutionWorldBuilder.closedWorldForTesting.commonMasks; - Expect.identical(commonMasks.uint31Type, _typeOf(compiler, firstParameter)); - Expect.identical(commonMasks.nullType, _typeOf(compiler, secondParameter)); - Expect.identical(commonMasks.nullType, _typeOf(compiler, thirdParameter)); - }); -} - -void main() { - testBasicTypes(); - testOptionalParameters(); -} - -_typeOf(compiler, parameter) => - compiler.globalInference.results.resultOfParameter(parameter).type; diff --git a/tests/compiler/dart2js/inference/data/call_site.dart b/tests/compiler/dart2js/inference/data/call_site.dart new file mode 100644 index 00000000000..e9bcd9f4daa --- /dev/null +++ b/tests/compiler/dart2js/inference/data/call_site.dart @@ -0,0 +1,309 @@ +// 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. + +/*element: main:[null]*/ +main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + test12(); + test13(); + test14(); + test15(); + test16(); + test17(); + test18(); + test19(); +} + +/*element: A1.:[exact=A1]*/ +class A1 { + /*element: A1.x1:Value([exact=JSString], value: "s")*/ + x1( + /*Value([exact=JSString], value: "s")*/ p) => + p; +} + +/*element: test1:[null]*/ +test1() { + new A1(). /*invoke: [exact=A1]*/ x1("s"); +} + +/*element: A2.:[exact=A2]*/ +class A2 { + /*element: A2.x2:[exact=JSUInt31]*/ + x2(/*[exact=JSUInt31]*/ p) => p; +} + +/*element: test2:[null]*/ +test2() { + new A2(). /*invoke: [exact=A2]*/ x2(1); +} + +/*element: A3.:[exact=A3]*/ +class A3 { + /*element: A3.x3:[empty]*/ + x3(/*[subclass=JSInt]*/ p) => /*invoke: [exact=A3]*/ x3( + p /*invoke: [subclass=JSInt]*/ - 1); +} + +/*element: test3:[null]*/ +test3() { + new A3(). /*invoke: [exact=A3]*/ x3(1); +} + +/*element: A4.:[exact=A4]*/ +class A4 { + /*element: A4.x4:[empty]*/ + x4(/*[subclass=JSNumber]*/ p) => /*invoke: [exact=A4]*/ x4( + p /*invoke: [subclass=JSNumber]*/ - 1); +} + +/*element: test4:[null]*/ +test4() { + new A4(). /*invoke: [exact=A4]*/ x4(1.5); +} + +/*element: A5.:[exact=A5]*/ +class A5 { + /*element: A5.x5:Union([exact=JSDouble], [exact=JSUInt31])*/ + x5( + /*Union([exact=JSDouble], [exact=JSUInt31])*/ p) => + p; +} + +/*element: test5:[null]*/ +test5() { + new A5(). /*invoke: [exact=A5]*/ x5(1); + new A5(). /*invoke: [exact=A5]*/ x5(1.5); +} + +/*element: A6.:[exact=A6]*/ +class A6 { + /*element: A6.x6:Union([exact=JSDouble], [exact=JSUInt31])*/ + x6( + /*Union([exact=JSDouble], [exact=JSUInt31])*/ p) => + p; +} + +/*element: test6:[null]*/ +test6() { + new A6(). /*invoke: [exact=A6]*/ x6(1.5); + new A6(). /*invoke: [exact=A6]*/ x6(1); +} + +/*element: A7.:[exact=A7]*/ +class A7 { + /*element: A7.x7:[empty]*/ + x7( + /*Union([exact=JSString], [exact=JSUInt31])*/ p) => /*invoke: [exact=A7]*/ x7("x"); +} + +/*element: test7:[null]*/ +test7() { + new A7(). /*invoke: [exact=A7]*/ x7(1); +} + +/*element: A8.:[exact=A8]*/ +class A8 { + /*element: A8.x8:[empty]*/ + x8( + /*Union([exact=JSString], [subclass=JsLinkedHashMap])*/ p) => + /*invoke: [exact=A8]*/ x8("x"); +} + +/*element: test8:[null]*/ +test8() { + new A8(). /*invoke: [exact=A8]*/ x8({}); +} + +/*element: A9.:[exact=A9]*/ +class A9 { + /*element: A9.x9:[empty]*/ x9( + /*[exact=JSUInt31]*/ p1, + /*Union([exact=JSString], [exact=JSUInt31])*/ p2, + /*Union([exact=JSUInt31], [subclass=JsLinkedHashMap])*/ p3) => + /*invoke: [exact=A9]*/ x9(p1, "x", {}); +} + +/*element: test9:[null]*/ +test9() { + new A9(). /*invoke: [exact=A9]*/ x9(1, 2, 3); +} + +/*element: A10.:[exact=A10]*/ +class A10 { + /*element: A10.x10:[empty]*/ x10( + /*[exact=JSUInt31]*/ p1, + /*[exact=JSUInt31]*/ p2) => /*invoke: [exact=A10]*/ x10(p1, p2); +} + +/*element: test10:[null]*/ +test10() { + new A10(). /*invoke: [exact=A10]*/ x10(1, 2); +} + +/*element: A11.:[exact=A11]*/ +class A11 { + /*element: A11.x11:[empty]*/ + x11( + /*[exact=JSUInt31]*/ p1, + /*[exact=JSUInt31]*/ p2) => /*invoke: [exact=A11]*/ x11(p1, p2); +} + +/*element: f11:[null]*/ +void f11(/*[null]*/ p) { + p. /*invoke: [null]*/ x11("x", "y"); +} + +/*element: test11:[null]*/ +test11() { + f11(null); + new A11(). /*invoke: [exact=A11]*/ x11(1, 2); +} + +/*element: A12.:[exact=A12]*/ +class A12 { + /*element: A12.x12:[empty]*/ + x12( + /*Union([exact=JSString], [exact=JSUInt31])*/ p1, + /*Union([exact=JSString], [exact=JSUInt31])*/ p2) => + /*invoke: [exact=A12]*/ x12(1, 2); +} + +/*element: test12:[null]*/ +test12() { + new A12(). /*invoke: [exact=A12]*/ x12("x", "y"); +} + +/*element: A13.:[exact=A13]*/ +class A13 { + /*element: A13.x13:[exact=JSUInt31]*/ + x13( + /*Value([exact=JSString], value: "x")*/ p1, + [/*[exact=JSUInt31]*/ p2 = 1]) => + 1; +} + +/*element: test13:[null]*/ +test13() { + new A13(). /*invoke: [exact=A13]*/ x13("x", 1); + new A13(). /*invoke: [exact=A13]*/ x13("x"); +} + +/*element: A14.:[exact=A14]*/ +class A14 { + /*element: A14.x14:[exact=JSUInt31]*/ + x14( + /*Union([exact=JSDouble], [exact=JSUInt31])*/ p) => + 1; +} + +/*element: f14:[exact=JSUInt31]*/ +f14(/*[exact=A14]*/ p) => p. /*invoke: [exact=A14]*/ x14(2.2); + +/*element: test14:[null]*/ +test14() { + new A14(). /*invoke: [exact=A14]*/ x14(1); + f14(new A14()); +} + +/*element: A15.:[exact=A15]*/ +class A15 { + /*element: A15.x15:[exact=JSUInt31]*/ + x15(/*[exact=JSUInt31]*/ p1, + [/*Value([exact=JSString], value: "s")*/ p2 = "s"]) => + 1; +} + +/*element: test15:[null]*/ +test15() { + new A15(). /*invoke: [exact=A15]*/ x15(1); +} + +/*element: A16.:[exact=A16]*/ +class A16 { + /*element: A16.x16:[exact=JSUInt31]*/ + x16( + /*Value([exact=JSString], value: "x")*/ p1, + [/*[exact=JSBool]*/ p2 = true]) => + 1; +} + +/*element: f16:[empty]*/ +f16(/*[null]*/ p) => p. /*invoke: [null]*/ a("x"); + +/*element: test16:[null]*/ +test16() { + new A16(). /*invoke: [exact=A16]*/ x16("x"); + new A16(). /*invoke: [exact=A16]*/ x16("x", false); + f16(null); +} + +/*element: A17.:[exact=A17]*/ +class A17 { + /*element: A17.x17:[exact=JSUInt31]*/ + x17(/*[exact=JSUInt31]*/ p1, + [/*[exact=JSUInt31]*/ p2 = 1, /*[exact=JSString]*/ p3 = "s"]) => + 1; +} + +/*element: test17:[null]*/ +test17() { + new A17(). /*invoke: [exact=A17]*/ x17(1); + new A17(). /*invoke: [exact=A17]*/ x17(1, 2); + new A17(). /*invoke: [exact=A17]*/ x17(1, 2, "x"); + // ignore: undefined_named_parameter + new A17(). /*invoke: [exact=A17]*/ x17(1, p2: 2); + // ignore: undefined_named_parameter + new A17(). /*invoke: [exact=A17]*/ x17(1, p3: "x"); + // ignore: undefined_named_parameter + new A17(). /*invoke: [exact=A17]*/ x17(1, p3: "x", p2: 2); + // ignore: undefined_named_parameter + new A17(). /*invoke: [exact=A17]*/ x17(1, p2: 2, p3: "x"); +} + +/*element: A18.:[exact=A18]*/ +class A18 { + /*element: A18.x18:[exact=JSUInt31]*/ + x18(/*[exact=JSUInt31]*/ p1, + [/*[exact=JSBool]*/ p2 = 1, /*[exact=JSDouble]*/ p3 = "s"]) => + 1; +} + +/*element: test18:[null]*/ +test18() { + new A18(). /*invoke: [exact=A18]*/ x18(1, true, 1.1); + new A18(). /*invoke: [exact=A18]*/ x18(1, false, 2.2); + // ignore: undefined_named_parameter + new A18(). /*invoke: [exact=A18]*/ x18(1, p3: 3.3, p2: true); + // ignore: undefined_named_parameter + new A18(). /*invoke: [exact=A18]*/ x18(1, p2: false, p3: 4.4); +} + +/*element: A19.:[exact=A19]*/ +class A19 { + /*element: A19.x19:[empty]*/ + x19( + /*Union([exact=JSString], [exact=JSUInt31])*/ p1, + /*Union([exact=JSString], [exact=JSUInt31])*/ p2) => + /*invoke: [subclass=A19]*/ x19(p1, p2); +} + +/*element: B19.:[exact=B19]*/ +class B19 extends A19 {} + +/*element: test19:[null]*/ +test19() { + new B19(). /*invoke: [exact=B19]*/ x19("a", "b"); + new A19(). /*invoke: [exact=A19]*/ x19(1, 2); +} diff --git a/tests/compiler/dart2js/inference/data/dictionary_types.dart b/tests/compiler/dart2js/inference/data/dictionary_types.dart new file mode 100644 index 00000000000..f6f3cc4b2dc --- /dev/null +++ b/tests/compiler/dart2js/inference/data/dictionary_types.dart @@ -0,0 +1,196 @@ +// 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. + +/*element: main:[null]*/ +main() { + test1(); + test2(); + test3(); + test4(); + test5(); +} + +/*element: dictionaryA1:Map([subclass=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/ +var dictionaryA1 = {'string': "aString", 'int': 42, 'double': 21.5, 'list': []}; + +/*element: dictionaryB1:Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null), stringTwo: Value([null|exact=JSString], value: "anotherString"), intTwo: [null|exact=JSUInt31]})*/ +var dictionaryB1 = {'string': "aString", 'int': 42, 'double': 21.5, 'list': []}; + +/*element: otherDict1:Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSUInt31], [null|exact=JSString]), map: {stringTwo: Value([exact=JSString], value: "anotherString"), intTwo: [exact=JSUInt31]})*/ +var otherDict1 = {'stringTwo': "anotherString", 'intTwo': 84}; + +/*element: int1:[exact=JSUInt31]*/ +var int1 = 0; + +/*element: anotherInt1:[exact=JSUInt31]*/ +var anotherInt1 = 0; + +/*element: nullOrInt1:[null|exact=JSUInt31]*/ +var nullOrInt1 = 0; + +/*element: dynamic1:[null|subclass=Object]*/ +var dynamic1 = 0; + +/*element: test1:[null]*/ +test1() { + dictionaryA1 + . /*invoke: Map([subclass=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/ + addAll(otherDict1); + dictionaryB1 + . /*invoke: Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null), stringTwo: Value([null|exact=JSString], value: "anotherString"), intTwo: [null|exact=JSUInt31]})*/ + addAll({'stringTwo': "anotherString", 'intTwo': 84}); + int1 = dictionaryB1 + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null), stringTwo: Value([null|exact=JSString], value: "anotherString"), intTwo: [null|exact=JSUInt31]})*/ + ['int']; + anotherInt1 = otherDict1 + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSUInt31], [null|exact=JSString]), map: {stringTwo: Value([exact=JSString], value: "anotherString"), intTwo: [exact=JSUInt31]})*/ + ['intTwo']; + dynamic1 = dictionaryA1 + /*Map([subclass=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/ [ + 'int']; + nullOrInt1 = dictionaryB1 + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null), stringTwo: Value([null|exact=JSString], value: "anotherString"), intTwo: [null|exact=JSUInt31]})*/ + ['intTwo']; +} + +/*element: dictionaryA2:Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ +var dictionaryA2 = {'string': "aString", 'int': 42, 'double': 21.5, 'list': []}; + +/*element: dictionaryB2:Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), intTwo: [exact=JSUInt31], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ +var dictionaryB2 = {'string': "aString", 'intTwo': 42, 'list': []}; + +/*element: nullOrInt2:[null|exact=JSUInt31]*/ +var nullOrInt2 = 0; + +/*element: aString2:[exact=JSString]*/ +var aString2 = ""; + +/*element: doubleOrNull2:[null|exact=JSDouble]*/ +var doubleOrNull2 = 22.2; + +/*element: test2:[null]*/ +test2() { + var union = dictionaryA2 + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ + ['foo'] + ? dictionaryA2 + : dictionaryB2; + nullOrInt2 = union + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {int: [null|exact=JSUInt31], double: [null|exact=JSDouble], string: Value([exact=JSString], value: "aString"), intTwo: [null|exact=JSUInt31], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ + ['intTwo']; + aString2 = union + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {int: [null|exact=JSUInt31], double: [null|exact=JSDouble], string: Value([exact=JSString], value: "aString"), intTwo: [null|exact=JSUInt31], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ + ['string']; + doubleOrNull2 = union + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {int: [null|exact=JSUInt31], double: [null|exact=JSDouble], string: Value([exact=JSString], value: "aString"), intTwo: [null|exact=JSUInt31], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ + ['double']; +} + +/*element: dictionary3:Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ +var dictionary3 = {'string': "aString", 'int': 42, 'double': 21.5, 'list': []}; +/*element: keyD3:Value([exact=JSString], value: "double")*/ +var keyD3 = 'double'; + +/*element: keyI3:Value([exact=JSString], value: "int")*/ +var keyI3 = 'int'; + +/*element: keyN3:Value([exact=JSString], value: "notFoundInMap")*/ +var keyN3 = 'notFoundInMap'; + +/*element: knownDouble3:[exact=JSDouble]*/ +var knownDouble3 = 42.2; + +/*element: intOrNull3:[null|exact=JSUInt31]*/ +var intOrNull3 = dictionary3 + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ + [keyI3]; + +/*element: justNull3:[null]*/ +var justNull3 = dictionary3 + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ + [keyN3]; + +/*element: test3:[null]*/ +test3() { + knownDouble3 = dictionary3 + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [exact=JSExtendableArray], [exact=JSUInt31], [null|exact=JSString]), map: {string: Value([exact=JSString], value: "aString"), int: [exact=JSUInt31], double: [exact=JSDouble], list: Container([exact=JSExtendableArray], element: [empty], length: 0)})*/ + [keyD3]; + // ignore: unused_local_variable + var x = [intOrNull3, justNull3]; +} + +class A4 { +/*element: A4.:[exact=A4]*/ + A4(); +/*element: A4.foo4:[exact=JSUInt31]*/ + foo4( + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSUInt31], [null|exact=JSString]), map: {anInt: [exact=JSUInt31], aString: Value([exact=JSString], value: "theString")})*/ value) { + return value /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSUInt31], [null|exact=JSString]), map: {anInt: [exact=JSUInt31], aString: Value([exact=JSString], value: "theString")})*/ [ + 'anInt']; + } +} + +class B4 { +/*element: B4.:[exact=B4]*/ + B4(); + +/*element: B4.foo4:[exact=JSUInt31]*/ + foo4( + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSUInt31], [null|exact=JSString]), map: {anInt: [exact=JSUInt31], aString: Value([exact=JSString], value: "theString")})*/ value) { + return 0; + } +} + +/*element: test4:[null]*/ +test4() { + var dictionary = {'anInt': 42, 'aString': "theString"}; + var it; + if ([true, false] + /*Container([exact=JSExtendableArray], element: [exact=JSBool], length: 2)*/ + [0]) { + it = new A4(); + } else { + it = new B4(); + } + print(it. /*invoke: Union([exact=A4], [exact=B4])*/ foo4( + dictionary) /*invoke: [exact=JSUInt31]*/ + + 2); +} + +/*element: dict5:Map([null|subclass=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/ +var dict5 = makeMap5([1, 2]); + +/*element: notInt5:[null|subclass=Object]*/ +var notInt5 = 0; + +/*element: alsoNotInt5:[null|subclass=Object]*/ +var alsoNotInt5 = 0; + +/*element: makeMap5:Map([subclass=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/ +makeMap5( + /*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 2)*/ values) { + return { + 'moo': values + /*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 2)*/ + [0], + 'boo': values + /*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 2)*/ + [1] + }; +} + +/*element: test5:[null]*/ +test5() { + dict5 + /*update: Map([null|subclass=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/ + ['goo'] = 42; + var closure = + /*Map([null|subclass=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/ + () => dict5; + notInt5 = closure()['boo']; + alsoNotInt5 = dict5 + /*Map([null|subclass=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/ + ['goo']; + print("$notInt5 and $alsoNotInt5."); +} diff --git a/tests/compiler/dart2js/inference/data/map_tracer_keys.dart b/tests/compiler/dart2js/inference/data/map_tracer_keys.dart new file mode 100644 index 00000000000..fb02458bcf1 --- /dev/null +++ b/tests/compiler/dart2js/inference/data/map_tracer_keys.dart @@ -0,0 +1,189 @@ +// 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. + +/*element: main:[null]*/ +main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); +} + +/*element: aDouble1:[null|exact=JSDouble]*/ +double aDouble1 = 42.5; + +/*element: aList1:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ +List aList1 = [42]; + +/*element: consume1:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ +consume1( + /*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ x) => + x; + +/*element: test1:[null]*/ +test1() { + var theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4}; + theMap + /*update: Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: [null|exact=JSDouble], map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: [null|exact=JSDouble]})*/ + ['d'] = 5.5; + /*iterator: [exact=LinkedHashMapKeyIterable]*/ + /*current: [exact=LinkedHashMapKeyIterator]*/ + /*moveNext: [exact=LinkedHashMapKeyIterator]*/ + for (var key in theMap. + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: [null|exact=JSDouble], map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: [null|exact=JSDouble]})*/ + keys) { + aDouble1 = theMap + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: [null|exact=JSDouble], map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: [null|exact=JSDouble]})*/ + [key]; + } + // We have to reference it somewhere, so that it always gets resolved. + consume1(aList1); +} + +/*element: aDouble2:[null|exact=JSDouble]*/ +double aDouble2 = 42.5; + +/*element: aList2:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ +List aList2 = [42]; + +/*element: consume2:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ +consume2( + /*Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ x) => + x; + +/*element: test2:[null]*/ +test2() { + dynamic theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4}; + theMap + /*update: Map([subclass=JsLinkedHashMap], key: Union([exact=JSExtendableArray], [exact=JSString]), value: [null|exact=JSDouble])*/ + [aList2] = 5.5; + /*iterator: [exact=LinkedHashMapKeyIterable]*/ + /*current: [exact=LinkedHashMapKeyIterator]*/ + /*moveNext: [exact=LinkedHashMapKeyIterator]*/ + for (var key in theMap. + /*Map([subclass=JsLinkedHashMap], key: Union([exact=JSExtendableArray], [exact=JSString]), value: [null|exact=JSDouble])*/ + keys) { + aDouble2 = theMap + /*Map([subclass=JsLinkedHashMap], key: Union([exact=JSExtendableArray], [exact=JSString]), value: [null|exact=JSDouble])*/ + [key]; + } + // We have to reference it somewhere, so that it always gets resolved. + consume2(aList2); +} + +/*element: aDouble3:Union([exact=JSDouble], [null|exact=JSExtendableArray])*/ +double aDouble3 = 42.5; + +/*element: aList3:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ +List aList3 = [42]; + +/*element: consume3:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ +consume3( + /*Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ x) => + x; + +/*element: test3:[null]*/ +test3() { + dynamic theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4}; + theMap + /*update: Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [null|exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([null|exact=JSExtendableArray], element: [null|subclass=Object], length: null)})*/ + ['d'] = aList3; + /*iterator: [exact=LinkedHashMapKeyIterable]*/ + /*current: [exact=LinkedHashMapKeyIterator]*/ + /*moveNext: [exact=LinkedHashMapKeyIterator]*/ + for (var key in theMap. + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [null|exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([null|exact=JSExtendableArray], element: [null|subclass=Object], length: null)})*/ + keys) { + aDouble3 = theMap + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [null|exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([null|exact=JSExtendableArray], element: [null|subclass=Object], length: null)})*/ + [key]; + } + // We have to reference it somewhere, so that it always gets resolved. + consume3(aList3); +} + +/*element: aDouble4:[null|exact=JSDouble]*/ +double aDouble4 = 42.5; + +/*element: aList4:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ +List aList4 = [42]; + +/*element: consume4:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ +consume4( + /*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ x) => + x; + +/*element: test4:[null]*/ +test4() { + var theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4, 'd': 5.5}; + /*iterator: [exact=LinkedHashMapKeyIterable]*/ + /*current: [exact=LinkedHashMapKeyIterator]*/ + /*moveNext: [exact=LinkedHashMapKeyIterator]*/ + for (var key in theMap. + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: [null|exact=JSDouble], map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: [exact=JSDouble]})*/ + keys) { + aDouble4 = theMap + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: [null|exact=JSDouble], map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: [exact=JSDouble]})*/ + [key]; + } + // We have to reference it somewhere, so that it always gets resolved. + consume4(aList4); +} + +/*element: aDouble5:[null|exact=JSDouble]*/ +double aDouble5 = 42.5; + +/*element: aList5:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ +List aList5 = [42]; + +/*element: consume5:Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ +consume5( + /*Container([exact=JSExtendableArray], element: [null|subclass=Object], length: null)*/ x) => + x; + +/*element: test5:[null]*/ +test5() { + var theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4, aList5: 5.5}; + /*iterator: [exact=LinkedHashMapKeyIterable]*/ + /*current: [exact=LinkedHashMapKeyIterator]*/ + /*moveNext: [exact=LinkedHashMapKeyIterator]*/ + for (var key in theMap. + /*Map([subclass=JsLinkedHashMap], key: Union([exact=JSExtendableArray], [exact=JSString]), value: [null|exact=JSDouble])*/ + keys) { + aDouble5 = theMap + /*Map([subclass=JsLinkedHashMap], key: Union([exact=JSExtendableArray], [exact=JSString]), value: [null|exact=JSDouble])*/ + [key]; + } + // We have to reference it somewhere, so that it always gets resolved. + consume5(aList5); +} + +/*element: aDouble6:Union([null|exact=JSDouble], [null|exact=JSExtendableArray])*/ +double aDouble6 = 42.5; +/*element: aList6:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ +List aList6 = [42]; + +/*element: consume6:Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ +consume6( + /*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)*/ x) => + x; + +/*element: test6:[null]*/ +test6() { + var theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4, 'd': aList6}; + /*iterator: [exact=LinkedHashMapKeyIterable]*/ + /*current: [exact=LinkedHashMapKeyIterator]*/ + /*moveNext: [exact=LinkedHashMapKeyIterator]*/ + for (var key in theMap. + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([exact=JSDouble], [null|exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)})*/ + keys) { + aDouble6 = theMap + /*Dictionary([subclass=JsLinkedHashMap], key: [exact=JSString], value: Union([null|exact=JSDouble], [null|exact=JSExtendableArray]), map: {a: [exact=JSDouble], b: [exact=JSDouble], c: [exact=JSDouble], d: Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)})*/ + [key]; + } + // We have to reference it somewhere, so that it always gets resolved. + consume6(aList6); +} diff --git a/tests/compiler/dart2js/inference/dictionary_types_test.dart b/tests/compiler/dart2js/inference/dictionary_types_test.dart deleted file mode 100644 index 1d934e68483..00000000000 --- a/tests/compiler/dart2js/inference/dictionary_types_test.dart +++ /dev/null @@ -1,173 +0,0 @@ -// 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. - -/// TODO(johnniwinther): Port this test to use the equivalence framework. - -import 'package:async_helper/async_helper.dart'; -import 'package:compiler/src/commandline_options.dart'; -import 'package:expect/expect.dart'; - -import '../memory_compiler.dart'; - -var SOURCES = const { - 'AddAll.dart': """ - var dictionaryA = {'string': "aString", 'int': 42, 'double': 21.5, - 'list': []}; - var dictionaryB = {'string': "aString", 'int': 42, 'double': 21.5, - 'list': []}; - var otherDict = {'stringTwo' : "anotherString", 'intTwo' : 84}; - var int = 0; - var anotherInt = 0; - var nullOrInt = 0; - var dynamic = 0; - - main() { - dictionaryA.addAll(otherDict); - dictionaryB.addAll({'stringTwo' : "anotherString", 'intTwo' : 84}); - int = dictionaryB['int']; - anotherInt = otherDict['intTwo']; - dynamic = dictionaryA['int']; - nullOrInt = dictionaryB['intTwo']; - } -""", - 'Union.dart': """ - var dictionaryA = {'string': "aString", 'int': 42, 'double': 21.5, - 'list': []}; - var dictionaryB = {'string': "aString", 'intTwo': 42, 'list': []}; - var nullOrInt = 0; - var aString = ""; - var doubleOrNull = 22.2; - var key = "string"; - - main() { - var union = dictionaryA['foo'] ? dictionaryA : dictionaryB; - nullOrInt = union['intTwo']; - aString = union['string']; - doubleOrNull = union['double']; - } -""", - 'ValueType.dart': """ - var dictionary = {'string': "aString", 'int': 42, 'double': 21.5, 'list': []}; - var keyD = 'double'; - var keyI = 'int'; - var keyN = 'notFoundInMap'; - var knownDouble = 42.2; - var intOrNull = dictionary[keyI]; - var justNull = dictionary[keyN]; - - main() { - knownDouble = dictionary[keyD]; - var x = [intOrNull, justNull]; - } -""", - 'Propagation.dart': """ - class A { - A(); - foo(value) { - return value['anInt']; - } - } - - class B { - B(); - foo(value) { - return 0; - } - } - - main() { - var dictionary = {'anInt': 42, 'aString': "theString"}; - var it; - if ([true, false][0]) { - it = new A(); - } else { - it = new B(); - } - print(it.foo(dictionary) + 2); - } -""", - 'Bailout.dart': """ - var dict = makeMap([1,2]); - var notInt = 0; - var alsoNotInt = 0; - - makeMap(values) { - return {'moo': values[0], 'boo': values[1]}; - } - - main () { - dict['goo'] = 42; - var closure = () => dict; - notInt = closure()['boo']; - alsoNotInt = dict['goo']; - print("\$notInt and \$alsoNotInt."); - } -""" -}; - -void main() { - asyncTest(() async { - print('--test from ast---------------------------------------------------'); - await runTests(useKernel: false); - print('--test from kernel------------------------------------------------'); - await runTests(useKernel: true); - }); -} - -runTests({bool useKernel}) async { - await compileAndTest("AddAll.dart", (types, getType, closedWorld) { - Expect.equals(getType('int'), types.uint31Type); - Expect.equals(getType('anotherInt'), types.uint31Type); - Expect.equals(getType('dynamic'), types.dynamicType); - Expect.equals(getType('nullOrInt'), types.uint31Type.nullable()); - }, useKernel: useKernel); - await compileAndTest("Union.dart", (types, getType, closedWorld) { - Expect.equals(getType('nullOrInt'), types.uint31Type.nullable()); - Expect.isTrue(getType('aString').containsOnlyString(closedWorld)); - Expect.equals(getType('doubleOrNull'), types.doubleType.nullable()); - }, useKernel: useKernel); - await compileAndTest("ValueType.dart", (types, getType, closedWorld) { - Expect.equals(getType('knownDouble'), types.doubleType); - Expect.equals(getType('intOrNull'), types.uint31Type.nullable()); - Expect.equals(getType('justNull'), types.nullType); - }, useKernel: useKernel); - await compileAndTest("Propagation.dart", (code) { - Expect.isFalse(code.contains("J.\$add\$ns")); - }, createCode: true, useKernel: useKernel); - await compileAndTest("Bailout.dart", (types, getType, closedWorld) { - Expect.equals(getType('notInt'), types.dynamicType); - Expect.equals(getType('alsoNotInt'), types.dynamicType); - Expect.isFalse(getType('dict').isDictionary); - }, useKernel: useKernel); -} - -compileAndTest(source, checker, - {bool createCode: false, bool useKernel}) async { - CompilationResult result = await runCompiler( - entryPoint: Uri.parse('memory:' + source), - memorySourceFiles: SOURCES, - beforeRun: (compiler) { - compiler.stopAfterTypeInference = !createCode; - }, - options: useKernel ? [Flags.useKernel] : []); - var compiler = result.compiler; - var typesInferrer = compiler.globalInference.typesInferrerInternal; - var closedWorld = typesInferrer.closedWorld; - var elementEnvironment = closedWorld.elementEnvironment; - var commonMasks = closedWorld.commonMasks; - getType(String name) { - var element = elementEnvironment.lookupLibraryMember( - elementEnvironment.mainLibrary, name); - Expect.isNotNull(element, "No class '$name' found."); - return typesInferrer.getTypeOfMember(element); - } - - if (!createCode) { - checker(commonMasks, getType, closedWorld); - } else { - var element = elementEnvironment.mainFunction; - var code = compiler.backend.getGeneratedCode(element); - checker(code); - } -} diff --git a/tests/compiler/dart2js/inference/field_type_simple_inferer_test.dart b/tests/compiler/dart2js/inference/field_type_simple_inferer_test.dart deleted file mode 100644 index 6b46ce7e6a0..00000000000 --- a/tests/compiler/dart2js/inference/field_type_simple_inferer_test.dart +++ /dev/null @@ -1,689 +0,0 @@ -// Copyright (c) 2013, 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. - -/// TODO(johnniwinther): Port this test to use the equivalence framework. -/// Currently it only works with the mock compiler. - -import 'package:expect/expect.dart'; -import 'package:async_helper/async_helper.dart'; -import 'package:compiler/src/types/types.dart' show TypeMask; -import 'package:compiler/src/world.dart' show ClosedWorld; - -import 'type_mask_test_helper.dart'; -import '../compiler_helper.dart'; - -void compileAndFind(String code, String className, String memberName, - bool disableInlining, check(compiler, element)) { - Uri uri = new Uri(scheme: 'source'); - var compiler = mockCompilerFor(code, uri, disableInlining: disableInlining); - asyncTest(() => compiler.run(uri).then((_) { - dynamic cls = findElement(compiler, className); - var member = cls.lookupMember(memberName); - check(compiler, member); - })); -} - -const String TEST_1 = r""" - class A { - int f; - } - main() { new A(); } -"""; - -const String TEST_2 = r""" - class A { - int f1; - int f2 = 1; - } - main() { new A(); } -"""; - -const String TEST_3 = r""" - class A { - int f1; - int f2; - A() : f1 = 1; - } - main() { new A().f2 = 2; } -"""; - -const String TEST_4 = r""" - class A { - int f1; - int f2; - A() : f1 = 1; - } - main() { - A a = new A(); - a.f1 = "a"; - a.f2 = "a"; - } -"""; - -const String TEST_5 = r""" - class A { - int f1 = 1; - int f2 = 1; - A(x) { - f1 = "1"; - if (x) { - f2 = "1"; - } else { - f2 = "2"; - } - } - } - main() { - new A(true); - new A(false); - } -"""; - -const String TEST_6 = r""" - class A { - int f1 = 1; - int f2 = 1; - A(x) { - f1 = "1"; - if (x) { - f2 = "1"; - } else { - f2 = "2"; - } - if (x) { - f2 = new List(); - } else { - f2 = new List(); - } - } - } - main() { - new A(true); - new A(false); - } -"""; - -const String TEST_7 = r""" - class A { - int f1 = 1; - int f2 = 1; - A(x) { - f1 = "1"; - if (x) { - f2 = "1"; - } else { - f2 = "2"; - } - if (x) { - f1 = new List(); - f2 = new List(); - } else { - f2 = new List(); - } - } - } - main() { - new A(true); - new A(false); - } -"""; - -const String TEST_8 = r""" - class A { - int f; - A(x) { - if (x) { - f = "1"; - } else { - } - } - } - main() { - new A(true); - new A(false); - } -"""; - -const String TEST_9 = r""" - class A { - int f; - A(x) { - if (x) { - } else { - f = "1"; - } - } - } - main() { - new A(true); - new A(false); - } -"""; - -const String TEST_10 = r""" - class A { - int f; - A() { - f = 1; - } - m() => f + 1; - } - void f(x) { x.f = "2"; } - main() { - A a; - f(a); - a = new A(); - a.m(); - } -"""; - -const String TEST_11 = r""" - class S { - int fs = 1; - ms() { fs = 1; } - } - - class A extends S { - m() { ms(); } - } - - main() { - A a = new A(); - a.m(); - } -"""; - -const String TEST_12 = r""" - class S { - int fs = 1; - S() { fs = "2"; } - } - - class A extends S { - } - - main() { - A a = new A(); - } -"""; - -const String TEST_13 = r""" - class S { - int fs; - S() { fs = 1; } - } - - class A extends S { - A() { fs = 1; } - } - - main() { - A a = new A(); - } -"""; - -const String TEST_14 = r""" - class A { - var f; - A() { f = 1; } - A.other() { f = 2; } - } - - main() { - A a = new A(); - a = new A.other(); - } -"""; - -const String TEST_15 = r""" - class A { - var f; - A() { f = "1"; } - A.other() { f = new List(); } - } - - main() { - A a = new A(); - a = new A.other(); - } -"""; - -const String TEST_16 = r""" - class A { - var f; - A() { f = "1"; } - A.other() : f = 1 { } - } - - main() { - A a = new A(); - a = new A.other(); - } -"""; - -const String TEST_17 = r""" - g([p]) => p.f = 1; - class A { - var f; - A(x) { - var a; - if (x) { - a = this; - } else { - a = g; - } - a(this); - } - } - main() { - new A(true); - new A(false); - } -"""; - -const String TEST_18 = r""" - class A { - var f1; - var f2; - var f3; - A(x) { - f1 = 1; - var a; - if (x) { - f2 = "1"; - a = this; - } else { - a = 1; - f2 = "1"; - } - f3 = a; - } - } - main() { - new A(true); - new A(false); - } -"""; - -const String TEST_19 = r""" - class A { - var f1; - var f2; - var f3; - A(x) { - f1 = 1; - var a; - if (x) { - f2 = "1"; - a = this; - } else { - a = 1; - f2 = "1"; - } - f3 = a; - a(); - } - } - main() { - new A(true); - new A(false); - } -"""; - -const String TEST_20 = r""" - class A { - var f; - A() { - for (f in this) { - } - } - get iterator => this; - get current => 42; - bool moveNext() => false; - } - main() { - new A(); - } -"""; - -const String TEST_21 = r""" - class A { - var f; - A() { - for (var i in this) { - } - f = 42; - } - get iterator => null; - } - main() { - new A(); - } -"""; - -const String TEST_22 = r""" - class A { - var f1; - var f2; - var f3; - A() { - f1 = 42; - f2 = f1 == null ? 42 : f3 == null ? 41: 43; - f3 = 'foo'; - } - } - main() { - new A(); - } -"""; - -const String TEST_23 = r""" - class A { - var f1 = 42; - var f2 = 42; - var f3 = 42; - var f4 = 42; - A() { - // Test string interpolation. - '${f1 = null}'; - // Test string juxtaposition. - '' - '${f2 = null}'; - // Test list literal. - [f3 = null]; - // Test map literal. - var c = {'foo': f4 = null }; - } - } - main() { - new A(); - } -"""; - -const String TEST_24 = r""" - class A { - var f1 = 42; - var f2 = 42; - var f3 = 42; - final f4; - var f5; - var f6 = null; - A() : f4 = 42 { - f1++; - f2 += 42; - var f6 = 'foo'; - this.f6 = f6; - } - A.foo(other) : f3 = other.f3, f4 = other.f4, f5 = other.bar(); - operator+(other) => 'foo'; - bar() => 42.5; - } - class B extends A { - bar() => 42; - } - main() { - new A(); - new A.foo(new A()); - new A.foo(new B()); - - } -"""; - -const String TEST_25 = r""" - class A { - var f1 = 42; - } - class B { - var f1 = '42'; - } - main() { - new B(); - new A().f1 = new A().f1; - } -"""; - -const String TEST_26 = r""" - class A { - var f1 = 42; - } - class B { - var f1 = 54; - } - main() { - new A().f1 = [new B(), new A()][0].f1 + 42; - } -"""; - -const String TEST_27 = r""" - class A { - var f1; - var f2; - A() { - this.f1 = 42; - this.f2 = 42; - } - } - class B extends A { - set f2(value) {} - } - main() { - new A(); - new B(); - } -"""; - -const String TEST_28 = r""" - class A { - var f1; - var f2; - A(x) { - this.f1 = x; - if (x == 0) return; - this.f2 = x; - } - } - main() { - new A(0); - new A(1); - } -"""; - -const String TEST_29 = r""" - class A { - var f1; - var f2; - A(x) { - this.f1 = x; - if (x == 0) { - } else { - return; - } - this.f2 = x; - } - } - main() { - new A(0); - new A(1); - } -"""; - -const String TEST_30 = r""" - class A { - var f1; - var f2; - var f3; - A(x) { - this.f1 = x; - if (x == 0) { - this.f2 = 1; - } else { - this.f2 = x; - return; - } - this.f3 = x; - } - } - main() { - new A(0); - new A(1); - } -"""; - -typedef TypeMask TestCallback(ClosedWorld closedWorld); - -void doTest( - String test, bool disableInlining, Map fields) { - fields.forEach((String name, TestCallback f) { - compileAndFind(test, 'A', name, disableInlining, (compiler, field) { - var inferrer = compiler.globalInference.typesInferrerInternal; - var closedWorld = inferrer.closedWorld; - TypeMask type = f(closedWorld); - TypeMask inferredType = - simplify(inferrer.getTypeOfMember(field), closedWorld); - Expect.equals(type, inferredType, '$name of:\n$test'); - }); - }); -} - -void runTest(String test, Map fields) { - doTest(test, false, fields); - doTest(test, true, fields); -} - -void test() { - runTest(TEST_1, { - 'f': (closedWorld) => closedWorld.commonMasks.nullType - }); - runTest(TEST_2, { - 'f1': (closedWorld) => closedWorld.commonMasks.nullType, - 'f2': (closedWorld) => closedWorld.commonMasks.uint31Type - }); - runTest(TEST_3, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f2': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable() - }); - runTest(TEST_4, { - 'f1': (closedWorld) => closedWorld.commonMasks.interceptorType, - 'f2': (closedWorld) => closedWorld.commonMasks.stringType.nullable() - }); - - // TODO(ngeoffray): We should try to infer that the initialization - // code at the declaration site of the fields does not matter. - runTest(TEST_5, { - 'f1': (closedWorld) => closedWorld.commonMasks.interceptorType, - 'f2': (closedWorld) => closedWorld.commonMasks.interceptorType, - }); - runTest(TEST_6, { - 'f1': (closedWorld) => closedWorld.commonMasks.interceptorType, - 'f2': (closedWorld) => closedWorld.commonMasks.interceptorType, - }); - runTest(TEST_7, { - 'f1': (closedWorld) => closedWorld.commonMasks.interceptorType, - 'f2': (closedWorld) => closedWorld.commonMasks.interceptorType, - }); - - runTest(TEST_8, { - 'f': (closedWorld) => closedWorld.commonMasks.stringType.nullable() - }); - runTest(TEST_9, { - 'f': (closedWorld) => closedWorld.commonMasks.stringType.nullable() - }); - runTest(TEST_10, { - 'f': (closedWorld) => closedWorld.commonMasks.uint31Type - }); - runTest(TEST_11, { - 'fs': (closedWorld) => closedWorld.commonMasks.uint31Type - }); - - // TODO(ngeoffray): We should try to infer that the initialization - // code at the declaration site of the fields does not matter. - runTest(TEST_12, { - 'fs': (closedWorld) => closedWorld.commonMasks.interceptorType - }); - - runTest(TEST_13, { - 'fs': (closedWorld) => closedWorld.commonMasks.uint31Type - }); - runTest(TEST_14, { - 'f': (closedWorld) => closedWorld.commonMasks.uint31Type - }); - runTest(TEST_15, { - 'f': (closedWorld) { - ClassElement cls = closedWorld.commonElements.jsIndexableClass; - return new TypeMask.nonNullSubtype(cls, closedWorld); - } - }); - runTest(TEST_16, { - 'f': (closedWorld) => closedWorld.commonMasks.interceptorType - }); - runTest(TEST_17, { - 'f': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable() - }); - runTest(TEST_18, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f2': (closedWorld) => closedWorld.commonMasks.stringType, - 'f3': (closedWorld) => closedWorld.commonMasks.dynamicType - }); - runTest(TEST_19, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f2': (closedWorld) => closedWorld.commonMasks.stringType, - 'f3': (closedWorld) => closedWorld.commonMasks.dynamicType - }); - runTest(TEST_20, { - 'f': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable() - }); - runTest(TEST_21, { - 'f': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable() - }); - - runTest(TEST_22, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f2': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f3': (closedWorld) => closedWorld.commonMasks.stringType.nullable() - }); - - runTest(TEST_23, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable(), - 'f2': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable(), - 'f3': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable(), - 'f4': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable() - }); - - runTest(TEST_24, { - 'f1': (closedWorld) => closedWorld.commonMasks.positiveIntType, - 'f2': (closedWorld) => closedWorld.commonMasks.positiveIntType, - 'f3': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f4': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f5': (closedWorld) => closedWorld.commonMasks.numType.nullable(), - 'f6': (closedWorld) => closedWorld.commonMasks.stringType.nullable() - }); - - runTest(TEST_25, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type - }); - runTest(TEST_26, { - 'f1': (closedWorld) => closedWorld.commonMasks.positiveIntType - }); - runTest(TEST_27, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f2': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable() - }); - runTest(TEST_28, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f2': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable() - }); - runTest(TEST_29, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f2': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable() - }); - runTest(TEST_30, { - 'f1': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f2': (closedWorld) => closedWorld.commonMasks.uint31Type, - 'f3': (closedWorld) => closedWorld.commonMasks.uint31Type.nullable() - }); -} - -void main() { - test(); -} diff --git a/tests/compiler/dart2js/inference/list_tracer_length_test.dart b/tests/compiler/dart2js/inference/list_tracer_length_test.dart index 5ad35069c7d..d5e8d7262d2 100644 --- a/tests/compiler/dart2js/inference/list_tracer_length_test.dart +++ b/tests/compiler/dart2js/inference/list_tracer_length_test.dart @@ -2,7 +2,8 @@ // 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. -/// TODO(johnniwinther): Currently this only works with the mock compiler. +/// TODO(johnniwinther): Move this to the codegen folder. Currently this only +/// works with the mock compiler. import "package:expect/expect.dart"; import "package:async_helper/async_helper.dart"; diff --git a/tests/compiler/dart2js/inference/list_tracer_node_type_test.dart b/tests/compiler/dart2js/inference/list_tracer_node_type_test.dart index b1d315f31f8..03ae59c093d 100644 --- a/tests/compiler/dart2js/inference/list_tracer_node_type_test.dart +++ b/tests/compiler/dart2js/inference/list_tracer_node_type_test.dart @@ -2,7 +2,8 @@ // 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. -/// TODO(johnniwinther): Currently this only works with the mock compiler. +/// TODO(johnniwinther): Move this to the codegen folder. Currently this only +/// works with the mock compiler. import "package:expect/expect.dart"; import "package:async_helper/async_helper.dart"; diff --git a/tests/compiler/dart2js/inference/list_tracer_test.dart b/tests/compiler/dart2js/inference/list_tracer_test.dart index b9f5e819055..831ead7e197 100644 --- a/tests/compiler/dart2js/inference/list_tracer_test.dart +++ b/tests/compiler/dart2js/inference/list_tracer_test.dart @@ -5,12 +5,13 @@ /// TODO(johnniwinther): Port this test to use the equivalence framework. /// Currently it only works with the mock compiler. -import 'package:expect/expect.dart'; -import "package:async_helper/async_helper.dart"; +import 'package:async_helper/async_helper.dart'; import 'package:compiler/src/types/types.dart' show ContainerTypeMask, TypeMask; +import 'package:compiler/src/commandline_options.dart'; +import 'package:expect/expect.dart'; import 'type_mask_test_helper.dart'; -import '../compiler_helper.dart'; +import '../memory_compiler.dart'; String generateTest(String listAllocation) { return """ @@ -189,58 +190,76 @@ main() { } void main() { - doTest('[]', nullify: false); // Test literal list. - doTest('new List()', nullify: false); // Test growable list. - doTest('new List(1)', nullify: true); // Test fixed list. - doTest('new List.filled(1, 0)', nullify: false); // Test List.filled. - doTest('new List.filled(1, null)', nullify: true); // Test List.filled. + runTest({bool useKernel}) async { + // Test literal list. + await doTest('[]', nullify: false, useKernel: useKernel); + // Test growable list. + await doTest('new List()', nullify: false, useKernel: useKernel); + // Test fixed list. + await doTest('new List(1)', nullify: true, useKernel: useKernel); + // Test List.filled. + await doTest('new List.filled(1, 0)', nullify: false, useKernel: useKernel); + // Test List.filled. + await doTest('new List.filled(1, null)', + nullify: true, useKernel: useKernel); + } + + asyncTest(() async { + print('--test from ast---------------------------------------------------'); + await runTest(useKernel: false); + print('--test from kernel------------------------------------------------'); + await runTest(useKernel: true); + }); } -void doTest(String allocation, {bool nullify}) { - Uri uri = new Uri(scheme: 'source'); - var compiler = mockCompilerFor(generateTest(allocation), uri, - expectedErrors: 0, expectedWarnings: 1); - asyncTest(() => compiler.run(uri).then((_) { - var typesInferrer = compiler.globalInference.typesInferrerInternal; - var closedWorld = typesInferrer.closedWorld; - var commonMasks = closedWorld.commonMasks; +doTest(String allocation, {bool nullify, bool useKernel}) async { + String source = generateTest(allocation); + var result = await runCompiler( + memorySourceFiles: {'main.dart': source}, + options: useKernel ? [Flags.useKernel] : []); + Expect.isTrue(result.isSuccess); + var compiler = result.compiler; + var typesInferrer = compiler.globalInference.typesInferrerInternal; + var closedWorld = typesInferrer.closedWorld; + var commonMasks = closedWorld.commonMasks; - checkType(String name, type) { - MemberElement element = findElement(compiler, name); - ContainerTypeMask mask = typesInferrer.getTypeOfMember(element); - if (nullify) type = type.nullable(); - Expect.equals(type, simplify(mask.elementType, closedWorld), name); - } + checkType(String name, type) { + var element = findMember(closedWorld, name); + ContainerTypeMask mask = typesInferrer.getTypeOfMember(element); + if (nullify) type = type.nullable(); + Expect.equals(type, simplify(mask.elementType, closedWorld), name); + } - checkType('listInField', commonMasks.numType); - checkType('listPassedToMethod', commonMasks.numType); - checkType('listReturnedFromMethod', commonMasks.numType); - checkType('listUsedWithCascade', commonMasks.numType); - checkType('listUsedInClosure', commonMasks.numType); - checkType('listPassedToSelector', commonMasks.numType); - checkType('listReturnedFromSelector', commonMasks.numType); - checkType('listUsedWithAddAndInsert', commonMasks.numType); - checkType('listUsedWithConstraint', commonMasks.positiveIntType); - checkType('listEscapingFromSetter', commonMasks.numType); - checkType('listUsedInLocal', commonMasks.numType); - checkType('listEscapingInSetterValue', commonMasks.numType); - checkType('listEscapingInIndex', commonMasks.numType); - checkType('listEscapingInIndexSet', commonMasks.uint31Type); - checkType('listEscapingTwiceInIndexSet', commonMasks.numType); - checkType('listSetInNonFinalField', commonMasks.numType); - checkType('listWithChangedLength', commonMasks.uint31Type.nullable()); + checkType('listInField', commonMasks.numType); + checkType('listPassedToMethod', commonMasks.numType); + checkType('listReturnedFromMethod', commonMasks.numType); + checkType('listUsedWithCascade', commonMasks.numType); + checkType('listUsedInClosure', commonMasks.numType); + checkType('listPassedToSelector', commonMasks.numType); + checkType('listReturnedFromSelector', commonMasks.numType); + checkType('listUsedWithAddAndInsert', commonMasks.numType); + checkType('listUsedWithConstraint', commonMasks.positiveIntType); + checkType('listEscapingFromSetter', commonMasks.numType); + checkType('listUsedInLocal', commonMasks.numType); + checkType('listEscapingInSetterValue', commonMasks.numType); + checkType('listEscapingInIndex', commonMasks.numType); + checkType('listEscapingInIndexSet', commonMasks.uint31Type); + // TODO(johnniwinther): Since Iterable.iterableToString is part of the closed + // world we find the `dynamicType` instead of `numType`. + checkType('listEscapingTwiceInIndexSet', commonMasks.dynamicType); + checkType('listSetInNonFinalField', commonMasks.numType); + checkType('listWithChangedLength', commonMasks.uint31Type.nullable()); - checkType('listPassedToClosure', commonMasks.dynamicType); - checkType('listReturnedFromClosure', commonMasks.dynamicType); - checkType('listUsedWithNonOkSelector', commonMasks.dynamicType); - checkType('listPassedAsOptionalParameter', commonMasks.numType); - checkType('listPassedAsNamedParameter', commonMasks.numType); - checkType('listStoredInList', commonMasks.uint31Type); - checkType('listStoredInListButEscapes', commonMasks.dynamicType); + checkType('listPassedToClosure', commonMasks.dynamicType); + checkType('listReturnedFromClosure', commonMasks.dynamicType); + checkType('listUsedWithNonOkSelector', commonMasks.dynamicType); + checkType('listPassedAsOptionalParameter', commonMasks.numType); + checkType('listPassedAsNamedParameter', commonMasks.numType); + checkType('listStoredInList', commonMasks.uint31Type); + checkType('listStoredInListButEscapes', commonMasks.dynamicType); - if (!allocation.contains('filled')) { - checkType('listUnset', new TypeMask.nonNullEmpty()); - checkType('listOnlySetWithConstraint', new TypeMask.nonNullEmpty()); - } - })); + if (!allocation.contains('filled')) { + checkType('listUnset', new TypeMask.nonNullEmpty()); + checkType('listOnlySetWithConstraint', new TypeMask.nonNullEmpty()); + } } diff --git a/tests/compiler/dart2js/inference/map_tracer_keys_test.dart b/tests/compiler/dart2js/inference/map_tracer_keys_test.dart deleted file mode 100644 index e9687334241..00000000000 --- a/tests/compiler/dart2js/inference/map_tracer_keys_test.dart +++ /dev/null @@ -1,80 +0,0 @@ -// 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. - -/// TODO(johnniwinther): Port this test to use the equivalence framework. -/// Currently it only works with the mock compiler. - -import 'package:expect/expect.dart'; -import "package:async_helper/async_helper.dart"; -import 'package:compiler/src/types/types.dart' show ContainerTypeMask, TypeMask; - -import '../compiler_helper.dart'; - -String generateTest(String key, String value, bool initial) { - return """ -double aDouble = 42.5; -List aList = [42]; - -consume(x) => x; - -main() { -""" + - (initial - ? """ - var theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4, $key: $value}; -""" - : """ - var theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4}; - theMap[$key] = $value; -""") + - """ - for (var key in theMap.keys) { - aDouble = theMap[key]; - } - // We have to reference it somewhere, so that it always gets resolved. - consume(aList); -} -"""; -} - -void main() { - // Test using keys without the list floating in - doTest(); - // Test using keys with the list floating in as key - doTest(key: "aList", bail: true); - // Test using keys with the list floating in as value - doTest(value: "aList"); - // And the above where we add the list as part of the map literal. - doTest(initial: true); - doTest(key: "aList", bail: true, initial: true); - doTest(value: "aList", initial: true); -} - -void doTest( - {String key: "'d'", - String value: "5.5", - bool bail: false, - bool initial: false}) { - Uri uri = new Uri(scheme: 'source'); - var compiler = mockCompilerFor(generateTest(key, value, initial), uri, - expectedErrors: 0, expectedWarnings: 0); - asyncTest(() => compiler.run(uri).then((_) { - var typesInferrer = compiler.globalInference.typesInferrerInternal; - var commonMasks = typesInferrer.closedWorld.commonMasks; - MemberElement aDouble = findElement(compiler, 'aDouble'); - var aDoubleType = typesInferrer.getTypeOfMember(aDouble); - MemberElement aList = findElement(compiler, 'aList'); - var aListType = typesInferrer.getTypeOfMember(aList); - - Expect.equals(aDoubleType, commonMasks.doubleType); - Expect.isTrue(aListType is ContainerTypeMask); - ContainerTypeMask container = aListType; - TypeMask elementType = container.elementType; - if (bail) { - Expect.equals(elementType, commonMasks.dynamicType); - } else { - Expect.equals(elementType, commonMasks.uint31Type); - } - })); -} diff --git a/tests/compiler/dart2js/inference/map_tracer_test.dart b/tests/compiler/dart2js/inference/map_tracer_test.dart index ddac6fd2a48..8e8309e56ff 100644 --- a/tests/compiler/dart2js/inference/map_tracer_test.dart +++ b/tests/compiler/dart2js/inference/map_tracer_test.dart @@ -5,12 +5,17 @@ /// TODO(johnniwinther): Port this test to use the equivalence framework. /// Currently it only works with the mock compiler. -import 'package:expect/expect.dart'; -import "package:async_helper/async_helper.dart"; +import 'package:async_helper/async_helper.dart'; +import 'package:compiler/src/commandline_options.dart'; +import 'package:compiler/src/compiler.dart'; +import 'package:compiler/src/elements/entities.dart'; +import 'package:compiler/src/inferrer/type_graph_inferrer.dart'; import 'package:compiler/src/types/types.dart' show MapTypeMask, TypeMask; +import 'package:compiler/src/world.dart'; +import 'package:expect/expect.dart'; import 'type_mask_test_helper.dart'; -import '../compiler_helper.dart'; +import '../memory_compiler.dart'; String generateTest(String mapAllocation) { return """ @@ -119,6 +124,8 @@ takeNamed({map}) { } main() { + anInt++; + mapReturnedFromMethod[aKey] = anInt; bar()[aKey] = aDouble; @@ -202,90 +209,103 @@ main() { } void main() { - // Test empty literal map - doTest('{}'); - // Test preset map of - doTest('{presetKey : anInt}', "presetKey", "anInt"); - // Test preset map of - doTest('{aDouble : anInt}', "aDouble", "anInt"); + runTests({bool useKernel}) async { + // Test empty literal map + await doTest('{}', useKernel: useKernel); + // Test preset map of + await doTest('{presetKey : anInt}', + keyElementName: "presetKey", + valueElementName: "anInt", + useKernel: useKernel); + // Test preset map of + await doTest('{aDouble : anInt}', + keyElementName: "aDouble", + valueElementName: "anInt", + useKernel: useKernel); + } + + asyncTest(() async { + print('--test from ast---------------------------------------------------'); + await runTests(useKernel: false); + print('--test from kernel------------------------------------------------'); + await runTests(useKernel: true); + }); } -void doTest(String allocation, - [String keyElementName, String valueElementName]) { - Uri uri = new Uri(scheme: 'source'); - var compiler = mockCompilerFor(generateTest(allocation), uri, - expectedErrors: 0, expectedWarnings: 1); - asyncTest(() => compiler.run(uri).then((_) { - var keyType, valueType; - var typesInferrer = compiler.globalInference.typesInferrerInternal; - var closedWorld = typesInferrer.closedWorld; - var commonMasks = closedWorld.commonMasks; - var emptyType = new TypeMask.nonNullEmpty(); - MemberElement aKey = findElement(compiler, 'aKey'); - var aKeyType = typesInferrer.getTypeOfMember(aKey); - if (keyElementName != null) { - MemberElement keyElement = findElement(compiler, keyElementName); - keyType = typesInferrer.getTypeOfMember(keyElement); - } - if (valueElementName != null) { - MemberElement valueElement = findElement(compiler, valueElementName); - valueType = typesInferrer.getTypeOfMember(valueElement); - } - if (keyType == null) keyType = emptyType; - if (valueType == null) valueType = emptyType; +doTest(String allocation, + {String keyElementName, String valueElementName, bool useKernel}) async { + String source = generateTest(allocation); + var result = await runCompiler( + memorySourceFiles: {'main.dart': source}, + options: useKernel ? [Flags.useKernel] : []); + Expect.isTrue(result.isSuccess); + Compiler compiler = result.compiler; + TypeMask keyType, valueType; + TypeGraphInferrer typesInferrer = + compiler.globalInference.typesInferrerInternal; + ClosedWorld closedWorld = typesInferrer.closedWorld; + CommonMasks commonMasks = closedWorld.commonMasks; + TypeMask emptyType = new TypeMask.nonNullEmpty(); + MemberEntity aKey = findMember(closedWorld, 'aKey'); + TypeMask aKeyType = typesInferrer.getTypeOfMember(aKey); + if (keyElementName != null) { + MemberEntity keyElement = findMember(closedWorld, keyElementName); + keyType = typesInferrer.getTypeOfMember(keyElement); + } + if (valueElementName != null) { + MemberEntity valueElement = findMember(closedWorld, valueElementName); + valueType = typesInferrer.getTypeOfMember(valueElement); + } + if (keyType == null) keyType = emptyType; + if (valueType == null) valueType = emptyType; - checkType(String name, keyType, valueType) { - MemberElement element = findElement(compiler, name); - MapTypeMask mask = typesInferrer.getTypeOfMember(element); - Expect.equals(keyType, simplify(mask.keyType, closedWorld), name); - Expect.equals(valueType, simplify(mask.valueType, closedWorld), name); - } + checkType(String name, keyType, valueType) { + MemberEntity element = findMember(closedWorld, name); + MapTypeMask mask = typesInferrer.getTypeOfMember(element); + Expect.equals(keyType, simplify(mask.keyType, closedWorld), name); + Expect.equals(valueType, simplify(mask.valueType, closedWorld), name); + } - K(TypeMask other) => - simplify(keyType.union(other, closedWorld), closedWorld); - V(TypeMask other) => - simplify(valueType.union(other, closedWorld), closedWorld) - .nullable(); + K(TypeMask other) => simplify(keyType.union(other, closedWorld), closedWorld); + V(TypeMask other) => + simplify(valueType.union(other, closedWorld), closedWorld).nullable(); - checkType('mapInField', K(aKeyType), V(commonMasks.numType)); - checkType('mapPassedToMethod', K(aKeyType), V(commonMasks.numType)); - checkType('mapReturnedFromMethod', K(aKeyType), V(commonMasks.numType)); - checkType('mapUsedWithCascade', K(aKeyType), V(commonMasks.numType)); - checkType('mapUsedInClosure', K(aKeyType), V(commonMasks.numType)); - checkType('mapPassedToSelector', K(aKeyType), V(commonMasks.numType)); - checkType( - 'mapReturnedFromSelector', K(aKeyType), V(commonMasks.numType)); - checkType( - 'mapUsedWithConstraint', K(aKeyType), V(commonMasks.uint31Type)); - checkType('mapEscapingFromSetter', K(aKeyType), V(commonMasks.numType)); - checkType('mapUsedInLocal', K(aKeyType), V(commonMasks.numType)); - checkType( - 'mapEscapingInSetterValue', K(aKeyType), V(commonMasks.numType)); - checkType('mapEscapingInIndex', K(aKeyType), V(commonMasks.numType)); - checkType( - 'mapEscapingInIndexSet', K(aKeyType), V(commonMasks.uint31Type)); - checkType( - 'mapEscapingTwiceInIndexSet', K(aKeyType), V(commonMasks.numType)); - checkType('mapSetInNonFinalField', K(aKeyType), V(commonMasks.numType)); + checkType('mapInField', K(aKeyType), V(commonMasks.numType)); + checkType('mapPassedToMethod', K(aKeyType), V(commonMasks.numType)); + checkType('mapReturnedFromMethod', K(aKeyType), V(commonMasks.numType)); + checkType('mapUsedWithCascade', K(aKeyType), V(commonMasks.numType)); + checkType('mapUsedInClosure', K(aKeyType), V(commonMasks.numType)); + checkType('mapPassedToSelector', K(aKeyType), V(commonMasks.numType)); + checkType('mapReturnedFromSelector', K(aKeyType), V(commonMasks.numType)); + checkType( + 'mapUsedWithConstraint', K(aKeyType), V(commonMasks.positiveIntType)); + checkType('mapEscapingFromSetter', K(aKeyType), V(commonMasks.numType)); + checkType('mapUsedInLocal', K(aKeyType), V(commonMasks.numType)); + checkType('mapEscapingInSetterValue', K(aKeyType), V(commonMasks.numType)); + checkType('mapEscapingInIndex', K(aKeyType), V(commonMasks.numType)); + checkType( + 'mapEscapingInIndexSet', K(aKeyType), V(commonMasks.positiveIntType)); + // TODO(johnniwinther): Reenable this when we don't bail out due to + // (benign) JS calls. + //checkType('mapEscapingTwiceInIndexSet', K(aKeyType), V(commonMasks.numType)); + checkType('mapSetInNonFinalField', K(aKeyType), V(commonMasks.numType)); - checkType('mapPassedToClosure', K(commonMasks.dynamicType), - V(commonMasks.dynamicType)); - checkType('mapReturnedFromClosure', K(commonMasks.dynamicType), - V(commonMasks.dynamicType)); - checkType('mapUsedWithNonOkSelector', K(commonMasks.dynamicType), - V(commonMasks.dynamicType)); - checkType('mapPassedAsOptionalParameter', K(aKeyType), - V(commonMasks.numType)); - checkType( - 'mapPassedAsNamedParameter', K(aKeyType), V(commonMasks.numType)); - checkType('mapStoredInList', K(aKeyType), V(commonMasks.uint31Type)); - checkType('mapStoredInListButEscapes', K(commonMasks.dynamicType), - V(commonMasks.dynamicType)); - checkType('mapStoredInMap', K(aKeyType), V(commonMasks.uint31Type)); - checkType('mapStoredInMapButEscapes', K(commonMasks.dynamicType), - V(commonMasks.dynamicType)); + checkType('mapPassedToClosure', K(commonMasks.dynamicType), + V(commonMasks.dynamicType)); + checkType('mapReturnedFromClosure', K(commonMasks.dynamicType), + V(commonMasks.dynamicType)); + checkType('mapUsedWithNonOkSelector', K(commonMasks.dynamicType), + V(commonMasks.dynamicType)); + checkType( + 'mapPassedAsOptionalParameter', K(aKeyType), V(commonMasks.numType)); + checkType('mapPassedAsNamedParameter', K(aKeyType), V(commonMasks.numType)); + checkType('mapStoredInList', K(aKeyType), V(commonMasks.uint31Type)); + checkType('mapStoredInListButEscapes', K(commonMasks.dynamicType), + V(commonMasks.dynamicType)); + checkType('mapStoredInMap', K(aKeyType), V(commonMasks.uint31Type)); + checkType('mapStoredInMapButEscapes', K(commonMasks.dynamicType), + V(commonMasks.dynamicType)); - checkType('mapUnset', K(emptyType), V(emptyType)); - checkType('mapOnlySetWithConstraint', K(aKeyType), V(emptyType)); - })); + checkType('mapUnset', K(emptyType), V(emptyType)); + checkType('mapOnlySetWithConstraint', K(aKeyType), V(emptyType)); } diff --git a/tests/compiler/dart2js/inference/show.dart b/tests/compiler/dart2js/inference/show.dart index 6870b5fc78d..3d7c465afb2 100644 --- a/tests/compiler/dart2js/inference/show.dart +++ b/tests/compiler/dart2js/inference/show.dart @@ -4,9 +4,35 @@ /// Helper program that shows the inferrer data on a dart program. +import 'package:args/args.dart'; +import 'package:compiler/src/inferrer/inferrer_engine.dart'; +import '../equivalence/id_equivalence_helper.dart'; import '../equivalence/show_helper.dart'; import 'inference_test_helper.dart'; +import 'side_effects_test.dart'; +import 'callers_test.dart'; main(List args) async { - await show(args, computeMemberAstTypeMasks, computeMemberIrTypeMasks); + ArgParser argParser = createArgParser(); + argParser.addFlag('inference', defaultsTo: true); + argParser.addFlag('side-effects', defaultsTo: false); + argParser.addFlag('callers', defaultsTo: false); + ArgResults results = argParser.parse(args); + + ComputeMemberDataFunction astFunction; + ComputeMemberDataFunction kernelFunction; + if (results['side-effects']) { + astFunction = computeMemberAstSideEffects; + kernelFunction = computeMemberIrSideEffects; + } + if (results['callers']) { + InferrerEngineImpl.retainDataForTesting = true; + astFunction = computeMemberAstCallers; + kernelFunction = computeMemberIrCallers; + } else { + InferrerEngineImpl.useSorterForTesting = true; + astFunction = computeMemberAstTypeMasks; + kernelFunction = computeMemberIrTypeMasks; + } + await show(results, astFunction, kernelFunction); } diff --git a/tests/compiler/dart2js/inference/simple_inferrer_callers_test.dart b/tests/compiler/dart2js/inference/simple_inferrer_callers_test.dart deleted file mode 100644 index 91fd91806fb..00000000000 --- a/tests/compiler/dart2js/inference/simple_inferrer_callers_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2013, 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. - -/// TODO(johnniwinther): Port this test to use the equivalence framework. - -// Test that computation of callers of an element works when two -// elements of the same name are being invoked in the same method. - -import 'package:async_helper/async_helper.dart'; -import 'package:expect/expect.dart'; -import 'package:compiler/src/common_elements.dart'; -import 'package:compiler/src/inferrer/type_graph_inferrer.dart'; -import 'package:compiler/src/world.dart' show ClosedWorld, ClosedWorldRefiner; - -import '../compiler_helper.dart'; - -const String TEST = """ -class A { - var field; -} - -class B { - var field; -} - -main() { - new A().field; - new B().field; -} -"""; - -// Create our own type inferrer to avoid clearing out the internal -// data structures. -class MyInferrer extends AstTypeGraphInferrer { - MyInferrer(compiler, closedWorld, closedWorldRefiner) - : super(compiler, closedWorld, closedWorldRefiner); - clear() {} -} - -void main() { - Uri uri = new Uri(scheme: 'source'); - var compiler = mockCompilerFor(TEST, uri, analyzeOnly: true); - asyncTest(() => compiler.run(uri).then((_) { - ElementEnvironment elementEnvironment = - compiler.frontendStrategy.elementEnvironment; - ClosedWorldRefiner closedWorldRefiner = - compiler.closeResolution(elementEnvironment.mainFunction); - ClosedWorld closedWorld = - compiler.resolutionWorldBuilder.closedWorldForTesting; - var inferrer = - new MyInferrer(compiler, closedWorld, closedWorldRefiner); - compiler.globalInference.typesInferrerInternal = inferrer; - compiler.globalInference.runGlobalTypeInference( - closedWorld.elementEnvironment.mainFunction, - closedWorld, - closedWorldRefiner); - var mainElement = findElement(compiler, 'main'); - dynamic classA = findElement(compiler, 'A'); - var fieldA = classA.lookupLocalMember('field'); - dynamic classB = findElement(compiler, 'B'); - var fieldB = classB.lookupLocalMember('field'); - - Expect.isTrue(inferrer.getCallersOf(fieldA).contains(mainElement)); - Expect.isTrue(inferrer.getCallersOf(fieldB).contains(mainElement)); - })); -} diff --git a/tests/compiler/dart2js/inlining/inlining_viewer.dart b/tests/compiler/dart2js/inlining/inlining_viewer.dart index ed25d9341e2..9ec07390c89 100644 --- a/tests/compiler/dart2js/inlining/inlining_viewer.dart +++ b/tests/compiler/dart2js/inlining/inlining_viewer.dart @@ -10,5 +10,6 @@ import 'inlining_test.dart'; main(List args) async { JavaScriptBackend.cacheCodegenImpactForTesting = true; - await show(args, computeMemberAstInlinings, computeMemberIrInlinings); + await show(createArgParser().parse(args), computeMemberAstInlinings, + computeMemberIrInlinings); }