[cfe] Add support for keeping const locals during constant evaluation

With this CL backends can opt in to retain constant local variables
in the AST that would otherwise have been removed through inlining.

Change-Id: I377a8679c89fe012d2ec4c7e087274a8052979ba
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153965
Reviewed-by: Anna Gringauze <annagrin@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2020-07-14 12:17:39 +00:00 committed by commit-bot@chromium.org
parent 76a4ae2931
commit e637f7054e
4 changed files with 49 additions and 21 deletions

View file

@ -76,13 +76,16 @@ Component transformComponent(
Map<String, String> environmentDefines,
ErrorReporter errorReporter,
EvaluationMode evaluationMode,
{bool keepFields: true,
bool evaluateAnnotations: true,
bool desugarSets: false,
bool enableTripleShift: false,
bool errorOnUnevaluatedConstant: false,
{bool evaluateAnnotations,
bool desugarSets,
bool enableTripleShift,
bool errorOnUnevaluatedConstant,
CoreTypes coreTypes,
ClassHierarchy hierarchy}) {
assert(evaluateAnnotations != null);
assert(desugarSets != null);
assert(enableTripleShift != null);
assert(errorOnUnevaluatedConstant != null);
coreTypes ??= new CoreTypes(component);
hierarchy ??= new ClassHierarchy(component, coreTypes);
@ -91,7 +94,6 @@ Component transformComponent(
transformLibraries(component.libraries, backend, environmentDefines,
typeEnvironment, errorReporter, evaluationMode,
keepFields: keepFields,
desugarSets: desugarSets,
enableTripleShift: enableTripleShift,
errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
@ -106,15 +108,17 @@ void transformLibraries(
TypeEnvironment typeEnvironment,
ErrorReporter errorReporter,
EvaluationMode evaluationMode,
{bool keepFields: true,
bool evaluateAnnotations: true,
bool desugarSets: false,
bool enableTripleShift: false,
bool errorOnUnevaluatedConstant: false}) {
{bool evaluateAnnotations,
bool desugarSets,
bool enableTripleShift,
bool errorOnUnevaluatedConstant}) {
assert(evaluateAnnotations != null);
assert(desugarSets != null);
assert(enableTripleShift != null);
assert(errorOnUnevaluatedConstant != null);
final ConstantsTransformer constantsTransformer = new ConstantsTransformer(
backend,
environmentDefines,
keepFields,
evaluateAnnotations,
desugarSets,
enableTripleShift,
@ -134,15 +138,17 @@ void transformProcedure(
TypeEnvironment typeEnvironment,
ErrorReporter errorReporter,
EvaluationMode evaluationMode,
{bool keepFields: true,
bool evaluateAnnotations: true,
{bool evaluateAnnotations: true,
bool desugarSets: false,
bool enableTripleShift: false,
bool errorOnUnevaluatedConstant: false}) {
assert(evaluateAnnotations != null);
assert(desugarSets != null);
assert(enableTripleShift != null);
assert(errorOnUnevaluatedConstant != null);
final ConstantsTransformer constantsTransformer = new ConstantsTransformer(
backend,
environmentDefines,
keepFields,
evaluateAnnotations,
desugarSets,
enableTripleShift,
@ -318,8 +324,6 @@ class ConstantsTransformer extends Transformer {
final TypeEnvironment typeEnvironment;
StaticTypeContext _staticTypeContext;
/// Whether to preserve constant [Field]s. All use-sites will be rewritten.
final bool keepFields;
final bool evaluateAnnotations;
final bool desugarSets;
final bool enableTripleShift;
@ -328,7 +332,6 @@ class ConstantsTransformer extends Transformer {
ConstantsTransformer(
this.backend,
Map<String, String> environmentDefines,
this.keepFields,
this.evaluateAnnotations,
this.desugarSets,
this.enableTripleShift,
@ -343,6 +346,13 @@ class ConstantsTransformer extends Transformer {
errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
evaluationMode: evaluationMode);
/// Whether to preserve constant [Field]s. All use-sites will be rewritten.
bool get keepFields => backend.keepFields;
/// Whether to preserve constant [VariableDeclaration]s. All use-sites will be
/// rewritten.
bool get keepLocals => backend.keepLocals;
// Transform the library/class members:
void convertLibrary(Library library) {
@ -515,7 +525,7 @@ class ConstantsTransformer extends Transformer {
..parent = node;
// If this constant is inlined, remove it.
if (shouldInline(node.initializer)) {
if (!keepLocals && shouldInline(node.initializer)) {
if (constant is! UnevaluatedConstant) {
// If the constant is unevaluated we need to keep the expression,
// so that, in the case the constant contains error but the local

View file

@ -1100,6 +1100,7 @@ class KernelTarget extends TargetImplementation {
environment,
new KernelConstantErrorReporter(loader),
evaluationMode,
evaluateAnnotations: true,
desugarSets: !backendTarget.supportsSetLiterals,
enableTripleShift:
isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
@ -1132,6 +1133,7 @@ class KernelTarget extends TargetImplementation {
environment,
new KernelConstantErrorReporter(loader),
evaluationMode,
evaluateAnnotations: true,
desugarSets: !backendTarget.supportsSetLiterals,
enableTripleShift:
isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),

View file

@ -101,7 +101,11 @@ Future<CompilerOutcome> runTransformation(List<String> arguments) async {
case 'constants':
final VmConstantsBackend backend = new VmConstantsBackend(coreTypes);
component = constants.transformComponent(component, backend, defines,
const constants.SimpleErrorReporter(), constants.EvaluationMode.weak);
const constants.SimpleErrorReporter(), constants.EvaluationMode.weak,
desugarSets: false,
evaluateAnnotations: true,
enableTripleShift: false,
errorOnUnevaluatedConstant: false);
break;
case 'empty':
component = empty.transformComponent(component);

View file

@ -96,7 +96,7 @@ class ConstantsBackend {
/// is the initializer of a [Field] or [VariableDeclaration] node.
/// If this method returns `true`, the variable will be inlined at all
/// points of reference and the variable itself removed (unless overridden
/// by the `keepFields` or `keepVariables` flag to the constant transformer).
/// by the `keepFields` or `keepLocals` properties).
/// This method must be deterministic, i.e. it must always return the same
/// value for the same constant value and place in the AST.
bool shouldInlineConstant(ConstantExpression initializer) => true;
@ -109,6 +109,18 @@ class ConstantsBackend {
/// This defaults to `false` since it requires additional work for a backend
/// to support unevaluated constants.
bool get supportsUnevaluatedConstants => false;
/// If `true` constant [Field] declarations are not removed from the AST even
/// when use-sites are inlined.
///
/// All use-sites will be rewritten based on [shouldInlineConstant].
bool get keepFields => true;
/// If `true` constant [VariableDeclaration]s are not removed from the AST
/// even when use-sites are inlined.
///
/// All use-sites will be rewritten based on [shouldInlineConstant].
bool get keepLocals => false;
}
/// A target provides backend-specific options for generating kernel IR.