Version 2.14.0-361.0.dev
Merge commit '9397b8ff055b3b97275e17aaf651bbb176b2b306' into 'dev'
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 3555b29..771e607 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -6583,9 +6583,7 @@
arguments))
..fileOffset = receiver.fileOffset;
} else {
- MethodInvocation node =
- forest.createMethodInvocation(offset, receiver, name, arguments);
- return node;
+ return forest.createMethodInvocation(offset, receiver, name, arguments);
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 5333b0c..82dbe5c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -752,7 +752,7 @@
Expression buildSimpleRead() {
VariableDeclarationImpl variable =
_helper.createVariableDeclarationForValue(receiverExpression);
- PropertyGet read = _forest.createPropertyGet(
+ Expression read = _forest.createPropertyGet(
fileOffset,
_helper.createVariableGet(variable, receiverExpression.fileOffset,
forNullGuardedAccess: true),
@@ -765,7 +765,7 @@
Expression buildAssignment(Expression value, {bool voidContext = false}) {
VariableDeclarationImpl variable =
_helper.createVariableDeclarationForValue(receiverExpression);
- PropertySet read = _helper.forest.createPropertySet(
+ Expression read = _helper.forest.createPropertySet(
fileOffset,
_helper.createVariableGet(variable, receiverExpression.fileOffset,
forNullGuardedAccess: true),
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 8ba13f0..9dc0296 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -722,11 +722,11 @@
..fileOffset = fileOffset;
}
- MethodInvocation createMethodInvocation(
+ Expression createMethodInvocation(
int fileOffset, Expression expression, Name name, Arguments arguments) {
// ignore: unnecessary_null_comparison
assert(fileOffset != null);
- return new MethodInvocation(expression, name, arguments)
+ return new InternalMethodInvocation(expression, name, arguments)
..fileOffset = fileOffset;
}
@@ -758,19 +758,18 @@
return new NullCheck(expression)..fileOffset = fileOffset;
}
- PropertyGet createPropertyGet(
- int fileOffset, Expression receiver, Name name) {
+ Expression createPropertyGet(int fileOffset, Expression receiver, Name name) {
// ignore: unnecessary_null_comparison
assert(fileOffset != null);
- return new PropertyGet(receiver, name)..fileOffset = fileOffset;
+ return new InternalPropertyGet(receiver, name)..fileOffset = fileOffset;
}
- PropertySet createPropertySet(
+ Expression createPropertySet(
int fileOffset, Expression receiver, Name name, Expression value,
{required bool forEffect, bool readOnlyReceiver: false}) {
// ignore: unnecessary_null_comparison
assert(fileOffset != null);
- return new PropertySetImpl(receiver, name, value,
+ return new InternalPropertySet(receiver, name, value,
forEffect: forEffect, readOnlyReceiver: readOnlyReceiver)
..fileOffset = fileOffset;
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 946ce03..719356e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -322,7 +322,7 @@
}
@override
- void visitInvalidInitializer(Initializer node) {
+ void visitInvalidInitializer(InvalidInitializer node) {
_unhandledInitializer(node);
}
@@ -1112,6 +1112,8 @@
return new LocalForInVariable(syntheticAssignment);
} else if (syntheticAssignment is PropertySet) {
return new PropertyForInVariable(syntheticAssignment);
+ } else if (syntheticAssignment is InternalPropertySet) {
+ return new InternalPropertyForInVariable(syntheticAssignment);
} else if (syntheticAssignment is SuperPropertySet) {
return new SuperPropertyForInVariable(syntheticAssignment);
} else if (syntheticAssignment is StaticSet) {
@@ -2820,6 +2822,19 @@
isExpressionInvocation: false, isImplicitCall: false);
}
+ ExpressionInferenceResult visitInternalMethodInvocation(
+ InternalMethodInvocation node, DartType typeContext) {
+ assert(node.name != unaryMinusName);
+ ExpressionInferenceResult result = inferrer.inferNullAwareExpression(
+ node.receiver, const UnknownType(), true);
+ Link<NullAwareGuard> nullAwareGuards = result.nullAwareGuards;
+ Expression receiver = result.nullAwareAction;
+ DartType receiverType = result.nullAwareActionType;
+ return inferrer.inferMethodInvocation(node.fileOffset, nullAwareGuards,
+ receiver, receiverType, node.name, node.arguments, typeContext,
+ isExpressionInvocation: false, isImplicitCall: false);
+ }
+
ExpressionInferenceResult visitExpressionInvocation(
ExpressionInvocation node, DartType typeContext) {
ExpressionInferenceResult result = inferrer.inferNullAwareExpression(
@@ -5900,6 +5915,44 @@
rhsType, replacement, nullAwareGuards);
}
+ ExpressionInferenceResult visitInternalPropertySet(
+ InternalPropertySet node, DartType typeContext) {
+ ExpressionInferenceResult receiverResult = inferrer
+ .inferNullAwareExpression(node.receiver, const UnknownType(), true,
+ isVoidAllowed: false);
+
+ Link<NullAwareGuard> nullAwareGuards = receiverResult.nullAwareGuards;
+ Expression receiver = receiverResult.nullAwareAction;
+ DartType receiverType = receiverResult.nullAwareActionType;
+
+ ObjectAccessTarget target = inferrer.findInterfaceMember(
+ receiverType, node.name, node.fileOffset,
+ setter: true, instrumented: true, includeExtensionMethods: true);
+ if (target.isInstanceMember || target.isObjectMember) {
+ if (inferrer.instrumentation != null &&
+ receiverType == const DynamicType()) {
+ inferrer.instrumentation!.record(
+ inferrer.uriForInstrumentation,
+ node.fileOffset,
+ 'target',
+ new InstrumentationValueForMember(target.member!));
+ }
+ }
+ DartType writeContext = inferrer.getSetterType(target, receiverType);
+ ExpressionInferenceResult rhsResult = inferrer
+ .inferExpression(node.value, writeContext, true, isVoidAllowed: true);
+ DartType rhsType = rhsResult.inferredType;
+ Expression rhs = inferrer.ensureAssignableResult(writeContext, rhsResult,
+ fileOffset: node.fileOffset, isVoidAllowed: writeContext is VoidType);
+
+ Expression replacement = _computePropertySet(
+ node.fileOffset, receiver, receiverType, node.name, target, rhs,
+ valueType: rhsType, forEffect: node.forEffect);
+
+ return inferrer.createNullAwareExpressionInferenceResult(
+ rhsType, replacement, nullAwareGuards);
+ }
+
ExpressionInferenceResult visitNullAwareIfNullSet(
NullAwareIfNullSet node, DartType typeContext) {
ExpressionInferenceResult receiverResult = inferrer
@@ -6030,6 +6083,31 @@
return expressionInferenceResult;
}
+ ExpressionInferenceResult visitInternalPropertyGet(
+ InternalPropertyGet node, DartType typeContext) {
+ ExpressionInferenceResult result = inferrer.inferNullAwareExpression(
+ node.receiver, const UnknownType(), true);
+
+ Link<NullAwareGuard> nullAwareGuards = result.nullAwareGuards;
+ Expression receiver = result.nullAwareAction;
+ DartType receiverType = result.nullAwareActionType;
+
+ node.receiver = receiver..parent = node;
+ PropertyGetInferenceResult propertyGetInferenceResult = _computePropertyGet(
+ node.fileOffset, receiver, receiverType, node.name, typeContext,
+ isThisReceiver: node.receiver is ThisExpression);
+ ExpressionInferenceResult readResult =
+ propertyGetInferenceResult.expressionInferenceResult;
+ inferrer.flowAnalysis.propertyGet(node, node.receiver, node.name.text,
+ propertyGetInferenceResult.member, readResult.inferredType);
+ ExpressionInferenceResult expressionInferenceResult =
+ inferrer.createNullAwareExpressionInferenceResult(
+ readResult.inferredType, readResult.expression, nullAwareGuards);
+ inferrer.flowAnalysis
+ .forwardExpression(expressionInferenceResult.nullAwareAction, node);
+ return expressionInferenceResult;
+ }
+
@override
void visitRedirectingInitializer(RedirectingInitializer node) {
inferrer.inferConstructorParameterTypes(node.target);
@@ -7316,6 +7394,69 @@
}
}
+class InternalPropertyForInVariable implements ForInVariable {
+ final InternalPropertySet propertySet;
+
+ DartType? _writeType;
+
+ Expression? _rhs;
+
+ InternalPropertyForInVariable(this.propertySet);
+
+ @override
+ DartType computeElementType(TypeInferrerImpl inferrer) {
+ ExpressionInferenceResult receiverResult = inferrer.inferExpression(
+ propertySet.receiver, const UnknownType(), true);
+ propertySet.receiver = receiverResult.expression..parent = propertySet;
+ DartType receiverType = receiverResult.inferredType;
+ ObjectAccessTarget writeTarget = inferrer.findInterfaceMember(
+ receiverType, propertySet.name, propertySet.fileOffset,
+ setter: true, instrumented: true, includeExtensionMethods: true);
+ DartType elementType =
+ _writeType = inferrer.getSetterType(writeTarget, receiverType);
+ Expression? error = inferrer.reportMissingInterfaceMember(
+ writeTarget,
+ receiverType,
+ propertySet.name,
+ propertySet.fileOffset,
+ templateUndefinedSetter);
+ if (error != null) {
+ _rhs = error;
+ } else {
+ if (writeTarget.isInstanceMember || writeTarget.isObjectMember) {
+ if (inferrer.instrumentation != null &&
+ receiverType == const DynamicType()) {
+ inferrer.instrumentation!.record(
+ inferrer.uriForInstrumentation,
+ propertySet.fileOffset,
+ 'target',
+ new InstrumentationValueForMember(writeTarget.member!));
+ }
+ }
+ _rhs = propertySet.value;
+ }
+ return elementType;
+ }
+
+ @override
+ Expression inferAssignment(TypeInferrerImpl inferrer, DartType rhsType) {
+ Expression rhs = inferrer.ensureAssignable(
+ inferrer.computeGreatestClosure(_writeType!), rhsType, _rhs!,
+ errorTemplate: templateForInLoopElementTypeNotAssignable,
+ nullabilityErrorTemplate:
+ templateForInLoopElementTypeNotAssignableNullability,
+ nullabilityPartErrorTemplate:
+ templateForInLoopElementTypeNotAssignablePartNullability,
+ isVoidAllowed: true);
+
+ propertySet.value = rhs..parent = propertySet;
+ ExpressionInferenceResult result = inferrer.inferExpression(
+ propertySet, const UnknownType(), !inferrer.isTopLevel,
+ isVoidAllowed: true);
+ return result.expression;
+ }
+}
+
class SuperPropertyForInVariable implements ForInVariable {
final SuperPropertySet superPropertySet;
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index 749419c..9389905 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -422,6 +422,7 @@
IndexSet,
LoadLibraryTearOff,
LocalPostIncDec,
+ MethodInvocation,
NullAwareCompoundSet,
NullAwareExtension,
NullAwareIfNullSet,
@@ -429,7 +430,9 @@
NullAwarePropertyGet,
NullAwarePropertySet,
Parenthesized,
+ PropertyGet,
PropertyPostIncDec,
+ PropertySet,
StaticPostIncDec,
SuperIndexSet,
SuperPostIncDec,
@@ -442,16 +445,19 @@
@override
R accept<R>(ExpressionVisitor<R> visitor) {
- if (visitor is Printer || visitor is Precedence) {
- // Allow visitors needed for toString.
+ if (visitor is Printer || visitor is Precedence || visitor is Transformer) {
+ // Allow visitors needed for toString and replaceWith.
return visitor.defaultExpression(this);
}
- return unsupported("${runtimeType}.accept", -1, null);
+ return unsupported(
+ "${runtimeType}.accept on ${visitor.runtimeType}", -1, null);
}
@override
- R accept1<R, A>(ExpressionVisitor1<R, A> visitor, A arg) =>
- unsupported("${runtimeType}.accept1", -1, null);
+ R accept1<R, A>(ExpressionVisitor1<R, A> visitor, A arg) {
+ return unsupported(
+ "${runtimeType}.accept1 on ${visitor.runtimeType}", -1, null);
+ }
@override
DartType getStaticType(StaticTypeContext context) =>
@@ -1341,14 +1347,13 @@
@override
void toTextInternal(AstPrinter printer) {
Expression propertyGet = read;
- if (propertyGet is PropertyGet) {
+ if (propertyGet is InternalPropertyGet) {
Expression receiver = propertyGet.receiver;
if (receiver is VariableGet && receiver.variable == variable) {
// Special-case the usual use of this node.
printer.writeExpression(variable.initializer!);
printer.write('?.');
- printer.writeInterfaceMemberName(
- propertyGet.interfaceTargetReference, propertyGet.name);
+ printer.writeName(propertyGet.name);
return;
}
}
@@ -4524,3 +4529,244 @@
}
throw new UnsupportedError("Clone not supported for ${node.runtimeType}.");
}
+
+/// A dynamically bound method invocation of the form `o.foo()`.
+///
+/// This will be transformed into an [InstanceInvocation], [DynamicInvocation],
+/// [FunctionInvocation] or [StaticInvocation] (for implicit extension method
+/// invocation) after type inference.
+// TODO(johnniwinther): Rename to `MethodInvocation` when [MethodInvocation]
+// has been removed.
+class InternalMethodInvocation extends InternalExpression {
+ Expression receiver;
+
+ Name name;
+
+ Arguments arguments;
+
+ InternalMethodInvocation(this.receiver, this.name, this.arguments)
+ // ignore: unnecessary_null_comparison
+ : assert(receiver != null),
+ // ignore: unnecessary_null_comparison
+ assert(arguments != null) {
+ receiver.parent = this;
+ arguments.parent = this;
+ }
+
+ @override
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
+ return visitor.visitInternalMethodInvocation(this, typeContext);
+ }
+
+ @override
+ InternalExpressionKind get kind => InternalExpressionKind.MethodInvocation;
+
+ @override
+ void visitChildren(Visitor<dynamic> v) {
+ receiver.accept(v);
+ arguments.accept(v);
+ }
+
+ @override
+ void transformChildren(Transformer v) {
+ // ignore: unnecessary_null_comparison
+ if (receiver != null) {
+ receiver = v.transform(receiver);
+ receiver.parent = this;
+ }
+ // ignore: unnecessary_null_comparison
+ if (arguments != null) {
+ arguments = v.transform(arguments);
+ arguments.parent = this;
+ }
+ }
+
+ @override
+ void transformOrRemoveChildren(RemovingTransformer v) {
+ // ignore: unnecessary_null_comparison
+ if (receiver != null) {
+ receiver = v.transform(receiver);
+ receiver.parent = this;
+ }
+ // ignore: unnecessary_null_comparison
+ if (arguments != null) {
+ arguments = v.transform(arguments);
+ arguments.parent = this;
+ }
+ }
+
+ @override
+ String toString() {
+ return "InternalMethodInvocation(${toStringInternal()})";
+ }
+
+ @override
+ int get precedence => Precedence.PRIMARY;
+
+ @override
+ void toTextInternal(AstPrinter printer) {
+ printer.writeExpression(receiver, minimumPrecedence: Precedence.PRIMARY);
+ printer.write('.');
+ printer.writeName(name);
+ printer.writeArguments(arguments);
+ }
+}
+
+/// A dynamically bound property read of the form `o.foo`.
+///
+/// This will be transformed into an [InstanceGet], [InstanceTearOff],
+/// [DynamicGet], [FunctionTearOff] or [StaticInvocation] (for implicit
+/// extension member access) after type inference.
+// TODO(johnniwinther): Rename to `PropertyGet` when [PropertyGet]
+// has been removed.
+class InternalPropertyGet extends InternalExpression {
+ Expression receiver;
+
+ Name name;
+
+ InternalPropertyGet(this.receiver, this.name)
+ // ignore: unnecessary_null_comparison
+ : assert(receiver != null) {
+ receiver.parent = this;
+ }
+
+ @override
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
+ return visitor.visitInternalPropertyGet(this, typeContext);
+ }
+
+ @override
+ InternalExpressionKind get kind => InternalExpressionKind.PropertyGet;
+
+ @override
+ void visitChildren(Visitor<dynamic> v) {
+ receiver.accept(v);
+ }
+
+ @override
+ void transformChildren(Transformer v) {
+ // ignore: unnecessary_null_comparison
+ if (receiver != null) {
+ receiver = v.transform(receiver);
+ receiver.parent = this;
+ }
+ }
+
+ @override
+ void transformOrRemoveChildren(RemovingTransformer v) {
+ // ignore: unnecessary_null_comparison
+ if (receiver != null) {
+ receiver = v.transform(receiver);
+ receiver.parent = this;
+ }
+ }
+
+ @override
+ String toString() {
+ return "InternalPropertyGet(${toStringInternal()})";
+ }
+
+ @override
+ int get precedence => Precedence.PRIMARY;
+
+ @override
+ void toTextInternal(AstPrinter printer) {
+ printer.writeExpression(receiver, minimumPrecedence: Precedence.PRIMARY);
+ printer.write('.');
+ printer.writeName(name);
+ }
+}
+
+/// A dynamically bound property write of the form `o.foo = e`.
+///
+/// This will be transformed into an [InstanceSet], [DynamicSet], or
+/// [StaticInvocation] (for implicit extension member access) after type
+/// inference.
+// TODO(johnniwinther): Rename to `PropertySet` when [PropertySet]
+// has been removed.
+class InternalPropertySet extends InternalExpression {
+ Expression receiver;
+ Name name;
+ Expression value;
+
+ /// If `true` the assignment is need for its effect and not for its value.
+ final bool forEffect;
+
+ /// If `true` the receiver can be cloned and doesn't need a temporary variable
+ /// for multiple reads.
+ final bool readOnlyReceiver;
+
+ InternalPropertySet(this.receiver, this.name, this.value,
+ {required this.forEffect, required this.readOnlyReceiver})
+ // ignore: unnecessary_null_comparison
+ : assert(receiver != null),
+ // ignore: unnecessary_null_comparison
+ assert(value != null),
+ // ignore: unnecessary_null_comparison
+ assert(forEffect != null),
+ // ignore: unnecessary_null_comparison
+ assert(readOnlyReceiver != null) {
+ receiver.parent = this;
+ value.parent = this;
+ }
+
+ @override
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
+ return visitor.visitInternalPropertySet(this, typeContext);
+ }
+
+ @override
+ InternalExpressionKind get kind => InternalExpressionKind.PropertySet;
+
+ @override
+ void visitChildren(Visitor v) {
+ receiver.accept(v);
+ name.accept(v);
+ value.accept(v);
+ }
+
+ @override
+ void transformChildren(Transformer v) {
+ // ignore: unnecessary_null_comparison
+ if (receiver != null) {
+ receiver = v.transform(receiver);
+ receiver.parent = this;
+ }
+ // ignore: unnecessary_null_comparison
+ if (value != null) {
+ value = v.transform(value);
+ value.parent = this;
+ }
+ }
+
+ @override
+ void transformOrRemoveChildren(RemovingTransformer v) {
+ // ignore: unnecessary_null_comparison
+ if (receiver != null) {
+ receiver = v.transform(receiver);
+ receiver.parent = this;
+ }
+ // ignore: unnecessary_null_comparison
+ if (value != null) {
+ value = v.transform(value);
+ value.parent = this;
+ }
+ }
+
+ @override
+ String toString() {
+ return "InternalPropertySet(${toStringInternal()})";
+ }
+
+ @override
+ void toTextInternal(AstPrinter printer) {
+ printer.writeExpression(receiver, minimumPrecedence: Precedence.PRIMARY);
+ printer.write('.');
+ printer.writeName(name);
+ printer.write(' = ');
+ printer.writeExpression(value);
+ }
+}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index e8b4e79..ae9d883 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -358,6 +358,7 @@
dummy
dupdate
dyn
+dynamically
e
easy
ecma
diff --git a/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart b/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart
index e1f4a5b..a88f79a 100644
--- a/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart
+++ b/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart
@@ -44,6 +44,8 @@
_testFunctionDeclarationImpl();
_testIfNullExpression();
_testIntLiterals();
+ _testInternalMethodInvocation();
+ _testInternalPropertyGet();
_testExpressionInvocation();
_testNamedFunctionExpressionJudgment();
_testNullAwareMethodInvocation();
@@ -372,6 +374,35 @@
testExpression(new ShadowLargeIntLiteral('bar', TreeNode.noOffset), 'bar');
}
+void _testInternalMethodInvocation() {
+ testExpression(
+ new InternalMethodInvocation(
+ new IntLiteral(0), new Name('boz'), new ArgumentsImpl([])),
+ '''
+0.boz()''');
+ testExpression(
+ new InternalMethodInvocation(
+ new IntLiteral(0),
+ new Name('boz'),
+ new ArgumentsImpl([
+ new IntLiteral(1)
+ ], types: [
+ const VoidType(),
+ const DynamicType()
+ ], named: [
+ new NamedExpression('foo', new IntLiteral(2)),
+ new NamedExpression('bar', new IntLiteral(3))
+ ])),
+ '''
+0.boz<void, dynamic>(1, foo: 2, bar: 3)''');
+}
+
+void _testInternalPropertyGet() {
+ testExpression(
+ new InternalPropertyGet(new IntLiteral(0), new Name('boz')), '''
+0.boz''');
+}
+
void _testExpressionInvocation() {
testExpression(
new ExpressionInvocation(new IntLiteral(0), new ArgumentsImpl([])), '''
@@ -417,7 +448,7 @@
// An unusual use of this node.
testExpression(
new NullAwareMethodInvocation(variable,
- new PropertyGet(new VariableGet(variable), new Name('foo'))),
+ new InternalPropertyGet(new VariableGet(variable), new Name('foo'))),
'''
let final dynamic #0 = 0 in null-aware #0.foo''');
}
@@ -429,7 +460,7 @@
// The usual use of this node.
testExpression(
new NullAwarePropertyGet(variable,
- new PropertyGet(new VariableGet(variable), new Name('foo'))),
+ new InternalPropertyGet(new VariableGet(variable), new Name('foo'))),
'''
0?.foo''');
diff --git a/pkg/front_end/testcases/general/invalid_super_initializer.dart b/pkg/front_end/testcases/general/invalid_super_initializer.dart
new file mode 100644
index 0000000..1e3f1aa
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_super_initializer.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2021, 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.
+
+abstract class A {}
+
+class B extends A {
+ B(): super()?.foo() {}
+}
+
+bad() {
+ new B();
+}
+
+main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/invalid_super_initializer.dart.textual_outline.expect b/pkg/front_end/testcases/general/invalid_super_initializer.dart.textual_outline.expect
new file mode 100644
index 0000000..946f9ea
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_super_initializer.dart.textual_outline.expect
@@ -0,0 +1,6 @@
+abstract class A {}
+class B extends A {
+ B(): super()?.foo() {}
+}
+bad() {}
+main() {}
diff --git a/pkg/front_end/testcases/general/invalid_super_initializer.dart.weak.expect b/pkg/front_end/testcases/general/invalid_super_initializer.dart.weak.expect
new file mode 100644
index 0000000..d8ef127
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_super_initializer.dart.weak.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/invalid_super_initializer.dart:8:8: Error: Can't use 'super' as an expression.
+// To delegate a constructor to a super constructor, put the super call as an initializer.
+// B(): super()?.foo() {}
+// ^
+//
+// pkg/front_end/testcases/general/invalid_super_initializer.dart:8:8: Error: Expected an initializer.
+// B(): super()?.foo() {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+class B extends self::A {
+ constructor •() → self::B
+ : final dynamic #t1 = let final dynamic #t2 = invalid-expression "pkg/front_end/testcases/general/invalid_super_initializer.dart:8:8: Error: Can't use 'super' as an expression.
+To delegate a constructor to a super constructor, put the super call as an initializer.
+ B(): super()?.foo() {}
+ ^" in #t2 == null ?{dynamic} null : #t2{dynamic}.foo() {}
+}
+static method bad() → dynamic {
+ new self::B::•();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/invalid_super_initializer.dart.weak.outline.expect b/pkg/front_end/testcases/general/invalid_super_initializer.dart.weak.outline.expect
new file mode 100644
index 0000000..13e0b1e
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_super_initializer.dart.weak.outline.expect
@@ -0,0 +1,16 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+ synthetic constructor •() → self::A
+ ;
+}
+class B extends self::A {
+ constructor •() → self::B
+ ;
+}
+static method bad() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/invalid_super_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/general/invalid_super_initializer.dart.weak.transformed.expect
new file mode 100644
index 0000000..d8ef127
--- /dev/null
+++ b/pkg/front_end/testcases/general/invalid_super_initializer.dart.weak.transformed.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/invalid_super_initializer.dart:8:8: Error: Can't use 'super' as an expression.
+// To delegate a constructor to a super constructor, put the super call as an initializer.
+// B(): super()?.foo() {}
+// ^
+//
+// pkg/front_end/testcases/general/invalid_super_initializer.dart:8:8: Error: Expected an initializer.
+// B(): super()?.foo() {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+class B extends self::A {
+ constructor •() → self::B
+ : final dynamic #t1 = let final dynamic #t2 = invalid-expression "pkg/front_end/testcases/general/invalid_super_initializer.dart:8:8: Error: Can't use 'super' as an expression.
+To delegate a constructor to a super constructor, put the super call as an initializer.
+ B(): super()?.foo() {}
+ ^" in #t2 == null ?{dynamic} null : #t2{dynamic}.foo() {}
+}
+static method bad() → dynamic {
+ new self::B::•();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart
new file mode 100644
index 0000000..d12b28b
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2021, 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.md file.
+
+class Class1 {
+ int field = 0;
+
+ factory Class1() = Class1._;
+
+ Class1._();
+
+ int get getter => 0;
+}
+
+class Class2 extends Class1 {
+ final Class2 _c2;
+
+ Class2(this._c2) : super._() {
+ // Invocation inside an invalid unary expression.
+ -new Class1();
+ // Invocation inside an invalid binary expression.
+ ('' + '') - new Class1();
+ // Invocation inside an invalid index set.
+ (0 + 1)[0] = new Class1();
+ _c2[0] = new Class1();
+ // Invocation inside an invalid index get.
+ (0 + 1)[new Class1()];
+ // Invocation inside an invalid property get.
+ new Class1().foo;
+ // Invocation inside an invalid property set.
+ (0 + 1).foo = new Class1();
+ // Invocation inside an invalid invocation.
+ new Class1().foo();
+ // Invocation inside an invalid implicit call invocation.
+ new Class1()();
+ // Invocation inside an invalid implicit field invocation.
+ new Class1().field();
+ // Invocation inside an invalid implicit getter invocation.
+ new Class1().getter();
+ // Invocation inside an invalid implicit call-getter invocation.
+ _c2(new Class1());
+ // Duplicate named arguments
+ method(a: 0, a: new Class1());
+ // Triple named arguments
+ method(a: 0, a: 1, a: new Class1());
+ // Invocation inside an invalid super index get.
+ super[new Class1()];
+ // Invocation inside an invalid super index set.
+ super[0] = new Class1();
+ // Invocation inside an invalid super set.
+ super.foo = new Class1();
+ // Invocation inside an invalid super invocation.
+ super.foo(new Class1());
+ // Invocation inside an invalid super binary.
+ super + new Class1();
+ }
+
+ method({a}) {}
+
+ int get call => 0;
+}
+
+main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.textual_outline.expect b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.textual_outline.expect
new file mode 100644
index 0000000..607b231
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.textual_outline.expect
@@ -0,0 +1,15 @@
+class Class1 {
+ int field = 0;
+ factory Class1() = Class1._;
+ Class1._();
+ int get getter => 0;
+}
+
+class Class2 extends Class1 {
+ final Class2 _c2;
+ Class2(this._c2) : super._() {}
+ method({a}) {}
+ int get call => 0;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..ca3ab16
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.textual_outline_modelled.expect
@@ -0,0 +1,15 @@
+class Class1 {
+ Class1._();
+ factory Class1() = Class1._;
+ int field = 0;
+ int get getter => 0;
+}
+
+class Class2 extends Class1 {
+ Class2(this._c2) : super._() {}
+ final Class2 _c2;
+ int get call => 0;
+ method({a}) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.weak.expect b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.weak.expect
new file mode 100644
index 0000000..232d5ac
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.weak.expect
@@ -0,0 +1,187 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:47:10: Error: Superclass has no method named '[]'.
+// super[new Class1()];
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:49:10: Error: Superclass has no method named '[]='.
+// super[0] = new Class1();
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:51:11: Error: Superclass has no setter named 'foo'.
+// super.foo = new Class1();
+// ^^^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:53:11: Error: Superclass has no method named 'foo'.
+// super.foo(new Class1());
+// ^^^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:55:11: Error: Superclass has no method named '+'.
+// super + new Class1();
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:20:5: Error: The operator 'unary-' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+// Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+// -new Class1();
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:22:15: Error: The operator '-' isn't defined for the class 'String'.
+// Try correcting the operator to an existing operator, or defining a '-' operator.
+// ('' + '') - new Class1();
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:24:12: Error: The operator '[]=' isn't defined for the class 'int'.
+// Try correcting the operator to an existing operator, or defining a '[]=' operator.
+// (0 + 1)[0] = new Class1();
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:25:8: Error: The operator '[]=' isn't defined for the class 'Class2'.
+// - 'Class2' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+// Try correcting the operator to an existing operator, or defining a '[]=' operator.
+// _c2[0] = new Class1();
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:27:12: Error: The operator '[]' isn't defined for the class 'int'.
+// Try correcting the operator to an existing operator, or defining a '[]' operator.
+// (0 + 1)[new Class1()];
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:29:18: Error: The getter 'foo' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
+// new Class1().foo;
+// ^^^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:31:13: Error: The setter 'foo' isn't defined for the class 'int'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'foo'.
+// (0 + 1).foo = new Class1();
+// ^^^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:33:18: Error: The method 'foo' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+// new Class1().foo();
+// ^^^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:35:17: Error: The method 'call' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'call'.
+// new Class1()();
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:37:23: Error: 'field' isn't a function or method and can't be invoked.
+// new Class1().field();
+// ^^^^...
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:39:24: Error: 'getter' isn't a function or method and can't be invoked.
+// new Class1().getter();
+// ^^^^...
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:41:8: Error: 'call' isn't a function or method and can't be invoked.
+// _c2(new Class1());
+// ^^^^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:43:18: Error: Duplicated named argument 'a'.
+// method(a: 0, a: new Class1());
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:45:18: Error: Duplicated named argument 'a'.
+// method(a: 0, a: 1, a: new Class1());
+// ^
+//
+// pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:45:24: Error: Duplicated named argument 'a'.
+// method(a: 0, a: 1, a: new Class1());
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int field = 0;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1
+ : super core::Object::•()
+ ;
+ static factory •() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+ get getter() → core::int
+ return 0;
+}
+class Class2 extends self::Class1 {
+ final field self::Class2 _c2;
+ constructor •(self::Class2 _c2) → self::Class2
+ : self::Class2::_c2 = _c2, super self::Class1::_() {
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:20:5: Error: The operator 'unary-' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+Try correcting the operator to an existing operator, or defining a 'unary-' operator.
+ -new Class1();
+ ^";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:22:15: Error: The operator '-' isn't defined for the class 'String'.
+Try correcting the operator to an existing operator, or defining a '-' operator.
+ ('' + '') - new Class1();
+ ^";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:24:12: Error: The operator '[]=' isn't defined for the class 'int'.
+Try correcting the operator to an existing operator, or defining a '[]=' operator.
+ (0 + 1)[0] = new Class1();
+ ^";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:25:8: Error: The operator '[]=' isn't defined for the class 'Class2'.
+ - 'Class2' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+Try correcting the operator to an existing operator, or defining a '[]=' operator.
+ _c2[0] = new Class1();
+ ^";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:27:12: Error: The operator '[]' isn't defined for the class 'int'.
+Try correcting the operator to an existing operator, or defining a '[]' operator.
+ (0 + 1)[new Class1()];
+ ^";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:29:18: Error: The getter 'foo' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'foo'.
+ new Class1().foo;
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:31:13: Error: The setter 'foo' isn't defined for the class 'int'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'foo'.
+ (0 + 1).foo = new Class1();
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:33:18: Error: The method 'foo' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'foo'.
+ new Class1().foo();
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:35:17: Error: The method 'call' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'call'.
+ new Class1()();
+ ^";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:37:23: Error: 'field' isn't a function or method and can't be invoked.
+ new Class1().field();
+ ^^^^...";
+ invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:39:24: Error: 'getter' isn't a function or method and can't be invoked.
+ new Class1().getter();
+ ^^^^...";
+ let final self::Class2 #t1 = this.{self::Class2::_c2}{self::Class2} in let final self::Class1 #t2 = new self::Class1::_() in invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:41:8: Error: 'call' isn't a function or method and can't be invoked.
+ _c2(new Class1());
+ ^^^^";
+ this.{self::Class2::method}(a: invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:43:18: Error: Duplicated named argument 'a'.
+ method(a: 0, a: new Class1());
+ ^"){({a: dynamic}) → dynamic};
+ this.{self::Class2::method}(a: invalid-expression "pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart:45:24: Error: Duplicated named argument 'a'.
+ method(a: 0, a: 1, a: new Class1());
+ ^"){({a: dynamic}) → dynamic};
+ super.[](new self::Class1::_());
+ super.[]=(0, new self::Class1::_());
+ super.foo = new self::Class1::_();
+ super.foo(new self::Class1::_());
+ super.+(new self::Class1::_());
+ }
+ method method({dynamic a = #C1}) → dynamic {}
+ get call() → core::int
+ return 0;
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.weak.outline.expect b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.weak.outline.expect
new file mode 100644
index 0000000..83aea2e
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_invocation_in_invalid.dart.weak.outline.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+ constructor _() → self::Class1
+ ;
+ static factory •() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+ get getter() → core::int
+ ;
+}
+class Class2 extends self::Class1 {
+ final field self::Class2 _c2;
+ constructor •(self::Class2 _c2) → self::Class2
+ ;
+ method method({dynamic a}) → dynamic
+ ;
+ get call() → core::int
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/redirection_chain_type_arguments.dart b/pkg/front_end/testcases/general/redirection_chain_type_arguments.dart
index 7b4cd53..7d7ffec 100644
--- a/pkg/front_end/testcases/general/redirection_chain_type_arguments.dart
+++ b/pkg/front_end/testcases/general/redirection_chain_type_arguments.dart
@@ -1,7 +1,9 @@
// Copyright (c) 2018, 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.md file.
+
// @dart=2.9
+
// The test checks that type arguments of the target of redirection factory
// constructors are preserved throughout the chain of redirections.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 6aacb2f..6d07e17 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -100,6 +100,7 @@
general/override_check_basic: TypeCheckError # Issue #31620
general/override_check_with_covariant_modifier: TypeCheckError # Issue #31620
general/override_setter_with_field: TypeCheckError
+general/redirecting_factory_invocation_in_invalid: TypeCheckError
general/spread_collection: RuntimeError # Should be fixed as part of implementing spread collection support
general/type_parameter_type_named_int: RuntimeError
general/type_variable_as_super: RuntimeError
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index e8cae1b..f4830a4 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -86,6 +86,7 @@
general/incomplete_field_formal_parameter: FormatterCrash
general/invalid_operator2: FormatterCrash
general/invalid_operator: FormatterCrash
+general/invalid_super_initializer: FormatterCrash
general/issue42997: FormatterCrash
general/issue43363: FormatterCrash
general/issue45490: FormatterCrash
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index d88eb7b16..9f50ba9 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -106,6 +106,7 @@
general/override_check_basic: TypeCheckError # Issue #31620
general/override_check_with_covariant_modifier: TypeCheckError # Issue #31620
general/override_setter_with_field: TypeCheckError
+general/redirecting_factory_invocation_in_invalid: TypeCheckError
general/spread_collection: RuntimeError
general/type_parameter_type_named_int: RuntimeError # Expected
general/type_variable_as_super: RuntimeError
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 0009adc..d7c72c7 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -3082,7 +3082,12 @@
@override
void toTextInternal(AstPrinter printer) {
- // TODO(johnniwinther): Implement this.
+ printer.write('super');
+ if (target.name.text.isNotEmpty) {
+ printer.write('.');
+ printer.write(target.name.text);
+ }
+ printer.writeArguments(arguments, includeTypeArguments: false);
}
}
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 5eec5a4..17a1c15 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -2804,6 +2804,7 @@
case Slot::Kind::kFunctionType_named_parameter_names:
case Slot::Kind::kFunctionType_parameter_types:
case Slot::Kind::kFunctionType_type_parameters:
+ case Slot::Kind::kInstance_native_fields_array:
case Slot::Kind::kPointerBase_data_field:
case Slot::Kind::kTypedDataView_data:
case Slot::Kind::kType_arguments:
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index cd8e80c..9f84201 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -210,6 +210,7 @@
case Slot::Kind::kArgumentsDescriptor_count:
case Slot::Kind::kArgumentsDescriptor_size:
case Slot::Kind::kArrayElement:
+ case Slot::Kind::kInstance_native_fields_array:
case Slot::Kind::kTypeArguments:
case Slot::Kind::kTypedDataView_offset_in_bytes:
case Slot::Kind::kTypedDataView_data:
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index 866e399..27adf00 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -61,6 +61,7 @@
V(Closure, UntaggedClosure, function_type_arguments, TypeArguments, FINAL) \
V(FunctionType, UntaggedFunctionType, type_parameters, TypeParameters, \
FINAL) \
+ V(Instance, UntaggedInstance, native_fields_array, Dynamic, VAR) \
V(Type, UntaggedType, arguments, TypeArguments, FINAL) \
V(TypeParameters, UntaggedTypeParameters, flags, Array, FINAL) \
V(TypeParameters, UntaggedTypeParameters, bounds, TypeArguments, FINAL) \
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 6968ff1..d35850e 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -854,6 +854,7 @@
case MethodRecognizer::kFfiStorePointer:
case MethodRecognizer::kFfiFromAddress:
case MethodRecognizer::kFfiGetAddress:
+ case MethodRecognizer::kGetNativeField:
case MethodRecognizer::kObjectEquals:
case MethodRecognizer::kStringBaseLength:
case MethodRecognizer::kStringBaseIsEmpty:
@@ -1491,6 +1492,20 @@
body += Constant(Bool::False());
#endif // defined(ARCH_IS_64_BIT)
} break;
+ case MethodRecognizer::kGetNativeField: {
+ auto& name = String::ZoneHandle(Z, function.name());
+ // Note: This method is force optimized so we can push untagged, etc.
+ // Load TypedDataArray from Instance Handle implementing
+ // NativeFieldWrapper.
+ body += LoadLocal(parsed_function_->RawParameterVariable(0)); // Object.
+ body += CheckNullOptimized(TokenPosition::kNoSource, name);
+ body += LoadNativeField(Slot::Instance_native_fields_array()); // Fields.
+ body += CheckNullOptimized(TokenPosition::kNoSource, name);
+ // Load the native field at index.
+ body += IntConstant(0); // Index.
+ body += LoadIndexed(kIntPtrCid);
+ body += Box(kUnboxedIntPtr);
+ } break;
default: {
UNREACHABLE();
break;
diff --git a/runtime/vm/compiler/method_recognizer.cc b/runtime/vm/compiler/method_recognizer.cc
index 0c5a85a..af01254 100644
--- a/runtime/vm/compiler/method_recognizer.cc
+++ b/runtime/vm/compiler/method_recognizer.cc
@@ -290,6 +290,7 @@
libs->Add(&Library::ZoneHandle(Library::DeveloperLibrary()));
libs->Add(&Library::ZoneHandle(Library::AsyncLibrary()));
libs->Add(&Library::ZoneHandle(Library::FfiLibrary()));
+ libs->Add(&Library::ZoneHandle(Library::NativeWrappersLibrary()));
}
static Token::Kind RecognizeTokenKindHelper(const String& name) {
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index f45e224..9680f0b 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -197,6 +197,7 @@
V(::, _storePointer, FfiStorePointer, 0xea6b7751) \
V(::, _fromAddress, FfiFromAddress, 0xfd8cb1cc) \
V(Pointer, get:address, FfiGetAddress, 0x7cde87be) \
+ V(::, getNativeField, GetNativeField, 0x95b4ec94) \
V(::, reachabilityFence, ReachabilityFence, 0x619235c1) \
V(_Utf8Decoder, _scan, Utf8DecoderScan, 0x1dcaf73d) \
V(_Future, timeout, FutureTimeout, 0x73041520) \
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index e1ad228..c8e499b 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -477,6 +477,10 @@
return TranslateOffsetInWords(dart::Instance::NextFieldOffset());
}
+word Instance::native_fields_array_offset() {
+ return TranslateOffsetInWords(dart::Instance::NativeFieldsOffset());
+}
+
word Instance::DataOffsetFor(intptr_t cid) {
if (dart::IsExternalTypedDataClassId(cid) ||
dart::IsExternalStringClassId(cid)) {
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 96342d7..52642b1 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -511,8 +511,8 @@
class Instance : public AllStatic {
public:
// Returns the offset to the first field of [UntaggedInstance].
- // Returns the offset to the first field of [UntaggedInstance].
static word first_field_offset();
+ static word native_fields_array_offset();
static word DataOffsetFor(intptr_t cid);
static word ElementSizeFor(intptr_t cid);
static word InstanceSize();
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 50b0ab9..b61e6c2 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -4166,6 +4166,61 @@
EXPECT_VALID(Dart_Invoke(lib, NewString("main"), 0, NULL));
}
+void FUNCTION_NAME(SecretKeeper_KeepSecret)(Dart_NativeArguments native_args) {
+ Dart_Handle receiver = Dart_GetNativeArgument(native_args, 0);
+ int64_t secret = 0;
+ Dart_GetNativeIntegerArgument(native_args, 1, &secret);
+ EXPECT_VALID(Dart_SetNativeInstanceField(receiver, 0, secret));
+}
+
+static Dart_NativeFunction SecretKeeperNativeResolver(Dart_Handle name,
+ int argument_count,
+ bool* auto_setup_scope) {
+ return reinterpret_cast<Dart_NativeFunction>(Builtin_SecretKeeper_KeepSecret);
+}
+
+TEST_CASE(DartAPI_NativeFieldAccess) {
+ const char* kScriptChars = R"(
+ import 'dart:nativewrappers';
+ class SecretKeeper extends NativeFieldWrapperClass1 {
+ SecretKeeper(int secret) { _keepSecret(secret); }
+ void _keepSecret(int secret) native "SecretKeeper_KeepSecret";
+ }
+ main() => getNativeField(SecretKeeper(321));
+ )";
+
+ Dart_Handle result;
+ Dart_Handle lib =
+ TestCase::LoadTestScript(kScriptChars, SecretKeeperNativeResolver);
+ result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
+
+ EXPECT_VALID(result);
+ EXPECT(Dart_IsInteger(result));
+ int64_t value = 0;
+ result = Dart_IntegerToInt64(result, &value);
+ EXPECT_VALID(result);
+ EXPECT_EQ(321, value);
+}
+
+TEST_CASE(DartAPI_NativeFieldAccess_Throws) {
+ const char* kScriptChars = R"(
+ import 'dart:nativewrappers';
+ class ForgetfulSecretKeeper extends NativeFieldWrapperClass1 {
+ ForgetfulSecretKeeper(int secret) { /* Forget to init. native field. */ }
+ }
+ main() => getNativeField(ForgetfulSecretKeeper(321));
+ )";
+
+ Dart_Handle result;
+ Dart_Handle lib =
+ TestCase::LoadTestScript(kScriptChars, SecretKeeperNativeResolver);
+
+ result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
+
+ EXPECT(Dart_IsError(result));
+ EXPECT(Dart_IsUnhandledExceptionError(result));
+}
+
static Dart_WeakPersistentHandle weak1 = NULL;
static Dart_WeakPersistentHandle weak2 = NULL;
static Dart_WeakPersistentHandle weak3 = NULL;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e7fb75d..68a8470 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -14393,6 +14393,7 @@
all_libs.Add(&Library::ZoneHandle(Library::ConvertLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::InternalLibrary()));
all_libs.Add(&Library::ZoneHandle(Library::FfiLibrary()));
+ all_libs.Add(&Library::ZoneHandle(Library::NativeWrappersLibrary()));
INTERNAL_LIB_INTRINSIC_LIST(CHECK_FINGERPRINTS_ASM_INTRINSIC);
OTHER_RECOGNIZED_LIST(CHECK_FINGERPRINTS_OTHER);
POLYMORPHIC_TARGET_LIST(CHECK_FINGERPRINTS);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 39b4940..5caf25f 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3101,7 +3101,7 @@
bool ForceOptimize() const {
return IsFfiFromAddress() || IsFfiGetAddress() || IsFfiLoad() ||
IsFfiStore() || IsFfiTrampoline() || IsTypedDataViewFactory() ||
- IsUtf8Scan();
+ IsUtf8Scan() || IsGetNativeField();
}
bool CanBeInlined() const;
@@ -3433,6 +3433,11 @@
return kind == MethodRecognizer::kFfiGetAddress;
}
+ bool IsGetNativeField() const {
+ const auto kind = recognized_kind();
+ return kind == MethodRecognizer::kGetNativeField;
+ }
+
bool IsUtf8Scan() const {
const auto kind = recognized_kind();
return kind == MethodRecognizer::kUtf8DecoderScan;
@@ -7423,6 +7428,8 @@
static intptr_t NextFieldOffset() { return sizeof(UntaggedInstance); }
+ static intptr_t NativeFieldsOffset() { return sizeof(UntaggedObject); }
+
protected:
#ifndef PRODUCT
virtual void PrintSharedInstanceJSON(JSONObject* jsobj, bool ref) const;
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 58b4696..f89ccf7 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -282,6 +282,9 @@
Sample* next = previous->is_allocation_sample()
? buffer->ReserveAllocationSample(isolate)
: buffer->ReserveCPUSample(isolate);
+ if (next == nullptr) {
+ return nullptr; // No blocks left, so drop sample.
+ }
next->Init(previous->port(), previous->timestamp(), previous->tid());
next->set_head_sample(false);
// Mark that previous continues at next.
diff --git a/sdk/lib/html/dartium/nativewrappers.dart b/sdk/lib/html/dartium/nativewrappers.dart
index b6d2dc4..1d7787e 100644
--- a/sdk/lib/html/dartium/nativewrappers.dart
+++ b/sdk/lib/html/dartium/nativewrappers.dart
@@ -6,8 +6,18 @@
class NativeFieldWrapperClass1 {}
-class NativeFieldWrapperClass2 {}
+class NativeFieldWrapperClass2 extends NativeFieldWrapperClass1 {}
-class NativeFieldWrapperClass3 {}
+class NativeFieldWrapperClass3 extends NativeFieldWrapperClass2 {}
-class NativeFieldWrapperClass4 {}
+class NativeFieldWrapperClass4 extends NativeFieldWrapperClass3 {}
+
+/// Gets the value of the native field of [object].
+///
+/// Throws an exception if [object] is null or if the native field was not set.
+///
+/// NOTE: This is function is temporary and will be deprecated in the near
+/// future.
+@pragma("vm:recognized", "other")
+int getNativeField(NativeFieldWrapperClass1 object)
+ native "FullyRecognizedMethod_NoNative";
diff --git a/tools/VERSION b/tools/VERSION
index dafe7ec..0e661f7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 360
+PRERELEASE 361
PRERELEASE_PATCH 0
\ No newline at end of file