From ad4d43cf5bd1d24b6e4e257dd582acf6b0987735 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Wed, 8 Jul 2020 07:17:40 +0000 Subject: [PATCH] [CFE] Constant transformation for expression compilation Fixes https://github.com/dart-lang/sdk/issues/42240 Change-Id: Idc75e99aed6acbb67755c77faa1904183a630f91 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153355 Commit-Queue: Jens Johansen Reviewed-by: Johnni Winther --- .../src/fasta/kernel/constant_evaluator.dart | 26 ++++++++ .../lib/src/fasta/kernel/kernel_target.dart | 64 +++++++++++++------ .../test/fasta/expression_suite.dart | 4 +- .../expression/const_usage.expression.yaml | 9 +++ .../const_usage.expression.yaml.expect | 8 +++ .../const_usage_class.expression.yaml | 9 +++ .../const_usage_class.expression.yaml.expect | 8 +++ .../lib_ctor.expression.yaml.expect | 6 +- pkg/front_end/testcases/expression/main.dart | 8 +++ .../test/src/expression_compiler_test.dart | 2 +- 10 files changed, 120 insertions(+), 24 deletions(-) create mode 100644 pkg/front_end/testcases/expression/const_usage.expression.yaml create mode 100644 pkg/front_end/testcases/expression/const_usage.expression.yaml.expect create mode 100644 pkg/front_end/testcases/expression/const_usage_class.expression.yaml create mode 100644 pkg/front_end/testcases/expression/const_usage_class.expression.yaml.expect diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart index e39ecdb20a2d..1d453d91ba1b 100644 --- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart +++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart @@ -127,6 +127,32 @@ void transformLibraries( } } +void transformProcedure( + Procedure procedure, + ConstantsBackend backend, + Map environmentDefines, + TypeEnvironment typeEnvironment, + ErrorReporter errorReporter, + EvaluationMode evaluationMode, + {bool keepFields: true, + bool evaluateAnnotations: true, + bool desugarSets: false, + bool enableTripleShift: false, + bool errorOnUnevaluatedConstant: false}) { + final ConstantsTransformer constantsTransformer = new ConstantsTransformer( + backend, + environmentDefines, + keepFields, + evaluateAnnotations, + desugarSets, + enableTripleShift, + errorOnUnevaluatedConstant, + typeEnvironment, + errorReporter, + evaluationMode); + constantsTransformer.visitProcedure(procedure); +} + enum EvaluationMode { weak, agnostic, diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart index d3e1c96caeb5..bf490f58da61 100644 --- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart @@ -122,7 +122,7 @@ import '../target_implementation.dart' show TargetImplementation; import '../uri_translator.dart' show UriTranslator; import 'constant_evaluator.dart' as constants - show EvaluationMode, transformLibraries; + show EvaluationMode, transformLibraries, transformProcedure; import 'kernel_constants.dart' show KernelConstantErrorReporter; @@ -1092,26 +1092,7 @@ class KernelTarget extends TargetImplementation { TypeEnvironment environment = new TypeEnvironment(loader.coreTypes, loader.hierarchy); - constants.EvaluationMode evaluationMode; - // If nnbd is not enabled we will use weak evaluation mode. This is needed - // because the SDK might be agnostic and therefore needs to be weakened - // for legacy mode. - assert( - isExperimentEnabledGlobally(ExperimentalFlag.nonNullable) || - loader.nnbdMode == NnbdMode.Weak, - "Non-weak nnbd mode found without experiment enabled: " - "${loader.nnbdMode}."); - switch (loader.nnbdMode) { - case NnbdMode.Weak: - evaluationMode = constants.EvaluationMode.weak; - break; - case NnbdMode.Strong: - evaluationMode = constants.EvaluationMode.strong; - break; - case NnbdMode.Agnostic: - evaluationMode = constants.EvaluationMode.agnostic; - break; - } + constants.EvaluationMode evaluationMode = _getConstantEvaluationMode(); constants.transformLibraries( loader.libraries, @@ -1141,11 +1122,52 @@ class KernelTarget extends TargetImplementation { ChangedStructureNotifier get changedStructureNotifier => null; void runProcedureTransformations(Procedure procedure) { + TypeEnvironment environment = + new TypeEnvironment(loader.coreTypes, loader.hierarchy); + constants.EvaluationMode evaluationMode = _getConstantEvaluationMode(); + + constants.transformProcedure( + procedure, + backendTarget.constantsBackend(loader.coreTypes), + environmentDefines, + environment, + new KernelConstantErrorReporter(loader), + evaluationMode, + desugarSets: !backendTarget.supportsSetLiterals, + enableTripleShift: + isExperimentEnabledGlobally(ExperimentalFlag.tripleShift), + errorOnUnevaluatedConstant: errorOnUnevaluatedConstant); + ticker.logMs("Evaluated constants"); + backendTarget.performTransformationsOnProcedure( loader.coreTypes, loader.hierarchy, procedure, logger: (String msg) => ticker.logMs(msg)); } + constants.EvaluationMode _getConstantEvaluationMode() { + constants.EvaluationMode evaluationMode; + // If nnbd is not enabled we will use weak evaluation mode. This is needed + // because the SDK might be agnostic and therefore needs to be weakened + // for legacy mode. + assert( + isExperimentEnabledGlobally(ExperimentalFlag.nonNullable) || + loader.nnbdMode == NnbdMode.Weak, + "Non-weak nnbd mode found without experiment enabled: " + "${loader.nnbdMode}."); + switch (loader.nnbdMode) { + case NnbdMode.Weak: + evaluationMode = constants.EvaluationMode.weak; + break; + case NnbdMode.Strong: + evaluationMode = constants.EvaluationMode.strong; + break; + case NnbdMode.Agnostic: + evaluationMode = constants.EvaluationMode.agnostic; + break; + } + return evaluationMode; + } + void verify() { // TODO(ahe): How to handle errors. verifyComponent(component); diff --git a/pkg/front_end/test/fasta/expression_suite.dart b/pkg/front_end/test/fasta/expression_suite.dart index 7ca9e566001a..03865e8afdce 100644 --- a/pkg/front_end/test/fasta/expression_suite.dart +++ b/pkg/front_end/test/fasta/expression_suite.dart @@ -113,7 +113,9 @@ class CompilationResult { if (compiledProcedure == null) { buffer.write(""); } else { - new Printer(buffer).visitProcedure(compiledProcedure); + Printer printer = new Printer(buffer); + printer.visitProcedure(compiledProcedure); + printer.writeConstantTable(new Component()); } Uri base = entryPoint.resolve("."); return "$buffer".replaceAll("$base", "org-dartlang-testcase:///"); diff --git a/pkg/front_end/testcases/expression/const_usage.expression.yaml b/pkg/front_end/testcases/expression/const_usage.expression.yaml new file mode 100644 index 000000000000..b017b2604fdd --- /dev/null +++ b/pkg/front_end/testcases/expression/const_usage.expression.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2020, 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. + +entry_point: "main.dart" +definitions: [] +position: "main.dart" +expression: | + const42.x diff --git a/pkg/front_end/testcases/expression/const_usage.expression.yaml.expect b/pkg/front_end/testcases/expression/const_usage.expression.yaml.expect new file mode 100644 index 000000000000..1d2b89084e7e --- /dev/null +++ b/pkg/front_end/testcases/expression/const_usage.expression.yaml.expect @@ -0,0 +1,8 @@ +Errors: { +} +method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr() → dynamic + return (#C2).{main::ConstClass::x}; +constants { + #C1 = 42 + #C2 = main::ConstClass {x:#C1} +} diff --git a/pkg/front_end/testcases/expression/const_usage_class.expression.yaml b/pkg/front_end/testcases/expression/const_usage_class.expression.yaml new file mode 100644 index 000000000000..9425ebba6ec9 --- /dev/null +++ b/pkg/front_end/testcases/expression/const_usage_class.expression.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2020, 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. + +entry_point: "main.dart" +definitions: [] +position: "main.dart#ConstClass" +expression: | + classConst42.x diff --git a/pkg/front_end/testcases/expression/const_usage_class.expression.yaml.expect b/pkg/front_end/testcases/expression/const_usage_class.expression.yaml.expect new file mode 100644 index 000000000000..1d2b89084e7e --- /dev/null +++ b/pkg/front_end/testcases/expression/const_usage_class.expression.yaml.expect @@ -0,0 +1,8 @@ +Errors: { +} +method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr() → dynamic + return (#C2).{main::ConstClass::x}; +constants { + #C1 = 42 + #C2 = main::ConstClass {x:#C1} +} diff --git a/pkg/front_end/testcases/expression/lib_ctor.expression.yaml.expect b/pkg/front_end/testcases/expression/lib_ctor.expression.yaml.expect index dc61171cddd0..45805ec0ef26 100644 --- a/pkg/front_end/testcases/expression/lib_ctor.expression.yaml.expect +++ b/pkg/front_end/testcases/expression/lib_ctor.expression.yaml.expect @@ -3,5 +3,9 @@ Errors: { method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr() → dynamic return () → dart.core::Null? { new main::A::•(); - const main::A::•(); + #C2; }; +constants { + #C1 = 0 + #C2 = main::A {_priv:#C1} +} diff --git a/pkg/front_end/testcases/expression/main.dart b/pkg/front_end/testcases/expression/main.dart index bdf80a96bd86..e38cbea4c205 100644 --- a/pkg/front_end/testcases/expression/main.dart +++ b/pkg/front_end/testcases/expression/main.dart @@ -14,6 +14,14 @@ int _privateToplevel(int x) => x + 1; int globalVar = 6; int _globalPrivate = 7; +const ConstClass const42 = ConstClass(42); + +class ConstClass { + static const ConstClass classConst42 = ConstClass(42); + final int x; + const ConstClass(this.x); +} + class A { const A(); static int doit(int x) => x + 1; diff --git a/pkg/frontend_server/test/src/expression_compiler_test.dart b/pkg/frontend_server/test/src/expression_compiler_test.dart index 52b309c9fd57..d758b2391f63 100644 --- a/pkg/frontend_server/test/src/expression_compiler_test.dart +++ b/pkg/frontend_server/test/src/expression_compiler_test.dart @@ -1164,7 +1164,7 @@ int main() { expression: 'const MyClass(1)', expectedResult: ''' (function(p) { - return dart.const(new foo.MyClass.new(1)); + return C0 || CT.C0; }( 1 ))