Skip to content

Commit

Permalink
Macro. Code optimizer. Update initializers of final fields, when has …
Browse files Browse the repository at this point in the history
…const constructor.

Change-Id: I7a0097e240c2e54c47e6a24cb07054f656950ea8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/353582
Reviewed-by: Brian Wilkerson <[email protected]>
Commit-Queue: Konstantin Shcheglov <[email protected]>
Reviewed-by: Phil Quitslund <[email protected]>
  • Loading branch information
scheglov authored and Commit Queue committed Feb 21, 2024
1 parent 35c6cc6 commit e0c0cab
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 9 deletions.
3 changes: 2 additions & 1 deletion pkg/analyzer/lib/src/summary2/library_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class LibraryBuilder {
/// The fields that were speculatively created as [ConstFieldElementImpl],
/// but we want to clear [ConstVariableElement.constantInitializer] for it
/// if the class will not end up with a `const` constructor. We don't know
/// at the time when we create them, because of future augmentations, use
/// at the time when we create them, because of future augmentations, user
/// written or macro generated.
final Set<ConstFieldElementImpl> finalInstanceFields = Set.identity();

Expand Down Expand Up @@ -555,6 +555,7 @@ class LibraryBuilder {
augmentation: augmentation,
).perform(updateConstants: () {
MacroUpdateConstantsForOptimizedCode(
libraryElement: element,
unitNode: mergedUnit,
codeEdits: optimizedCodeEdits,
unitElement: unitElement,
Expand Down
55 changes: 48 additions & 7 deletions pkg/analyzer/lib/src/summary2/macro_merge.dart
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ class MacroElementsMerger {
}

class MacroUpdateConstantsForOptimizedCode {
/// The container of [unitElement].
final LibraryElementImpl libraryElement;

/// The parsed merged code.
final ast.CompilationUnit unitNode;

Expand All @@ -245,7 +248,11 @@ class MacroUpdateConstantsForOptimizedCode {
/// The merged element, with elements in the same order as in [unitNode].
final CompilationUnitElementImpl unitElement;

/// The names of classes that have a `const` constructor.
final Set<String> _namesOfConstClasses = {};

MacroUpdateConstantsForOptimizedCode({
required this.libraryElement,
required this.unitNode,
required this.codeEdits,
required this.unitElement,
Expand All @@ -263,6 +270,7 @@ class MacroUpdateConstantsForOptimizedCode {
/// The same elements, in the same order.
/// If not, we have a bug in [MacroElementsMerger].
void perform() {
_findConstClasses();
var nodeRecords = _orderedForNodes();
var elementRecords = _orderedForElement();
assert(nodeRecords.length == elementRecords.length);
Expand Down Expand Up @@ -295,6 +303,21 @@ class MacroUpdateConstantsForOptimizedCode {
}
}

void _findConstClasses() {
for (var element in libraryElement.topLevelElements) {
if (element is! ClassElementImpl) continue;
if (element.isAugmentation) continue;

var augmented = element.augmented;
if (augmented == null) continue;

var hasConst = augmented.constructors.any((e) => e.isConst);
if (hasConst) {
_namesOfConstClasses.add(element.name);
}
}
}

List<(ElementImpl, ast.AstNodeImpl)> _orderedForElement() {
var result = <(ElementImpl, ast.AstNodeImpl)>[];

Expand Down Expand Up @@ -390,22 +413,31 @@ class MacroUpdateConstantsForOptimizedCode {

void addVariableList(
ast.VariableDeclarationListImpl variableList,
List<ast.AnnotationImpl> metadata,
) {
List<ast.AnnotationImpl> metadata, {
required bool withFinals,
}) {
for (var variable in variableList.variables) {
addMetadata(variable, metadata);
if (variableList.isConst) {

if (variableList.isConst || variableList.isFinal && withFinals) {
if (variable.initializer case var initializer?) {
result.add((variable, initializer));
}
}
}
}

void addInterfaceMembers(List<ast.ClassMemberImpl> members) {
void addInterfaceMembers(
List<ast.ClassMemberImpl> members, {
required bool hasConstConstructor,
}) {
for (var field in members) {
if (field is ast.FieldDeclarationImpl) {
addVariableList(field.fields, field.metadata);
addVariableList(
field.fields,
field.metadata,
withFinals: hasConstConstructor && !field.isStatic,
);
}
}

Expand Down Expand Up @@ -438,13 +470,22 @@ class MacroUpdateConstantsForOptimizedCode {
for (var class_ in unitNode.declarations) {
if (class_ is ast.ClassDeclarationImpl) {
addAnnotatedNode(class_);
addInterfaceMembers(class_.members);
addInterfaceMembers(
class_.members,
hasConstConstructor: _namesOfConstClasses.contains(
class_.name.lexeme,
),
);
}
}

for (var topVariable in unitNode.declarations) {
if (topVariable is ast.TopLevelVariableDeclarationImpl) {
addVariableList(topVariable.variables, topVariable.metadata);
addVariableList(
topVariable.variables,
topVariable.metadata,
withFinals: false,
);
}
}

Expand Down
103 changes: 102 additions & 1 deletion pkg/analyzer/test/src/summary/macro_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2861,7 +2861,7 @@ augment class A {
''');
}

test_codeOptimizer_constant_classField_constant() async {
test_codeOptimizer_constant_classField_const() async {
newFile('$testPackageLibPath/a.dart', r'''
const a = 0;
''');
Expand Down Expand Up @@ -2913,6 +2913,107 @@ augment class B {
''');
}

test_codeOptimizer_constant_classField_final_hasConstConstructor() async {
newFile('$testPackageLibPath/a.dart', r'''
const a = 0;
''');

var library = await buildLibrary(r'''
import 'append.dart';
import 'a.dart';
@DeclareInType(' final x = {{package:test/a.dart@a}};')
class B {
const B();
}
''');

configuration.forCodeOptimizer();
checkElementText(library, r'''
library
imports
package:test/append.dart
package:test/a.dart
augmentationImports
package:test/test.macro.dart
macroGeneratedCode
---
library augment 'test.dart';
import 'package:test/a.dart';
augment class B {
final x = a;
}
---
imports
package:test/a.dart
definingUnit
classes
augment class B @75
augmentationTarget: self::@class::B
fields
final x @87
type: int
shouldUseTypeForInitializerInference: false
constantInitializer
SimpleIdentifier
token: a @91
staticElement: package:test/a.dart::@getter::a
staticType: int
accessors
synthetic get x @-1
returnType: int
''');
}

test_codeOptimizer_constant_classField_final_noConstConstructor() async {
newFile('$testPackageLibPath/a.dart', r'''
const a = 0;
''');

var library = await buildLibrary(r'''
import 'append.dart';
import 'a.dart';
@DeclareInType(' final x = {{package:test/a.dart@a}};')
class B {}
''');

configuration.forCodeOptimizer();
checkElementText(library, r'''
library
imports
package:test/append.dart
package:test/a.dart
augmentationImports
package:test/test.macro.dart
macroGeneratedCode
---
library augment 'test.dart';
import 'package:test/a.dart';
augment class B {
final x = a;
}
---
imports
package:test/a.dart
definingUnit
classes
augment class B @75
augmentationTarget: self::@class::B
fields
final x @87
type: int
shouldUseTypeForInitializerInference: false
accessors
synthetic get x @-1
returnType: int
''');
}

test_codeOptimizer_constant_classField_namedType() async {
newFile('$testPackageLibPath/a.dart', r'''
class A<T> {}
Expand Down

0 comments on commit e0c0cab

Please sign in to comment.