Wrap field initializers copied by TFA in a FileUriExpression.
Before TFA runs, MixinFullResolution will clone a mixin's fields into the application classes for that mixin. The cloned Field on the application class will have a fileUri that refers to the original mixin file.
However, TFA then copies those fields into FieldInitializers which don't have a fileUri context and so the fileUri for the surrounding Constructor is used. This leaves expressions in the initializer with offsets relative to the mixin's file but in the context of the mixin application's file.
To fix this, we can wrap the initializer in a FileUriExpression referring to the original mixin class. We only do this if the field the initializer is copied from refers to a different file than the target constructor.
Also add handlers for FileUriExpressions to several visitors that don't already support this new AST node.
Change-Id: I47b0d48dfe87303949130a40216b199949cfa1d9
Tested: Existing test suite.
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360420
Commit-Queue: Nate Biggs <natebiggs@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/compiler/lib/src/inferrer/builder.dart b/pkg/compiler/lib/src/inferrer/builder.dart
index d6c18dd..73d25ea 100644
--- a/pkg/compiler/lib/src/inferrer/builder.dart
+++ b/pkg/compiler/lib/src/inferrer/builder.dart
@@ -2246,6 +2246,11 @@
return TypeInformationConstantVisitor(this, node)
.visitConstant(node.constant);
}
+
+ @override
+ TypeInformation visitFileUriExpression(ir.FileUriExpression node) {
+ return visit(node.expression)!;
+ }
}
class TypeInformationConstantVisitor
diff --git a/pkg/compiler/lib/src/ir/scope_visitor.dart b/pkg/compiler/lib/src/ir/scope_visitor.dart
index 501c21e..782dafc 100644
--- a/pkg/compiler/lib/src/ir/scope_visitor.dart
+++ b/pkg/compiler/lib/src/ir/scope_visitor.dart
@@ -1443,6 +1443,11 @@
return const EvaluationComplexity.constant();
}
+ @override
+ EvaluationComplexity visitFileUriExpression(ir.FileUriExpression node) {
+ return visitNode(node.expression);
+ }
+
/// Returns true if the node is a field, or a constructor (factory or
/// generative).
bool _isFieldOrConstructor(ir.Node node) =>
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 5d90641..1c44d91 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -6228,6 +6228,11 @@
..cleanUp();
}
+ @override
+ void visitFileUriExpression(ir.FileUriExpression node) {
+ node.expression.accept(this);
+ }
+
bool _tryInlineMethod(
FunctionEntity function,
Selector? selector,
diff --git a/pkg/dart2wasm/lib/await_transformer.dart b/pkg/dart2wasm/lib/await_transformer.dart
index a7f5b29..e882385 100644
--- a/pkg/dart2wasm/lib/await_transformer.dart
+++ b/pkg/dart2wasm/lib/await_transformer.dart
@@ -768,6 +768,9 @@
TreeNode visitRethrow(Rethrow expr) => nullary(expr);
@override
+ TreeNode visitFileUriExpression(FileUriExpression expr) => unary(expr);
+
+ @override
TreeNode visitVariableGet(VariableGet expr) {
Expression result = expr;
// Getting a final or const variable is not an effect so it can be
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 224258e..18db4b8 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -3160,6 +3160,12 @@
return translator.topInfo.nullableType;
}
+ @override
+ w.ValueType visitFileUriExpression(
+ FileUriExpression node, w.ValueType expectedType) {
+ return wrap(node.expression, expectedType);
+ }
+
// Generates a function for a constructor's body, where the allocated struct
// object is passed to this function.
void generateConstructorBody(Reference target) {
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 369572a..68cec03 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -2635,6 +2635,11 @@
_visit(node.operand);
return _staticType(node);
}
+
+ @override
+ TypeExpr visitFileUriExpression(FileUriExpression node) {
+ return _visit(node.expression);
+ }
}
class RuntimeTypeTranslatorImpl
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 2e1f872..d04c01b 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -221,6 +221,14 @@
if (!isFirst) {
initExpr = CloneVisitorNotMembers().clone(initExpr);
}
+ if (c.fileUri != f.fileUri) {
+ if (initExpr is ConstantExpression) {
+ initExpr = FileUriConstantExpression(initExpr.constant,
+ type: initExpr.type, fileUri: f.fileUri);
+ } else {
+ initExpr = FileUriExpression(initExpr, f.fileUri);
+ }
+ }
final Initializer newInit = initializedFields.contains(f)
? LocalInitializer(VariableDeclaration(null,
initializer: initExpr, isSynthesized: true))