Skip to content

Commit 3175e42

Browse files
jensjohaCommit Queue
authored andcommitted
[CFE] Keep const locals by default; expression evaluation can evaluate const locals
Note: Const locals are still off for VM aot and dart2js for the entry points I've found in an attempt to retain the old behaviour there. It might be better if those targets could remove such locals in a whole-world analysis instead. * Keep const locals by default (except as noted above). Update the verifier to accept that. For the platforms this has increased the size by at most 6584 bytes. With this the VM will pass in any const locals as it does normal locals, but as the variable is never captured it will never pass a const local defined in a method when inside a local function in that method. * Change the dart scope calculation(s) to return the found variables instead of just the types of the found variables. * When the incremental compilers expression compilation - via the dart scope calculation - finds a const local that it wasn't told about, it will pass it on as an extra variable that it knows about, allowing for evaluating const locals in the case not covered by the first bullet. With luck this can in future CLs be extended to know about other variables that we're not told about, allowing to give a message saying something like "yes, we know what 'foo' is, but you can't currently use it" as wanted in for instance #60316 and #53996. Tested: Existing tests for existing functionality; new tests for the new Change-Id: I1ec24350273e6f81574bb2888f6bf46e3b8b1b47 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/445461 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Jens Johansen <[email protected]> Reviewed-by: Nicholas Shahan <[email protected]> Reviewed-by: Daco Harkes <[email protected]>
1 parent a571ba7 commit 3175e42

File tree

871 files changed

+4421
-410
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

871 files changed

+4421
-410
lines changed

pkg/compiler/lib/src/kernel/dart2js_target.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ class Dart2jsConstantsBackend extends ConstantsBackend {
389389
@override
390390
final bool supportsUnevaluatedConstants;
391391

392-
const Dart2jsConstantsBackend({required this.supportsUnevaluatedConstants});
392+
const Dart2jsConstantsBackend({required this.supportsUnevaluatedConstants})
393+
: super(keepLocals: false);
393394

394395
@override
395396
NumberSemantics get numberSemantics => NumberSemantics.js;

pkg/dart2wasm/lib/target.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ enum Mode {
4141
}
4242

4343
class Dart2WasmConstantsBackend extends ConstantsBackend {
44-
const Dart2WasmConstantsBackend();
44+
const Dart2WasmConstantsBackend() : super(keepLocals: false);
4545

4646
@override
4747
bool get supportsUnevaluatedConstants => true;

pkg/dev_compiler/lib/src/kernel/expression_compiler.dart

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,11 @@ class ExpressionCompiler {
125125
// extracted from the lowering.
126126
// See https://github.com/dart-lang/sdk/issues/55918
127127
var dartLateLocals = [
128-
for (var name in dartScope.definitions.keys)
128+
for (var name in dartScope.variables.keys)
129129
if (isLateLoweredLocalName(name)) name,
130130
];
131131
for (var localName in dartLateLocals) {
132-
dartScope.definitions[extractLocalName(localName)] = dartScope
133-
.definitions
132+
dartScope.variables[extractLocalName(localName)] = dartScope.variables
134133
.remove(localName)!;
135134
}
136135

@@ -151,7 +150,7 @@ class ExpressionCompiler {
151150
// shorter Dart name. Since longer Dart names can't incorrectly match a
152151
// shorter JS name (JS names are always at least as long as the Dart
153152
// name), we process them from longest to shortest.
154-
final dartNames = [...dartScope.definitions.keys]..sort(nameCompare);
153+
final dartNames = [...dartScope.variables.keys]..sort(nameCompare);
155154

156155
// Sort JS names so that the highest suffix value gets assigned to the
157156
// corresponding Dart name first. Since names are suffixed in ascending
@@ -245,15 +244,15 @@ class ExpressionCompiler {
245244
}
246245
}
247246

248-
dartScope.definitions.removeWhere(
249-
(variable, type) =>
247+
dartScope.variables.removeWhere(
248+
(variableName, _) =>
250249
// Remove undefined js variables (this allows us to get a reference
251250
// error from chrome on evaluation).
252-
!dartNameToJsValue.containsKey(variable) ||
251+
!dartNameToJsValue.containsKey(variableName) ||
253252
// Remove wildcard method arguments which are lowered to have Dart
254253
// names that are invalid for Dart compilations.
255254
// Wildcard local variables are not appearing here at this time.
256-
isWildcardLoweredFormalParameter(variable),
255+
isWildcardLoweredFormalParameter(variableName),
257256
);
258257

259258
// Wildcard type parameters already matched by this existing test.
@@ -265,7 +264,7 @@ class ExpressionCompiler {
265264
// captured variables optimized away in chrome)
266265
var localJsScope = [
267266
...dartScope.typeParameters.map((parameter) => jsScope[parameter.name]),
268-
...dartScope.definitions.keys.map(
267+
...dartScope.variables.keys.map(
269268
(variable) => dartNameToJsValue[variable],
270269
),
271270
];
@@ -412,7 +411,7 @@ class ExpressionCompiler {
412411
}
413412
var procedure = await _compiler.compileExpression(
414413
expression,
415-
scope.definitions,
414+
scope.variablesAsMapToType(),
416415
scope.typeParameters,
417416
debugProcedureName,
418417
scope.library.importUri,

pkg/dev_compiler/test/scopes/scope_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class ScopeDataExtractor extends DdcDataExtractor<Features> {
109109
printer.writeTypeParameterName(typeParameter);
110110
features.addElement(Tags.typeParameter, printer.getText());
111111
}
112-
for (var variable in scope.definitions.keys) {
112+
for (var variable in scope.variables.keys) {
113113
features.addElement(Tags.variables, variable);
114114
}
115115
return features;

pkg/front_end/lib/src/base/incremental_compiler.dart

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import 'package:kernel/kernel.dart'
2626
show
2727
Class,
2828
Component,
29+
ConstantExpression,
2930
DartType,
3031
DynamicType,
3132
Expression,
@@ -1644,6 +1645,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
16441645
return null;
16451646
}
16461647
LibraryBuilder libraryBuilder = compilationUnit.libraryBuilder;
1648+
List<VariableDeclarationImpl> extraKnownVariables = [];
16471649
if (scriptUri != null && offset != TreeNode.noOffset) {
16481650
Uri? scriptUriAsUri = Uri.tryParse(scriptUri);
16491651
if (scriptUriAsUri != null) {
@@ -1667,19 +1669,35 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
16671669
}
16681670
DartScope foundScope = DartScopeBuilder2.findScopeFromOffsetAndClass(
16691671
library, scriptUriAsUri, cls, offset);
1672+
final bool alwaysInlineConstants = lastGoodKernelTarget
1673+
.backendTarget.constantsBackend.alwaysInlineConstants;
16701674
// For now, if any definition is (or contains) an Extension Type,
16711675
// we'll overwrite the given (runtime?) definitions so we know about
16721676
// the extension type. If any definition is said to be dynamic we'll
16731677
// overwrite as well because that mostly means that the value is
16741678
// currently null. This can also mean that the VM can't send over the
16751679
// information - this for instance happens for function types.
1676-
for (MapEntry<String, DartType> def
1677-
in foundScope.definitions.entries) {
1680+
for (MapEntry<String, VariableDeclaration> def
1681+
in foundScope.variables.entries) {
16781682
DartType? existingType = usedDefinitions[def.key];
1679-
if (existingType == null) continue;
1680-
if (existingType is DynamicType ||
1681-
_ExtensionTypeFinder.isOrContainsExtensionType(def.value)) {
1682-
usedDefinitions[def.key] = def.value;
1683+
if (existingType == null) {
1684+
// We found a variable, but we weren't told about it.
1685+
// For now we'll only do something special if it's a const
1686+
// variable that will be inlined.
1687+
if (alwaysInlineConstants &&
1688+
def.value.isConst &&
1689+
def.value.initializer is ConstantExpression) {
1690+
extraKnownVariables.add(new VariableDeclarationImpl(def.key,
1691+
type: def.value.type,
1692+
isConst: true,
1693+
hasDeclaredInitializer: true,
1694+
initializer: def.value.initializer)
1695+
..fileOffset = def.value.fileOffset);
1696+
}
1697+
} else if (existingType is DynamicType ||
1698+
_ExtensionTypeFinder.isOrContainsExtensionType(
1699+
def.value.type)) {
1700+
usedDefinitions[def.key] = def.value.type;
16831701
}
16841702
}
16851703
}
@@ -1920,7 +1938,8 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
19201938
className ?? extensionName,
19211939
(className != null && !isStatic) || extensionThis != null,
19221940
procedure,
1923-
extensionThis);
1941+
extensionThis,
1942+
extraKnownVariables);
19241943

19251944
parameters.body = new ReturnStatement(compiledExpression)
19261945
..parent = parameters;

pkg/front_end/lib/src/kernel/body_builder.dart

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1587,7 +1587,10 @@ class BodyBuilder extends StackListenerImpl
15871587

15881588
// Coverage-ignore(suite): Only used in expression compilation.
15891589
Expression parseSingleExpression(
1590-
Parser parser, Token token, FunctionNode parameters) {
1590+
Parser parser,
1591+
Token token,
1592+
FunctionNode parameters,
1593+
List<VariableDeclarationImpl> extraKnownVariables) {
15911594
int fileOffset = offsetForToken(token);
15921595
List<NominalParameterBuilder>? typeParameterBuilders;
15931596
for (TypeParameter typeParameter in parameters.typeParameters) {
@@ -1629,6 +1632,17 @@ class BodyBuilder extends StackListenerImpl
16291632
wildcardVariablesEnabled: libraryFeatures.wildcardVariables.isEnabled,
16301633
));
16311634

1635+
if (extraKnownVariables.isNotEmpty) {
1636+
LocalScope extraKnownVariablesScope = _localScope.createNestedScope(
1637+
debugName: "expression compilation extra known variables scope",
1638+
kind: ScopeKind.ifElement);
1639+
enterLocalScope(extraKnownVariablesScope);
1640+
for (VariableDeclarationImpl extraVariable in extraKnownVariables) {
1641+
declareVariable(extraVariable, _localScope);
1642+
typeInferrer.assignedVariables.declare(extraVariable);
1643+
}
1644+
}
1645+
16321646
Token endToken =
16331647
parser.parseExpression(parser.syntheticPreviousToken(token));
16341648

@@ -1657,6 +1671,12 @@ class BodyBuilder extends StackListenerImpl
16571671
initialized: true);
16581672
}
16591673
}
1674+
for (VariableDeclarationImpl extraVariable in extraKnownVariables) {
1675+
typeInferrer.flowAnalysis.declare(
1676+
extraVariable, new SharedTypeView(extraVariable.type),
1677+
initialized: true);
1678+
}
1679+
16601680
InferredFunctionBody inferredFunctionBody = typeInferrer.inferFunctionBody(
16611681
this, fileOffset, const DynamicType(), AsyncMarker.Sync, fakeReturn);
16621682
assert(

pkg/front_end/lib/src/kernel/constant_evaluator.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,10 @@ class ConstantsTransformer extends RemovingTransformer {
407407
makeConstantExpression(constant, initializer)..parent = node;
408408

409409
// If this constant is inlined, remove it.
410-
if (!keepLocals && shouldInline(initializer)) {
410+
if (!keepLocals &&
411+
// Coverage-ignore(suite): Not run.
412+
shouldInline(initializer)) {
413+
// Coverage-ignore-block(suite): Not run.
411414
if (constant is! UnevaluatedConstant) {
412415
// If the constant is unevaluated we need to keep the expression,
413416
// so that, in the case the constant contains error but the local
@@ -590,6 +593,7 @@ class ConstantsTransformer extends RemovingTransformer {
590593
}
591594
}
592595
if (storeIndex < node.statements.length) {
596+
// Coverage-ignore-block(suite): Not run.
593597
node.statements.length = storeIndex;
594598
}
595599
return node;

pkg/front_end/lib/src/source/source_loader.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
1919
ScannerResult,
2020
Token,
2121
scan;
22+
import 'package:front_end/src/kernel/internal_ast.dart'
23+
show VariableDeclarationImpl;
2224
import 'package:kernel/ast.dart';
2325
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
2426
import 'package:kernel/core_types.dart' show CoreTypes;
@@ -1246,7 +1248,8 @@ severity: $severity
12461248
String? enclosingClassOrExtension,
12471249
bool isClassInstanceMember,
12481250
Procedure procedure,
1249-
VariableDeclaration? extensionThis) async {
1251+
VariableDeclaration? extensionThis,
1252+
List<VariableDeclarationImpl> extraKnownVariables) async {
12501253
// TODO(johnniwinther): Support expression compilation in a specific
12511254
// compilation unit.
12521255
LookupScope memberScope =
@@ -1311,7 +1314,8 @@ severity: $severity
13111314
enableFeatureEnhancedParts:
13121315
libraryBuilder.libraryFeatures.enhancedParts.isEnabled),
13131316
token,
1314-
procedure.function);
1317+
procedure.function,
1318+
extraKnownVariables);
13151319
}
13161320

13171321
DietListener createDietListener(SourceLibraryBuilder library,

pkg/front_end/test/scopes/scope_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class ScopeDataExtractor extends CfeDataExtractor<Features> {
8585
printer.writeTypeParameterName(typeParameter);
8686
features.addElement(Tags.typeParameter, printer.getText());
8787
}
88-
for (String variable in scope.definitions.keys) {
88+
for (String variable in scope.variables.keys) {
8989
features.addElement(Tags.variables, variable);
9090
}
9191
return features;

pkg/front_end/test/spell_checking_list_code.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,7 @@ indentations
875875
independently
876876
indexer
877877
indexing
878+
indicator
878879
indirection
879880
individual
880881
individually
@@ -1939,6 +1940,7 @@ tokenize
19391940
tokenized
19401941
tokenizer
19411942
tokenizing
1943+
told
19421944
tolerant
19431945
tolerate
19441946
tolerated

0 commit comments

Comments
 (0)