Version 2.14.0-344.0.dev
Merge commit 'b89c35472f7b5cf41be01111620f92c644cb4c74' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 666d9be..41a201a 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2361,6 +2361,15 @@
/// children of this element's parent.
String get identifier => name!;
+ /// Return `true` if this element was created from a macro-generated code.
+ bool get isFromMacro {
+ return hasModifier(Modifier.IS_FROM_MACRO);
+ }
+
+ set isFromMacro(bool isFromMacro) {
+ setModifier(Modifier.IS_FROM_MACRO, isFromMacro);
+ }
+
bool get isNonFunctionTypeAliasesEnabled {
return library!.featureSet.isEnabled(Feature.nonfunction_type_aliases);
}
@@ -4281,23 +4290,26 @@
/// type being referred to is the return type.
static const Modifier IMPLICIT_TYPE = Modifier('IMPLICIT_TYPE', 16);
+ /// Indicates that this element was created from macro-generated code.
+ static const Modifier IS_FROM_MACRO = Modifier('IS_FROM_MACRO', 17);
+
/// Indicates that modifier 'lazy' was applied to the element.
- static const Modifier LATE = Modifier('LATE', 17);
+ static const Modifier LATE = Modifier('LATE', 18);
/// Indicates that a class is a mixin application.
- static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 18);
+ static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 19);
/// Indicates that the pseudo-modifier 'set' was applied to the element.
- static const Modifier SETTER = Modifier('SETTER', 19);
+ static const Modifier SETTER = Modifier('SETTER', 20);
/// Indicates that the modifier 'static' was applied to the element.
- static const Modifier STATIC = Modifier('STATIC', 20);
+ static const Modifier STATIC = Modifier('STATIC', 21);
/// Indicates that the element does not appear in the source code but was
/// implicitly created. For example, if a class does not define any
/// constructors, an implicit zero-argument constructor will be created and it
/// will be marked as being synthetic.
- static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 21);
+ static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 22);
static const List<Modifier> values = [
ABSTRACT,
@@ -4316,6 +4328,7 @@
HAS_INITIALIZER,
HAS_PART_OF_DIRECTIVE,
IMPLICIT_TYPE,
+ IS_FROM_MACRO,
LATE,
MIXIN_APPLICATION,
SETTER,
diff --git a/pkg/analyzer/lib/src/macro/api/code.dart b/pkg/analyzer/lib/src/macro/api/code.dart
new file mode 100644
index 0000000..0c06310
--- /dev/null
+++ b/pkg/analyzer/lib/src/macro/api/code.dart
@@ -0,0 +1,58 @@
+// 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.
+
+/// Combines [parts] into a [String].
+/// Must only contain [Code] or [String] instances.
+String _combineParts(List<Object> parts) {
+ var buffer = StringBuffer();
+ for (var part in parts) {
+ if (part is String) {
+ buffer.write(part);
+ } else if (part is Code) {
+ buffer.write(part.code);
+ } else if (part is List<Code>) {
+ buffer.write(part.map((p) => p.code).join());
+ } else {
+ throw UnsupportedError(
+ 'Only String, Code, and List<Code> are allowed but got $part',
+ );
+ }
+ }
+ return buffer.toString();
+}
+
+/// The representation of a piece of code.
+abstract class Code {
+ String get code;
+
+ @override
+ String toString() => code;
+}
+
+/// A piece of code representing a syntactically valid declaration.
+class Declaration extends Code {
+ @override
+ final String code;
+
+ Declaration(this.code);
+
+ /// Creates a [Declaration] from [parts], which must be of type [Code],
+ /// `List<Code>`, or [String].
+ factory Declaration.fromParts(List<Object> parts) =>
+ Declaration(_combineParts(parts));
+}
+
+/// A piece of code that can't be parsed into a valid language construct in its
+/// current form. No validation or parsing is performed.
+class Fragment extends Code {
+ @override
+ final String code;
+
+ Fragment(this.code);
+
+ /// Creates a [Fragment] from [parts], which must be of type [Code],
+ /// `List<Code>`, or [String].
+ factory Fragment.fromParts(List<Object> parts) =>
+ Fragment(_combineParts(parts));
+}
diff --git a/pkg/analyzer/lib/src/macro/api/macro.dart b/pkg/analyzer/lib/src/macro/api/macro.dart
new file mode 100644
index 0000000..0f65d38
--- /dev/null
+++ b/pkg/analyzer/lib/src/macro/api/macro.dart
@@ -0,0 +1,72 @@
+// 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.
+
+import 'package:analyzer/dart/ast/ast.dart' as ast;
+import 'package:analyzer/src/macro/api/code.dart';
+
+/// The api used by [DeclarationMacro]s to contribute new declarations to the
+/// current class.
+///
+/// Note that this is available to macros that run directly on classes, as well
+/// as macros that run on any members of a class.
+abstract class ClassDeclarationBuilder implements DeclarationBuilder {
+ /// Adds a new declaration to the surrounding class.
+ void addToClass(Declaration declaration);
+}
+
+/// The api used by [DeclarationMacro]s to contribute new declarations to the
+/// current library.
+abstract class DeclarationBuilder {
+ /// Adds a new regular declaration to the surrounding library.
+ ///
+ /// Note that type declarations are not supported.
+ void addToLibrary(Declaration declaration);
+
+ /// Return the [Code] of the [node].
+ Code typeAnnotationCode(ast.TypeAnnotation node);
+}
+
+/// The marker interface for macros that are allowed to contribute new
+/// declarations to the program, including both top level and class level
+/// declarations.
+///
+/// These macros run after [TypeMacro] macros, but before [DefinitionMacro]
+/// macros.
+///
+/// These macros can resolve type annotations to specific declarations, and
+/// inspect type hierarchies, but they cannot inspect the declarations on those
+/// type annotations, since new declarations could still be added in this phase.
+abstract class DeclarationMacro implements Macro {}
+
+/// The marker interface for macros that are only allowed to implement or wrap
+/// existing declarations in the program. They cannot introduce any new
+/// declarations that are visible to the program, but are allowed to add
+/// declarations that only they can see.
+///
+/// These macros run after all other types of macros.
+///
+/// These macros can fully reflect on the program since the static shape is
+/// fully defined by the time they run.
+abstract class DefinitionMacro implements Macro {}
+
+/// The interface for [DeclarationMacro]s that can be applied to fields.
+abstract class FieldDeclarationMacro implements DeclarationMacro {
+ void visitFieldDeclaration(
+ ast.FieldDeclaration declaration,
+ ClassDeclarationBuilder builder,
+ );
+}
+
+/// The marker interface for all types of macros.
+abstract class Macro {}
+
+/// The marker interface for macros that are allowed to contribute new type
+/// declarations into the program.
+///
+/// These macros run before all other types of macros.
+///
+/// In exchange for the power to add new type declarations, these macros have
+/// limited introspections capabilities, since new types can be added in this
+/// phase you cannot follow type references back to their declarations.
+abstract class TypeMacro implements Macro {}
diff --git a/pkg/analyzer/lib/src/macro/builders/observable.dart b/pkg/analyzer/lib/src/macro/builders/observable.dart
new file mode 100644
index 0000000..6857d34
--- /dev/null
+++ b/pkg/analyzer/lib/src/macro/builders/observable.dart
@@ -0,0 +1,48 @@
+// 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.
+
+import 'package:analyzer/dart/ast/ast.dart' as ast;
+import 'package:analyzer/src/macro/api/code.dart';
+import 'package:analyzer/src/macro/api/macro.dart';
+
+class ObservableMacro implements FieldDeclarationMacro {
+ const ObservableMacro();
+
+ @override
+ void visitFieldDeclaration(
+ ast.FieldDeclaration node,
+ ClassDeclarationBuilder builder,
+ ) {
+ var typeNode = node.fields.type;
+ if (typeNode == null) {
+ throw ArgumentError('@observable can only annotate typed fields.');
+ }
+ var typeCode = builder.typeAnnotationCode(typeNode);
+
+ var fields = node.fields.variables;
+ for (var field in fields) {
+ var name = field.name.name;
+ if (!name.startsWith('_')) {
+ throw ArgumentError(
+ '@observable can only annotate private fields, and it will create '
+ 'public getters and setters for them, but the public field '
+ '$name was annotated.',
+ );
+ }
+ var publicName = name.substring(1);
+
+ var getter = Declaration(
+ '$typeCode get $publicName => $name;',
+ );
+ builder.addToClass(getter);
+
+ var setter = Declaration('''
+set $publicName($typeCode val) {
+ print('Setting $publicName to \${val}');
+ $name = val;
+}''');
+ builder.addToClass(setter);
+ }
+ }
+}
diff --git a/pkg/analyzer/lib/src/macro/impl/macro.dart b/pkg/analyzer/lib/src/macro/impl/macro.dart
new file mode 100644
index 0000000..6459a6c
--- /dev/null
+++ b/pkg/analyzer/lib/src/macro/impl/macro.dart
@@ -0,0 +1,54 @@
+// 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.
+
+import 'package:analyzer/dart/analysis/utilities.dart';
+import 'package:analyzer/dart/ast/ast.dart' as ast;
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/ast.dart' as ast;
+import 'package:analyzer/src/macro/api/code.dart';
+import 'package:analyzer/src/macro/api/macro.dart';
+
+class ClassDeclarationBuilderImpl extends DeclarationBuilderImpl
+ implements ClassDeclarationBuilder {
+ final ast.ClassDeclarationImpl node;
+
+ ClassDeclarationBuilderImpl(this.node);
+
+ @override
+ void addToClass(Declaration declaration) {
+ // TODO(scheglov) feature set
+ // TODO(scheglov) throw if errors?
+ var parseResult = parseString(
+ content: 'class ${node.name.name} { $declaration }',
+ );
+ var parsedDeclarations = parseResult.unit.declarations;
+ var parsedClass = parsedDeclarations.single as ast.ClassDeclaration;
+ var parsedMember = parsedClass.members.single;
+ _resetOffsets(parsedMember);
+
+ node.members.add(parsedMember);
+ }
+
+ /// We parsed [node] in the context of some synthetic code string, its
+ /// current offsets are meaningless. So, we reset them for now.
+ static void _resetOffsets(ast.AstNode node) {
+ for (Token? t = node.beginToken;
+ t != null && t != node.endToken;
+ t = t.next) {
+ t.offset = -1;
+ }
+ }
+}
+
+class DeclarationBuilderImpl implements DeclarationBuilder {
+ @override
+ void addToLibrary(Declaration declaration) {
+ // TODO: implement addToLibrary
+ }
+
+ @override
+ Code typeAnnotationCode(ast.TypeAnnotation node) {
+ return Fragment(node.toSource());
+ }
+}
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 3737f6e..983c60a 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -89,6 +89,34 @@
}
}
+ /// Build elements for [members] and add into the [element].
+ void buildMacroClassMembers(
+ ClassElementImpl element,
+ List<ClassMember> members,
+ ) {
+ var holder = _buildClassMembers(element, members);
+
+ for (var newElement in holder.propertyAccessors) {
+ newElement.isFromMacro = true;
+ element.accessors.add(newElement);
+ }
+
+ for (var newElement in holder.constructors) {
+ newElement.isFromMacro = true;
+ element.constructors.add(newElement);
+ }
+
+ for (var newElement in holder.properties.whereType<FieldElementImpl>()) {
+ newElement.isFromMacro = true;
+ element.fields.add(newElement);
+ }
+
+ for (var newElement in holder.methods) {
+ newElement.isFromMacro = true;
+ element.methods.add(newElement);
+ }
+ }
+
@override
void visitClassDeclaration(covariant ClassDeclarationImpl node) {
var nameNode = node.name;
@@ -868,7 +896,7 @@
}
_EnclosingContext _buildClassMembers(
- ElementImpl element, NodeList<ClassMember> members) {
+ ElementImpl element, List<ClassMember> members) {
var hasConstConstructor = members.any((e) {
return e is ConstructorDeclaration && e.constKeyword != null;
});
diff --git a/pkg/analyzer/lib/src/summary2/element_flags.dart b/pkg/analyzer/lib/src/summary2/element_flags.dart
index e808000..f43df16 100644
--- a/pkg/analyzer/lib/src/summary2/element_flags.dart
+++ b/pkg/analyzer/lib/src/summary2/element_flags.dart
@@ -8,12 +8,14 @@
class ClassElementFlags {
static const int _isAbstract = 1 << 0;
- static const int _isMixinApplication = 1 << 1;
- static const int _isSimplyBounded = 1 << 2;
+ static const int _isFromMacro = 1 << 1;
+ static const int _isMixinApplication = 1 << 2;
+ static const int _isSimplyBounded = 1 << 3;
static void read(SummaryDataReader reader, ClassElementImpl element) {
var byte = reader.readByte();
element.isAbstract = (byte & _isAbstract) != 0;
+ element.isFromMacro = (byte & _isFromMacro) != 0;
element.isMixinApplication = (byte & _isMixinApplication) != 0;
element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
}
@@ -21,6 +23,7 @@
static void write(BufferedSink sink, ClassElementImpl element) {
var result = 0;
result |= element.isAbstract ? _isAbstract : 0;
+ result |= element.isFromMacro ? _isFromMacro : 0;
result |= element.isMixinApplication ? _isMixinApplication : 0;
result |= element.isSimplyBounded ? _isSimplyBounded : 0;
sink.writeByte(result);
@@ -60,8 +63,9 @@
static const int _isCovariant = 1 << 5;
static const int _isExternal = 1 << 6;
static const int _isFinal = 1 << 7;
- static const int _isLate = 1 << 8;
- static const int _isStatic = 1 << 9;
+ static const int _isFromMacro = 1 << 8;
+ static const int _isLate = 1 << 9;
+ static const int _isStatic = 1 << 10;
static void read(SummaryDataReader reader, FieldElementImpl element) {
var byte = reader.readUInt30();
@@ -73,6 +77,7 @@
element.isCovariant = (byte & _isCovariant) != 0;
element.isExternal = (byte & _isExternal) != 0;
element.isFinal = (byte & _isFinal) != 0;
+ element.isFromMacro = (byte & _isFromMacro) != 0;
element.isLate = (byte & _isLate) != 0;
element.isStatic = (byte & _isStatic) != 0;
}
@@ -87,6 +92,7 @@
result |= element.isCovariant ? _isCovariant : 0;
result |= element.isExternal ? _isExternal : 0;
result |= element.isFinal ? _isFinal : 0;
+ result |= element.isFromMacro ? _isFromMacro : 0;
result |= element.isLate ? _isLate : 0;
result |= element.isStatic ? _isStatic : 0;
sink.writeUInt30(result);
@@ -161,8 +167,9 @@
static const int _isAbstract = 1 << 1;
static const int _isAsynchronous = 1 << 2;
static const int _isExternal = 1 << 3;
- static const int _isGenerator = 1 << 4;
- static const int _isStatic = 1 << 5;
+ static const int _isFromMacro = 1 << 4;
+ static const int _isGenerator = 1 << 5;
+ static const int _isStatic = 1 << 6;
static void read(SummaryDataReader reader, MethodElementImpl element) {
var byte = reader.readByte();
@@ -170,6 +177,7 @@
element.isAbstract = (byte & _isAbstract) != 0;
element.isAsynchronous = (byte & _isAsynchronous) != 0;
element.isExternal = (byte & _isExternal) != 0;
+ element.isFromMacro = (byte & _isFromMacro) != 0;
element.isGenerator = (byte & _isGenerator) != 0;
element.isStatic = (byte & _isStatic) != 0;
}
@@ -180,6 +188,7 @@
result |= element.isAbstract ? _isAbstract : 0;
result |= element.isAsynchronous ? _isAsynchronous : 0;
result |= element.isExternal ? _isExternal : 0;
+ result |= element.isFromMacro ? _isFromMacro : 0;
result |= element.isGenerator ? _isGenerator : 0;
result |= element.isStatic ? _isStatic : 0;
sink.writeByte(result);
@@ -217,8 +226,9 @@
static const int _isAbstract = 1 << 3;
static const int _isAsynchronous = 1 << 4;
static const int _isExternal = 1 << 5;
- static const int _isGenerator = 1 << 6;
- static const int _isStatic = 1 << 7;
+ static const int _isFromMacro = 1 << 6;
+ static const int _isGenerator = 1 << 7;
+ static const int _isStatic = 1 << 8;
static void read(
SummaryDataReader reader,
@@ -231,6 +241,7 @@
element.isAbstract = (byte & _isAbstract) != 0;
element.isAsynchronous = (byte & _isAsynchronous) != 0;
element.isExternal = (byte & _isExternal) != 0;
+ element.isFromMacro = (byte & _isFromMacro) != 0;
element.isGenerator = (byte & _isGenerator) != 0;
element.isStatic = (byte & _isStatic) != 0;
}
@@ -243,6 +254,7 @@
result |= element.isAbstract ? _isAbstract : 0;
result |= element.isAsynchronous ? _isAsynchronous : 0;
result |= element.isExternal ? _isExternal : 0;
+ result |= element.isFromMacro ? _isFromMacro : 0;
result |= element.isGenerator ? _isGenerator : 0;
result |= element.isStatic ? _isStatic : 0;
sink.writeUInt30(result);
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index ba1e230..e500aa1 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -9,6 +9,8 @@
import 'package:analyzer/src/dart/ast/mixin_super_invoked_names.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
+import 'package:analyzer/src/macro/builders/observable.dart' as macro;
+import 'package:analyzer/src/macro/impl/macro.dart' as macro;
import 'package:analyzer/src/summary2/combinator.dart';
import 'package:analyzer/src/summary2/constructor_initializer_resolver.dart';
import 'package:analyzer/src/summary2/default_value_resolver.dart';
@@ -159,18 +161,69 @@
void resolveTypes(NodesToBuildType nodesToBuildType) {
for (var linkingUnit in units) {
- var resolver = ReferenceResolver(
- linker,
- nodesToBuildType,
- linker.elementFactory,
- element,
- linkingUnit.reference,
- linkingUnit.node.featureSet.isEnabled(Feature.non_nullable),
- );
+ var resolver = _newTypeReferenceResolver(nodesToBuildType, linkingUnit);
linkingUnit.node.accept(resolver);
}
}
+ /// Run built-in declaration macros.
+ void runDeclarationMacros() {
+ bool hasMacroAnnotation(ast.AnnotatedNode node, String name) {
+ for (var annotation in node.metadata) {
+ var nameNode = annotation.name;
+ if (nameNode is ast.SimpleIdentifier &&
+ annotation.arguments == null &&
+ annotation.constructorName == null &&
+ nameNode.name == name) {
+ var nameElement = element.scope.lookup(name).getter;
+ return nameElement != null &&
+ nameElement.library?.name == 'analyzer.macro.annotations';
+ }
+ }
+ return false;
+ }
+
+ for (var linkingUnit in units) {
+ for (var declaration in linkingUnit.node.declarations) {
+ if (declaration is ast.ClassDeclarationImpl) {
+ var members = declaration.members.toList();
+ for (var member in members) {
+ if (member is ast.FieldDeclarationImpl) {
+ if (hasMacroAnnotation(member, 'observable')) {
+ macro.ObservableMacro().visitFieldDeclaration(
+ member,
+ macro.ClassDeclarationBuilderImpl(declaration),
+ );
+ }
+ }
+ }
+
+ var newMembers = declaration.members.sublist(members.length);
+ if (newMembers.isNotEmpty) {
+ var elementBuilder = ElementBuilder(
+ libraryBuilder: this,
+ unitReference: linkingUnit.reference,
+ unitElement: linkingUnit.element,
+ );
+ var classElement = declaration.declaredElement as ClassElementImpl;
+ elementBuilder.buildMacroClassMembers(classElement, newMembers);
+
+ // TODO(scheglov) extract
+ {
+ var nodesToBuildType = NodesToBuildType();
+ var resolver =
+ _newTypeReferenceResolver(nodesToBuildType, linkingUnit);
+ for (var newMember in newMembers) {
+ newMember.accept(resolver);
+ }
+ TypesBuilder(linker).build(nodesToBuildType);
+ }
+ }
+ }
+ }
+ }
+ }
+
void storeExportScope() {
exports = exportScope.map.values.toList();
linker.elementFactory.setExportsOfLibrary('$uri', exports);
@@ -205,6 +258,21 @@
}
}
+ ReferenceResolver _newTypeReferenceResolver(
+ NodesToBuildType nodesToBuildType,
+ LinkingUnit linkingUnit,
+ ) {
+ /// TODO(scheglov) Do we need all these parameters?
+ return ReferenceResolver(
+ linker,
+ nodesToBuildType,
+ linker.elementFactory,
+ element,
+ linkingUnit.reference,
+ linkingUnit.node.featureSet.isEnabled(Feature.non_nullable),
+ );
+ }
+
static void build(Linker linker, LinkInputLibrary inputLibrary) {
var elementFactory = linker.elementFactory;
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index f0b0174..d0fe559 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -93,6 +93,7 @@
_createTypeSystem();
_buildEnumChildren();
_resolveTypes();
+ _runDeclarationMacros();
_performTopLevelInference();
_resolveConstructors();
_resolveConstantInitializers();
@@ -213,6 +214,12 @@
TypesBuilder(this).build(nodesToBuildType);
}
+ void _runDeclarationMacros() {
+ for (var library in builders.values) {
+ library.runDeclarationMacros();
+ }
+ }
+
void _writeLibraries() {
var bundleWriter = BundleWriter(
elementFactory.dynamicRef,
diff --git a/pkg/analyzer/test/src/dart/resolution/macro_test.dart b/pkg/analyzer/test/src/dart/resolution/macro_test.dart
new file mode 100644
index 0000000..4dd8ebc
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/macro_test.dart
@@ -0,0 +1,47 @@
+// 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.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../generated/elements_types_mixin.dart';
+import 'context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(MacroResolutionTest);
+ });
+}
+
+@reflectiveTest
+class MacroResolutionTest extends PubPackageResolutionTest
+ with ElementsTypesMixin {
+ @override
+ void setUp() {
+ super.setUp();
+
+ newFile('$testPackageLibPath/macro_annotations.dart', content: r'''
+library analyzer.macro.annotations;
+const observable = 0;
+''');
+ }
+
+ test_observable() async {
+ await assertErrorsInCode(r'''
+import 'macro_annotations.dart';
+
+class A {
+ @observable
+ int _foo = 0;
+}
+
+void f(A a) {
+ a.foo;
+ a.foo = 2;
+}
+''', [
+ error(HintCode.UNUSED_FIELD, 64, 4),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/test_all.dart b/pkg/analyzer/test/src/dart/resolution/test_all.dart
index 5f1c71d..08c23ad 100644
--- a/pkg/analyzer/test/src/dart/resolution/test_all.dart
+++ b/pkg/analyzer/test/src/dart/resolution/test_all.dart
@@ -42,6 +42,7 @@
import 'library_element_test.dart' as library_element;
import 'local_function_test.dart' as local_function;
import 'local_variable_test.dart' as local_variable;
+import 'macro_test.dart' as macro;
import 'metadata_test.dart' as metadata;
import 'method_declaration_test.dart' as method_declaration;
import 'method_invocation_test.dart' as method_invocation;
@@ -101,6 +102,7 @@
library_element.main();
local_function.main();
local_variable.main();
+ macro.main();
metadata.main();
method_declaration.main();
method_invocation.main();
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index acbd956..e7884a5 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -645,6 +645,8 @@
}
void _writePropertyAccessorElement(PropertyAccessorElement e) {
+ e as PropertyAccessorElementImpl;
+
PropertyInducingElement variable = e.variable;
expect(variable, isNotNull);
@@ -667,7 +669,7 @@
}
}
- if (e.isSynthetic) {
+ if (e.isSynthetic || e.isFromMacro) {
expect(e.nameOffset, -1);
} else {
expect(e.nameOffset, isPositive);
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index caee60d..8c5f16e 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -21246,6 +21246,58 @@
''');
}
+ test_macro_observable() async {
+ addLibrarySource('/macro_annotations.dart', r'''
+library analyzer.macro.annotations;
+const observable = 0;
+''');
+ var library = await checkLibrary(r'''
+import 'macro_annotations.dart';
+class A {
+ @observable
+ int _f = 0;
+}
+''');
+ checkElementText(library, r'''
+library
+ imports
+ macro_annotations.dart
+ definingUnit
+ classes
+ class A @39
+ fields
+ _f @63
+ metadata
+ Annotation
+ atSign: @ @45
+ element: macro_annotations.dart::@getter::observable
+ name: SimpleIdentifier
+ staticElement: macro_annotations.dart::@getter::observable
+ staticType: null
+ token: observable @46
+ type: int
+ synthetic f @-1
+ type: int
+ constructors
+ synthetic @-1
+ accessors
+ synthetic get _f @-1
+ returnType: int
+ synthetic set _f @-1
+ parameters
+ requiredPositional __f @-1
+ type: int
+ returnType: void
+ get f @-1
+ returnType: int
+ set f @-1
+ parameters
+ requiredPositional val @-1
+ type: int
+ returnType: void
+''');
+ }
+
test_main_class() async {
var library = await checkLibrary('class main {}');
checkElementText(library, r'''
diff --git a/pkg/dds/lib/src/dap/adapters/dart.dart b/pkg/dds/lib/src/dap/adapters/dart.dart
index d7811e0..64b66be 100644
--- a/pkg/dds/lib/src/dap/adapters/dart.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart.dart
@@ -139,6 +139,9 @@
/// processed its initial paused state).
Future<void> get debuggerInitialized => _debuggerInitializedCompleter.future;
+ bool get evaluateToStringInDebugViews =>
+ args.evaluateToStringInDebugViews ?? false;
+
/// [attachRequest] is called by the client when it wants us to to attach to
/// an existing app. This will only be called once (and only one of this or
/// launchRequest will be called).
@@ -318,6 +321,15 @@
sendResponse(protocols?.toJson());
break;
+ /// Used to toggle debug settings such as whether SDK/Packages are
+ /// debuggable while the session is in progress.
+ case 'updateDebugOptions':
+ if (args != null) {
+ await _updateDebugOptions(args.args);
+ }
+ sendResponse(null);
+ break;
+
default:
await super.customRequest(request, args, sendResponse);
}
@@ -421,7 +433,7 @@
final resultString = await _converter.convertVmInstanceRefToDisplayString(
thread,
result,
- allowCallingToString: true,
+ allowCallingToString: evaluateToStringInDebugViews,
);
// TODO(dantup): We may need to store `expression` with this data
// to allow building nested evaluateNames.
@@ -845,7 +857,8 @@
thread,
variable.value,
name: variable.name,
- allowCallingToString: index <= maxToStringsPerEvaluation,
+ allowCallingToString: evaluateToStringInDebugViews &&
+ index <= maxToStringsPerEvaluation,
);
}
@@ -871,6 +884,7 @@
variables.addAll(await _converter.convertVmInstanceToVariablesList(
thread,
object,
+ allowCallingToString: evaluateToStringInDebugViews,
startItem: childStart,
numItems: childCount,
));
@@ -972,8 +986,15 @@
if (ref == null || ref.kind == vm.InstanceKind.kNull) {
return null;
}
- // TODO(dantup): This should handle truncation and complex types.
- return ref.valueAsString;
+ return _converter.convertVmInstanceRefToDisplayString(
+ thread,
+ ref,
+ // Always allow calling toString() here as the user expects the full
+ // string they logged regardless of the evaluateToStringInDebugViews
+ // setting.
+ allowCallingToString: true,
+ includeQuotesAroundString: false,
+ );
}
var loggerName = await asString(record.loggerName);
@@ -987,13 +1008,13 @@
final prefix = '[$loggerName] ';
if (message != null) {
- sendPrefixedOutput('stdout', prefix, '$message\n');
+ sendPrefixedOutput('console', prefix, '$message\n');
}
if (error != null) {
- sendPrefixedOutput('stderr', prefix, '$error\n');
+ sendPrefixedOutput('console', prefix, '$error\n');
}
if (stack != null) {
- sendPrefixedOutput('stderr', prefix, '$stack\n');
+ sendPrefixedOutput('console', prefix, '$stack\n');
}
}
@@ -1009,7 +1030,29 @@
// Notify IsolateManager if we'll be debugging so it knows whether to set
// up breakpoints etc. when isolates are registered.
final debug = !(args.noDebug ?? false);
- _isolateManager.setDebugEnabled(debug);
+ _isolateManager.debug = debug;
+ _isolateManager.debugSdkLibraries = args.debugSdkLibraries ?? true;
+ _isolateManager.debugExternalPackageLibraries =
+ args.debugExternalPackageLibraries ?? true;
+ }
+
+ /// Updates the current debug options for the session.
+ ///
+ /// Clients may not know about all debug options, so anything not included
+ /// in the map will not be updated by this method.
+ Future<void> _updateDebugOptions(Map<String, Object?> args) async {
+ // TODO(dantup): Document this - it's a public API we expect to be used
+ // by editors that can support it (although it will require custom
+ // code as it's there's no DAP standard for this, or the settings it
+ // toggles).
+ if (args.containsKey('debugSdkLibraries')) {
+ _isolateManager.debugSdkLibraries = args['debugSdkLibraries'] as bool;
+ }
+ if (args.containsKey('debugExternalPackageLibraries')) {
+ _isolateManager.debugExternalPackageLibraries =
+ args['debugExternalPackageLibraries'] as bool;
+ }
+ await _isolateManager.applyDebugOptions();
}
/// A wrapper around the same name function from package:vm_service that
diff --git a/pkg/dds/lib/src/dap/adapters/dart_cli.dart b/pkg/dds/lib/src/dap/adapters/dart_cli.dart
index b0fd701..c01214d 100644
--- a/pkg/dds/lib/src/dap/adapters/dart_cli.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart_cli.dart
@@ -53,7 +53,9 @@
enableDds: enableDds,
enableAuthCodes: enableAuthCodes,
logger: logger,
- );
+ ) {
+ channel.closed.then((_) => shutdown());
+ }
Future<void> debuggerConnected(vm.VM vmInfo) async {
if (!isAttach) {
diff --git a/pkg/dds/lib/src/dap/base_debug_adapter.dart b/pkg/dds/lib/src/dap/base_debug_adapter.dart
index cd2b99a..a74f1f3 100644
--- a/pkg/dds/lib/src/dap/base_debug_adapter.dart
+++ b/pkg/dds/lib/src/dap/base_debug_adapter.dart
@@ -65,14 +65,7 @@
RawRequestArguments? args,
void Function(Object?) sendResponse,
) async {
- final response = Response(
- success: false,
- requestSeq: request.seq,
- seq: _sequence++,
- command: request.command,
- message: 'Unknown command: ${request.command}',
- );
- sendResponse(response);
+ throw DebugAdapterException('Unknown command ${request.command}');
}
Future<void> disconnectRequest(
@@ -251,7 +244,7 @@
} else if (message is Response) {
_handleIncomingResponse(message);
} else {
- throw Exception('Unknown Protocol message ${message.type}');
+ throw DebugAdapterException('Unknown Protocol message ${message.type}');
}
}
diff --git a/pkg/dds/lib/src/dap/isolate_manager.dart b/pkg/dds/lib/src/dap/isolate_manager.dart
index 99ee743..9c16536 100644
--- a/pkg/dds/lib/src/dap/isolate_manager.dart
+++ b/pkg/dds/lib/src/dap/isolate_manager.dart
@@ -23,15 +23,33 @@
final Map<int, ThreadInfo> _threadsByThreadId = {};
int _nextThreadNumber = 1;
- /// Whether debugging is enabled.
+ /// Whether debugging is enabled for this session.
///
/// This must be set before any isolates are spawned and controls whether
/// breakpoints or exception pause modes are sent to the VM.
///
+ /// If false, requests to send breakpoints or exception pause mode will be
+ /// dropped. Other functionality (handling pause events, resuming, etc.) will
+ /// all still function.
+ ///
/// This is used to support debug sessions that have VM Service connections
/// but were run with noDebug: true (for example we may need a VM Service
/// connection for a noDebug flutter app in order to support hot reload).
- bool _debug = false;
+ bool debug = false;
+
+ /// Whether SDK libraries should be marked as debuggable.
+ ///
+ /// Calling [sendLibraryDebuggables] is required after changing this value to
+ /// apply changes. This allows applying both [debugSdkLibraries] and
+ /// [debugExternalPackageLibraries] in one step.
+ bool debugSdkLibraries = true;
+
+ /// Whether external package libraries should be marked as debuggable.
+ ///
+ /// Calling [sendLibraryDebuggables] is required after changing this value to
+ /// apply changes. This allows applying both [debugSdkLibraries] and
+ /// [debugExternalPackageLibraries] in one step.
+ bool debugExternalPackageLibraries = true;
/// Tracks breakpoints last provided by the client so they can be sent to new
/// isolates that appear after initial breakpoints were sent.
@@ -72,6 +90,18 @@
/// not exited between accessing this list and trying to use the results.
List<ThreadInfo> get threads => _threadsByIsolateId.values.toList();
+ /// Re-applies debug options to all isolates/libraries.
+ ///
+ /// This is required if options like debugSdkLibraries are modified, but is a
+ /// separate step to batch together changes to multiple options.
+ Future<void> applyDebugOptions() async {
+ await Future.wait(_threadsByThreadId.values.map(
+ // debuggable libraries is the only thing currently affected by these
+ // changable options.
+ (isolate) => _sendLibraryDebuggables(isolate.isolate),
+ ));
+ }
+
Future<T> getObject<T extends vm.Response>(
vm.IsolateRef isolate, vm.ObjRef object) async {
final res = await _adapter.vmService?.getObject(isolate.id!, object.id!);
@@ -219,19 +249,6 @@
.map((isolate) => _sendBreakpoints(isolate.isolate, uri: uri)));
}
- /// Sets whether debugging is enabled for this session.
- ///
- /// If not, requests to send breakpoints or exception pause mode will be
- /// dropped. Other functionality (handling pause events, resuming, etc.) will
- /// all still function.
- ///
- /// This is used to support debug sessions that have VM Service connections
- /// but were run with noDebug: true (for example we may need a VM Service
- /// connection for a noDebug flutter app in order to support hot reload).
- void setDebugEnabled(bool debug) {
- _debug = debug;
- }
-
/// Records exception pause mode as one of 'None', 'Unhandled' or 'All'. All
/// existing isolates will be updated to reflect the new setting.
Future<void> setExceptionPauseMode(String mode) async {
@@ -371,13 +388,13 @@
/// Checks whether a library should be considered debuggable.
///
- /// This usesthe settings from the launch arguments (debugSdkLibraries
- /// and debugExternalPackageLibraries) against the type of library given.
+ /// Initial values are provided in the launch arguments, but may be updated
+ /// by the `updateDebugOptions` custom request.
bool _libaryIsDebuggable(vm.LibraryRef library) {
if (_isSdkLibrary(library)) {
- return _adapter.args.debugSdkLibraries ?? false;
+ return debugSdkLibraries;
} else if (_isExternalPackageLibrary(library)) {
- return _adapter.args.debugExternalPackageLibraries ?? false;
+ return debugExternalPackageLibraries;
} else {
return true;
}
@@ -391,7 +408,7 @@
/// newly-created isolates).
Future<void> _sendBreakpoints(vm.IsolateRef isolate, {String? uri}) async {
final service = _adapter.vmService;
- if (!_debug || service == null) {
+ if (!debug || service == null) {
return;
}
@@ -425,7 +442,7 @@
/// Sets the exception pause mode for an individual isolate.
Future<void> _sendExceptionPauseMode(vm.IsolateRef isolate) async {
final service = _adapter.vmService;
- if (!_debug || service == null) {
+ if (!debug || service == null) {
return;
}
@@ -436,7 +453,7 @@
/// on the debug settings.
Future<void> _sendLibraryDebuggables(vm.IsolateRef isolateRef) async {
final service = _adapter.vmService;
- if (!_debug || service == null) {
+ if (!debug || service == null) {
return;
}
diff --git a/pkg/dds/lib/src/dap/protocol_converter.dart b/pkg/dds/lib/src/dap/protocol_converter.dart
index 85ef5f8..6285121 100644
--- a/pkg/dds/lib/src/dap/protocol_converter.dart
+++ b/pkg/dds/lib/src/dap/protocol_converter.dart
@@ -57,21 +57,32 @@
required bool allowCallingToString,
bool includeQuotesAroundString = true,
}) async {
- final canCallToString = allowCallingToString &&
- (_adapter.args.evaluateToStringInDebugViews ?? false);
+ final isTruncated = ref.valueAsStringIsTruncated ?? false;
+ if (ref.kind == vm.InstanceKind.kString && isTruncated) {
+ // Call toString() if allowed, otherwise (or if it returns null) fall back
+ // to the truncated value with "…" suffix.
+ var stringValue = allowCallingToString
+ ? await _callToString(
+ thread,
+ ref,
+ includeQuotesAroundString: includeQuotesAroundString,
+ )
+ : null;
+ stringValue ??= '${ref.valueAsString}…';
- if (ref.kind == 'String' || ref.valueAsString != null) {
- var stringValue = ref.valueAsString.toString();
- if (ref.valueAsStringIsTruncated ?? false) {
- stringValue = '$stringValue…';
- }
- if (ref.kind == 'String' && includeQuotesAroundString) {
- stringValue = '"$stringValue"';
- }
- return stringValue;
+ return includeQuotesAroundString ? '"$stringValue"' : stringValue;
+ } else if (ref.kind == vm.InstanceKind.kString) {
+ // Untruncated strings.
+ return includeQuotesAroundString
+ ? '"${ref.valueAsString}"'
+ : ref.valueAsString.toString();
+ } else if (ref.valueAsString != null) {
+ return isTruncated
+ ? '${ref.valueAsString}…'
+ : ref.valueAsString.toString();
} else if (ref.kind == 'PlainInstance') {
var stringValue = ref.classRef?.name ?? '<unknown instance>';
- if (canCallToString) {
+ if (allowCallingToString) {
final toStringValue = await _callToString(
thread,
ref,
@@ -99,6 +110,7 @@
Future<List<dap.Variable>> convertVmInstanceToVariablesList(
ThreadInfo thread,
vm.Instance instance, {
+ required bool allowCallingToString,
int? startItem = 0,
int? numItems,
}) async {
@@ -112,7 +124,7 @@
await convertVmResponseToVariable(
thread,
instance,
- allowCallingToString: true,
+ allowCallingToString: allowCallingToString,
)
];
} else if (elements != null) {
@@ -121,10 +133,15 @@
return Future.wait(elements
.cast<vm.Response>()
.sublist(start, numItems != null ? start + numItems : null)
- .mapIndexed((index, response) async => convertVmResponseToVariable(
- thread, response,
+ .mapIndexed(
+ (index, response) => convertVmResponseToVariable(
+ thread,
+ response,
name: '${start + index}',
- allowCallingToString: index <= maxToStringsPerEvaluation)));
+ allowCallingToString:
+ allowCallingToString && index <= maxToStringsPerEvaluation,
+ ),
+ ));
} else if (associations != null) {
// For maps, create a variable for each entry (in the requested subset).
// Use the keys and values to create a display string in the form
@@ -135,13 +152,14 @@
return Future.wait(associations
.sublist(start, numItems != null ? start + numItems : null)
.mapIndexed((index, mapEntry) async {
- final allowCallingToString = index <= maxToStringsPerEvaluation;
+ final callToString =
+ allowCallingToString && index <= maxToStringsPerEvaluation;
final keyDisplay = await convertVmResponseToDisplayString(
thread, mapEntry.key,
- allowCallingToString: allowCallingToString);
+ allowCallingToString: callToString);
final valueDisplay = await convertVmResponseToDisplayString(
thread, mapEntry.value,
- allowCallingToString: allowCallingToString);
+ allowCallingToString: callToString);
return dap.Variable(
name: '${start + index}',
value: '$keyDisplay -> $valueDisplay',
@@ -154,7 +172,8 @@
(index, field) async => convertVmResponseToVariable(
thread, field.value,
name: field.decl?.name ?? '<unnamed field>',
- allowCallingToString: index <= maxToStringsPerEvaluation)));
+ allowCallingToString:
+ allowCallingToString && index <= maxToStringsPerEvaluation)));
// Also evaluate the getters if evaluateGettersInDebugViews=true enabled.
final service = _adapter.vmService;
@@ -177,7 +196,8 @@
thread,
response,
name: getterName,
- allowCallingToString: index <= maxToStringsPerEvaluation,
+ allowCallingToString:
+ allowCallingToString && index <= maxToStringsPerEvaluation,
);
}
@@ -397,7 +417,7 @@
if (service == null) {
return null;
}
- final result = await service.invoke(
+ var result = await service.invoke(
thread.isolate.id!,
ref.id!,
'toString',
@@ -405,10 +425,18 @@
disableBreakpoints: true,
);
+ // If the response is a string and is truncated, use getObject() to get the
+ // full value.
+ if (result is vm.InstanceRef &&
+ result.kind == 'String' &&
+ (result.valueAsStringIsTruncated ?? false)) {
+ result = await service.getObject(thread.isolate.id!, result.id!);
+ }
+
return convertVmResponseToDisplayString(
thread,
result,
- allowCallingToString: false,
+ allowCallingToString: false, // Don't allow recursing.
includeQuotesAroundString: includeQuotesAroundString,
);
}
diff --git a/pkg/dds/lib/src/dap/protocol_stream_transformers.dart b/pkg/dds/lib/src/dap/protocol_stream_transformers.dart
index 6bd6caa..424fa84 100644
--- a/pkg/dds/lib/src/dap/protocol_stream_transformers.dart
+++ b/pkg/dds/lib/src/dap/protocol_stream_transformers.dart
@@ -4,7 +4,6 @@
import 'dart:async';
import 'dart:convert';
-import 'dart:typed_data';
class InvalidEncodingError {
final String headers;
@@ -107,28 +106,3 @@
final String? encoding;
ProtocolHeaders(this.rawHeaders, this.contentLength, this.encoding);
}
-
-/// Transforms a stream of [Uint8List]s to [List<int>]s. Used because
-/// [ServerSocket] and [Socket] use [Uint8List] but stdin and stdout use
-/// [List<int>] and the LSP server needs to operate against both.
-class Uint8ListTransformer extends StreamTransformerBase<Uint8List, List<int>> {
- // TODO(dantup): Is there a built-in (or better) way to do this?
- @override
- Stream<List<int>> bind(Stream<Uint8List> stream) {
- late StreamSubscription<Uint8List> input;
- late StreamController<List<int>> _output;
- _output = StreamController<List<int>>(
- onListen: () {
- input = stream.listen(
- (uints) => _output.add(uints),
- onError: _output.addError,
- onDone: _output.close,
- );
- },
- onPause: () => input.pause(),
- onResume: () => input.resume(),
- onCancel: () => input.cancel(),
- );
- return _output.stream;
- }
-}
diff --git a/pkg/dds/lib/src/dap/server.dart b/pkg/dds/lib/src/dap/server.dart
index f2530a3..8a38138 100644
--- a/pkg/dds/lib/src/dap/server.dart
+++ b/pkg/dds/lib/src/dap/server.dart
@@ -3,92 +3,45 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
-import 'dart:io';
import 'package:dds/src/dap/adapters/dart.dart';
-import 'package:pedantic/pedantic.dart';
import 'adapters/dart_cli.dart';
import 'logging.dart';
import 'protocol_stream.dart';
-import 'protocol_stream_transformers.dart';
-/// A DAP server that binds to a port and runs in multi-session mode.
+/// A DAP server that communicates over a [ByteStreamServerChannel], usually
+/// constructed from the processes stdin/stdout streams.
+///
+/// The server runs in single-user mode and services only a single client. For
+/// multiple debug sessions, there would be multiple servers (and the editor
+/// would have a client for each of them).
class DapServer {
- final ServerSocket _socket;
+ final ByteStreamServerChannel channel;
+ late final DartDebugAdapter adapter;
final bool ipv6;
final bool enableDds;
final bool enableAuthCodes;
final Logger? logger;
- final _channels = <ByteStreamServerChannel>{};
- final _adapters = <DartDebugAdapter>{};
- DapServer._(
- this._socket, {
+ DapServer(
+ Stream<List<int>> _input,
+ StreamSink<List<int>> _output, {
this.ipv6 = false,
this.enableDds = true,
this.enableAuthCodes = true,
this.logger,
- }) {
- _socket.listen(_acceptConnection);
- }
-
- String get host => _socket.address.host;
- int get port => _socket.port;
-
- Future<void> stop() async {
- _channels.forEach((client) => client.close());
- await _socket.close();
- }
-
- void _acceptConnection(Socket client) {
- final address = client.remoteAddress;
- logger?.call('Accepted connection from $address');
- client.done.then((_) {
- logger?.call('Connection from $address closed');
- });
- _createAdapter(client.transform(Uint8ListTransformer()), client);
- }
-
- void _createAdapter(Stream<List<int>> _input, StreamSink<List<int>> _output) {
- // TODO(dantup): This is hard-coded to DartCliDebugAdapter but will
- // ultimately need to support having a factory passed in to support
- // tests and/or being used in flutter_tools.
- final channel = ByteStreamServerChannel(_input, _output, logger);
- final adapter = DartCliDebugAdapter(
+ }) : channel = ByteStreamServerChannel(_input, _output, logger) {
+ adapter = DartCliDebugAdapter(
channel,
ipv6: ipv6,
enableDds: enableDds,
enableAuthCodes: enableAuthCodes,
logger: logger,
);
- _channels.add(channel);
- _adapters.add(adapter);
- unawaited(channel.closed.then((_) {
- _channels.remove(channel);
- _adapters.remove(adapter);
- adapter.shutdown();
- }));
}
- /// Starts a DAP Server listening on [host]:[port].
- static Future<DapServer> create({
- String? host,
- int port = 0,
- bool ipv6 = false,
- bool enableDdds = true,
- bool enableAuthCodes = true,
- Logger? logger,
- }) async {
- final hostFallback =
- ipv6 ? InternetAddress.loopbackIPv6 : InternetAddress.loopbackIPv4;
- final _socket = await ServerSocket.bind(host ?? hostFallback, port);
- return DapServer._(
- _socket,
- ipv6: ipv6,
- enableDds: enableDdds,
- enableAuthCodes: enableAuthCodes,
- logger: logger,
- );
+ void stop() {
+ channel.close();
}
}
diff --git a/pkg/dds/test/dap/integration/debug_breakpoints_test.dart b/pkg/dds/test/dap/integration/debug_breakpoints_test.dart
index 9a50b03..62cacbf 100644
--- a/pkg/dds/test/dap/integration/debug_breakpoints_test.dart
+++ b/pkg/dds/test/dap/integration/debug_breakpoints_test.dart
@@ -9,56 +9,61 @@
import 'test_support.dart';
main() {
- testDap((dap) async {
- group('debug mode breakpoints', () {
- test('stops at a line breakpoint', () async {
- final client = dap.client;
- final testFile = dap.createTestFile(simpleBreakpointProgram);
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ late DapTestSession dap;
+ setUp(() async {
+ dap = await DapTestSession.setUp();
+ });
+ tearDown(() => dap.tearDown());
- await client.hitBreakpoint(testFile, breakpointLine);
- });
+ group('debug mode breakpoints', () {
+ test('stops at a line breakpoint', () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- test('stops at a line breakpoint and can be resumed', () async {
- final client = dap.client;
- final testFile = dap.createTestFile(simpleBreakpointProgram);
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ await client.hitBreakpoint(testFile, breakpointLine);
+ });
- // Hit the initial breakpoint.
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ test('stops at a line breakpoint and can be resumed', () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- // Resume and expect termination (as the script will get to the end).
- await Future.wait([
- client.event('terminated'),
- client.continue_(stop.threadId!),
- ], eagerError: true);
- });
+ // Hit the initial breakpoint.
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
- test('stops at a line breakpoint and can step over (next)', () async {
- final testFile = dap.createTestFile(r'''
+ // Resume and expect termination (as the script will get to the end).
+ await Future.wait([
+ client.event('terminated'),
+ client.continue_(stop.threadId!),
+ ], eagerError: true);
+ });
+
+ test('stops at a line breakpoint and can step over (next)', () async {
+ final testFile = dap.createTestFile(r'''
void main(List<String> args) async {
print('Hello!'); // BREAKPOINT
print('Hello!'); // STEP
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stepLine = lineWith(testFile, '// STEP');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final stepLine = lineWith(testFile, '// STEP');
- // Hit the initial breakpoint.
- final stop = await dap.client.hitBreakpoint(testFile, breakpointLine);
+ // Hit the initial breakpoint.
+ final stop = await dap.client.hitBreakpoint(testFile, breakpointLine);
- // Step and expect stopping on the next line with a 'step' stop type.
- await Future.wait([
- dap.client.expectStop('step', file: testFile, line: stepLine),
- dap.client.next(stop.threadId!),
- ], eagerError: true);
- });
+ // Step and expect stopping on the next line with a 'step' stop type.
+ await Future.wait([
+ dap.client.expectStop('step', file: testFile, line: stepLine),
+ dap.client.next(stop.threadId!),
+ ], eagerError: true);
+ });
- test(
- 'stops at a line breakpoint and can step over (next) an async boundary',
- () async {
- final client = dap.client;
- final testFile = dap.createTestFile(r'''
+ test(
+ 'stops at a line breakpoint and can step over (next) an async boundary',
+ () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(r'''
Future<void> main(List<String> args) async {
await asyncPrint('Hello!'); // BREAKPOINT
await asyncPrint('Hello!'); // STEP
@@ -68,30 +73,30 @@
await Future.delayed(const Duration(milliseconds: 1));
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stepLine = lineWith(testFile, '// STEP');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final stepLine = lineWith(testFile, '// STEP');
- // Hit the initial breakpoint.
- final stop = await dap.client.hitBreakpoint(testFile, breakpointLine);
+ // Hit the initial breakpoint.
+ final stop = await dap.client.hitBreakpoint(testFile, breakpointLine);
- // The first step will move from `asyncPrint` to the `await`.
- await Future.wait([
- client.expectStop('step', file: testFile, line: breakpointLine),
- client.next(stop.threadId!),
- ], eagerError: true);
+ // The first step will move from `asyncPrint` to the `await`.
+ await Future.wait([
+ client.expectStop('step', file: testFile, line: breakpointLine),
+ client.next(stop.threadId!),
+ ], eagerError: true);
- // The next step should go over the async boundary and to stepLine (if
- // we did not correctly send kOverAsyncSuspension we would end up in
- // the asyncPrint method).
- await Future.wait([
- client.expectStop('step', file: testFile, line: stepLine),
- client.next(stop.threadId!),
- ], eagerError: true);
- });
+ // The next step should go over the async boundary and to stepLine (if
+ // we did not correctly send kOverAsyncSuspension we would end up in
+ // the asyncPrint method).
+ await Future.wait([
+ client.expectStop('step', file: testFile, line: stepLine),
+ client.next(stop.threadId!),
+ ], eagerError: true);
+ });
- test('stops at a line breakpoint and can step in', () async {
- final client = dap.client;
- final testFile = dap.createTestFile(r'''
+ test('stops at a line breakpoint and can step in', () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(r'''
void main(List<String> args) async {
log('Hello!'); // BREAKPOINT
}
@@ -100,22 +105,22 @@
print(message);
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stepLine = lineWith(testFile, '// STEP');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final stepLine = lineWith(testFile, '// STEP');
- // Hit the initial breakpoint.
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ // Hit the initial breakpoint.
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
- // Step and expect stopping in the inner function with a 'step' stop type.
- await Future.wait([
- client.expectStop('step', file: testFile, line: stepLine),
- client.stepIn(stop.threadId!),
- ], eagerError: true);
- });
+ // Step and expect stopping in the inner function with a 'step' stop type.
+ await Future.wait([
+ client.expectStop('step', file: testFile, line: stepLine),
+ client.stepIn(stop.threadId!),
+ ], eagerError: true);
+ });
- test('stops at a line breakpoint and can step out', () async {
- final client = dap.client;
- final testFile = dap.createTestFile(r'''
+ test('stops at a line breakpoint and can step out', () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(r'''
void main(List<String> args) async {
log('Hello!');
log('Hello!'); // STEP
@@ -125,87 +130,119 @@
print(message); // BREAKPOINT
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stepLine = lineWith(testFile, '// STEP');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final stepLine = lineWith(testFile, '// STEP');
- // Hit the initial breakpoint.
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ // Hit the initial breakpoint.
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
- // Step and expect stopping in the inner function with a 'step' stop type.
- await Future.wait([
- client.expectStop('step', file: testFile, line: stepLine),
- client.stepOut(stop.threadId!),
- ], eagerError: true);
- });
+ // Step and expect stopping in the inner function with a 'step' stop type.
+ await Future.wait([
+ client.expectStop('step', file: testFile, line: stepLine),
+ client.stepOut(stop.threadId!),
+ ], eagerError: true);
+ });
- test('does not step into SDK code with debugSdkLibraries=false',
- () async {
- final client = dap.client;
- final testFile = dap.createTestFile(r'''
+ test('does not step into SDK code with debugSdkLibraries=false', () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(r'''
void main(List<String> args) async {
print('Hello!'); // BREAKPOINT
print('Hello!'); // STEP
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stepLine = lineWith(testFile, '// STEP');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final stepLine = lineWith(testFile, '// STEP');
- // Hit the initial breakpoint.
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ // Hit the initial breakpoint.
+ final stop = await client.hitBreakpoint(
+ testFile,
+ breakpointLine,
+ launch: () => client.launch(
+ testFile.path,
+ debugSdkLibraries: false,
+ ),
+ );
- // Step in and expect stopping on the next line (don't go into print).
- await Future.wait([
- client.expectStop('step', file: testFile, line: stepLine),
- client.stepIn(stop.threadId!),
- ], eagerError: true);
- });
+ // Step in and expect stopping on the next line (don't go into print).
+ await Future.wait([
+ client.expectStop('step', file: testFile, line: stepLine),
+ client.stepIn(stop.threadId!),
+ ], eagerError: true);
+ });
- test('steps into SDK code with debugSdkLibraries=true', () async {
- final client = dap.client;
- final testFile = dap.createTestFile(r'''
+ test('steps into SDK code with debugSdkLibraries=true', () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(r'''
void main(List<String> args) async {
print('Hello!'); // BREAKPOINT
print('Hello!');
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- // Hit the initial breakpoint.
- final stop = await dap.client.hitBreakpoint(
- testFile,
- breakpointLine,
- launch: () => client.launch(
- testFile.path,
- debugSdkLibraries: true,
- ),
- );
+ // Hit the initial breakpoint.
+ final stop = await dap.client.hitBreakpoint(
+ testFile,
+ breakpointLine,
+ launch: () => client.launch(
+ testFile.path,
+ debugSdkLibraries: true,
+ ),
+ );
- // Step in and expect to go into print.
- await Future.wait([
- client.expectStop('step', sourceName: 'dart:core/print.dart'),
- client.stepIn(stop.threadId!),
- ], eagerError: true);
+ // Step in and expect to go into print.
+ await Future.wait([
+ client.expectStop('step', sourceName: 'dart:core/print.dart'),
+ client.stepIn(stop.threadId!),
+ ], eagerError: true);
+ });
+
+ test(
+ 'does not step into external package code with debugExternalPackageLibraries=false',
+ () {
+ // TODO(dantup): Support for debugExternalPackageLibraries
+ }, skip: true);
+
+ test(
+ 'steps into external package code with debugExternalPackageLibraries=true',
+ () {
+ // TODO(dantup): Support for debugExternalPackageLibraries
+ }, skip: true);
+
+ test('allows changing debug settings during session', () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(r'''
+void main(List<String> args) async {
+ print('Hello!'); // BREAKPOINT
+ print('Hello!'); // STEP
+}
+ ''');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final stepLine = lineWith(testFile, '// STEP');
+
+ // Start with debugSdkLibraryes _enabled_ and hit the breakpoint.
+ final stop = await client.hitBreakpoint(
+ testFile,
+ breakpointLine,
+ launch: () => client.launch(
+ testFile.path,
+ debugSdkLibraries: true,
+ ),
+ );
+
+ // Turn off debugSdkLibraries.
+ await client.custom('updateDebugOptions', {
+ 'debugSdkLibraries': false,
});
- test(
- 'does not step into external package code with debugExternalPackageLibraries=false',
- () {
- // TODO(dantup): Support for debugExternalPackageLibraries
- }, skip: true);
-
- test(
- 'steps into external package code with debugExternalPackageLibraries=true',
- () {
- // TODO(dantup): Support for debugExternalPackageLibraries
- }, skip: true);
-
- test('allows changing debug settings during session', () {
- // TODO(dantup): !
- // Dart-Code's DAP has a custom method that allows an editor to change
- // the debug settings (debugSdkLibraries/debugExternalPackageLibraries)
- // during a debug session.
- }, skip: true);
- // These tests can be slow due to starting up the external server process.
- }, timeout: Timeout.none);
- });
+ // Step in and expect stopping on the next line (don't go into print
+ // because we turned off SDK debugging).
+ await Future.wait([
+ client.expectStop('step', file: testFile, line: stepLine),
+ client.stepIn(stop.threadId!),
+ ], eagerError: true);
+ });
+ // These tests can be slow due to starting up the external server process.
+ }, timeout: Timeout.none);
}
diff --git a/pkg/dds/test/dap/integration/debug_eval_test.dart b/pkg/dds/test/dap/integration/debug_eval_test.dart
index 9b59310..ab24f0c 100644
--- a/pkg/dds/test/dap/integration/debug_eval_test.dart
+++ b/pkg/dds/test/dap/integration/debug_eval_test.dart
@@ -10,126 +10,131 @@
import 'test_support.dart';
main() {
- testDap((dap) async {
- group('debug mode evaluation', () {
- test('evaluates expressions with simple results', () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ late DapTestSession dap;
+ setUp(() async {
+ dap = await DapTestSession.setUp();
+ });
+ tearDown(() => dap.tearDown());
+
+ group('debug mode evaluation', () {
+ test('evaluates expressions with simple results', () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
var a = 1;
var b = 2;
var c = 'test';
print('Hello!'); // BREAKPOINT
}''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
- await client.expectTopFrameEvalResult(stop.threadId!, 'a', '1');
- await client.expectTopFrameEvalResult(stop.threadId!, 'a * b', '2');
- await client.expectTopFrameEvalResult(stop.threadId!, 'c', '"test"');
- });
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ await client.expectTopFrameEvalResult(stop.threadId!, 'a', '1');
+ await client.expectTopFrameEvalResult(stop.threadId!, 'a * b', '2');
+ await client.expectTopFrameEvalResult(stop.threadId!, 'c', '"test"');
+ });
- test('evaluates expressions with complex results', () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(simpleBreakpointProgram);
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ test('evaluates expressions with complex results', () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(simpleBreakpointProgram);
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
- final result = await client.expectTopFrameEvalResult(
- stop.threadId!,
- 'DateTime(2000, 1, 1)',
- 'DateTime',
- );
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ final result = await client.expectTopFrameEvalResult(
+ stop.threadId!,
+ 'DateTime(2000, 1, 1)',
+ 'DateTime',
+ );
- // Check we got a variablesReference that maps on to the fields.
- expect(result.variablesReference, greaterThan(0));
- await client.expectVariables(
- result.variablesReference,
- '''
+ // Check we got a variablesReference that maps on to the fields.
+ expect(result.variablesReference, greaterThan(0));
+ await client.expectVariables(
+ result.variablesReference,
+ '''
isUtc: false
''',
- );
- });
+ );
+ });
- test(
- 'evaluates complex expressions expressions with evaluateToStringInDebugViews=true',
- () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(simpleBreakpointProgram);
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ test(
+ 'evaluates complex expressions expressions with evaluateToStringInDebugViews=true',
+ () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(simpleBreakpointProgram);
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stop = await client.hitBreakpoint(
- testFile,
- breakpointLine,
- launch: () =>
- client.launch(testFile.path, evaluateToStringInDebugViews: true),
- );
+ final stop = await client.hitBreakpoint(
+ testFile,
+ breakpointLine,
+ launch: () =>
+ client.launch(testFile.path, evaluateToStringInDebugViews: true),
+ );
- await client.expectTopFrameEvalResult(
- stop.threadId!,
- 'DateTime(2000, 1, 1)',
- 'DateTime (2000-01-01 00:00:00.000)',
- );
- });
+ await client.expectTopFrameEvalResult(
+ stop.threadId!,
+ 'DateTime(2000, 1, 1)',
+ 'DateTime (2000-01-01 00:00:00.000)',
+ );
+ });
- test(
- 'evaluates $threadExceptionExpression to the threads exception (simple type)',
- () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test(
+ 'evaluates $threadExceptionExpression to the threads exception (simple type)',
+ () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
throw 'my error';
}''');
- final stop = await client.hitException(testFile);
+ final stop = await client.hitException(testFile);
- final result = await client.expectTopFrameEvalResult(
- stop.threadId!,
- threadExceptionExpression,
- '"my error"',
- );
- expect(result.variablesReference, equals(0));
- });
+ final result = await client.expectTopFrameEvalResult(
+ stop.threadId!,
+ threadExceptionExpression,
+ '"my error"',
+ );
+ expect(result.variablesReference, equals(0));
+ });
- test(
- 'evaluates $threadExceptionExpression to the threads exception (complex type)',
- () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test(
+ 'evaluates $threadExceptionExpression to the threads exception (complex type)',
+ () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
throw Exception('my error');
}''');
- final stop = await client.hitException(testFile);
- final result = await client.expectTopFrameEvalResult(
- stop.threadId!,
- threadExceptionExpression,
- '_Exception',
- );
- expect(result.variablesReference, greaterThan(0));
- });
+ final stop = await client.hitException(testFile);
+ final result = await client.expectTopFrameEvalResult(
+ stop.threadId!,
+ threadExceptionExpression,
+ '_Exception',
+ );
+ expect(result.variablesReference, greaterThan(0));
+ });
- test(
- 'evaluates $threadExceptionExpression.x.y to x.y on the threads exception',
- () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test(
+ 'evaluates $threadExceptionExpression.x.y to x.y on the threads exception',
+ () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
throw Exception('12345');
}
''');
- final stop = await client.hitException(testFile);
- await client.expectTopFrameEvalResult(
- stop.threadId!,
- '$threadExceptionExpression.message.length',
- '5',
- );
- });
+ final stop = await client.hitException(testFile);
+ await client.expectTopFrameEvalResult(
+ stop.threadId!,
+ '$threadExceptionExpression.message.length',
+ '5',
+ );
+ });
- test('can evaluate expressions in non-top frames', () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test('can evaluate expressions in non-top frames', () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
var a = 999;
foo();
@@ -138,17 +143,16 @@
void foo() {
var a = 111; // BREAKPOINT
}''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
- final stack = await client.getValidStack(stop.threadId!,
- startFrame: 0, numFrames: 2);
- final secondFrameId = stack.stackFrames[1].id;
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ final stack = await client.getValidStack(stop.threadId!,
+ startFrame: 0, numFrames: 2);
+ final secondFrameId = stack.stackFrames[1].id;
- await client.expectEvalResult(secondFrameId, 'a', '999');
- });
+ await client.expectEvalResult(secondFrameId, 'a', '999');
+ });
- // These tests can be slow due to starting up the external server process.
- }, timeout: Timeout.none);
- });
+ // These tests can be slow due to starting up the external server process.
+ }, timeout: Timeout.none);
}
diff --git a/pkg/dds/test/dap/integration/debug_logging_test.dart b/pkg/dds/test/dap/integration/debug_logging_test.dart
index 1df090c..27578f5 100644
--- a/pkg/dds/test/dap/integration/debug_logging_test.dart
+++ b/pkg/dds/test/dap/integration/debug_logging_test.dart
@@ -4,13 +4,19 @@
import 'package:test/test.dart';
+import 'test_client.dart';
import 'test_support.dart';
main() {
- testDap((dap) async {
- group('debug mode', () {
- test('prints messages from dart:developer log()', () async {
- final testFile = dap.createTestFile(r'''
+ late DapTestSession dap;
+ setUp(() async {
+ dap = await DapTestSession.setUp();
+ });
+ tearDown(() => dap.tearDown());
+
+ group('debug mode', () {
+ test('prints messages from dart:developer log()', () async {
+ final testFile = dap.createTestFile(r'''
import 'dart:developer';
void main(List<String> args) async {
@@ -19,19 +25,45 @@
}
''');
- var outputEvents = await dap.client.collectOutput(file: testFile);
+ var outputEvents = await dap.client.collectOutput(file: testFile);
- // Skip the first line because it's the VM Service connection info.
- final output = outputEvents.skip(1).map((e) => e.output).join();
- expectLines(output, [
- '[log] this is a test',
- ' across two lines',
- '[foo] this is a test',
- '',
- 'Exited.',
- ]);
- });
- // These tests can be slow due to starting up the external server process.
- }, timeout: Timeout.none);
- });
+ // Skip the first line because it's the VM Service connection info.
+ final output = outputEvents.skip(1).map((e) => e.output).join();
+ expectLines(output, [
+ '[log] this is a test',
+ ' across two lines',
+ '[foo] this is a test',
+ '',
+ 'Exited.',
+ ]);
+ });
+
+ test('prints long messages from dart:developer log()', () async {
+ // Make a long message that's more than 255 chars (where the VM truncates
+ // log strings by default).
+ final longMessage = 'this is a test' * 20;
+ final testFile = dap.createTestFile('''
+import 'dart:developer';
+
+void main(List<String> args) async {
+ log('$longMessage');
+ // Prevent us exiting before the async log messages may have completed.
+ // The test will terminate the script early once the expectations are met.
+ await Future.delayed(const Duration(seconds: 30));
+}
+ ''');
+ final expectedLogMessage = '[log] $longMessage\n';
+
+ final consoleOutputs = dap.client.outputEvents
+ .where((event) => event.category == 'console')
+ .map((event) => event.output);
+
+ await Future.wait([
+ expectLater(consoleOutputs, emitsThrough(expectedLogMessage)),
+ dap.client.start(file: testFile),
+ ]);
+ await dap.client.terminate();
+ });
+ // These tests can be slow due to starting up the external server process.
+ }, timeout: Timeout.none);
}
diff --git a/pkg/dds/test/dap/integration/debug_test.dart b/pkg/dds/test/dap/integration/debug_test.dart
index 7b80af0..41863f9 100644
--- a/pkg/dds/test/dap/integration/debug_test.dart
+++ b/pkg/dds/test/dap/integration/debug_test.dart
@@ -10,10 +10,15 @@
import 'test_support.dart';
main() {
- testDap((dap) async {
- group('debug mode', () {
- test('runs a simple script', () async {
- final testFile = dap.createTestFile(r'''
+ group('debug mode', () {
+ late DapTestSession dap;
+ setUp(() async {
+ dap = await DapTestSession.setUp();
+ });
+ tearDown(() => dap.tearDown());
+
+ test('runs a simple script', () async {
+ final testFile = dap.createTestFile(r'''
void main(List<String> args) async {
print('Hello!');
print('World!');
@@ -21,100 +26,99 @@
}
''');
- final outputEvents = await dap.client.collectOutput(
- launch: () => dap.client.launch(
- testFile.path,
- args: ['one', 'two'],
- ),
- );
+ final outputEvents = await dap.client.collectOutput(
+ launch: () => dap.client.launch(
+ testFile.path,
+ args: ['one', 'two'],
+ ),
+ );
- // Expect a "console" output event that prints the URI of the VM Service
- // the debugger connects to.
- final vmConnection = outputEvents.first;
- expect(vmConnection.output,
- startsWith('Connecting to VM Service at ws://127.0.0.1:'));
- expect(vmConnection.category, equals('console'));
+ // Expect a "console" output event that prints the URI of the VM Service
+ // the debugger connects to.
+ final vmConnection = outputEvents.first;
+ expect(vmConnection.output,
+ startsWith('Connecting to VM Service at ws://127.0.0.1:'));
+ expect(vmConnection.category, equals('console'));
- // Expect the normal applications output.
- final output = outputEvents.skip(1).map((e) => e.output).join();
- expectLines(output, [
- 'Hello!',
- 'World!',
- 'args: [one, two]',
- '',
- 'Exited.',
- ]);
- });
+ // Expect the normal applications output.
+ final output = outputEvents.skip(1).map((e) => e.output).join();
+ expectLines(output, [
+ 'Hello!',
+ 'World!',
+ 'args: [one, two]',
+ '',
+ 'Exited.',
+ ]);
+ });
- test('provides a list of threads', () async {
- final client = dap.client;
- final testFile = dap.createTestFile(simpleBreakpointProgram);
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ test('provides a list of threads', () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- await client.hitBreakpoint(testFile, breakpointLine);
- final response = await client.getValidThreads();
+ await client.hitBreakpoint(testFile, breakpointLine);
+ final response = await client.getValidThreads();
- expect(response.threads, hasLength(1));
- expect(response.threads.first.name, equals('main'));
- });
+ expect(response.threads, hasLength(1));
+ expect(response.threads.first.name, equals('main'));
+ });
- test('runs with DDS', () async {
- final client = dap.client;
- final testFile = dap.createTestFile(simpleBreakpointProgram);
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ test('runs with DDS by default', () async {
+ final client = dap.client;
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- await client.hitBreakpoint(testFile, breakpointLine);
- expect(await client.ddsAvailable, isTrue);
- });
- // These tests can be slow due to starting up the external server process.
- }, timeout: Timeout.none);
+ await client.hitBreakpoint(testFile, breakpointLine);
+ expect(await client.ddsAvailable, isTrue);
+ });
- test('runs with auth codes enabled', () async {
+ test('runs with auth codes enabled by default', () async {
final testFile = dap.createTestFile(emptyProgram);
final outputEvents = await dap.client.collectOutput(file: testFile);
- expect(_hasAuthCode(outputEvents.first), isTrue);
+ final vmServiceUri = _extractVmServiceUri(outputEvents.first);
+ expect(vmServiceUri.path, matches(vmServiceAuthCodePathPattern));
});
- });
+ // These tests can be slow due to starting up the external server process.
+ }, timeout: Timeout.none);
- testDap((dap) async {
- group('debug mode', () {
- test('runs without DDS', () async {
- final client = dap.client;
- final testFile = dap.createTestFile(simpleBreakpointProgram);
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ group('debug mode', () {
+ test('can run without DDS', () async {
+ final dap = await DapTestSession.setUp(additionalArgs: ['--no-dds']);
+ addTearDown(dap.tearDown);
- await client.hitBreakpoint(testFile, breakpointLine);
+ final client = dap.client;
+ final testFile = dap.createTestFile(simpleBreakpointProgram);
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- expect(await client.ddsAvailable, isFalse);
- });
+ await client.hitBreakpoint(testFile, breakpointLine);
- test('runs with auth tokens disabled', () async {
- final testFile = dap.createTestFile(emptyProgram);
+ expect(await client.ddsAvailable, isFalse);
+ });
- final outputEvents = await dap.client.collectOutput(file: testFile);
- expect(_hasAuthCode(outputEvents.first), isFalse);
- });
- // These tests can be slow due to starting up the external server process.
- }, timeout: Timeout.none);
- }, additionalArgs: ['--no-dds', '--no-auth-codes']);
+ test('can run without auth codes', () async {
+ final dap =
+ await DapTestSession.setUp(additionalArgs: ['--no-auth-codes']);
+ addTearDown(dap.tearDown);
- testDap((dap) async {
- group('debug mode', () {
- test('can run with ipv6', () async {
- final testFile = dap.createTestFile(emptyProgram);
+ final testFile = dap.createTestFile(emptyProgram);
+ final outputEvents = await dap.client.collectOutput(file: testFile);
+ final vmServiceUri = _extractVmServiceUri(outputEvents.first);
+ expect(vmServiceUri.path, isNot(matches(vmServiceAuthCodePathPattern)));
+ });
- final outputEvents = await dap.client.collectOutput(file: testFile);
- final vmServiceUri = _extractVmServiceUri(outputEvents.first);
+ test('can run with ipv6', () async {
+ final dap = await DapTestSession.setUp(additionalArgs: ['--ipv6']);
+ addTearDown(dap.tearDown);
- // Check DAP server host.
- expect(dap.server.host, equals('::1'));
- // Check VM Service/DDS host.
- expect(vmServiceUri.host, equals('::1'));
- });
- // These tests can be slow due to starting up the external server process.
- }, timeout: Timeout.none);
- }, additionalArgs: ['--ipv6']);
+ final testFile = dap.createTestFile(emptyProgram);
+ final outputEvents = await dap.client.collectOutput(file: testFile);
+ final vmServiceUri = _extractVmServiceUri(outputEvents.first);
+
+ expect(vmServiceUri.host, equals('::1'));
+ });
+ // These tests can be slow due to starting up the external server process.
+ }, timeout: Timeout.none);
}
/// Extracts the VM Service URI from the "Connecting to ..." banner output by
@@ -122,15 +126,6 @@
Uri _extractVmServiceUri(OutputEventBody vmConnectionBanner) {
// TODO(dantup): Change this to use the dart.debuggerUris custom event
// if implemented (whch VS Code also needs).
- final vmServiceUriPattern = RegExp(r'Connecting to VM Service at ([^\s]+)\s');
final match = vmServiceUriPattern.firstMatch(vmConnectionBanner.output);
return Uri.parse(match!.group(1)!);
}
-
-/// Checks for the presence of an auth token in a VM Service URI in the
-/// "Connecting to VM Service" [OutputEvent].
-bool _hasAuthCode(OutputEventBody vmConnectionBanner) {
- final vmServiceUri = _extractVmServiceUri(vmConnectionBanner);
- final authCodePattern = RegExp(r'^/[\w=]{5,15}/ws');
- return authCodePattern.hasMatch(vmServiceUri.path);
-}
diff --git a/pkg/dds/test/dap/integration/debug_variables_test.dart b/pkg/dds/test/dap/integration/debug_variables_test.dart
index e04e36e..b5e357c 100644
--- a/pkg/dds/test/dap/integration/debug_variables_test.dart
+++ b/pkg/dds/test/dap/integration/debug_variables_test.dart
@@ -8,11 +8,16 @@
import 'test_support.dart';
main() {
- testDap((dap) async {
- group('debug mode variables', () {
- test('provides variable list for frames', () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ late DapTestSession dap;
+ setUp(() async {
+ dap = await DapTestSession.setUp();
+ });
+ tearDown(() => dap.tearDown());
+
+ group('debug mode variables', () {
+ test('provides variable list for frames', () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
final myVariable = 1;
foo();
@@ -23,135 +28,135 @@
print('Hello!'); // BREAKPOINT
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
- final stack = await client.getValidStack(
- stop.threadId!,
- startFrame: 0,
- numFrames: 2,
- );
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ final stack = await client.getValidStack(
+ stop.threadId!,
+ startFrame: 0,
+ numFrames: 2,
+ );
- // Check top two frames (in `foo` and in `main`).
- await client.expectScopeVariables(
- stack.stackFrames[0].id, // Top frame: foo
- 'Variables',
- '''
+ // Check top two frames (in `foo` and in `main`).
+ await client.expectScopeVariables(
+ stack.stackFrames[0].id, // Top frame: foo
+ 'Variables',
+ '''
b: 2
''',
- );
- await client.expectScopeVariables(
- stack.stackFrames[1].id, // Second frame: main
- 'Variables',
- '''
+ );
+ await client.expectScopeVariables(
+ stack.stackFrames[1].id, // Second frame: main
+ 'Variables',
+ '''
args: List (0 items)
myVariable: 1
''',
- );
- });
+ );
+ });
- test('provides simple exception types for frames', () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test('provides simple exception types for frames', () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
throw 'my error';
}
''');
- final stop = await client.hitException(testFile);
- final stack = await client.getValidStack(
- stop.threadId!,
- startFrame: 0,
- numFrames: 1,
- );
- final topFrameId = stack.stackFrames.first.id;
+ final stop = await client.hitException(testFile);
+ final stack = await client.getValidStack(
+ stop.threadId!,
+ startFrame: 0,
+ numFrames: 1,
+ );
+ final topFrameId = stack.stackFrames.first.id;
- // Check for an additional Scope named "Exceptions" that includes the
- // exception.
- await client.expectScopeVariables(
- topFrameId,
- 'Exceptions',
- '''
+ // Check for an additional Scope named "Exceptions" that includes the
+ // exception.
+ await client.expectScopeVariables(
+ topFrameId,
+ 'Exceptions',
+ '''
String: "my error"
''',
- );
- });
+ );
+ });
- test('provides complex exception types frames', () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test('provides complex exception types frames', () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
throw ArgumentError.notNull('args');
}
''');
- final stop = await client.hitException(testFile);
- final stack = await client.getValidStack(
- stop.threadId!,
- startFrame: 0,
- numFrames: 1,
- );
- final topFrameId = stack.stackFrames.first.id;
+ final stop = await client.hitException(testFile);
+ final stack = await client.getValidStack(
+ stop.threadId!,
+ startFrame: 0,
+ numFrames: 1,
+ );
+ final topFrameId = stack.stackFrames.first.id;
- // Check for an additional Scope named "Exceptions" that includes the
- // exception.
- await client.expectScopeVariables(
- topFrameId,
- 'Exceptions',
- // TODO(dantup): evaluateNames
- '''
+ // Check for an additional Scope named "Exceptions" that includes the
+ // exception.
+ await client.expectScopeVariables(
+ topFrameId,
+ 'Exceptions',
+ // TODO(dantup): evaluateNames
+ '''
invalidValue: null
message: "Must not be null"
name: "args"
''',
- );
- });
+ );
+ });
- test('includes simple variable fields', () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test('includes simple variable fields', () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
final myVariable = DateTime(2000, 1, 1);
print('Hello!'); // BREAKPOINT
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
- await client.expectLocalVariable(
- stop.threadId!,
- expectedName: 'myVariable',
- expectedDisplayString: 'DateTime',
- expectedVariables: '''
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ await client.expectLocalVariable(
+ stop.threadId!,
+ expectedName: 'myVariable',
+ expectedDisplayString: 'DateTime',
+ expectedVariables: '''
isUtc: false
''',
- );
- });
+ );
+ });
- test('includes variable getters when evaluateGettersInDebugViews=true',
- () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test('includes variable getters when evaluateGettersInDebugViews=true',
+ () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
final myVariable = DateTime(2000, 1, 1);
print('Hello!'); // BREAKPOINT
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stop = await client.hitBreakpoint(
- testFile,
- breakpointLine,
- launch: () => client.launch(
- testFile.path,
- evaluateGettersInDebugViews: true,
- ),
- );
- await client.expectLocalVariable(
- stop.threadId!,
- expectedName: 'myVariable',
- expectedDisplayString: 'DateTime',
- expectedVariables: '''
+ final stop = await client.hitBreakpoint(
+ testFile,
+ breakpointLine,
+ launch: () => client.launch(
+ testFile.path,
+ evaluateGettersInDebugViews: true,
+ ),
+ );
+ await client.expectLocalVariable(
+ stop.threadId!,
+ expectedName: 'myVariable',
+ expectedDisplayString: 'DateTime',
+ expectedVariables: '''
day: 1
hour: 0
isUtc: false
@@ -165,72 +170,71 @@
weekday: 6
year: 2000
''',
- ignore: {
- // Don't check fields that may very based on timezone as it'll make
- // these tests fragile, and this isn't really what's being tested.
- 'timeZoneName',
- 'microsecondsSinceEpoch',
- 'millisecondsSinceEpoch',
- },
- );
- });
+ ignore: {
+ // Don't check fields that may very based on timezone as it'll make
+ // these tests fragile, and this isn't really what's being tested.
+ 'timeZoneName',
+ 'microsecondsSinceEpoch',
+ 'millisecondsSinceEpoch',
+ },
+ );
+ });
- test('renders a simple list', () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test('renders a simple list', () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
final myVariable = ["first", "second", "third"];
print('Hello!'); // BREAKPOINT
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
- await client.expectLocalVariable(
- stop.threadId!,
- expectedName: 'myVariable',
- expectedDisplayString: 'List (3 items)',
- // TODO(dantup): evaluateNames
- expectedVariables: '''
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ await client.expectLocalVariable(
+ stop.threadId!,
+ expectedName: 'myVariable',
+ expectedDisplayString: 'List (3 items)',
+ // TODO(dantup): evaluateNames
+ expectedVariables: '''
0: "first"
1: "second"
2: "third"
''',
- );
- });
+ );
+ });
- test('renders a simple list subset', () async {
- final client = dap.client;
- final testFile = await dap.createTestFile(r'''
+ test('renders a simple list subset', () async {
+ final client = dap.client;
+ final testFile = await dap.createTestFile(r'''
void main(List<String> args) {
final myVariable = ["first", "second", "third"];
print('Hello!'); // BREAKPOINT
}
''');
- final breakpointLine = lineWith(testFile, '// BREAKPOINT');
+ final breakpointLine = lineWith(testFile, '// BREAKPOINT');
- final stop = await client.hitBreakpoint(testFile, breakpointLine);
- await client.expectLocalVariable(
- stop.threadId!,
- expectedName: 'myVariable',
- expectedDisplayString: 'List (3 items)',
- // TODO(dantup): evaluateNames
- expectedVariables: '''
+ final stop = await client.hitBreakpoint(testFile, breakpointLine);
+ await client.expectLocalVariable(
+ stop.threadId!,
+ expectedName: 'myVariable',
+ expectedDisplayString: 'List (3 items)',
+ // TODO(dantup): evaluateNames
+ expectedVariables: '''
1: "second"
''',
- start: 1,
- count: 1,
- );
- });
+ start: 1,
+ count: 1,
+ );
+ });
- test('renders a simple map', () {
- // TODO(dantup): Implement this (inc evaluateNames)
- }, skip: true);
+ test('renders a simple map', () {
+ // TODO(dantup): Implement this (inc evaluateNames)
+ }, skip: true);
- test('renders a simple map subset', () {
- // TODO(dantup): Implement this (inc evaluateNames)
- }, skip: true);
- // These tests can be slow due to starting up the external server process.
- }, timeout: Timeout.none);
- });
+ test('renders a simple map subset', () {
+ // TODO(dantup): Implement this (inc evaluateNames)
+ }, skip: true);
+ // These tests can be slow due to starting up the external server process.
+ }, timeout: Timeout.none);
}
diff --git a/pkg/dds/test/dap/integration/no_debug_test.dart b/pkg/dds/test/dap/integration/no_debug_test.dart
index e9f5dd2..bb0af1d 100644
--- a/pkg/dds/test/dap/integration/no_debug_test.dart
+++ b/pkg/dds/test/dap/integration/no_debug_test.dart
@@ -4,13 +4,19 @@
import 'package:test/test.dart';
+import 'test_client.dart';
import 'test_support.dart';
main() {
- testDap((dap) async {
- group('noDebug mode', () {
- test('runs a simple script', () async {
- final testFile = dap.createTestFile(r'''
+ late DapTestSession dap;
+ setUp(() async {
+ dap = await DapTestSession.setUp();
+ });
+ tearDown(() => dap.tearDown());
+
+ group('noDebug mode', () {
+ test('runs a simple script', () async {
+ final testFile = dap.createTestFile(r'''
void main(List<String> args) async {
print('Hello!');
print('World!');
@@ -18,24 +24,23 @@
}
''');
- final outputEvents = await dap.client.collectOutput(
- launch: () => dap.client.launch(
- testFile.path,
- noDebug: true,
- args: ['one', 'two'],
- ),
- );
+ final outputEvents = await dap.client.collectOutput(
+ launch: () => dap.client.launch(
+ testFile.path,
+ noDebug: true,
+ args: ['one', 'two'],
+ ),
+ );
- final output = outputEvents.map((e) => e.output).join();
- expectLines(output, [
- 'Hello!',
- 'World!',
- 'args: [one, two]',
- '',
- 'Exited.',
- ]);
- });
- // These tests can be slow due to starting up the external server process.
- }, timeout: Timeout.none);
- });
+ final output = outputEvents.map((e) => e.output).join();
+ expectLines(output, [
+ 'Hello!',
+ 'World!',
+ 'args: [one, two]',
+ '',
+ 'Exited.',
+ ]);
+ });
+ // These tests can be slow due to starting up the external server process.
+ }, timeout: Timeout.none);
}
diff --git a/pkg/dds/test/dap/integration/test_client.dart b/pkg/dds/test/dap/integration/test_client.dart
index c130e00..bfa05c6 100644
--- a/pkg/dds/test/dap/integration/test_client.dart
+++ b/pkg/dds/test/dap/integration/test_client.dart
@@ -10,7 +10,6 @@
import 'package:dds/src/dap/logging.dart';
import 'package:dds/src/dap/protocol_generated.dart';
import 'package:dds/src/dap/protocol_stream.dart';
-import 'package:dds/src/dap/protocol_stream_transformers.dart';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart' as vm;
@@ -22,19 +21,17 @@
/// Methods on this class should map directly to protocol methods. Additional
/// helpers are available in [DapTestClientExtension].
class DapTestClient {
- final Socket _socket;
final ByteStreamServerChannel _channel;
late final StreamSubscription<String> _subscription;
final Logger? _logger;
final bool captureVmServiceTraffic;
- final _requestWarningDuration = const Duration(seconds: 2);
+ final _requestWarningDuration = const Duration(seconds: 5);
final Map<int, _OutgoingRequest> _pendingRequests = {};
final _eventController = StreamController<Event>.broadcast();
int _seq = 1;
DapTestClient._(
- this._socket,
this._channel,
this._logger, {
this.captureVmServiceTraffic = false,
@@ -57,21 +54,6 @@
Stream<OutputEventBody> get outputEvents => events('output')
.map((e) => OutputEventBody.fromJson(e.body as Map<String, Object?>));
- /// Collects all output events until the program terminates.
- Future<List<OutputEventBody>> collectOutput(
- {File? file, Future<Response> Function()? launch}) async {
- final outputEventsFuture = outputEvents.toList();
-
- // Launch script and wait for termination.
- await Future.wait([
- event('terminated'),
- initialize(),
- launch?.call() ?? this.launch(file!.path),
- ], eagerError: true);
-
- return outputEventsFuture;
- }
-
/// Sends a continue request for the given thread.
///
/// Returns a Future that completes when the server returns a corresponding
@@ -210,6 +192,19 @@
sendRequest(StackTraceArguments(
threadId: threadId, startFrame: startFrame, levels: numFrames));
+ /// Initializes the debug adapter and launches [file] or calls the custom
+ /// [launch] method.
+ Future<void> start({
+ File? file,
+ Future<Response> Function()? launch,
+ }) {
+ // Launch script and wait for termination.
+ return Future.wait([
+ initialize(),
+ launch?.call() ?? this.launch(file!.path),
+ ], eagerError: true);
+ }
+
/// Sends a stepIn request for the given thread.
///
/// Returns a Future that completes when the server returns a corresponding
@@ -226,7 +221,6 @@
Future<void> stop() async {
_channel.close();
- await _socket.close();
await _subscription.cancel();
}
@@ -305,16 +299,12 @@
/// Creates a [DapTestClient] that connects the server listening on
/// [host]:[port].
static Future<DapTestClient> connect(
- String host,
- int port, {
+ DapTestServer server, {
bool captureVmServiceTraffic = false,
Logger? logger,
}) async {
- final socket = await Socket.connect(host, port);
- final channel = ByteStreamServerChannel(
- socket.transform(Uint8ListTransformer()), socket, logger);
-
- return DapTestClient._(socket, channel, logger,
+ final channel = ByteStreamServerChannel(server.stream, server.sink, logger);
+ return DapTestClient._(channel, logger,
captureVmServiceTraffic: captureVmServiceTraffic);
}
}
@@ -441,6 +431,21 @@
return ThreadsResponseBody.fromJson(response.body as Map<String, Object?>);
}
+ /// Collects all output events until the program terminates.
+ ///
+ /// These results include all events in the order they are recieved, including
+ /// console, stdout and stderr.
+ Future<List<OutputEventBody>> collectOutput({
+ File? file,
+ Future<Response> Function()? launch,
+ }) async {
+ final outputEventsFuture = outputEvents.toList();
+
+ await start(file: file, launch: launch);
+
+ return outputEventsFuture;
+ }
+
/// A helper that fetches scopes for a frame, checks for one with the name
/// [expectedName] and verifies its variables.
Future<Scope> expectScopeVariables(
diff --git a/pkg/dds/test/dap/integration/test_server.dart b/pkg/dds/test/dap/integration/test_server.dart
index c2a11f7..dc96dc7 100644
--- a/pkg/dds/test/dap/integration/test_server.dart
+++ b/pkg/dds/test/dap/integration/test_server.dart
@@ -13,10 +13,9 @@
import 'package:pedantic/pedantic.dart';
abstract class DapTestServer {
- List<String> get errorLogs;
- String get host;
- int get port;
Future<void> stop();
+ StreamSink<List<int>> get sink;
+ Stream<List<int>> get stream;
}
/// An instance of a DAP server running in-process (to aid debugging).
@@ -25,22 +24,27 @@
/// serialized and deserialized but it's not quite the same running out of
/// process.
class InProcessDapTestServer extends DapTestServer {
- final DapServer _server;
+ late final DapServer _server;
+ final stdinController = StreamController<List<int>>();
+ final stdoutController = StreamController<List<int>>();
- InProcessDapTestServer._(this._server);
+ StreamSink<List<int>> get sink => stdinController.sink;
+ Stream<List<int>> get stream => stdoutController.stream;
- String get host => _server.host;
- int get port => _server.port;
- List<String> get errorLogs => const []; // In-proc errors just throw in-line.
+ InProcessDapTestServer._() {
+ _server = DapServer(stdinController.stream, stdoutController.sink);
+ }
@override
Future<void> stop() async {
- await _server.stop();
+ _server.stop();
}
- static Future<InProcessDapTestServer> create({Logger? logger}) async {
- final DapServer server = await DapServer.create(logger: logger);
- return InProcessDapTestServer._(server);
+ static Future<InProcessDapTestServer> create({
+ Logger? logger,
+ List<String>? additionalArgs,
+ }) async {
+ return InProcessDapTestServer._();
}
}
@@ -52,28 +56,22 @@
class OutOfProcessDapTestServer extends DapTestServer {
var _isShuttingDown = false;
final Process _process;
- final int port;
- final String host;
- final List<String> _errors = [];
- List<String> get errorLogs => _errors;
+ StreamSink<List<int>> get sink => _process.stdin;
+ Stream<List<int>> get stream => _process.stdout;
OutOfProcessDapTestServer._(
this._process,
- this.host,
- this.port,
Logger? logger,
) {
// Treat anything written to stderr as the DAP crashing and fail the test.
_process.stderr.transform(utf8.decoder).listen((error) {
logger?.call(error);
- _errors.add(error);
throw error;
});
unawaited(_process.exitCode.then((code) {
final message = 'Out-of-process DAP server terminated with code $code';
logger?.call(message);
- _errors.add(message);
if (!_isShuttingDown && code != 0) {
throw message;
}
@@ -107,27 +105,6 @@
],
);
- final startedCompleter = Completer<void>();
- late String host;
- late int port;
-
- // Scrape the `started` event to get the host/port. Any other output
- // should be sent to the logger (as it may be verbose output for diagnostic
- // purposes).
- _process.stdout.transform(utf8.decoder).listen((text) {
- if (!startedCompleter.isCompleted) {
- final event = jsonDecode(text);
- if (event['state'] == 'started') {
- host = event['dapHost'];
- port = event['dapPort'];
- startedCompleter.complete();
- return;
- }
- }
- logger?.call(text);
- });
- await startedCompleter.future;
-
- return OutOfProcessDapTestServer._(_process, host, port, logger);
+ return OutOfProcessDapTestServer._(_process, logger);
}
}
diff --git a/pkg/dds/test/dap/integration/test_support.dart b/pkg/dds/test/dap/integration/test_support.dart
index 45460b2..a44a791 100644
--- a/pkg/dds/test/dap/integration/test_support.dart
+++ b/pkg/dds/test/dap/integration/test_support.dart
@@ -12,20 +12,6 @@
import 'test_client.dart';
import 'test_server.dart';
-/// A logger to use to log all traffic (both DAP and VM) to stdout.
-///
-/// If the enviroment variable is `DAP_TEST_VERBOSE` then `print` will be used,
-/// otherwise there will be no verbose logging.
-///
-/// DAP_TEST_VERBOSE=true pub run test --chain-stack-traces test/dap/integration
-///
-///
-/// When using the out-of-process DAP, this causes `--verbose` to be passed to
-/// the server which causes it to write all traffic to `stdout` which is then
-/// picked up by [OutOfProcessDapTestServer] and passed to this logger.
-final logger =
- Platform.environment['DAP_TEST_VERBOSE'] == 'true' ? print : null;
-
/// Whether to run the DAP server in-process with the tests, or externally in
/// another process.
///
@@ -35,6 +21,14 @@
/// simplified in VS Code by using a launch config with custom CodeLens links).
final useInProcessDap = Platform.environment['DAP_TEST_INTERNAL'] == 'true';
+/// A [RegExp] that matches the `path` part of a VM Service URI that contains
+/// an authentication token.
+final vmServiceAuthCodePathPattern = RegExp(r'^/[\w_\-=]{5,15}/ws$');
+
+/// A [RegExp] that matches the "Connecting to VM Service" banner that is sent
+/// as the first output event for a debug session.
+final vmServiceUriPattern = RegExp(r'Connecting to VM Service at ([^\s]+)\s');
+
/// Expects [actual] to equal the lines [expected], ignoring differences in line
/// endings.
void expectLines(String actual, List<String> expected) {
@@ -45,33 +39,13 @@
int lineWith(File file, String searchText) =>
file.readAsLinesSync().indexWhere((line) => line.contains(searchText)) + 1;
-/// A helper function to wrap all tests in a library with setup/teardown functions
-/// to start a shared server for all tests in the library and an individual
-/// client for each test.
-testDap(
- Future<void> Function(DapTestSession session) tests, {
- List<String>? additionalArgs,
-}) {
- final session = DapTestSession(additionalArgs: additionalArgs);
-
- setUpAll(session.setUpAll);
- tearDownAll(session.tearDownAll);
- setUp(session.setUp);
- tearDown(session.tearDown);
-
- return tests(session);
-}
-
-/// A helper class provided to DAP integration tests run with [testDap] to
-/// easily share setup/teardown without sharing state across tests from different
-/// files.
+/// A helper class containing the DAP server/client for DAP integration tests.
class DapTestSession {
- late DapTestServer server;
- late DapTestClient client;
+ DapTestServer server;
+ DapTestClient client;
final _testFolders = <Directory>[];
- final List<String>? additionalArgs;
- DapTestSession({this.additionalArgs});
+ DapTestSession._(this.server, this.client);
/// Creates a file in a temporary folder to be used as an application for testing.
///
@@ -84,60 +58,32 @@
return testFile;
}
- Future<void> setUp() async {
- client = await _startClient(server);
+ static Future<DapTestSession> setUp({List<String>? additionalArgs}) async {
+ final server = await _startServer(additionalArgs: additionalArgs);
+ final client = await DapTestClient.connect(server);
+ return DapTestSession._(server, client);
}
- Future<void> setUpAll() async {
- server = await _startServer(logger: logger, additionalArgs: additionalArgs);
- }
-
- Future<void> tearDown() => client.stop();
-
- Future<void> tearDownAll() async {
+ Future<void> tearDown() async {
+ await client.stop();
await server.stop();
// Clean up any temp folders created during the test runs.
- _testFolders.forEach((dir) => dir.deleteSync(recursive: true));
- }
-
- /// Creates and connects a new [DapTestClient] to [server].
- Future<DapTestClient> _startClient(DapTestServer server) async {
- // Since we don't get a signal from the DAP server when it's ready and we
- // just started it, add a short retry to connections.
- // Since the bots can be quite slow, it may take 6-7 seconds for the server
- // to initially start up (including compilation).
- var attempt = 1;
- while (attempt++ <= 100) {
- try {
- return await DapTestClient.connect(server.host, server.port);
- } catch (e) {
- await Future.delayed(const Duration(milliseconds: 200));
- }
- }
-
- final errorMessage = StringBuffer();
- errorMessage.writeln(
- 'Failed to connect to DAP server on port ${server.port}'
- ' after $attempt attempts. Did the server start correctly?',
- );
-
- final serverErrorLogs = server.errorLogs;
- if (serverErrorLogs.isNotEmpty) {
- errorMessage.writeln('Server errors:');
- errorMessage.writeAll(serverErrorLogs);
- }
-
- throw Exception(errorMessage.toString());
+ _testFolders
+ ..forEach((dir) => dir.deleteSync(recursive: true))
+ ..clear();
}
/// Starts a DAP server that can be shared across tests.
- Future<DapTestServer> _startServer({
+ static Future<DapTestServer> _startServer({
Logger? logger,
List<String>? additionalArgs,
}) async {
return useInProcessDap
- ? await InProcessDapTestServer.create(logger: logger)
+ ? await InProcessDapTestServer.create(
+ logger: logger,
+ additionalArgs: additionalArgs,
+ )
: await OutOfProcessDapTestServer.create(
logger: logger,
additionalArgs: additionalArgs,
diff --git a/pkg/dds/tool/dap/run_server.dart b/pkg/dds/tool/dap/run_server.dart
index 5fd19f2..cfddd48 100644
--- a/pkg/dds/tool/dap/run_server.dart
+++ b/pkg/dds/tool/dap/run_server.dart
@@ -2,7 +2,7 @@
// 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.
-import 'dart:convert';
+import 'dart:async';
import 'dart:io';
import 'package:args/command_runner.dart';
@@ -12,7 +12,7 @@
// TODO(dantup): "dap_tool" is a placeholder and will likely eventually be a
// "dart" command.
final runner = CommandRunner('dap_tool', 'Dart DAP Tool')
- ..addCommand(DapCommand());
+ ..addCommand(DapCommand(stdin, stdout.nonBlocking));
try {
await runner.run(arguments);
@@ -23,33 +23,22 @@
}
class DapCommand extends Command {
- static const argHost = 'host';
- static const argPort = 'port';
static const argIpv6 = 'ipv6';
static const argDds = 'dds';
static const argAuthCodes = 'auth-codes';
static const argVerbose = 'verbose';
+ final Stream<List<int>> _inputStream;
+ final StreamSink<List<int>> _outputSink;
+
@override
final String description = 'Start a DAP debug server.';
@override
final String name = 'dap';
- DapCommand() {
+ DapCommand(this._inputStream, this._outputSink) {
argParser
- ..addOption(
- argHost,
- help: 'The hostname/IP to bind the server to. If not supplied, will'
- ' use the appropriate loopback address depending on whether'
- ' --ipv6 is set',
- )
- ..addOption(
- argPort,
- abbr: 'p',
- defaultsTo: '0',
- help: 'The port to bind the server to',
- )
..addFlag(
argIpv6,
help: 'Whether to bind DAP/VM Service/DDS to IPv6 addresses',
@@ -63,33 +52,21 @@
argAuthCodes,
defaultsTo: true,
help: 'Whether to enable authentication codes for VM Services',
- )
- ..addFlag(
- argVerbose,
- abbr: 'v',
- help: 'Whether to print diagnostic output to stdout',
);
}
Future<void> run() async {
final args = argResults!;
- final port = int.parse(args[argPort]);
- final host = args[argHost];
final ipv6 = args[argIpv6] as bool;
- final server = await DapServer.create(
- host: host,
- port: port,
+ final server = DapServer(
+ _inputStream,
+ _outputSink,
ipv6: ipv6,
- enableDdds: args[argDds],
+ enableDds: args[argDds],
enableAuthCodes: args[argAuthCodes],
- logger: args[argVerbose] ? print : null,
);
- stdout.write(jsonEncode({
- 'state': 'started',
- 'dapHost': server.host,
- 'dapPort': server.port,
- }));
+ await server.channel.closed;
}
}
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 8a3759b..716a5a2 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -124,7 +124,7 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes);
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes);
/// Registers a constructor redirection for this class and returns true if
/// this redirection gives rise to a cycle that has not been reported before.
@@ -345,11 +345,11 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
void build(String ignore, Builder declaration) {
MemberBuilder member = declaration as MemberBuilder;
- member.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
+ member.buildOutlineExpressions(library, coreTypes,
+ delayedActionPerformers, synthesizedFunctionNodes);
}
MetadataBuilder.buildAnnotations(
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
index b0a984c..e49c0c7 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -20,7 +20,7 @@
show ExpressionGeneratorHelper;
import '../kernel/kernel_builder.dart'
show isRedirectingGenerativeConstructorImplementation;
-import '../kernel/kernel_target.dart' show ClonedFunctionNode;
+import '../kernel/kernel_target.dart' show SynthesizedFunctionNode;
import '../loader.dart' show Loader;
@@ -252,9 +252,9 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
super.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
+ library, coreTypes, delayedActionPerformers, synthesizedFunctionNodes);
// For modular compilation purposes we need to include initializers
// for const constructors into the outline.
@@ -471,13 +471,14 @@
class SyntheticConstructorBuilder extends DillConstructorBuilder {
MemberBuilderImpl? _origin;
- ClonedFunctionNode? _clonedFunctionNode;
+ SynthesizedFunctionNode? _synthesizedFunctionNode;
SyntheticConstructorBuilder(SourceClassBuilder parent,
Constructor constructor, Procedure? constructorTearOff,
- {MemberBuilderImpl? origin, ClonedFunctionNode? clonedFunctionNode})
+ {MemberBuilderImpl? origin,
+ SynthesizedFunctionNode? synthesizedFunctionNode})
: _origin = origin,
- _clonedFunctionNode = clonedFunctionNode,
+ _synthesizedFunctionNode = synthesizedFunctionNode,
super(constructor, constructorTearOff, parent);
@override
@@ -485,7 +486,7 @@
SourceLibraryBuilder libraryBuilder,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
if (_origin != null) {
// Ensure that default value expressions have been created for [_origin].
LibraryBuilder originLibraryBuilder = _origin!.library;
@@ -493,10 +494,10 @@
// If [_origin] is from a source library, we need to build the default
// values and initializers first.
_origin!.buildOutlineExpressions(originLibraryBuilder, coreTypes,
- delayedActionPerformers, clonedFunctionNodes);
+ delayedActionPerformers, synthesizedFunctionNodes);
}
- _clonedFunctionNode!.cloneDefaultValues();
- _clonedFunctionNode = null;
+ _synthesizedFunctionNode!.cloneDefaultValues();
+ _synthesizedFunctionNode = null;
_origin = null;
}
}
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
index 6c173ef..463174c 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -523,7 +523,7 @@
SourceLibraryBuilder libraryBuilder,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
List<Expression> values = <Expression>[];
if (enumConstantInfos != null) {
for (EnumConstantInfo? enumConstantInfo in enumConstantInfos!) {
@@ -568,7 +568,7 @@
}
}
super.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
+ library, coreTypes, delayedActionPerformers, synthesizedFunctionNodes);
}
@override
diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
index d52ae6f..9435193 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -38,7 +38,7 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes);
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes);
/// Looks up extension member by [name] taking privacy into account.
///
diff --git a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
index 4ca72bb..4646515 100644
--- a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
@@ -341,10 +341,9 @@
}
updatePrivateMemberName(_procedureInternal, libraryBuilder);
if (_factoryTearOff != null) {
- _tearOffTypeParameters = buildRedirectingFactoryTearOffProcedure(
- _factoryTearOff!,
- _procedure,
- library as SourceLibraryBuilder);
+ _tearOffTypeParameters =
+ buildRedirectingFactoryTearOffProcedureParameters(
+ _factoryTearOff!, _procedure, library);
}
return _procedureInternal;
}
@@ -354,9 +353,9 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
super.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
+ library, coreTypes, delayedActionPerformers, synthesizedFunctionNodes);
RedirectingFactoryBody redirectingFactoryBody =
_procedure.function.body as RedirectingFactoryBody;
List<DartType>? typeArguments = redirectingFactoryBody.typeArguments;
@@ -416,14 +415,13 @@
}
member.function!.body = new RedirectingFactoryBody(target, typeArguments);
}
- if (_factoryTearOff != null) {
- clonedFunctionNodes.add(buildRedirectingFactoryTearOffBody(
+ if (_factoryTearOff != null &&
+ (target is Constructor || target is Procedure && target.isFactory)) {
+ synthesizedFunctionNodes.add(buildRedirectingFactoryTearOffBody(
_factoryTearOff!,
- target as Constructor,
+ target!,
typeArguments ?? [],
_tearOffTypeParameters!));
- delayedActionPerformers.add(new _CopyDefaultValues(
- _factoryTearOff!, redirectingFactoryBody.target!.function!));
}
}
@@ -445,18 +443,3 @@
return getRedirectingFactoryBody(_procedure)!.typeArguments;
}
}
-
-class _CopyDefaultValues implements DelayedActionPerformer {
- final Procedure _tearOff;
- final FunctionNode _function;
-
- _CopyDefaultValues(this._tearOff, this._function);
-
- @override
- bool get hasDelayedActions => true;
-
- @override
- void performDelayedActions() {
- copyTearOffDefaultValues(_tearOff, _function);
- }
-}
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index b1ae35f..4fd424a 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -400,7 +400,7 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
_fieldEncoding.completeSignature(coreTypes);
for (Annotatable annotatable in _fieldEncoding.annotatables) {
diff --git a/pkg/front_end/lib/src/fasta/builder/function_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
index 638c80f..e4cab78 100644
--- a/pkg/front_end/lib/src/fasta/builder/function_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
@@ -480,7 +480,7 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
if (!_hasBuiltOutlineExpressions) {
DeclarationBuilder? classOrExtensionBuilder =
isClassMember || isExtensionMember
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
index c7d1f9d..87167ef 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -80,7 +80,7 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes);
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes);
/// Returns the [ClassMember]s for the non-setter members created for this
/// member builder.
@@ -187,7 +187,7 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {}
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {}
/// Builds the core AST structures for this member as needed for the outline.
void buildMembers(
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
index 0c5d28f..c9aba98 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
@@ -109,7 +109,7 @@
LibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
// TODO(johnniwinther): Remove the need for this.
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
index f7603ef..2383c40 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
@@ -4,6 +4,7 @@
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart';
+import '../builder/library_builder.dart';
import '../builder/member_builder.dart';
import '../source/source_library_builder.dart';
import 'kernel_api.dart';
@@ -61,7 +62,7 @@
void buildConstructorTearOffProcedure(Procedure tearOff, Member constructor,
Class enclosingClass, SourceLibraryBuilder libraryBuilder) {
assert(constructor is Constructor ||
- (constructor is Procedure && constructor.kind == ProcedureKind.Factory));
+ (constructor is Procedure && constructor.isFactory));
int fileOffset = tearOff.fileOffset;
@@ -84,19 +85,7 @@
Substitution substitution = freshTypeParameters.substitution;
_createParameters(tearOff, function, substitution);
Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
-
- Expression constructorInvocation;
- if (constructor is Constructor) {
- constructorInvocation = new ConstructorInvocation(constructor, arguments)
- ..fileOffset = tearOff.fileOffset;
- } else {
- constructorInvocation =
- new StaticInvocation(constructor as Procedure, arguments)
- ..fileOffset = tearOff.fileOffset;
- }
- tearOff.function.body = new ReturnStatement(constructorInvocation)
- ..fileOffset = tearOff.fileOffset
- ..parent = tearOff.function;
+ _createTearOffBody(tearOff, constructor, arguments);
tearOff.function.fileOffset = tearOff.fileOffset;
tearOff.function.fileEndOffset = tearOff.fileOffset;
updatePrivateMemberName(tearOff, libraryBuilder);
@@ -157,10 +146,10 @@
/// Creates the parameters for the redirecting factory [tearOff] based on the
/// [redirectingConstructor] declaration.
-FreshTypeParameters buildRedirectingFactoryTearOffProcedure(
+FreshTypeParameters buildRedirectingFactoryTearOffProcedureParameters(
Procedure tearOff,
Procedure redirectingConstructor,
- SourceLibraryBuilder libraryBuilder) {
+ LibraryBuilder libraryBuilder) {
assert(redirectingConstructor.isRedirectingFactory);
FunctionNode function = redirectingConstructor.function;
FreshTypeParameters freshTypeParameters =
@@ -176,11 +165,11 @@
/// Creates the body for the redirecting factory [tearOff] with the target
/// [constructor] and [typeArguments].
///
-/// Returns the [ClonedFunctionNode] object need to perform default value
+/// Returns the [SynthesizedFunctionNode] object need to perform default value
/// computation.
-ClonedFunctionNode buildRedirectingFactoryTearOffBody(
+SynthesizedFunctionNode buildRedirectingFactoryTearOffBody(
Procedure tearOff,
- Constructor constructor,
+ Member target,
List<DartType> typeArguments,
FreshTypeParameters freshTypeParameters) {
int fileOffset = tearOff.fileOffset;
@@ -196,18 +185,13 @@
}
Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
- Expression constructorInvocation =
- new ConstructorInvocation(constructor, arguments)
- ..fileOffset = tearOff.fileOffset;
- tearOff.function.body = new ReturnStatement(constructorInvocation)
- ..fileOffset = tearOff.fileOffset
- ..parent = tearOff.function;
-
- return new ClonedFunctionNode(
+ _createTearOffBody(tearOff, target, arguments);
+ return new SynthesizedFunctionNode(
new Map<TypeParameter, DartType>.fromIterables(
- constructor.enclosingClass.typeParameters, typeArguments),
- constructor.function,
- tearOff.function);
+ target.enclosingClass!.typeParameters, typeArguments),
+ target.function!,
+ tearOff.function,
+ identicalSignatures: false);
}
/// Creates the synthesized name to use for the lowering of the tear off of a
@@ -363,3 +347,20 @@
..fileOffset = tearOff.fileOffset;
return arguments;
}
+
+/// Creates the tear of body for [tearOff] which calls [target] with
+/// [arguments].
+void _createTearOffBody(Procedure tearOff, Member target, Arguments arguments) {
+ assert(target is Constructor || (target is Procedure && target.isFactory));
+ Expression constructorInvocation;
+ if (target is Constructor) {
+ constructorInvocation = new ConstructorInvocation(target, arguments)
+ ..fileOffset = tearOff.fileOffset;
+ } else {
+ constructorInvocation = new StaticInvocation(target as Procedure, arguments)
+ ..fileOffset = tearOff.fileOffset;
+ }
+ tearOff.function.body = new ReturnStatement(constructorInvocation)
+ ..fileOffset = tearOff.fileOffset
+ ..parent = tearOff.function;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index a49ae77..7363aa8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -139,7 +139,8 @@
final bool errorOnUnevaluatedConstant =
CompilerContext.current.options.errorOnUnevaluatedConstant;
- final List<ClonedFunctionNode> clonedFunctionNodes = <ClonedFunctionNode>[];
+ final List<SynthesizedFunctionNode> synthesizedFunctionNodes =
+ <SynthesizedFunctionNode>[];
KernelTarget(this.fileSystem, this.includeComments, DillTarget dillTarget,
UriTranslator uriTranslator)
@@ -336,7 +337,8 @@
loader.checkAbstractMembers(myClasses);
loader.addNoSuchMethodForwarders(myClasses);
loader.checkMixins(myClasses);
- loader.buildOutlineExpressions(loader.coreTypes, clonedFunctionNodes);
+ loader.buildOutlineExpressions(
+ loader.coreTypes, synthesizedFunctionNodes);
loader.checkTypes();
loader.checkRedirectingFactories(myClasses);
loader.checkMainMethods();
@@ -757,16 +759,17 @@
returnType: makeConstructorReturnType(cls));
SuperInitializer initializer = new SuperInitializer(
constructor, new Arguments(positional, named: named));
- ClonedFunctionNode clonedFunctionNode =
- new ClonedFunctionNode(substitutionMap, constructor.function, function);
+ SynthesizedFunctionNode synthesizedFunctionNode =
+ new SynthesizedFunctionNode(
+ substitutionMap, constructor.function, function);
if (!isConst) {
// For constant constructors default values are computed and cloned part
// of the outline expression and therefore passed to the
// [SyntheticConstructorBuilder] below.
//
// For non-constant constructors default values are cloned as part of the
- // full compilation using [clonedFunctionNodes].
- clonedFunctionNodes.add(clonedFunctionNode);
+ // full compilation using [synthesizedFunctionNodes].
+ synthesizedFunctionNodes.add(synthesizedFunctionNode);
}
return new SyntheticConstructorBuilder(
classBuilder,
@@ -785,14 +788,15 @@
// cloned function nodes to ensure that the default values are computed
// and cloned for the outline.
origin: isConst ? memberBuilder : null,
- clonedFunctionNode: isConst ? clonedFunctionNode : null);
+ synthesizedFunctionNode: isConst ? synthesizedFunctionNode : null);
}
void finishClonedParameters() {
- for (ClonedFunctionNode clonedFunctionNode in clonedFunctionNodes) {
- clonedFunctionNode.cloneDefaultValues();
+ for (SynthesizedFunctionNode synthesizedFunctionNode
+ in synthesizedFunctionNodes) {
+ synthesizedFunctionNode.cloneDefaultValues();
}
- clonedFunctionNodes.clear();
+ synthesizedFunctionNodes.clear();
ticker.logMs("Cloned default values of formals");
}
@@ -1424,12 +1428,36 @@
}
}
-class ClonedFunctionNode {
+/// Data for clone default values for synthesized function nodes once the
+/// original default values have been computed.
+///
+/// This is used for constructors in unnamed mixin application, which are
+/// created from the constructors in the superclass, and for tear off lowerings
+/// for redirecting factories, which are created from the effective target
+/// constructor.
+class SynthesizedFunctionNode {
+ /// Type parameter map from type parameters in scope [_original] to types
+ /// in scope of [_synthesized].
+ // TODO(johnniwinther): Is this ever needed? Should occurrence of type
+ // variable types in default values be a compile time error?
final Map<TypeParameter, DartType> _typeSubstitution;
- final FunctionNode _original;
- final FunctionNode _clone;
- ClonedFunctionNode(this._typeSubstitution, this._original, this._clone);
+ /// The original function node.
+ final FunctionNode _original;
+
+ /// The synthesized function node.
+ final FunctionNode _synthesized;
+
+ /// If `true`, the [_synthesized] is guaranteed to have the same parameters in
+ /// the same order as [_original]. Otherwise [_original] is only guaranteed to
+ /// be callable from [_synthesized], meaning that is has at most the same
+ /// number of positional parameters and a, possibly reordered, subset of the
+ /// named parameters.
+ final bool identicalSignatures;
+
+ SynthesizedFunctionNode(
+ this._typeSubstitution, this._original, this._synthesized,
+ {this.identicalSignatures: true});
void cloneDefaultValues() {
// TODO(ahe): It is unclear if it is legal to use type variables in
@@ -1449,13 +1477,35 @@
}
}
- for (int i = 0; i < _original.positionalParameters.length; i++) {
- cloneInitializer(
- _original.positionalParameters[i], _clone.positionalParameters[i]);
+ // For mixin application constructors, the argument count is the same, but
+ // for redirecting tear off lowerings, the argument count of the tear off
+ // can be less than that of the redirection target.
+
+ assert(_synthesized.positionalParameters.length <=
+ _original.positionalParameters.length);
+ for (int i = 0; i < _synthesized.positionalParameters.length; i++) {
+ cloneInitializer(_original.positionalParameters[i],
+ _synthesized.positionalParameters[i]);
}
- for (int i = 0; i < _original.namedParameters.length; i++) {
- cloneInitializer(_original.namedParameters[i], _clone.namedParameters[i]);
+ if (identicalSignatures) {
+ assert(_synthesized.namedParameters.length ==
+ _original.namedParameters.length);
+ for (int i = 0; i < _synthesized.namedParameters.length; i++) {
+ cloneInitializer(
+ _original.namedParameters[i], _synthesized.namedParameters[i]);
+ }
+ } else if (_synthesized.namedParameters.isNotEmpty) {
+ Map<String, VariableDeclaration> originalParameters = {};
+ for (int i = 0; i < _original.namedParameters.length; i++) {
+ originalParameters[_original.namedParameters[i].name!] =
+ _original.namedParameters[i];
+ }
+ for (int i = 0; i < _synthesized.namedParameters.length; i++) {
+ cloneInitializer(
+ originalParameters[_synthesized.namedParameters[i].name!]!,
+ _synthesized.namedParameters[i]);
+ }
}
}
}
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 9427c99..4027001 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -811,7 +811,7 @@
LibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
throw new UnsupportedError(
'AmbiguousMemberBuilder.buildOutlineExpressions');
}
diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
index 30f4fff..d6a21ef 100644
--- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
@@ -276,7 +276,7 @@
SourceLibraryBuilder library,
CoreTypes coreTypes,
List<DelayedActionPerformer> delayedActionPerformers,
- List<ClonedFunctionNode> clonedFunctionNodes) {
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
MetadataBuilder.buildAnnotations(isPatch ? origin.extension : extension,
metadata, library, this, null, fileUri);
if (typeParameters != null) {
@@ -288,8 +288,8 @@
void build(String ignore, Builder declaration) {
MemberBuilder member = declaration as MemberBuilder;
- member.buildOutlineExpressions(
- library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
+ member.buildOutlineExpressions(library, coreTypes,
+ delayedActionPerformers, synthesizedFunctionNodes);
}
scope.forEach(build);
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 843754e..db885ca 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -92,7 +92,8 @@
import '../kernel/kernel_builder.dart'
show ClassHierarchyBuilder, ClassMember, DelayedCheck;
-import '../kernel/kernel_target.dart' show ClonedFunctionNode, KernelTarget;
+import '../kernel/kernel_target.dart'
+ show SynthesizedFunctionNode, KernelTarget;
import '../kernel/body_builder.dart' show BodyBuilder;
@@ -1182,8 +1183,8 @@
ticker.logMs("Checked mixin declaration applications");
}
- void buildOutlineExpressions(
- CoreTypes coreTypes, List<ClonedFunctionNode> clonedFunctionNodes) {
+ void buildOutlineExpressions(CoreTypes coreTypes,
+ List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
List<DelayedActionPerformer> delayedActionPerformers =
<DelayedActionPerformer>[];
for (LibraryBuilder library in builders.values) {
@@ -1194,13 +1195,13 @@
Builder declaration = iterator.current;
if (declaration is ClassBuilder) {
declaration.buildOutlineExpressions(library, coreTypes,
- delayedActionPerformers, clonedFunctionNodes);
+ delayedActionPerformers, synthesizedFunctionNodes);
} else if (declaration is ExtensionBuilder) {
declaration.buildOutlineExpressions(library, coreTypes,
- delayedActionPerformers, clonedFunctionNodes);
+ delayedActionPerformers, synthesizedFunctionNodes);
} else if (declaration is MemberBuilder) {
declaration.buildOutlineExpressions(library, coreTypes,
- delayedActionPerformers, clonedFunctionNodes);
+ delayedActionPerformers, synthesizedFunctionNodes);
} else if (declaration is TypeAliasBuilder) {
declaration.buildOutlineExpressions(
library, coreTypes, delayedActionPerformers);
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 07ed5c1..e8b4e79 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -1018,6 +1018,7 @@
remover
renames
render
+reordered
reparse
repeating
replacements
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 922e0ac..a51d1da 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -111,10 +111,13 @@
c1b
c1c
c1d
+c1e
+c1f
c2a
c2b
c2c
c2d
+c2e
c3a
c3b
c3c
@@ -125,6 +128,10 @@
c4b
c4c
c4d
+c4e
+c4f
+c4g
+c4h
c59cdee365b94ce066344840f9e3412d642019b
c5a
c5b
@@ -133,6 +140,9 @@
c6a
c6b
c6c
+c7a
+c8a
+c8b
ca
cafebabe
calloc
@@ -163,6 +173,10 @@
class5b
class5c
class5d
+class7a
+class7b
+class8a
+class8b
cloneable
cm
cmd
@@ -331,6 +345,9 @@
f2
f2a
f2b
+f2c
+f2d
+f2e
f3
f3a
f3b
@@ -342,10 +359,15 @@
f4a
f4b
f4c
+f4d
+f4e
+f4f
f5a
f5b
f6a
f6b
+f7a
+f8a
fac
faking
falling
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart
index e9ac4b7..ff03d6e 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart
@@ -27,6 +27,16 @@
expect(true, identical(f2a, f2b));
+ var f2c = Class2.redirect;
+ var c2c = f2c();
+ expect(true, c2c is Class2);
+
+ dynamic f2d = Class2.redirect;
+ var c2d = f2d();
+ expect(true, c2d is Class2);
+
+ expect(true, identical(f2c, f2d));
+
var f3a = Class3.new;
var c3a = f3a(42);
expect(42, c3a.field);
@@ -66,6 +76,31 @@
expect(false, c4d is Class4<int>);
throws(() => f4c<int, String>());
+ var f4d = Class4.redirect;
+ var c4e = f4d();
+ expect(true, c4e is Class4<dynamic>);
+ expect(false, c4e is Class4<int>);
+ var c4f = f4d<int>();
+ expect(true, c4f is Class4<int>);
+ expect(false, c4f is Class4<String>);
+ () {
+ f4d<int, String>(); // error
+ };
+
+ var f4e = f4d<int>;
+ var c4g = f4e();
+ expect(true, c4g is Class4<int>);
+ expect(false, c4g is Class4<String>);
+ () {
+ f4e<int>(); // error
+ };
+
+ dynamic f4f = Class4.redirect;
+ var c4h = f4f();
+ expect(true, c4h is Class4<dynamic>);
+ expect(false, c4h is Class4<int>);
+ throws(() => f4f<int, String>());
+
var f5a = Class5.new;
var c5a = f5a();
expect(true, c5a is Class5<num>);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.expect
index 5f219e3..1806fdc 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.expect
@@ -2,29 +2,37 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:44:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:45:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:62:8: Error: Expected 1 type arguments.
// f4a<int, String>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:70:8: Error: Expected 0 type arguments.
// f4b<int>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:77:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:87:8: Error: Expected 1 type arguments.
+// f4d<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:95:8: Error: Expected 0 type arguments.
+// f4e<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:112:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
// Try changing type arguments so that they conform to the bounds.
// f5a<String>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:113:8: Error: Expected 1 type arguments.
// f5a<int, String>(); // error
// ^
//
@@ -50,24 +58,31 @@
dynamic c2b = f2b{dynamic}.call();
self::expect(true, c2b is{ForNonNullableByDefault} mai::Class2);
self::expect(true, core::identical(f2a, f2b));
- (core::int) → mai::Class3 f3a = #C3;
+ () → mai::Class2 f2c = #C3;
+ mai::Class2 c2c = f2c(){() → mai::Class2};
+ self::expect(true, c2c is{ForNonNullableByDefault} mai::Class2);
+ dynamic f2d = #C3;
+ dynamic c2d = f2d{dynamic}.call();
+ self::expect(true, c2d is{ForNonNullableByDefault} mai::Class2);
+ self::expect(true, core::identical(f2c, f2d));
+ (core::int) → mai::Class3 f3a = #C4;
mai::Class3 c3a = f3a(42){(core::int) → mai::Class3};
self::expect(42, c3a.{mai::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:44:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:45:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
};
- dynamic f3b = #C3;
+ dynamic f3b = #C4;
dynamic c3b = f3b{dynamic}.call(87);
self::expect(87, c3b{dynamic}.field);
self::throws(() → dynamic => f3b{dynamic}.call());
self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
- <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C4;
+ <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C5;
mai::Class4<dynamic> c4a = f4a<dynamic>(){() → mai::Class4<dynamic>};
self::expect(true, c4a is{ForNonNullableByDefault} mai::Class4<dynamic>);
self::expect(false, c4a is{ForNonNullableByDefault} mai::Class4<core::int>);
@@ -75,7 +90,7 @@
self::expect(true, c4b is{ForNonNullableByDefault} mai::Class4<core::int>);
self::expect(false, c4b is{ForNonNullableByDefault} mai::Class4<core::String>);
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:62:8: Error: Expected 1 type arguments.
f4a<int, String>(); // error
^" in f4a{<inapplicable>}.<core::int, core::String>();
};
@@ -84,16 +99,42 @@
self::expect(true, c4c is{ForNonNullableByDefault} mai::Class4<core::int>);
self::expect(false, c4c is{ForNonNullableByDefault} mai::Class4<core::String>);
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:70:8: Error: Expected 0 type arguments.
f4b<int>(); // error
^" in f4b{<inapplicable>}.<core::int>();
};
- dynamic f4c = #C4;
+ dynamic f4c = #C5;
dynamic c4d = f4c{dynamic}.call();
self::expect(true, c4d is{ForNonNullableByDefault} mai::Class4<dynamic>);
self::expect(false, c4d is{ForNonNullableByDefault} mai::Class4<core::int>);
self::throws(() → dynamic => f4c{dynamic}.call<core::int, core::String>());
- <T extends core::num>() → mai::Class5<T> f5a = #C5;
+ <T extends core::Object? = dynamic>() → mai::Class4<T%> f4d = #C6;
+ mai::Class4<dynamic> c4e = f4d<dynamic>(){() → mai::Class4<dynamic>};
+ self::expect(true, c4e is{ForNonNullableByDefault} mai::Class4<dynamic>);
+ self::expect(false, c4e is{ForNonNullableByDefault} mai::Class4<core::int>);
+ mai::Class4<core::int> c4f = f4d<core::int>(){() → mai::Class4<core::int>};
+ self::expect(true, c4f is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::expect(false, c4f is{ForNonNullableByDefault} mai::Class4<core::String>);
+ () → Null {
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:87:8: Error: Expected 1 type arguments.
+ f4d<int, String>(); // error
+ ^" in f4d{<inapplicable>}.<core::int, core::String>();
+ };
+ () → mai::Class4<core::int> f4e = f4d<core::int>;
+ mai::Class4<core::int> c4g = f4e(){() → mai::Class4<core::int>};
+ self::expect(true, c4g is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::expect(false, c4g is{ForNonNullableByDefault} mai::Class4<core::String>);
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:95:8: Error: Expected 0 type arguments.
+ f4e<int>(); // error
+ ^" in f4e{<inapplicable>}.<core::int>();
+ };
+ dynamic f4f = #C6;
+ dynamic c4h = f4f{dynamic}.call();
+ self::expect(true, c4h is{ForNonNullableByDefault} mai::Class4<dynamic>);
+ self::expect(false, c4h is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::throws(() → dynamic => f4f{dynamic}.call<core::int, core::String>());
+ <T extends core::num>() → mai::Class5<T> f5a = #C7;
mai::Class5<core::num> c5a = f5a<core::num>(){() → mai::Class5<core::num>};
self::expect(true, c5a is{ForNonNullableByDefault} mai::Class5<core::num>);
self::expect(false, c5a is{ForNonNullableByDefault} mai::Class5<core::int>);
@@ -102,11 +143,11 @@
self::expect(false, c5b is{ForNonNullableByDefault} mai::Class5<core::double>);
() → Null {
f5a<core::String>(){() → mai::Class5<core::String>};
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:113:8: Error: Expected 1 type arguments.
f5a<int, String>(); // error
^" in f5a{<inapplicable>}.<core::int, core::String>();
};
- dynamic f5b = #C5;
+ dynamic f5b = #C7;
dynamic c5c = f5b{dynamic}.call();
self::expect(true, c5c is{ForNonNullableByDefault} mai::Class5<core::num>);
self::expect(false, c5c is{ForNonNullableByDefault} mai::Class5<core::int>);
@@ -120,7 +161,7 @@
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C6}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
try {
f(){() → dynamic};
}
@@ -146,11 +187,16 @@
return new mai::Class1::•();
}
class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[mai::Class2::redirect]/*isLegacy*/;
constructor named() → mai::Class2
: super core::Object::•()
;
static method _#named#tearOff() → mai::Class2
return new mai::Class2::named();
+ static factory redirect() → mai::Class2
+ let dynamic #redirecting_factory = mai::Class2::named in invalid-expression;
+ static method _#redirect#tearOff() → mai::Class2
+ return new mai::Class2::named();
}
class Class3 extends core::Object {
final field core::int field;
@@ -161,6 +207,7 @@
return new mai::Class3::•(field);
}
class Class4<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[mai::Class4::redirect]/*isLegacy*/;
constructor _() → mai::Class4<mai::Class4::T%>
: super core::Object::•()
;
@@ -170,6 +217,10 @@
return new mai::Class4::_<mai::Class4::•::T%>();
static method _#new#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#new#tearOff::T%>
return mai::Class4::•<mai::Class4::_#new#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::redirect::T%>
+ let dynamic #redirecting_factory = mai::Class4::_ in let mai::Class4::redirect::T% #typeArg0 = null in invalid-expression;
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#redirect#tearOff::T%>
+ return new mai::Class4::_<mai::Class4::_#redirect#tearOff::T%>();
}
class Class5<T extends core::num> extends core::Object {
constructor _() → mai::Class5<mai::Class5::T>
@@ -186,8 +237,10 @@
constants {
#C1 = static-tearoff mai::Class1::_#new#tearOff
#C2 = static-tearoff mai::Class2::_#named#tearOff
- #C3 = static-tearoff mai::Class3::_#new#tearOff
- #C4 = static-tearoff mai::Class4::_#new#tearOff
- #C5 = static-tearoff mai::Class5::_#new#tearOff
- #C6 = false
+ #C3 = static-tearoff mai::Class2::_#redirect#tearOff
+ #C4 = static-tearoff mai::Class3::_#new#tearOff
+ #C5 = static-tearoff mai::Class4::_#new#tearOff
+ #C6 = static-tearoff mai::Class4::_#redirect#tearOff
+ #C7 = static-tearoff mai::Class5::_#new#tearOff
+ #C8 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.transformed.expect
index 42623ded..9edd33a 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.transformed.expect
@@ -2,29 +2,37 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:44:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:45:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:62:8: Error: Expected 1 type arguments.
// f4a<int, String>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:70:8: Error: Expected 0 type arguments.
// f4b<int>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:77:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:87:8: Error: Expected 1 type arguments.
+// f4d<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:95:8: Error: Expected 0 type arguments.
+// f4e<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:112:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
// Try changing type arguments so that they conform to the bounds.
// f5a<String>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:113:8: Error: Expected 1 type arguments.
// f5a<int, String>(); // error
// ^
//
@@ -50,24 +58,31 @@
dynamic c2b = f2b{dynamic}.call();
self::expect(true, c2b is{ForNonNullableByDefault} mai::Class2);
self::expect(true, core::identical(f2a, f2b));
- (core::int) → mai::Class3 f3a = #C3;
+ () → mai::Class2 f2c = #C3;
+ mai::Class2 c2c = f2c(){() → mai::Class2};
+ self::expect(true, c2c is{ForNonNullableByDefault} mai::Class2);
+ dynamic f2d = #C3;
+ dynamic c2d = f2d{dynamic}.call();
+ self::expect(true, c2d is{ForNonNullableByDefault} mai::Class2);
+ self::expect(true, core::identical(f2c, f2d));
+ (core::int) → mai::Class3 f3a = #C4;
mai::Class3 c3a = f3a(42){(core::int) → mai::Class3};
self::expect(42, c3a.{mai::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:44:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:45:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
};
- dynamic f3b = #C3;
+ dynamic f3b = #C4;
dynamic c3b = f3b{dynamic}.call(87);
self::expect(87, c3b{dynamic}.field);
self::throws(() → dynamic => f3b{dynamic}.call());
self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
- <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C4;
+ <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C5;
mai::Class4<dynamic> c4a = f4a<dynamic>(){() → mai::Class4<dynamic>};
self::expect(true, c4a is{ForNonNullableByDefault} mai::Class4<dynamic>);
self::expect(false, c4a is{ForNonNullableByDefault} mai::Class4<core::int>);
@@ -75,7 +90,7 @@
self::expect(true, c4b is{ForNonNullableByDefault} mai::Class4<core::int>);
self::expect(false, c4b is{ForNonNullableByDefault} mai::Class4<core::String>);
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:62:8: Error: Expected 1 type arguments.
f4a<int, String>(); // error
^" in f4a{<inapplicable>}.<core::int, core::String>();
};
@@ -84,16 +99,42 @@
self::expect(true, c4c is{ForNonNullableByDefault} mai::Class4<core::int>);
self::expect(false, c4c is{ForNonNullableByDefault} mai::Class4<core::String>);
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:70:8: Error: Expected 0 type arguments.
f4b<int>(); // error
^" in f4b{<inapplicable>}.<core::int>();
};
- dynamic f4c = #C4;
+ dynamic f4c = #C5;
dynamic c4d = f4c{dynamic}.call();
self::expect(true, c4d is{ForNonNullableByDefault} mai::Class4<dynamic>);
self::expect(false, c4d is{ForNonNullableByDefault} mai::Class4<core::int>);
self::throws(() → dynamic => f4c{dynamic}.call<core::int, core::String>());
- <T extends core::num>() → mai::Class5<T> f5a = #C5;
+ <T extends core::Object? = dynamic>() → mai::Class4<T%> f4d = #C6;
+ mai::Class4<dynamic> c4e = f4d<dynamic>(){() → mai::Class4<dynamic>};
+ self::expect(true, c4e is{ForNonNullableByDefault} mai::Class4<dynamic>);
+ self::expect(false, c4e is{ForNonNullableByDefault} mai::Class4<core::int>);
+ mai::Class4<core::int> c4f = f4d<core::int>(){() → mai::Class4<core::int>};
+ self::expect(true, c4f is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::expect(false, c4f is{ForNonNullableByDefault} mai::Class4<core::String>);
+ () → Null {
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:87:8: Error: Expected 1 type arguments.
+ f4d<int, String>(); // error
+ ^" in f4d{<inapplicable>}.<core::int, core::String>();
+ };
+ () → mai::Class4<core::int> f4e = f4d<core::int>;
+ mai::Class4<core::int> c4g = f4e(){() → mai::Class4<core::int>};
+ self::expect(true, c4g is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::expect(false, c4g is{ForNonNullableByDefault} mai::Class4<core::String>);
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:95:8: Error: Expected 0 type arguments.
+ f4e<int>(); // error
+ ^" in f4e{<inapplicable>}.<core::int>();
+ };
+ dynamic f4f = #C6;
+ dynamic c4h = f4f{dynamic}.call();
+ self::expect(true, c4h is{ForNonNullableByDefault} mai::Class4<dynamic>);
+ self::expect(false, c4h is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::throws(() → dynamic => f4f{dynamic}.call<core::int, core::String>());
+ <T extends core::num>() → mai::Class5<T> f5a = #C7;
mai::Class5<core::num> c5a = f5a<core::num>(){() → mai::Class5<core::num>};
self::expect(true, c5a is{ForNonNullableByDefault} mai::Class5<core::num>);
self::expect(false, c5a is{ForNonNullableByDefault} mai::Class5<core::int>);
@@ -102,11 +143,11 @@
self::expect(false, c5b is{ForNonNullableByDefault} mai::Class5<core::double>);
() → Null {
f5a<core::String>(){() → mai::Class5<core::String>};
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:113:8: Error: Expected 1 type arguments.
f5a<int, String>(); // error
^" in f5a{<inapplicable>}.<core::int, core::String>();
};
- dynamic f5b = #C5;
+ dynamic f5b = #C7;
dynamic c5c = f5b{dynamic}.call();
self::expect(true, c5c is{ForNonNullableByDefault} mai::Class5<core::num>);
self::expect(false, c5c is{ForNonNullableByDefault} mai::Class5<core::int>);
@@ -120,7 +161,7 @@
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C6}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
try {
f(){() → dynamic};
}
@@ -146,11 +187,16 @@
return new mai::Class1::•();
}
class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[mai::Class2::redirect]/*isLegacy*/;
constructor named() → mai::Class2
: super core::Object::•()
;
static method _#named#tearOff() → mai::Class2
return new mai::Class2::named();
+ static factory redirect() → mai::Class2
+ let Never #redirecting_factory = mai::Class2::named in invalid-expression;
+ static method _#redirect#tearOff() → mai::Class2
+ return new mai::Class2::named();
}
class Class3 extends core::Object {
final field core::int field;
@@ -161,6 +207,7 @@
return new mai::Class3::•(field);
}
class Class4<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[mai::Class4::redirect]/*isLegacy*/;
constructor _() → mai::Class4<mai::Class4::T%>
: super core::Object::•()
;
@@ -170,6 +217,10 @@
return new mai::Class4::_<mai::Class4::•::T%>();
static method _#new#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#new#tearOff::T%>
return mai::Class4::•<mai::Class4::_#new#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::redirect::T%>
+ let Never #redirecting_factory = mai::Class4::_ in let mai::Class4::redirect::T% #typeArg0 = null in invalid-expression;
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#redirect#tearOff::T%>
+ return new mai::Class4::_<mai::Class4::_#redirect#tearOff::T%>();
}
class Class5<T extends core::num> extends core::Object {
constructor _() → mai::Class5<mai::Class5::T>
@@ -186,8 +237,10 @@
constants {
#C1 = static-tearoff mai::Class1::_#new#tearOff
#C2 = static-tearoff mai::Class2::_#named#tearOff
- #C3 = static-tearoff mai::Class3::_#new#tearOff
- #C4 = static-tearoff mai::Class4::_#new#tearOff
- #C5 = static-tearoff mai::Class5::_#new#tearOff
- #C6 = false
+ #C3 = static-tearoff mai::Class2::_#redirect#tearOff
+ #C4 = static-tearoff mai::Class3::_#new#tearOff
+ #C5 = static-tearoff mai::Class4::_#new#tearOff
+ #C6 = static-tearoff mai::Class4::_#redirect#tearOff
+ #C7 = static-tearoff mai::Class5::_#new#tearOff
+ #C8 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.expect
index 5f219e3..1806fdc 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.expect
@@ -2,29 +2,37 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:44:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:45:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:62:8: Error: Expected 1 type arguments.
// f4a<int, String>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:70:8: Error: Expected 0 type arguments.
// f4b<int>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:77:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:87:8: Error: Expected 1 type arguments.
+// f4d<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:95:8: Error: Expected 0 type arguments.
+// f4e<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:112:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
// Try changing type arguments so that they conform to the bounds.
// f5a<String>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:113:8: Error: Expected 1 type arguments.
// f5a<int, String>(); // error
// ^
//
@@ -50,24 +58,31 @@
dynamic c2b = f2b{dynamic}.call();
self::expect(true, c2b is{ForNonNullableByDefault} mai::Class2);
self::expect(true, core::identical(f2a, f2b));
- (core::int) → mai::Class3 f3a = #C3;
+ () → mai::Class2 f2c = #C3;
+ mai::Class2 c2c = f2c(){() → mai::Class2};
+ self::expect(true, c2c is{ForNonNullableByDefault} mai::Class2);
+ dynamic f2d = #C3;
+ dynamic c2d = f2d{dynamic}.call();
+ self::expect(true, c2d is{ForNonNullableByDefault} mai::Class2);
+ self::expect(true, core::identical(f2c, f2d));
+ (core::int) → mai::Class3 f3a = #C4;
mai::Class3 c3a = f3a(42){(core::int) → mai::Class3};
self::expect(42, c3a.{mai::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:44:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:45:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
};
- dynamic f3b = #C3;
+ dynamic f3b = #C4;
dynamic c3b = f3b{dynamic}.call(87);
self::expect(87, c3b{dynamic}.field);
self::throws(() → dynamic => f3b{dynamic}.call());
self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
- <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C4;
+ <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C5;
mai::Class4<dynamic> c4a = f4a<dynamic>(){() → mai::Class4<dynamic>};
self::expect(true, c4a is{ForNonNullableByDefault} mai::Class4<dynamic>);
self::expect(false, c4a is{ForNonNullableByDefault} mai::Class4<core::int>);
@@ -75,7 +90,7 @@
self::expect(true, c4b is{ForNonNullableByDefault} mai::Class4<core::int>);
self::expect(false, c4b is{ForNonNullableByDefault} mai::Class4<core::String>);
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:62:8: Error: Expected 1 type arguments.
f4a<int, String>(); // error
^" in f4a{<inapplicable>}.<core::int, core::String>();
};
@@ -84,16 +99,42 @@
self::expect(true, c4c is{ForNonNullableByDefault} mai::Class4<core::int>);
self::expect(false, c4c is{ForNonNullableByDefault} mai::Class4<core::String>);
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:70:8: Error: Expected 0 type arguments.
f4b<int>(); // error
^" in f4b{<inapplicable>}.<core::int>();
};
- dynamic f4c = #C4;
+ dynamic f4c = #C5;
dynamic c4d = f4c{dynamic}.call();
self::expect(true, c4d is{ForNonNullableByDefault} mai::Class4<dynamic>);
self::expect(false, c4d is{ForNonNullableByDefault} mai::Class4<core::int>);
self::throws(() → dynamic => f4c{dynamic}.call<core::int, core::String>());
- <T extends core::num>() → mai::Class5<T> f5a = #C5;
+ <T extends core::Object? = dynamic>() → mai::Class4<T%> f4d = #C6;
+ mai::Class4<dynamic> c4e = f4d<dynamic>(){() → mai::Class4<dynamic>};
+ self::expect(true, c4e is{ForNonNullableByDefault} mai::Class4<dynamic>);
+ self::expect(false, c4e is{ForNonNullableByDefault} mai::Class4<core::int>);
+ mai::Class4<core::int> c4f = f4d<core::int>(){() → mai::Class4<core::int>};
+ self::expect(true, c4f is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::expect(false, c4f is{ForNonNullableByDefault} mai::Class4<core::String>);
+ () → Null {
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:87:8: Error: Expected 1 type arguments.
+ f4d<int, String>(); // error
+ ^" in f4d{<inapplicable>}.<core::int, core::String>();
+ };
+ () → mai::Class4<core::int> f4e = f4d<core::int>;
+ mai::Class4<core::int> c4g = f4e(){() → mai::Class4<core::int>};
+ self::expect(true, c4g is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::expect(false, c4g is{ForNonNullableByDefault} mai::Class4<core::String>);
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:95:8: Error: Expected 0 type arguments.
+ f4e<int>(); // error
+ ^" in f4e{<inapplicable>}.<core::int>();
+ };
+ dynamic f4f = #C6;
+ dynamic c4h = f4f{dynamic}.call();
+ self::expect(true, c4h is{ForNonNullableByDefault} mai::Class4<dynamic>);
+ self::expect(false, c4h is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::throws(() → dynamic => f4f{dynamic}.call<core::int, core::String>());
+ <T extends core::num>() → mai::Class5<T> f5a = #C7;
mai::Class5<core::num> c5a = f5a<core::num>(){() → mai::Class5<core::num>};
self::expect(true, c5a is{ForNonNullableByDefault} mai::Class5<core::num>);
self::expect(false, c5a is{ForNonNullableByDefault} mai::Class5<core::int>);
@@ -102,11 +143,11 @@
self::expect(false, c5b is{ForNonNullableByDefault} mai::Class5<core::double>);
() → Null {
f5a<core::String>(){() → mai::Class5<core::String>};
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:113:8: Error: Expected 1 type arguments.
f5a<int, String>(); // error
^" in f5a{<inapplicable>}.<core::int, core::String>();
};
- dynamic f5b = #C5;
+ dynamic f5b = #C7;
dynamic c5c = f5b{dynamic}.call();
self::expect(true, c5c is{ForNonNullableByDefault} mai::Class5<core::num>);
self::expect(false, c5c is{ForNonNullableByDefault} mai::Class5<core::int>);
@@ -120,7 +161,7 @@
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C6}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
try {
f(){() → dynamic};
}
@@ -146,11 +187,16 @@
return new mai::Class1::•();
}
class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[mai::Class2::redirect]/*isLegacy*/;
constructor named() → mai::Class2
: super core::Object::•()
;
static method _#named#tearOff() → mai::Class2
return new mai::Class2::named();
+ static factory redirect() → mai::Class2
+ let dynamic #redirecting_factory = mai::Class2::named in invalid-expression;
+ static method _#redirect#tearOff() → mai::Class2
+ return new mai::Class2::named();
}
class Class3 extends core::Object {
final field core::int field;
@@ -161,6 +207,7 @@
return new mai::Class3::•(field);
}
class Class4<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[mai::Class4::redirect]/*isLegacy*/;
constructor _() → mai::Class4<mai::Class4::T%>
: super core::Object::•()
;
@@ -170,6 +217,10 @@
return new mai::Class4::_<mai::Class4::•::T%>();
static method _#new#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#new#tearOff::T%>
return mai::Class4::•<mai::Class4::_#new#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::redirect::T%>
+ let dynamic #redirecting_factory = mai::Class4::_ in let mai::Class4::redirect::T% #typeArg0 = null in invalid-expression;
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#redirect#tearOff::T%>
+ return new mai::Class4::_<mai::Class4::_#redirect#tearOff::T%>();
}
class Class5<T extends core::num> extends core::Object {
constructor _() → mai::Class5<mai::Class5::T>
@@ -186,8 +237,10 @@
constants {
#C1 = static-tearoff mai::Class1::_#new#tearOff
#C2 = static-tearoff mai::Class2::_#named#tearOff
- #C3 = static-tearoff mai::Class3::_#new#tearOff
- #C4 = static-tearoff mai::Class4::_#new#tearOff
- #C5 = static-tearoff mai::Class5::_#new#tearOff
- #C6 = false
+ #C3 = static-tearoff mai::Class2::_#redirect#tearOff
+ #C4 = static-tearoff mai::Class3::_#new#tearOff
+ #C5 = static-tearoff mai::Class4::_#new#tearOff
+ #C6 = static-tearoff mai::Class4::_#redirect#tearOff
+ #C7 = static-tearoff mai::Class5::_#new#tearOff
+ #C8 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.outline.expect
index 2591204..a682b15 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.outline.expect
@@ -23,10 +23,15 @@
return new self2::Class1::•();
}
class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self2::Class2::redirect]/*isLegacy*/;
constructor named() → self2::Class2
;
static method _#named#tearOff() → self2::Class2
return new self2::Class2::named();
+ static factory redirect() → self2::Class2
+ let dynamic #redirecting_factory = self2::Class2::named in invalid-expression;
+ static method _#redirect#tearOff() → self2::Class2
+ return new self2::Class2::named();
}
class Class3 extends core::Object {
final field core::int field;
@@ -36,6 +41,7 @@
return new self2::Class3::•(field);
}
class Class4<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self2::Class4::redirect]/*isLegacy*/;
constructor _() → self2::Class4<self2::Class4::T%>
;
static method _#_#tearOff<T extends core::Object? = dynamic>() → self2::Class4<self2::Class4::_#_#tearOff::T%>
@@ -44,6 +50,10 @@
;
static method _#new#tearOff<T extends core::Object? = dynamic>() → self2::Class4<self2::Class4::_#new#tearOff::T%>
return self2::Class4::•<self2::Class4::_#new#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → self2::Class4<self2::Class4::redirect::T%>
+ let dynamic #redirecting_factory = self2::Class4::_ in let self2::Class4::redirect::T% #typeArg0 = null in invalid-expression;
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → self2::Class4<self2::Class4::_#redirect#tearOff::T%>
+ return new self2::Class4::_<self2::Class4::_#redirect#tearOff::T%>();
}
class Class5<T extends core::num> extends core::Object {
constructor _() → self2::Class5<self2::Class5::T>
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.transformed.expect
index 42623ded..9edd33a 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.transformed.expect
@@ -2,29 +2,37 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:44:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:45:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:62:8: Error: Expected 1 type arguments.
// f4a<int, String>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:70:8: Error: Expected 0 type arguments.
// f4b<int>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:77:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:87:8: Error: Expected 1 type arguments.
+// f4d<int, String>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:95:8: Error: Expected 0 type arguments.
+// f4e<int>(); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:112:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
// Try changing type arguments so that they conform to the bounds.
// f5a<String>(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:113:8: Error: Expected 1 type arguments.
// f5a<int, String>(); // error
// ^
//
@@ -50,24 +58,31 @@
dynamic c2b = f2b{dynamic}.call();
self::expect(true, c2b is{ForNonNullableByDefault} mai::Class2);
self::expect(true, core::identical(f2a, f2b));
- (core::int) → mai::Class3 f3a = #C3;
+ () → mai::Class2 f2c = #C3;
+ mai::Class2 c2c = f2c(){() → mai::Class2};
+ self::expect(true, c2c is{ForNonNullableByDefault} mai::Class2);
+ dynamic f2d = #C3;
+ dynamic c2d = f2d{dynamic}.call();
+ self::expect(true, c2d is{ForNonNullableByDefault} mai::Class2);
+ self::expect(true, core::identical(f2c, f2d));
+ (core::int) → mai::Class3 f3a = #C4;
mai::Class3 c3a = f3a(42){(core::int) → mai::Class3};
self::expect(42, c3a.{mai::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:44:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:45:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
};
- dynamic f3b = #C3;
+ dynamic f3b = #C4;
dynamic c3b = f3b{dynamic}.call(87);
self::expect(87, c3b{dynamic}.field);
self::throws(() → dynamic => f3b{dynamic}.call());
self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
- <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C4;
+ <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C5;
mai::Class4<dynamic> c4a = f4a<dynamic>(){() → mai::Class4<dynamic>};
self::expect(true, c4a is{ForNonNullableByDefault} mai::Class4<dynamic>);
self::expect(false, c4a is{ForNonNullableByDefault} mai::Class4<core::int>);
@@ -75,7 +90,7 @@
self::expect(true, c4b is{ForNonNullableByDefault} mai::Class4<core::int>);
self::expect(false, c4b is{ForNonNullableByDefault} mai::Class4<core::String>);
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:62:8: Error: Expected 1 type arguments.
f4a<int, String>(); // error
^" in f4a{<inapplicable>}.<core::int, core::String>();
};
@@ -84,16 +99,42 @@
self::expect(true, c4c is{ForNonNullableByDefault} mai::Class4<core::int>);
self::expect(false, c4c is{ForNonNullableByDefault} mai::Class4<core::String>);
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:70:8: Error: Expected 0 type arguments.
f4b<int>(); // error
^" in f4b{<inapplicable>}.<core::int>();
};
- dynamic f4c = #C4;
+ dynamic f4c = #C5;
dynamic c4d = f4c{dynamic}.call();
self::expect(true, c4d is{ForNonNullableByDefault} mai::Class4<dynamic>);
self::expect(false, c4d is{ForNonNullableByDefault} mai::Class4<core::int>);
self::throws(() → dynamic => f4c{dynamic}.call<core::int, core::String>());
- <T extends core::num>() → mai::Class5<T> f5a = #C5;
+ <T extends core::Object? = dynamic>() → mai::Class4<T%> f4d = #C6;
+ mai::Class4<dynamic> c4e = f4d<dynamic>(){() → mai::Class4<dynamic>};
+ self::expect(true, c4e is{ForNonNullableByDefault} mai::Class4<dynamic>);
+ self::expect(false, c4e is{ForNonNullableByDefault} mai::Class4<core::int>);
+ mai::Class4<core::int> c4f = f4d<core::int>(){() → mai::Class4<core::int>};
+ self::expect(true, c4f is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::expect(false, c4f is{ForNonNullableByDefault} mai::Class4<core::String>);
+ () → Null {
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:87:8: Error: Expected 1 type arguments.
+ f4d<int, String>(); // error
+ ^" in f4d{<inapplicable>}.<core::int, core::String>();
+ };
+ () → mai::Class4<core::int> f4e = f4d<core::int>;
+ mai::Class4<core::int> c4g = f4e(){() → mai::Class4<core::int>};
+ self::expect(true, c4g is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::expect(false, c4g is{ForNonNullableByDefault} mai::Class4<core::String>);
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:95:8: Error: Expected 0 type arguments.
+ f4e<int>(); // error
+ ^" in f4e{<inapplicable>}.<core::int>();
+ };
+ dynamic f4f = #C6;
+ dynamic c4h = f4f{dynamic}.call();
+ self::expect(true, c4h is{ForNonNullableByDefault} mai::Class4<dynamic>);
+ self::expect(false, c4h is{ForNonNullableByDefault} mai::Class4<core::int>);
+ self::throws(() → dynamic => f4f{dynamic}.call<core::int, core::String>());
+ <T extends core::num>() → mai::Class5<T> f5a = #C7;
mai::Class5<core::num> c5a = f5a<core::num>(){() → mai::Class5<core::num>};
self::expect(true, c5a is{ForNonNullableByDefault} mai::Class5<core::num>);
self::expect(false, c5a is{ForNonNullableByDefault} mai::Class5<core::int>);
@@ -102,11 +143,11 @@
self::expect(false, c5b is{ForNonNullableByDefault} mai::Class5<core::double>);
() → Null {
f5a<core::String>(){() → mai::Class5<core::String>};
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:113:8: Error: Expected 1 type arguments.
f5a<int, String>(); // error
^" in f5a{<inapplicable>}.<core::int, core::String>();
};
- dynamic f5b = #C5;
+ dynamic f5b = #C7;
dynamic c5c = f5b{dynamic}.call();
self::expect(true, c5c is{ForNonNullableByDefault} mai::Class5<core::num>);
self::expect(false, c5c is{ForNonNullableByDefault} mai::Class5<core::int>);
@@ -120,7 +161,7 @@
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C6}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
try {
f(){() → dynamic};
}
@@ -146,11 +187,16 @@
return new mai::Class1::•();
}
class Class2 extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[mai::Class2::redirect]/*isLegacy*/;
constructor named() → mai::Class2
: super core::Object::•()
;
static method _#named#tearOff() → mai::Class2
return new mai::Class2::named();
+ static factory redirect() → mai::Class2
+ let Never #redirecting_factory = mai::Class2::named in invalid-expression;
+ static method _#redirect#tearOff() → mai::Class2
+ return new mai::Class2::named();
}
class Class3 extends core::Object {
final field core::int field;
@@ -161,6 +207,7 @@
return new mai::Class3::•(field);
}
class Class4<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[mai::Class4::redirect]/*isLegacy*/;
constructor _() → mai::Class4<mai::Class4::T%>
: super core::Object::•()
;
@@ -170,6 +217,10 @@
return new mai::Class4::_<mai::Class4::•::T%>();
static method _#new#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#new#tearOff::T%>
return mai::Class4::•<mai::Class4::_#new#tearOff::T%>();
+ static factory redirect<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::redirect::T%>
+ let Never #redirecting_factory = mai::Class4::_ in let mai::Class4::redirect::T% #typeArg0 = null in invalid-expression;
+ static method _#redirect#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#redirect#tearOff::T%>
+ return new mai::Class4::_<mai::Class4::_#redirect#tearOff::T%>();
}
class Class5<T extends core::num> extends core::Object {
constructor _() → mai::Class5<mai::Class5::T>
@@ -186,8 +237,10 @@
constants {
#C1 = static-tearoff mai::Class1::_#new#tearOff
#C2 = static-tearoff mai::Class2::_#named#tearOff
- #C3 = static-tearoff mai::Class3::_#new#tearOff
- #C4 = static-tearoff mai::Class4::_#new#tearOff
- #C5 = static-tearoff mai::Class5::_#new#tearOff
- #C6 = false
+ #C3 = static-tearoff mai::Class2::_#redirect#tearOff
+ #C4 = static-tearoff mai::Class3::_#new#tearOff
+ #C5 = static-tearoff mai::Class4::_#new#tearOff
+ #C6 = static-tearoff mai::Class4::_#redirect#tearOff
+ #C7 = static-tearoff mai::Class5::_#new#tearOff
+ #C8 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main_lib.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main_lib.dart
index f50d3cd..eed7823 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main_lib.dart
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main_lib.dart
@@ -6,6 +6,7 @@
class Class2 {
Class2.named();
+ factory Class2.redirect() = Class2.named;
}
class Class3 {
@@ -17,6 +18,7 @@
class Class4<T> {
Class4._();
factory Class4() => new Class4<T>._();
+ factory Class4.redirect() = Class4._;
}
class Class5<T extends num> {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart
new file mode 100644
index 0000000..ed7af3d1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart
@@ -0,0 +1,14 @@
+// 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.
+
+class Class {
+ Class._();
+ static Class constructor() => new Class._();
+ static Class Function() field = () => new Class._();
+
+ factory Class.a() = Class.nonexisting;
+ factory Class.b() = Class.constructor;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.strong.expect
new file mode 100644
index 0000000..d55e231
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.strong.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:10:23: Error: Redirection constructor target not found: 'Class.nonexisting'
+// factory Class.a() = Class.nonexisting;
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:11:23: Error: Redirection constructor target not found: 'Class.constructor'
+// factory Class.b() = Class.constructor;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ static field () → self::Class field = () → self::Class => new self::Class::_();
+ static final field dynamic _redirecting# = <dynamic>[self::Class::a, self::Class::b]/*isLegacy*/;
+ constructor _() → self::Class
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class
+ return new self::Class::_();
+ static method constructor() → self::Class
+ return new self::Class::_();
+ static factory a() → self::Class
+ let dynamic #redirecting_factory = "Class.nonexisting" in invalid-expression;
+ static method _#a#tearOff() → self::Class;
+ static factory b() → self::Class
+ let dynamic #redirecting_factory = "Class.constructor" in invalid-expression;
+ static method _#b#tearOff() → self::Class;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.strong.transformed.expect
new file mode 100644
index 0000000..fe5e039
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.strong.transformed.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:10:23: Error: Redirection constructor target not found: 'Class.nonexisting'
+// factory Class.a() = Class.nonexisting;
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:11:23: Error: Redirection constructor target not found: 'Class.constructor'
+// factory Class.b() = Class.constructor;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ static field () → self::Class field = () → self::Class => new self::Class::_();
+ static final field dynamic _redirecting# = <dynamic>[self::Class::a, self::Class::b]/*isLegacy*/;
+ constructor _() → self::Class
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class
+ return new self::Class::_();
+ static method constructor() → self::Class
+ return new self::Class::_();
+ static factory a() → self::Class
+ let core::String* #redirecting_factory = "Class.nonexisting" in invalid-expression;
+ static method _#a#tearOff() → self::Class;
+ static factory b() → self::Class
+ let core::String* #redirecting_factory = "Class.constructor" in invalid-expression;
+ static method _#b#tearOff() → self::Class;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.textual_outline.expect
new file mode 100644
index 0000000..1dc9515
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.textual_outline.expect
@@ -0,0 +1,9 @@
+class Class {
+ Class._();
+ static Class constructor() => new Class._();
+ static Class Function() field = () => new Class._();
+ factory Class.a() = Class.nonexisting;
+ factory Class.b() = Class.constructor;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..f765ff19
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.textual_outline_modelled.expect
@@ -0,0 +1,9 @@
+class Class {
+ Class._();
+ factory Class.a() = Class.nonexisting;
+ factory Class.b() = Class.constructor;
+ static Class Function() field = () => new Class._();
+ static Class constructor() => new Class._();
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.weak.expect
new file mode 100644
index 0000000..d55e231
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.weak.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:10:23: Error: Redirection constructor target not found: 'Class.nonexisting'
+// factory Class.a() = Class.nonexisting;
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:11:23: Error: Redirection constructor target not found: 'Class.constructor'
+// factory Class.b() = Class.constructor;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ static field () → self::Class field = () → self::Class => new self::Class::_();
+ static final field dynamic _redirecting# = <dynamic>[self::Class::a, self::Class::b]/*isLegacy*/;
+ constructor _() → self::Class
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class
+ return new self::Class::_();
+ static method constructor() → self::Class
+ return new self::Class::_();
+ static factory a() → self::Class
+ let dynamic #redirecting_factory = "Class.nonexisting" in invalid-expression;
+ static method _#a#tearOff() → self::Class;
+ static factory b() → self::Class
+ let dynamic #redirecting_factory = "Class.constructor" in invalid-expression;
+ static method _#b#tearOff() → self::Class;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.weak.outline.expect
new file mode 100644
index 0000000..7a6886a
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.weak.outline.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:10:23: Error: Redirection constructor target not found: 'Class.nonexisting'
+// factory Class.a() = Class.nonexisting;
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:11:23: Error: Redirection constructor target not found: 'Class.constructor'
+// factory Class.b() = Class.constructor;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ static field () → self::Class field;
+ static final field dynamic _redirecting# = <dynamic>[self::Class::a, self::Class::b]/*isLegacy*/;
+ constructor _() → self::Class
+ ;
+ static method _#_#tearOff() → self::Class
+ return new self::Class::_();
+ static method constructor() → self::Class
+ ;
+ static factory a() → self::Class
+ let dynamic #redirecting_factory = "Class.nonexisting" in invalid-expression;
+ static method _#a#tearOff() → self::Class;
+ static factory b() → self::Class
+ let dynamic #redirecting_factory = "Class.constructor" in invalid-expression;
+ static method _#b#tearOff() → self::Class;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.weak.transformed.expect
new file mode 100644
index 0000000..fe5e039
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart.weak.transformed.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:10:23: Error: Redirection constructor target not found: 'Class.nonexisting'
+// factory Class.a() = Class.nonexisting;
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/missing_redirecting_target.dart:11:23: Error: Redirection constructor target not found: 'Class.constructor'
+// factory Class.b() = Class.constructor;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ static field () → self::Class field = () → self::Class => new self::Class::_();
+ static final field dynamic _redirecting# = <dynamic>[self::Class::a, self::Class::b]/*isLegacy*/;
+ constructor _() → self::Class
+ : super core::Object::•()
+ ;
+ static method _#_#tearOff() → self::Class
+ return new self::Class::_();
+ static method constructor() → self::Class
+ return new self::Class::_();
+ static factory a() → self::Class
+ let core::String* #redirecting_factory = "Class.nonexisting" in invalid-expression;
+ static method _#a#tearOff() → self::Class;
+ static factory b() → self::Class
+ let core::String* #redirecting_factory = "Class.constructor" in invalid-expression;
+ static method _#b#tearOff() → self::Class;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart
index 75d63fa..765da64 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart
@@ -16,8 +16,9 @@
}
class Class2 {
- Class2._();
- factory Class2.named() = Class2._;
+ Class2.__();
+ factory Class2._() => Class2.__();
+ factory Class2.named() = Class2._;
}
testNoArgs() {
@@ -74,6 +75,22 @@
Class6._;
}
+class Class7a implements Class7b {
+ Class7a();
+}
+
+class Class7b {
+ factory Class7b() = Class7a;
+}
+
+class Class8a<T> implements Class8b<T> {
+ Class8a();
+}
+
+class Class8b<T> {
+ factory Class8b() = Class8a<T>;
+}
+
testArgs() {
var f3a = Class3.new;
var c3a = f3a(42);
@@ -143,6 +160,20 @@
throws(() => f6b(42), inSoundModeOnly: true);
throws(() => f6b(42, 87), inSoundModeOnly: true);
throws(() => f6b(field1: 87, field2: 87));
+
+ var f7a = Class7b.new;
+ var c7a = f7a();
+ expect(true, c7a is Class7a);
+ expect(true, c7a is Class7b);
+
+ var f8a = Class8b.new;
+ var c8a = f8a();
+ expect(true, c8a is Class8a);
+ expect(true, c8a is Class8b);
+ var c8b = f8a<int>();
+ expect(true, c8b is Class8a<int>);
+ expect(true, c8b is Class8b<int>);
+ expect(false, c8b is Class8b<String>);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect
index f5b0f3e..a115126 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect
@@ -2,43 +2,43 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f4a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
// f5a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// f5a(42, 87, 123); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
// f6a(42); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f6a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(field1: 87, field2: 87); // error
// ^
//
@@ -59,15 +59,19 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
: super core::Object::•()
;
+ static method _#__#tearOff() → self::Class2
+ return new self::Class2::__();
+ static factory _() → self::Class2
+ return new self::Class2::__();
static method _#_#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
static factory named() → self::Class2
let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
static method _#named#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
}
class Class3 extends core::Object {
final field core::int field;
@@ -124,6 +128,34 @@
static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return new self::Class6::_(field1, field2: field2, field3: field3);
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff() → self::Class7a
+ return new self::Class7a::•();
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let dynamic #redirecting_factory = self::Class7a::• in invalid-expression;
+ static method _#new#tearOff() → self::Class7b
+ return new self::Class7a::•();
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let dynamic #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+}
static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -151,10 +183,10 @@
self::Class3 c3a = f3a(42){(core::int) → self::Class3};
self::expect(42, c3a.{self::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
@@ -170,7 +202,7 @@
self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
self::expect(42, c4b.{self::Class4::field}{core::int?});
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f4a(42, 87); // error
^" in f4a{<inapplicable>}.(42, 87);
@@ -185,10 +217,10 @@
self::expect(87, c5b.{self::Class5::field1}{core::int});
self::expect(42, c5b.{self::Class5::field2}{core::int?});
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
f5a(); // error
^" in f5a{<inapplicable>}.();
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
f5a(42, 87, 123); // error
^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -202,17 +234,17 @@
self::expect(null, c6a.{self::Class6::field2}{core::int?});
self::expect(87, c6a.{self::Class6::field3}{core::int});
() → Null {
- let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(); // error
^" in f6a{<inapplicable>}.();
- let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
f6a(42); // error
^" in f6a{<inapplicable>}.(42);
- let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f6a(42, 87); // error
^" in f6a{<inapplicable>}.(42, 87);
- let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(field1: 87, field2: 87); // error
^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
};
@@ -229,12 +261,24 @@
self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+ () → self::Class7b f7a = #C8;
+ self::Class7b c7a = f7a(){() → self::Class7b};
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7a);
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7b);
+ <T extends core::Object? = dynamic>() → self::Class8b<T%> f8a = #C9;
+ self::Class8b<dynamic> c8a = f8a<dynamic>(){() → self::Class8b<dynamic>};
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8a<dynamic>);
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8b<dynamic>);
+ self::Class8b<core::int> c8b = f8a<core::int>(){() → self::Class8b<core::int>};
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
+ self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
try {
f(){() → dynamic};
}
@@ -256,5 +300,7 @@
#C5 = static-tearoff self::Class4::_#new#tearOff
#C6 = static-tearoff self::Class5::_#new#tearOff
#C7 = static-tearoff self::Class6::_#new#tearOff
- #C8 = false
+ #C8 = static-tearoff self::Class7b::_#new#tearOff
+ #C9 = static-tearoff self::Class8b::_#new#tearOff
+ #C10 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect
index 59fb725..02a4614 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect
@@ -2,43 +2,43 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f4a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
// f5a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// f5a(42, 87, 123); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
// f6a(42); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f6a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(field1: 87, field2: 87); // error
// ^
//
@@ -59,15 +59,19 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
: super core::Object::•()
;
+ static method _#__#tearOff() → self::Class2
+ return new self::Class2::__();
+ static factory _() → self::Class2
+ return new self::Class2::__();
static method _#_#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
static factory named() → self::Class2
- let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+ let () → self::Class2 #redirecting_factory = self::Class2::_ in invalid-expression;
static method _#named#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
}
class Class3 extends core::Object {
final field core::int field;
@@ -124,6 +128,34 @@
static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return new self::Class6::_(field1, field2: field2, field3: field3);
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff() → self::Class7a
+ return new self::Class7a::•();
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let Never #redirecting_factory = self::Class7a::• in invalid-expression;
+ static method _#new#tearOff() → self::Class7b
+ return new self::Class7a::•();
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let Never #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+}
static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -151,10 +183,10 @@
self::Class3 c3a = f3a(42){(core::int) → self::Class3};
self::expect(42, c3a.{self::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
@@ -170,7 +202,7 @@
self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
self::expect(42, c4b.{self::Class4::field}{core::int?});
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f4a(42, 87); // error
^" in f4a{<inapplicable>}.(42, 87);
@@ -185,10 +217,10 @@
self::expect(87, c5b.{self::Class5::field1}{core::int});
self::expect(42, c5b.{self::Class5::field2}{core::int?});
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
f5a(); // error
^" in f5a{<inapplicable>}.();
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
f5a(42, 87, 123); // error
^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -202,17 +234,17 @@
self::expect(null, c6a.{self::Class6::field2}{core::int?});
self::expect(87, c6a.{self::Class6::field3}{core::int});
() → Null {
- let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(); // error
^" in f6a{<inapplicable>}.();
- let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
f6a(42); // error
^" in f6a{<inapplicable>}.(42);
- let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f6a(42, 87); // error
^" in f6a{<inapplicable>}.(42, 87);
- let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(field1: 87, field2: 87); // error
^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
};
@@ -229,12 +261,24 @@
self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+ () → self::Class7b f7a = #C8;
+ self::Class7b c7a = f7a(){() → self::Class7b};
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7a);
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7b);
+ <T extends core::Object? = dynamic>() → self::Class8b<T%> f8a = #C9;
+ self::Class8b<dynamic> c8a = f8a<dynamic>(){() → self::Class8b<dynamic>};
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8a<dynamic>);
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8b<dynamic>);
+ self::Class8b<core::int> c8b = f8a<core::int>(){() → self::Class8b<core::int>};
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
+ self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
try {
f(){() → dynamic};
}
@@ -256,5 +300,7 @@
#C5 = static-tearoff self::Class4::_#new#tearOff
#C6 = static-tearoff self::Class5::_#new#tearOff
#C7 = static-tearoff self::Class6::_#new#tearOff
- #C8 = false
+ #C8 = static-tearoff self::Class7b::_#new#tearOff
+ #C9 = static-tearoff self::Class8b::_#new#tearOff
+ #C10 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect
index 999b5d2..2fa25d6 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect
@@ -7,7 +7,8 @@
}
class Class2 {
- Class2._();
+ Class2.__();
+ factory Class2._() => Class2.__();
factory Class2.named() = Class2._;
}
@@ -40,6 +41,22 @@
factory Class6(int field1, {int? field2, required int field3}) = Class6._;
}
+class Class7a implements Class7b {
+ Class7a();
+}
+
+class Class7b {
+ factory Class7b() = Class7a;
+}
+
+class Class8a<T> implements Class8b<T> {
+ Class8a();
+}
+
+class Class8b<T> {
+ factory Class8b() = Class8a<T>;
+}
+
testArgs() {}
expect(expected, actual) {}
throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
index edb4f68..0500e74 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
@@ -4,7 +4,8 @@
}
class Class2 {
- Class2._();
+ Class2.__();
+ factory Class2._() => Class2.__();
factory Class2.named() = Class2._;
}
@@ -35,6 +36,22 @@
final int field3;
}
+class Class7a implements Class7b {
+ Class7a();
+}
+
+class Class7b {
+ factory Class7b() = Class7a;
+}
+
+class Class8a<T> implements Class8b<T> {
+ Class8a();
+}
+
+class Class8b<T> {
+ factory Class8b() = Class8a<T>;
+}
+
expect(expected, actual) {}
final bool inSoundMode = <int?>[] is! List<int>;
main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect
index f5b0f3e..a115126 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect
@@ -2,43 +2,43 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f4a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
// f5a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// f5a(42, 87, 123); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
// f6a(42); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f6a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(field1: 87, field2: 87); // error
// ^
//
@@ -59,15 +59,19 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
: super core::Object::•()
;
+ static method _#__#tearOff() → self::Class2
+ return new self::Class2::__();
+ static factory _() → self::Class2
+ return new self::Class2::__();
static method _#_#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
static factory named() → self::Class2
let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
static method _#named#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
}
class Class3 extends core::Object {
final field core::int field;
@@ -124,6 +128,34 @@
static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return new self::Class6::_(field1, field2: field2, field3: field3);
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff() → self::Class7a
+ return new self::Class7a::•();
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let dynamic #redirecting_factory = self::Class7a::• in invalid-expression;
+ static method _#new#tearOff() → self::Class7b
+ return new self::Class7a::•();
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let dynamic #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+}
static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -151,10 +183,10 @@
self::Class3 c3a = f3a(42){(core::int) → self::Class3};
self::expect(42, c3a.{self::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
@@ -170,7 +202,7 @@
self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
self::expect(42, c4b.{self::Class4::field}{core::int?});
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f4a(42, 87); // error
^" in f4a{<inapplicable>}.(42, 87);
@@ -185,10 +217,10 @@
self::expect(87, c5b.{self::Class5::field1}{core::int});
self::expect(42, c5b.{self::Class5::field2}{core::int?});
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
f5a(); // error
^" in f5a{<inapplicable>}.();
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
f5a(42, 87, 123); // error
^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -202,17 +234,17 @@
self::expect(null, c6a.{self::Class6::field2}{core::int?});
self::expect(87, c6a.{self::Class6::field3}{core::int});
() → Null {
- let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(); // error
^" in f6a{<inapplicable>}.();
- let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
f6a(42); // error
^" in f6a{<inapplicable>}.(42);
- let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f6a(42, 87); // error
^" in f6a{<inapplicable>}.(42, 87);
- let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(field1: 87, field2: 87); // error
^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
};
@@ -229,12 +261,24 @@
self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+ () → self::Class7b f7a = #C8;
+ self::Class7b c7a = f7a(){() → self::Class7b};
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7a);
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7b);
+ <T extends core::Object? = dynamic>() → self::Class8b<T%> f8a = #C9;
+ self::Class8b<dynamic> c8a = f8a<dynamic>(){() → self::Class8b<dynamic>};
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8a<dynamic>);
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8b<dynamic>);
+ self::Class8b<core::int> c8b = f8a<core::int>(){() → self::Class8b<core::int>};
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
+ self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
try {
f(){() → dynamic};
}
@@ -256,5 +300,7 @@
#C5 = static-tearoff self::Class4::_#new#tearOff
#C6 = static-tearoff self::Class5::_#new#tearOff
#C7 = static-tearoff self::Class6::_#new#tearOff
- #C8 = false
+ #C8 = static-tearoff self::Class7b::_#new#tearOff
+ #C9 = static-tearoff self::Class8b::_#new#tearOff
+ #C10 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect
index f5e4544..0067daa 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect
@@ -15,14 +15,18 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
+ ;
+ static method _#__#tearOff() → self::Class2
+ return new self::Class2::__();
+ static factory _() → self::Class2
;
static method _#_#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
static factory named() → self::Class2
let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
static method _#named#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
}
class Class3 extends core::Object {
final field core::int field;
@@ -75,6 +79,32 @@
static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
return new self::Class6::_(field1, field2: field2, field3: field3);
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ ;
+ static method _#new#tearOff() → self::Class7a
+ return new self::Class7a::•();
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let dynamic #redirecting_factory = self::Class7a::• in invalid-expression;
+ static method _#new#tearOff() → self::Class7b
+ return new self::Class7a::•();
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let dynamic #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+}
static final field core::bool inSoundMode;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect
index 59fb725..02a4614 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect
@@ -2,43 +2,43 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f4a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
// f5a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// f5a(42, 87, 123); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
// f6a(42); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f6a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(field1: 87, field2: 87); // error
// ^
//
@@ -59,15 +59,19 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
: super core::Object::•()
;
+ static method _#__#tearOff() → self::Class2
+ return new self::Class2::__();
+ static factory _() → self::Class2
+ return new self::Class2::__();
static method _#_#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
static factory named() → self::Class2
- let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+ let () → self::Class2 #redirecting_factory = self::Class2::_ in invalid-expression;
static method _#named#tearOff() → self::Class2
- return new self::Class2::_();
+ return self::Class2::_();
}
class Class3 extends core::Object {
final field core::int field;
@@ -124,6 +128,34 @@
static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
return new self::Class6::_(field1, field2: field2, field3: field3);
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff() → self::Class7a
+ return new self::Class7a::•();
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let Never #redirecting_factory = self::Class7a::• in invalid-expression;
+ static method _#new#tearOff() → self::Class7b
+ return new self::Class7a::•();
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ : super core::Object::•()
+ ;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let Never #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+ static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
+ return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+}
static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -151,10 +183,10 @@
self::Class3 c3a = f3a(42){(core::int) → self::Class3};
self::expect(42, c3a.{self::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
@@ -170,7 +202,7 @@
self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
self::expect(42, c4b.{self::Class4::field}{core::int?});
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f4a(42, 87); // error
^" in f4a{<inapplicable>}.(42, 87);
@@ -185,10 +217,10 @@
self::expect(87, c5b.{self::Class5::field1}{core::int});
self::expect(42, c5b.{self::Class5::field2}{core::int?});
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
f5a(); // error
^" in f5a{<inapplicable>}.();
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
f5a(42, 87, 123); // error
^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -202,17 +234,17 @@
self::expect(null, c6a.{self::Class6::field2}{core::int?});
self::expect(87, c6a.{self::Class6::field3}{core::int});
() → Null {
- let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(); // error
^" in f6a{<inapplicable>}.();
- let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
f6a(42); // error
^" in f6a{<inapplicable>}.(42);
- let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f6a(42, 87); // error
^" in f6a{<inapplicable>}.(42, 87);
- let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(field1: 87, field2: 87); // error
^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
};
@@ -229,12 +261,24 @@
self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+ () → self::Class7b f7a = #C8;
+ self::Class7b c7a = f7a(){() → self::Class7b};
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7a);
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7b);
+ <T extends core::Object? = dynamic>() → self::Class8b<T%> f8a = #C9;
+ self::Class8b<dynamic> c8a = f8a<dynamic>(){() → self::Class8b<dynamic>};
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8a<dynamic>);
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8b<dynamic>);
+ self::Class8b<core::int> c8b = f8a<core::int>(){() → self::Class8b<core::int>};
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
+ self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
try {
f(){() → dynamic};
}
@@ -256,5 +300,7 @@
#C5 = static-tearoff self::Class4::_#new#tearOff
#C6 = static-tearoff self::Class5::_#new#tearOff
#C7 = static-tearoff self::Class6::_#new#tearOff
- #C8 = false
+ #C8 = static-tearoff self::Class7b::_#new#tearOff
+ #C9 = static-tearoff self::Class8b::_#new#tearOff
+ #C10 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart
new file mode 100644
index 0000000..605ae05
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart
@@ -0,0 +1,152 @@
+// 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.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+ print('inSoundMode: $inSoundMode');
+ testDefaultValues();
+}
+
+class Class1 {
+ final int field1;
+ final int field2;
+
+ Class1.positional([this.field1 = 1, this.field2 = 2]);
+
+ factory Class1.redirectPositionalSame([int field1, int field2]) =
+ Class1.positional;
+
+ factory Class1.redirectPositionalFewer1([int field1]) = Class1.positional;
+
+ factory Class1.redirectPositionalFewer2() = Class1.positional;
+
+ Class1.named({this.field1 = 1, this.field2 = 2});
+
+ factory Class1.redirectNamedSame({int field1, int field2}) = Class1.named;
+
+ factory Class1.redirectNamedReorder({int field2, int field1}) = Class1.named;
+
+ factory Class1.redirectNamedFewer1({int field1}) = Class1.named;
+
+ factory Class1.redirectNamedFewer2({int field2}) = Class1.named;
+
+ factory Class1.redirectNamedFewer3() = Class1.named;
+}
+
+testDefaultValues() {
+ var f1a = Class1.redirectPositionalSame;
+ var c1a = f1a();
+ expect(1, c1a.field1);
+ expect(2, c1a.field2);
+ var c1b = f1a(42);
+ expect(42, c1b.field1);
+ expect(2, c1b.field2);
+ var c1c = f1a(42, 87);
+ expect(42, c1c.field1);
+ expect(87, c1c.field2);
+
+ var f1b = Class1.redirectPositionalFewer1;
+ var c1d = f1b();
+ expect(1, c1d.field1);
+ expect(2, c1d.field2);
+ var c1e = f1b(42);
+ expect(42, c1e.field1);
+ expect(2, c1e.field2);
+ () {
+ f1b(42, 87); // error
+ };
+
+ var f1c = Class1.redirectPositionalFewer2;
+ var c1f = f1c();
+ expect(1, c1f.field1);
+ expect(2, c1f.field2);
+ () {
+ f1c(42); // error
+ f1c(42, 87); // error
+ };
+
+ var f2a = Class1.redirectNamedSame;
+ var c2a = f2a();
+ expect(1, c2a.field1);
+ expect(2, c2a.field2);
+ var c2b = f2a(field1: 42);
+ expect(42, c2b.field1);
+ expect(2, c2b.field2);
+ var c2c = f2a(field1: 42, field2: 87);
+ expect(42, c2c.field1);
+ expect(87, c2c.field2);
+ var c2d = f2a(field2: 87);
+ expect(1, c2d.field1);
+ expect(87, c2d.field2);
+ var c2e = f2a(field2: 87, field1: 42);
+ expect(42, c2e.field1);
+ expect(87, c2e.field2);
+
+ var f2b = Class1.redirectNamedReorder;
+ var c3a = f2b();
+ expect(1, c3a.field1);
+ expect(2, c3a.field2);
+ var c3b = f2b(field1: 42);
+ expect(42, c3b.field1);
+ expect(2, c3b.field2);
+ var c3c = f2b(field1: 42, field2: 87);
+ expect(42, c3c.field1);
+ expect(87, c3c.field2);
+ var c3d = f2b(field2: 87);
+ expect(1, c3d.field1);
+ expect(87, c3d.field2);
+ var c3e = f2b(field2: 87, field1: 42);
+ expect(42, c3e.field1);
+ expect(87, c3e.field2);
+
+ var f2c = Class1.redirectNamedFewer1;
+ var c4a = f2c();
+ expect(1, c4a.field1);
+ expect(2, c4a.field2);
+ var c4b = f2c(field1: 42);
+ expect(42, c4b.field1);
+ expect(2, c4b.field2);
+ () {
+ f2c(field1: 42, field2: 87); // error
+ };
+
+ var f2d = Class1.redirectNamedFewer2;
+ var c5a = f2d();
+ expect(1, c5a.field1);
+ expect(2, c5a.field2);
+ var c5b = f2d(field2: 87);
+ expect(1, c5b.field1);
+ expect(87, c5b.field2);
+ () {
+ f2d(field1: 42, field2: 87); // error
+ };
+
+ var f2e = Class1.redirectNamedFewer3;
+ var c6a = f2e();
+ expect(1, c6a.field1);
+ expect(2, c6a.field2);
+ () {
+ f2e(field1: 42); // error
+ f2e(field2: 87); // error
+ f2e(field1: 42, field2: 87); // error
+ };
+}
+
+expect(expected, actual) {
+ if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+ try {
+ f();
+ } catch (e) {
+ print('Thrown: $e');
+ return;
+ }
+ if (!inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw 'Expected exception';
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.strong.expect
new file mode 100644
index 0000000..6d9d205
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.strong.expect
@@ -0,0 +1,236 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:58:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1b(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:66:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f1c(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:67:8: Error: Too many positional arguments: 0 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1c(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:112:21: Error: No named parameter with the name 'field2'.
+// f2c(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:123:9: Error: No named parameter with the name 'field1'.
+// f2d(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:131:9: Error: No named parameter with the name 'field1'.
+// f2e(field1: 42); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:132:9: Error: No named parameter with the name 'field2'.
+// f2e(field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:133:9: Error: No named parameter with the name 'field1'.
+// f2e(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field1;
+ final field core::int field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::redirectPositionalSame, self::Class1::redirectPositionalFewer1, self::Class1::redirectPositionalFewer2, self::Class1::redirectNamedSame, self::Class1::redirectNamedReorder, self::Class1::redirectNamedFewer1, self::Class1::redirectNamedFewer2, self::Class1::redirectNamedFewer3]/*isLegacy*/;
+ constructor positional([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ : self::Class1::field1 = field1, self::Class1::field2 = field2, super core::Object::•()
+ ;
+ constructor named({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ : self::Class1::field1 = field1, self::Class1::field2 = field2, super core::Object::•()
+ ;
+ static method _#positional#tearOff([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalSame([core::int field1 = #C3, core::int field2 = #C3]) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalSame#tearOff([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalFewer1([core::int field1 = #C3]) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer1#tearOff([core::int field1 = #C1]) → self::Class1
+ return new self::Class1::positional(field1);
+ static factory redirectPositionalFewer2() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer2#tearOff() → self::Class1
+ return new self::Class1::positional();
+ static method _#named#tearOff({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedSame({core::int field1 = #C3, core::int field2 = #C3}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedSame#tearOff({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedReorder({core::int field2 = #C3, core::int field1 = #C3}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedReorder#tearOff({core::int field2 = #C2, core::int field1 = #C1}) → self::Class1
+ return new self::Class1::named(field2: field2, field1: field1);
+ static factory redirectNamedFewer1({core::int field1 = #C3}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer1#tearOff({core::int field1 = #C1}) → self::Class1
+ return new self::Class1::named(field1: field1);
+ static factory redirectNamedFewer2({core::int field2 = #C3}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer2#tearOff({core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field2: field2);
+ static factory redirectNamedFewer3() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer3#tearOff() → self::Class1
+ return new self::Class1::named();
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → dynamic {
+ ([core::int, core::int]) → self::Class1 f1a = #C4;
+ self::Class1 c1a = f1a(){([core::int, core::int]) → self::Class1};
+ self::expect(1, c1a.{self::Class1::field1}{core::int});
+ self::expect(2, c1a.{self::Class1::field2}{core::int});
+ self::Class1 c1b = f1a(42){([core::int, core::int]) → self::Class1};
+ self::expect(42, c1b.{self::Class1::field1}{core::int});
+ self::expect(2, c1b.{self::Class1::field2}{core::int});
+ self::Class1 c1c = f1a(42, 87){([core::int, core::int]) → self::Class1};
+ self::expect(42, c1c.{self::Class1::field1}{core::int});
+ self::expect(87, c1c.{self::Class1::field2}{core::int});
+ ([core::int]) → self::Class1 f1b = #C5;
+ self::Class1 c1d = f1b(){([core::int]) → self::Class1};
+ self::expect(1, c1d.{self::Class1::field1}{core::int});
+ self::expect(2, c1d.{self::Class1::field2}{core::int});
+ self::Class1 c1e = f1b(42){([core::int]) → self::Class1};
+ self::expect(42, c1e.{self::Class1::field1}{core::int});
+ self::expect(2, c1e.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:58:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1b(42, 87); // error
+ ^" in f1b{<inapplicable>}.(42, 87);
+ };
+ () → self::Class1 f1c = #C6;
+ self::Class1 c1f = f1c(){() → self::Class1};
+ self::expect(1, c1f.{self::Class1::field1}{core::int});
+ self::expect(2, c1f.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:66:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f1c(42); // error
+ ^" in f1c{<inapplicable>}.(42);
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:67:8: Error: Too many positional arguments: 0 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1c(42, 87); // error
+ ^" in f1c{<inapplicable>}.(42, 87);
+ };
+ ({field1: core::int, field2: core::int}) → self::Class1 f2a = #C7;
+ self::Class1 c2a = f2a(){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c2a.{self::Class1::field1}{core::int});
+ self::expect(2, c2a.{self::Class1::field2}{core::int});
+ self::Class1 c2b = f2a(field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2b.{self::Class1::field1}{core::int});
+ self::expect(2, c2b.{self::Class1::field2}{core::int});
+ self::Class1 c2c = f2a(field1: 42, field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2c.{self::Class1::field1}{core::int});
+ self::expect(87, c2c.{self::Class1::field2}{core::int});
+ self::Class1 c2d = f2a(field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c2d.{self::Class1::field1}{core::int});
+ self::expect(87, c2d.{self::Class1::field2}{core::int});
+ self::Class1 c2e = f2a(field2: 87, field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2e.{self::Class1::field1}{core::int});
+ self::expect(87, c2e.{self::Class1::field2}{core::int});
+ ({field1: core::int, field2: core::int}) → self::Class1 f2b = #C8;
+ self::Class1 c3a = f2b(){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c3a.{self::Class1::field1}{core::int});
+ self::expect(2, c3a.{self::Class1::field2}{core::int});
+ self::Class1 c3b = f2b(field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3b.{self::Class1::field1}{core::int});
+ self::expect(2, c3b.{self::Class1::field2}{core::int});
+ self::Class1 c3c = f2b(field1: 42, field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3c.{self::Class1::field1}{core::int});
+ self::expect(87, c3c.{self::Class1::field2}{core::int});
+ self::Class1 c3d = f2b(field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c3d.{self::Class1::field1}{core::int});
+ self::expect(87, c3d.{self::Class1::field2}{core::int});
+ self::Class1 c3e = f2b(field2: 87, field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3e.{self::Class1::field1}{core::int});
+ self::expect(87, c3e.{self::Class1::field2}{core::int});
+ ({field1: core::int}) → self::Class1 f2c = #C9;
+ self::Class1 c4a = f2c(){({field1: core::int}) → self::Class1};
+ self::expect(1, c4a.{self::Class1::field1}{core::int});
+ self::expect(2, c4a.{self::Class1::field2}{core::int});
+ self::Class1 c4b = f2c(field1: 42){({field1: core::int}) → self::Class1};
+ self::expect(42, c4b.{self::Class1::field1}{core::int});
+ self::expect(2, c4b.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:112:21: Error: No named parameter with the name 'field2'.
+ f2c(field1: 42, field2: 87); // error
+ ^^^^^^" in f2c{<inapplicable>}.(field1: 42, field2: 87);
+ };
+ ({field2: core::int}) → self::Class1 f2d = #C10;
+ self::Class1 c5a = f2d(){({field2: core::int}) → self::Class1};
+ self::expect(1, c5a.{self::Class1::field1}{core::int});
+ self::expect(2, c5a.{self::Class1::field2}{core::int});
+ self::Class1 c5b = f2d(field2: 87){({field2: core::int}) → self::Class1};
+ self::expect(1, c5b.{self::Class1::field1}{core::int});
+ self::expect(87, c5b.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:123:9: Error: No named parameter with the name 'field1'.
+ f2d(field1: 42, field2: 87); // error
+ ^^^^^^" in f2d{<inapplicable>}.(field1: 42, field2: 87);
+ };
+ () → self::Class1 f2e = #C11;
+ self::Class1 c6a = f2e(){() → self::Class1};
+ self::expect(1, c6a.{self::Class1::field1}{core::int});
+ self::expect(2, c6a.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:131:9: Error: No named parameter with the name 'field1'.
+ f2e(field1: 42); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field1: 42);
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:132:9: Error: No named parameter with the name 'field2'.
+ f2e(field2: 87); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field2: 87);
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:133:9: Error: No named parameter with the name 'field1'.
+ f2e(field1: 42, field2: 87); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field1: 42, field2: 87);
+ };
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C12}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 1
+ #C2 = 2
+ #C3 = null
+ #C4 = static-tearoff self::Class1::_#redirectPositionalSame#tearOff
+ #C5 = static-tearoff self::Class1::_#redirectPositionalFewer1#tearOff
+ #C6 = static-tearoff self::Class1::_#redirectPositionalFewer2#tearOff
+ #C7 = static-tearoff self::Class1::_#redirectNamedSame#tearOff
+ #C8 = static-tearoff self::Class1::_#redirectNamedReorder#tearOff
+ #C9 = static-tearoff self::Class1::_#redirectNamedFewer1#tearOff
+ #C10 = static-tearoff self::Class1::_#redirectNamedFewer2#tearOff
+ #C11 = static-tearoff self::Class1::_#redirectNamedFewer3#tearOff
+ #C12 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.strong.transformed.expect
new file mode 100644
index 0000000..ae52285
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.strong.transformed.expect
@@ -0,0 +1,236 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:58:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1b(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:66:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f1c(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:67:8: Error: Too many positional arguments: 0 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1c(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:112:21: Error: No named parameter with the name 'field2'.
+// f2c(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:123:9: Error: No named parameter with the name 'field1'.
+// f2d(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:131:9: Error: No named parameter with the name 'field1'.
+// f2e(field1: 42); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:132:9: Error: No named parameter with the name 'field2'.
+// f2e(field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:133:9: Error: No named parameter with the name 'field1'.
+// f2e(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field1;
+ final field core::int field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::redirectPositionalSame, self::Class1::redirectPositionalFewer1, self::Class1::redirectPositionalFewer2, self::Class1::redirectNamedSame, self::Class1::redirectNamedReorder, self::Class1::redirectNamedFewer1, self::Class1::redirectNamedFewer2, self::Class1::redirectNamedFewer3]/*isLegacy*/;
+ constructor positional([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ : self::Class1::field1 = field1, self::Class1::field2 = field2, super core::Object::•()
+ ;
+ constructor named({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ : self::Class1::field1 = field1, self::Class1::field2 = field2, super core::Object::•()
+ ;
+ static method _#positional#tearOff([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalSame([core::int field1 = #C3, core::int field2 = #C3]) → self::Class1
+ let Never #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalSame#tearOff([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalFewer1([core::int field1 = #C3]) → self::Class1
+ let Never #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer1#tearOff([core::int field1 = #C1]) → self::Class1
+ return new self::Class1::positional(field1);
+ static factory redirectPositionalFewer2() → self::Class1
+ let Never #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer2#tearOff() → self::Class1
+ return new self::Class1::positional();
+ static method _#named#tearOff({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedSame({core::int field1 = #C3, core::int field2 = #C3}) → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedSame#tearOff({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedReorder({core::int field2 = #C3, core::int field1 = #C3}) → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedReorder#tearOff({core::int field2 = #C2, core::int field1 = #C1}) → self::Class1
+ return new self::Class1::named(field2: field2, field1: field1);
+ static factory redirectNamedFewer1({core::int field1 = #C3}) → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer1#tearOff({core::int field1 = #C1}) → self::Class1
+ return new self::Class1::named(field1: field1);
+ static factory redirectNamedFewer2({core::int field2 = #C3}) → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer2#tearOff({core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field2: field2);
+ static factory redirectNamedFewer3() → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer3#tearOff() → self::Class1
+ return new self::Class1::named();
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → dynamic {
+ ([core::int, core::int]) → self::Class1 f1a = #C4;
+ self::Class1 c1a = f1a(){([core::int, core::int]) → self::Class1};
+ self::expect(1, c1a.{self::Class1::field1}{core::int});
+ self::expect(2, c1a.{self::Class1::field2}{core::int});
+ self::Class1 c1b = f1a(42){([core::int, core::int]) → self::Class1};
+ self::expect(42, c1b.{self::Class1::field1}{core::int});
+ self::expect(2, c1b.{self::Class1::field2}{core::int});
+ self::Class1 c1c = f1a(42, 87){([core::int, core::int]) → self::Class1};
+ self::expect(42, c1c.{self::Class1::field1}{core::int});
+ self::expect(87, c1c.{self::Class1::field2}{core::int});
+ ([core::int]) → self::Class1 f1b = #C5;
+ self::Class1 c1d = f1b(){([core::int]) → self::Class1};
+ self::expect(1, c1d.{self::Class1::field1}{core::int});
+ self::expect(2, c1d.{self::Class1::field2}{core::int});
+ self::Class1 c1e = f1b(42){([core::int]) → self::Class1};
+ self::expect(42, c1e.{self::Class1::field1}{core::int});
+ self::expect(2, c1e.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:58:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1b(42, 87); // error
+ ^" in f1b{<inapplicable>}.(42, 87);
+ };
+ () → self::Class1 f1c = #C6;
+ self::Class1 c1f = f1c(){() → self::Class1};
+ self::expect(1, c1f.{self::Class1::field1}{core::int});
+ self::expect(2, c1f.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:66:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f1c(42); // error
+ ^" in f1c{<inapplicable>}.(42);
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:67:8: Error: Too many positional arguments: 0 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1c(42, 87); // error
+ ^" in f1c{<inapplicable>}.(42, 87);
+ };
+ ({field1: core::int, field2: core::int}) → self::Class1 f2a = #C7;
+ self::Class1 c2a = f2a(){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c2a.{self::Class1::field1}{core::int});
+ self::expect(2, c2a.{self::Class1::field2}{core::int});
+ self::Class1 c2b = f2a(field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2b.{self::Class1::field1}{core::int});
+ self::expect(2, c2b.{self::Class1::field2}{core::int});
+ self::Class1 c2c = f2a(field1: 42, field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2c.{self::Class1::field1}{core::int});
+ self::expect(87, c2c.{self::Class1::field2}{core::int});
+ self::Class1 c2d = f2a(field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c2d.{self::Class1::field1}{core::int});
+ self::expect(87, c2d.{self::Class1::field2}{core::int});
+ self::Class1 c2e = f2a(field2: 87, field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2e.{self::Class1::field1}{core::int});
+ self::expect(87, c2e.{self::Class1::field2}{core::int});
+ ({field1: core::int, field2: core::int}) → self::Class1 f2b = #C8;
+ self::Class1 c3a = f2b(){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c3a.{self::Class1::field1}{core::int});
+ self::expect(2, c3a.{self::Class1::field2}{core::int});
+ self::Class1 c3b = f2b(field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3b.{self::Class1::field1}{core::int});
+ self::expect(2, c3b.{self::Class1::field2}{core::int});
+ self::Class1 c3c = f2b(field1: 42, field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3c.{self::Class1::field1}{core::int});
+ self::expect(87, c3c.{self::Class1::field2}{core::int});
+ self::Class1 c3d = f2b(field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c3d.{self::Class1::field1}{core::int});
+ self::expect(87, c3d.{self::Class1::field2}{core::int});
+ self::Class1 c3e = f2b(field2: 87, field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3e.{self::Class1::field1}{core::int});
+ self::expect(87, c3e.{self::Class1::field2}{core::int});
+ ({field1: core::int}) → self::Class1 f2c = #C9;
+ self::Class1 c4a = f2c(){({field1: core::int}) → self::Class1};
+ self::expect(1, c4a.{self::Class1::field1}{core::int});
+ self::expect(2, c4a.{self::Class1::field2}{core::int});
+ self::Class1 c4b = f2c(field1: 42){({field1: core::int}) → self::Class1};
+ self::expect(42, c4b.{self::Class1::field1}{core::int});
+ self::expect(2, c4b.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:112:21: Error: No named parameter with the name 'field2'.
+ f2c(field1: 42, field2: 87); // error
+ ^^^^^^" in f2c{<inapplicable>}.(field1: 42, field2: 87);
+ };
+ ({field2: core::int}) → self::Class1 f2d = #C10;
+ self::Class1 c5a = f2d(){({field2: core::int}) → self::Class1};
+ self::expect(1, c5a.{self::Class1::field1}{core::int});
+ self::expect(2, c5a.{self::Class1::field2}{core::int});
+ self::Class1 c5b = f2d(field2: 87){({field2: core::int}) → self::Class1};
+ self::expect(1, c5b.{self::Class1::field1}{core::int});
+ self::expect(87, c5b.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:123:9: Error: No named parameter with the name 'field1'.
+ f2d(field1: 42, field2: 87); // error
+ ^^^^^^" in f2d{<inapplicable>}.(field1: 42, field2: 87);
+ };
+ () → self::Class1 f2e = #C11;
+ self::Class1 c6a = f2e(){() → self::Class1};
+ self::expect(1, c6a.{self::Class1::field1}{core::int});
+ self::expect(2, c6a.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:131:9: Error: No named parameter with the name 'field1'.
+ f2e(field1: 42); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field1: 42);
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:132:9: Error: No named parameter with the name 'field2'.
+ f2e(field2: 87); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field2: 87);
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:133:9: Error: No named parameter with the name 'field1'.
+ f2e(field1: 42, field2: 87); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field1: 42, field2: 87);
+ };
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C12}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 1
+ #C2 = 2
+ #C3 = null
+ #C4 = static-tearoff self::Class1::_#redirectPositionalSame#tearOff
+ #C5 = static-tearoff self::Class1::_#redirectPositionalFewer1#tearOff
+ #C6 = static-tearoff self::Class1::_#redirectPositionalFewer2#tearOff
+ #C7 = static-tearoff self::Class1::_#redirectNamedSame#tearOff
+ #C8 = static-tearoff self::Class1::_#redirectNamedReorder#tearOff
+ #C9 = static-tearoff self::Class1::_#redirectNamedFewer1#tearOff
+ #C10 = static-tearoff self::Class1::_#redirectNamedFewer2#tearOff
+ #C11 = static-tearoff self::Class1::_#redirectNamedFewer3#tearOff
+ #C12 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.textual_outline.expect
new file mode 100644
index 0000000..90fc9da
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.textual_outline.expect
@@ -0,0 +1,22 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+ final int field1;
+ final int field2;
+ Class1.positional([this.field1 = 1, this.field2 = 2]);
+ factory Class1.redirectPositionalSame([int field1, int field2]) =
+ Class1.positional;
+ factory Class1.redirectPositionalFewer1([int field1]) = Class1.positional;
+ factory Class1.redirectPositionalFewer2() = Class1.positional;
+ Class1.named({this.field1 = 1, this.field2 = 2});
+ factory Class1.redirectNamedSame({int field1, int field2}) = Class1.named;
+ factory Class1.redirectNamedReorder({int field2, int field1}) = Class1.named;
+ factory Class1.redirectNamedFewer1({int field1}) = Class1.named;
+ factory Class1.redirectNamedFewer2({int field2}) = Class1.named;
+ factory Class1.redirectNamedFewer3() = Class1.named;
+}
+
+testDefaultValues() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..5735aef
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.textual_outline_modelled.expect
@@ -0,0 +1,21 @@
+class Class1 {
+ Class1.named({this.field1 = 1, this.field2 = 2});
+ Class1.positional([this.field1 = 1, this.field2 = 2]);
+ factory Class1.redirectNamedFewer1({int field1}) = Class1.named;
+ factory Class1.redirectNamedFewer2({int field2}) = Class1.named;
+ factory Class1.redirectNamedFewer3() = Class1.named;
+ factory Class1.redirectNamedReorder({int field2, int field1}) = Class1.named;
+ factory Class1.redirectNamedSame({int field1, int field2}) = Class1.named;
+ factory Class1.redirectPositionalFewer1([int field1]) = Class1.positional;
+ factory Class1.redirectPositionalFewer2() = Class1.positional;
+ factory Class1.redirectPositionalSame([int field1, int field2]) =
+ Class1.positional;
+ final int field1;
+ final int field2;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+testDefaultValues() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.weak.expect
new file mode 100644
index 0000000..6d9d205
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.weak.expect
@@ -0,0 +1,236 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:58:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1b(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:66:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f1c(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:67:8: Error: Too many positional arguments: 0 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1c(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:112:21: Error: No named parameter with the name 'field2'.
+// f2c(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:123:9: Error: No named parameter with the name 'field1'.
+// f2d(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:131:9: Error: No named parameter with the name 'field1'.
+// f2e(field1: 42); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:132:9: Error: No named parameter with the name 'field2'.
+// f2e(field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:133:9: Error: No named parameter with the name 'field1'.
+// f2e(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field1;
+ final field core::int field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::redirectPositionalSame, self::Class1::redirectPositionalFewer1, self::Class1::redirectPositionalFewer2, self::Class1::redirectNamedSame, self::Class1::redirectNamedReorder, self::Class1::redirectNamedFewer1, self::Class1::redirectNamedFewer2, self::Class1::redirectNamedFewer3]/*isLegacy*/;
+ constructor positional([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ : self::Class1::field1 = field1, self::Class1::field2 = field2, super core::Object::•()
+ ;
+ constructor named({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ : self::Class1::field1 = field1, self::Class1::field2 = field2, super core::Object::•()
+ ;
+ static method _#positional#tearOff([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalSame([core::int field1 = #C3, core::int field2 = #C3]) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalSame#tearOff([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalFewer1([core::int field1 = #C3]) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer1#tearOff([core::int field1 = #C1]) → self::Class1
+ return new self::Class1::positional(field1);
+ static factory redirectPositionalFewer2() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer2#tearOff() → self::Class1
+ return new self::Class1::positional();
+ static method _#named#tearOff({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedSame({core::int field1 = #C3, core::int field2 = #C3}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedSame#tearOff({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedReorder({core::int field2 = #C3, core::int field1 = #C3}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedReorder#tearOff({core::int field2 = #C2, core::int field1 = #C1}) → self::Class1
+ return new self::Class1::named(field2: field2, field1: field1);
+ static factory redirectNamedFewer1({core::int field1 = #C3}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer1#tearOff({core::int field1 = #C1}) → self::Class1
+ return new self::Class1::named(field1: field1);
+ static factory redirectNamedFewer2({core::int field2 = #C3}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer2#tearOff({core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field2: field2);
+ static factory redirectNamedFewer3() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer3#tearOff() → self::Class1
+ return new self::Class1::named();
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → dynamic {
+ ([core::int, core::int]) → self::Class1 f1a = #C4;
+ self::Class1 c1a = f1a(){([core::int, core::int]) → self::Class1};
+ self::expect(1, c1a.{self::Class1::field1}{core::int});
+ self::expect(2, c1a.{self::Class1::field2}{core::int});
+ self::Class1 c1b = f1a(42){([core::int, core::int]) → self::Class1};
+ self::expect(42, c1b.{self::Class1::field1}{core::int});
+ self::expect(2, c1b.{self::Class1::field2}{core::int});
+ self::Class1 c1c = f1a(42, 87){([core::int, core::int]) → self::Class1};
+ self::expect(42, c1c.{self::Class1::field1}{core::int});
+ self::expect(87, c1c.{self::Class1::field2}{core::int});
+ ([core::int]) → self::Class1 f1b = #C5;
+ self::Class1 c1d = f1b(){([core::int]) → self::Class1};
+ self::expect(1, c1d.{self::Class1::field1}{core::int});
+ self::expect(2, c1d.{self::Class1::field2}{core::int});
+ self::Class1 c1e = f1b(42){([core::int]) → self::Class1};
+ self::expect(42, c1e.{self::Class1::field1}{core::int});
+ self::expect(2, c1e.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:58:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1b(42, 87); // error
+ ^" in f1b{<inapplicable>}.(42, 87);
+ };
+ () → self::Class1 f1c = #C6;
+ self::Class1 c1f = f1c(){() → self::Class1};
+ self::expect(1, c1f.{self::Class1::field1}{core::int});
+ self::expect(2, c1f.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:66:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f1c(42); // error
+ ^" in f1c{<inapplicable>}.(42);
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:67:8: Error: Too many positional arguments: 0 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1c(42, 87); // error
+ ^" in f1c{<inapplicable>}.(42, 87);
+ };
+ ({field1: core::int, field2: core::int}) → self::Class1 f2a = #C7;
+ self::Class1 c2a = f2a(){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c2a.{self::Class1::field1}{core::int});
+ self::expect(2, c2a.{self::Class1::field2}{core::int});
+ self::Class1 c2b = f2a(field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2b.{self::Class1::field1}{core::int});
+ self::expect(2, c2b.{self::Class1::field2}{core::int});
+ self::Class1 c2c = f2a(field1: 42, field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2c.{self::Class1::field1}{core::int});
+ self::expect(87, c2c.{self::Class1::field2}{core::int});
+ self::Class1 c2d = f2a(field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c2d.{self::Class1::field1}{core::int});
+ self::expect(87, c2d.{self::Class1::field2}{core::int});
+ self::Class1 c2e = f2a(field2: 87, field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2e.{self::Class1::field1}{core::int});
+ self::expect(87, c2e.{self::Class1::field2}{core::int});
+ ({field1: core::int, field2: core::int}) → self::Class1 f2b = #C8;
+ self::Class1 c3a = f2b(){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c3a.{self::Class1::field1}{core::int});
+ self::expect(2, c3a.{self::Class1::field2}{core::int});
+ self::Class1 c3b = f2b(field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3b.{self::Class1::field1}{core::int});
+ self::expect(2, c3b.{self::Class1::field2}{core::int});
+ self::Class1 c3c = f2b(field1: 42, field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3c.{self::Class1::field1}{core::int});
+ self::expect(87, c3c.{self::Class1::field2}{core::int});
+ self::Class1 c3d = f2b(field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c3d.{self::Class1::field1}{core::int});
+ self::expect(87, c3d.{self::Class1::field2}{core::int});
+ self::Class1 c3e = f2b(field2: 87, field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3e.{self::Class1::field1}{core::int});
+ self::expect(87, c3e.{self::Class1::field2}{core::int});
+ ({field1: core::int}) → self::Class1 f2c = #C9;
+ self::Class1 c4a = f2c(){({field1: core::int}) → self::Class1};
+ self::expect(1, c4a.{self::Class1::field1}{core::int});
+ self::expect(2, c4a.{self::Class1::field2}{core::int});
+ self::Class1 c4b = f2c(field1: 42){({field1: core::int}) → self::Class1};
+ self::expect(42, c4b.{self::Class1::field1}{core::int});
+ self::expect(2, c4b.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:112:21: Error: No named parameter with the name 'field2'.
+ f2c(field1: 42, field2: 87); // error
+ ^^^^^^" in f2c{<inapplicable>}.(field1: 42, field2: 87);
+ };
+ ({field2: core::int}) → self::Class1 f2d = #C10;
+ self::Class1 c5a = f2d(){({field2: core::int}) → self::Class1};
+ self::expect(1, c5a.{self::Class1::field1}{core::int});
+ self::expect(2, c5a.{self::Class1::field2}{core::int});
+ self::Class1 c5b = f2d(field2: 87){({field2: core::int}) → self::Class1};
+ self::expect(1, c5b.{self::Class1::field1}{core::int});
+ self::expect(87, c5b.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:123:9: Error: No named parameter with the name 'field1'.
+ f2d(field1: 42, field2: 87); // error
+ ^^^^^^" in f2d{<inapplicable>}.(field1: 42, field2: 87);
+ };
+ () → self::Class1 f2e = #C11;
+ self::Class1 c6a = f2e(){() → self::Class1};
+ self::expect(1, c6a.{self::Class1::field1}{core::int});
+ self::expect(2, c6a.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:131:9: Error: No named parameter with the name 'field1'.
+ f2e(field1: 42); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field1: 42);
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:132:9: Error: No named parameter with the name 'field2'.
+ f2e(field2: 87); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field2: 87);
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:133:9: Error: No named parameter with the name 'field1'.
+ f2e(field1: 42, field2: 87); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field1: 42, field2: 87);
+ };
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C12}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 1
+ #C2 = 2
+ #C3 = null
+ #C4 = static-tearoff self::Class1::_#redirectPositionalSame#tearOff
+ #C5 = static-tearoff self::Class1::_#redirectPositionalFewer1#tearOff
+ #C6 = static-tearoff self::Class1::_#redirectPositionalFewer2#tearOff
+ #C7 = static-tearoff self::Class1::_#redirectNamedSame#tearOff
+ #C8 = static-tearoff self::Class1::_#redirectNamedReorder#tearOff
+ #C9 = static-tearoff self::Class1::_#redirectNamedFewer1#tearOff
+ #C10 = static-tearoff self::Class1::_#redirectNamedFewer2#tearOff
+ #C11 = static-tearoff self::Class1::_#redirectNamedFewer3#tearOff
+ #C12 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.weak.outline.expect
new file mode 100644
index 0000000..9ef35eb
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.weak.outline.expect
@@ -0,0 +1,58 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field1;
+ final field core::int field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::redirectPositionalSame, self::Class1::redirectPositionalFewer1, self::Class1::redirectPositionalFewer2, self::Class1::redirectNamedSame, self::Class1::redirectNamedReorder, self::Class1::redirectNamedFewer1, self::Class1::redirectNamedFewer2, self::Class1::redirectNamedFewer3]/*isLegacy*/;
+ constructor positional([core::int field1, core::int field2]) → self::Class1
+ ;
+ constructor named({core::int field1, core::int field2}) → self::Class1
+ ;
+ static method _#positional#tearOff([core::int field1, core::int field2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalSame([core::int field1, core::int field2]) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalSame#tearOff([core::int field1, core::int field2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalFewer1([core::int field1]) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer1#tearOff([core::int field1]) → self::Class1
+ return new self::Class1::positional(field1);
+ static factory redirectPositionalFewer2() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer2#tearOff() → self::Class1
+ return new self::Class1::positional();
+ static method _#named#tearOff({core::int field1, core::int field2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedSame({core::int field1, core::int field2}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedSame#tearOff({core::int field1, core::int field2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedReorder({core::int field2, core::int field1}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedReorder#tearOff({core::int field2, core::int field1}) → self::Class1
+ return new self::Class1::named(field2: field2, field1: field1);
+ static factory redirectNamedFewer1({core::int field1}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer1#tearOff({core::int field1}) → self::Class1
+ return new self::Class1::named(field1: field1);
+ static factory redirectNamedFewer2({core::int field2}) → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer2#tearOff({core::int field2}) → self::Class1
+ return new self::Class1::named(field2: field2);
+ static factory redirectNamedFewer3() → self::Class1
+ let dynamic #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer3#tearOff() → self::Class1
+ return new self::Class1::named();
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+ ;
+static method testDefaultValues() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.weak.transformed.expect
new file mode 100644
index 0000000..ae52285
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart.weak.transformed.expect
@@ -0,0 +1,236 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:58:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1b(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:66:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+// f1c(42); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:67:8: Error: Too many positional arguments: 0 allowed, but 2 found.
+// Try removing the extra positional arguments.
+// f1c(42, 87); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:112:21: Error: No named parameter with the name 'field2'.
+// f2c(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:123:9: Error: No named parameter with the name 'field1'.
+// f2d(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:131:9: Error: No named parameter with the name 'field1'.
+// f2e(field1: 42); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:132:9: Error: No named parameter with the name 'field2'.
+// f2e(field2: 87); // error
+// ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:133:9: Error: No named parameter with the name 'field1'.
+// f2e(field1: 42, field2: 87); // error
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ final field core::int field1;
+ final field core::int field2;
+ static final field dynamic _redirecting# = <dynamic>[self::Class1::redirectPositionalSame, self::Class1::redirectPositionalFewer1, self::Class1::redirectPositionalFewer2, self::Class1::redirectNamedSame, self::Class1::redirectNamedReorder, self::Class1::redirectNamedFewer1, self::Class1::redirectNamedFewer2, self::Class1::redirectNamedFewer3]/*isLegacy*/;
+ constructor positional([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ : self::Class1::field1 = field1, self::Class1::field2 = field2, super core::Object::•()
+ ;
+ constructor named({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ : self::Class1::field1 = field1, self::Class1::field2 = field2, super core::Object::•()
+ ;
+ static method _#positional#tearOff([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalSame([core::int field1 = #C3, core::int field2 = #C3]) → self::Class1
+ let Never #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalSame#tearOff([core::int field1 = #C1, core::int field2 = #C2]) → self::Class1
+ return new self::Class1::positional(field1, field2);
+ static factory redirectPositionalFewer1([core::int field1 = #C3]) → self::Class1
+ let Never #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer1#tearOff([core::int field1 = #C1]) → self::Class1
+ return new self::Class1::positional(field1);
+ static factory redirectPositionalFewer2() → self::Class1
+ let Never #redirecting_factory = self::Class1::positional in invalid-expression;
+ static method _#redirectPositionalFewer2#tearOff() → self::Class1
+ return new self::Class1::positional();
+ static method _#named#tearOff({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedSame({core::int field1 = #C3, core::int field2 = #C3}) → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedSame#tearOff({core::int field1 = #C1, core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field1: field1, field2: field2);
+ static factory redirectNamedReorder({core::int field2 = #C3, core::int field1 = #C3}) → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedReorder#tearOff({core::int field2 = #C2, core::int field1 = #C1}) → self::Class1
+ return new self::Class1::named(field2: field2, field1: field1);
+ static factory redirectNamedFewer1({core::int field1 = #C3}) → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer1#tearOff({core::int field1 = #C1}) → self::Class1
+ return new self::Class1::named(field1: field1);
+ static factory redirectNamedFewer2({core::int field2 = #C3}) → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer2#tearOff({core::int field2 = #C2}) → self::Class1
+ return new self::Class1::named(field2: field2);
+ static factory redirectNamedFewer3() → self::Class1
+ let Never #redirecting_factory = self::Class1::named in invalid-expression;
+ static method _#redirectNamedFewer3#tearOff() → self::Class1
+ return new self::Class1::named();
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testDefaultValues();
+}
+static method testDefaultValues() → dynamic {
+ ([core::int, core::int]) → self::Class1 f1a = #C4;
+ self::Class1 c1a = f1a(){([core::int, core::int]) → self::Class1};
+ self::expect(1, c1a.{self::Class1::field1}{core::int});
+ self::expect(2, c1a.{self::Class1::field2}{core::int});
+ self::Class1 c1b = f1a(42){([core::int, core::int]) → self::Class1};
+ self::expect(42, c1b.{self::Class1::field1}{core::int});
+ self::expect(2, c1b.{self::Class1::field2}{core::int});
+ self::Class1 c1c = f1a(42, 87){([core::int, core::int]) → self::Class1};
+ self::expect(42, c1c.{self::Class1::field1}{core::int});
+ self::expect(87, c1c.{self::Class1::field2}{core::int});
+ ([core::int]) → self::Class1 f1b = #C5;
+ self::Class1 c1d = f1b(){([core::int]) → self::Class1};
+ self::expect(1, c1d.{self::Class1::field1}{core::int});
+ self::expect(2, c1d.{self::Class1::field2}{core::int});
+ self::Class1 c1e = f1b(42){([core::int]) → self::Class1};
+ self::expect(42, c1e.{self::Class1::field1}{core::int});
+ self::expect(2, c1e.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:58:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1b(42, 87); // error
+ ^" in f1b{<inapplicable>}.(42, 87);
+ };
+ () → self::Class1 f1c = #C6;
+ self::Class1 c1f = f1c(){() → self::Class1};
+ self::expect(1, c1f.{self::Class1::field1}{core::int});
+ self::expect(2, c1f.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:66:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+ f1c(42); // error
+ ^" in f1c{<inapplicable>}.(42);
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:67:8: Error: Too many positional arguments: 0 allowed, but 2 found.
+Try removing the extra positional arguments.
+ f1c(42, 87); // error
+ ^" in f1c{<inapplicable>}.(42, 87);
+ };
+ ({field1: core::int, field2: core::int}) → self::Class1 f2a = #C7;
+ self::Class1 c2a = f2a(){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c2a.{self::Class1::field1}{core::int});
+ self::expect(2, c2a.{self::Class1::field2}{core::int});
+ self::Class1 c2b = f2a(field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2b.{self::Class1::field1}{core::int});
+ self::expect(2, c2b.{self::Class1::field2}{core::int});
+ self::Class1 c2c = f2a(field1: 42, field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2c.{self::Class1::field1}{core::int});
+ self::expect(87, c2c.{self::Class1::field2}{core::int});
+ self::Class1 c2d = f2a(field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c2d.{self::Class1::field1}{core::int});
+ self::expect(87, c2d.{self::Class1::field2}{core::int});
+ self::Class1 c2e = f2a(field2: 87, field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c2e.{self::Class1::field1}{core::int});
+ self::expect(87, c2e.{self::Class1::field2}{core::int});
+ ({field1: core::int, field2: core::int}) → self::Class1 f2b = #C8;
+ self::Class1 c3a = f2b(){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c3a.{self::Class1::field1}{core::int});
+ self::expect(2, c3a.{self::Class1::field2}{core::int});
+ self::Class1 c3b = f2b(field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3b.{self::Class1::field1}{core::int});
+ self::expect(2, c3b.{self::Class1::field2}{core::int});
+ self::Class1 c3c = f2b(field1: 42, field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3c.{self::Class1::field1}{core::int});
+ self::expect(87, c3c.{self::Class1::field2}{core::int});
+ self::Class1 c3d = f2b(field2: 87){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(1, c3d.{self::Class1::field1}{core::int});
+ self::expect(87, c3d.{self::Class1::field2}{core::int});
+ self::Class1 c3e = f2b(field2: 87, field1: 42){({field1: core::int, field2: core::int}) → self::Class1};
+ self::expect(42, c3e.{self::Class1::field1}{core::int});
+ self::expect(87, c3e.{self::Class1::field2}{core::int});
+ ({field1: core::int}) → self::Class1 f2c = #C9;
+ self::Class1 c4a = f2c(){({field1: core::int}) → self::Class1};
+ self::expect(1, c4a.{self::Class1::field1}{core::int});
+ self::expect(2, c4a.{self::Class1::field2}{core::int});
+ self::Class1 c4b = f2c(field1: 42){({field1: core::int}) → self::Class1};
+ self::expect(42, c4b.{self::Class1::field1}{core::int});
+ self::expect(2, c4b.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:112:21: Error: No named parameter with the name 'field2'.
+ f2c(field1: 42, field2: 87); // error
+ ^^^^^^" in f2c{<inapplicable>}.(field1: 42, field2: 87);
+ };
+ ({field2: core::int}) → self::Class1 f2d = #C10;
+ self::Class1 c5a = f2d(){({field2: core::int}) → self::Class1};
+ self::expect(1, c5a.{self::Class1::field1}{core::int});
+ self::expect(2, c5a.{self::Class1::field2}{core::int});
+ self::Class1 c5b = f2d(field2: 87){({field2: core::int}) → self::Class1};
+ self::expect(1, c5b.{self::Class1::field1}{core::int});
+ self::expect(87, c5b.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:123:9: Error: No named parameter with the name 'field1'.
+ f2d(field1: 42, field2: 87); // error
+ ^^^^^^" in f2d{<inapplicable>}.(field1: 42, field2: 87);
+ };
+ () → self::Class1 f2e = #C11;
+ self::Class1 c6a = f2e(){() → self::Class1};
+ self::expect(1, c6a.{self::Class1::field1}{core::int});
+ self::expect(2, c6a.{self::Class1::field2}{core::int});
+ () → Null {
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:131:9: Error: No named parameter with the name 'field1'.
+ f2e(field1: 42); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field1: 42);
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:132:9: Error: No named parameter with the name 'field2'.
+ f2e(field2: 87); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field2: 87);
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values_complex.dart:133:9: Error: No named parameter with the name 'field1'.
+ f2e(field1: 42, field2: 87); // error
+ ^^^^^^" in f2e{<inapplicable>}.(field1: 42, field2: 87);
+ };
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C12}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = 1
+ #C2 = 2
+ #C3 = null
+ #C4 = static-tearoff self::Class1::_#redirectPositionalSame#tearOff
+ #C5 = static-tearoff self::Class1::_#redirectPositionalFewer1#tearOff
+ #C6 = static-tearoff self::Class1::_#redirectPositionalFewer2#tearOff
+ #C7 = static-tearoff self::Class1::_#redirectNamedSame#tearOff
+ #C8 = static-tearoff self::Class1::_#redirectNamedReorder#tearOff
+ #C9 = static-tearoff self::Class1::_#redirectNamedFewer1#tearOff
+ #C10 = static-tearoff self::Class1::_#redirectNamedFewer2#tearOff
+ #C11 = static-tearoff self::Class1::_#redirectNamedFewer3#tearOff
+ #C12 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart
index 75d63fa..4ac8aea 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart
@@ -16,7 +16,8 @@
}
class Class2 {
- Class2._();
+ Class2.__();
+ factory Class2._() => Class2.__();
factory Class2.named() = Class2._;
}
@@ -74,6 +75,22 @@
Class6._;
}
+class Class7a implements Class7b {
+ Class7a();
+}
+
+class Class7b {
+ factory Class7b() = Class7a;
+}
+
+class Class8a<T> implements Class8b<T> {
+ Class8a();
+}
+
+class Class8b<T> {
+ factory Class8b() = Class8a<T>;
+}
+
testArgs() {
var f3a = Class3.new;
var c3a = f3a(42);
@@ -143,6 +160,20 @@
throws(() => f6b(42), inSoundModeOnly: true);
throws(() => f6b(42, 87), inSoundModeOnly: true);
throws(() => f6b(field1: 87, field2: 87));
+
+ var f7a = Class7b.new;
+ var c7a = f7a();
+ expect(true, c7a is Class7a);
+ expect(true, c7a is Class7b);
+
+ var f8a = Class8b.new;
+ var c8a = f8a();
+ expect(true, c8a is Class8a);
+ expect(true, c8a is Class8b);
+ var c8b = f8a<int>();
+ expect(true, c8b is Class8a<int>);
+ expect(true, c8b is Class8b<int>);
+ expect(false, c8b is Class8b<String>);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.expect
index f2dd642..ce07a22 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.expect
@@ -2,43 +2,43 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f4a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
// f5a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// f5a(42, 87, 123); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
// f6a(42); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f6a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(field1: 87, field2: 87); // error
// ^
//
@@ -55,9 +55,11 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
: super core::Object::•()
;
+ static factory _() → self::Class2
+ return new self::Class2::__();
static factory named() → self::Class2
let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
}
@@ -100,6 +102,26 @@
static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ : super core::Object::•()
+ ;
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let dynamic #redirecting_factory = self::Class7a::• in invalid-expression;
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ : super core::Object::•()
+ ;
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let dynamic #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+}
static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -127,10 +149,10 @@
self::Class3 c3a = f3a(42){(core::int) → self::Class3};
self::expect(42, c3a.{self::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
@@ -146,7 +168,7 @@
self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
self::expect(42, c4b.{self::Class4::field}{core::int?});
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f4a(42, 87); // error
^" in f4a{<inapplicable>}.(42, 87);
@@ -161,10 +183,10 @@
self::expect(87, c5b.{self::Class5::field1}{core::int});
self::expect(42, c5b.{self::Class5::field2}{core::int?});
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
f5a(); // error
^" in f5a{<inapplicable>}.();
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
f5a(42, 87, 123); // error
^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -178,17 +200,17 @@
self::expect(null, c6a.{self::Class6::field2}{core::int?});
self::expect(87, c6a.{self::Class6::field3}{core::int});
() → Null {
- let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(); // error
^" in f6a{<inapplicable>}.();
- let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
f6a(42); // error
^" in f6a{<inapplicable>}.(42);
- let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f6a(42, 87); // error
^" in f6a{<inapplicable>}.(42, 87);
- let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(field1: 87, field2: 87); // error
^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
};
@@ -205,12 +227,24 @@
self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+ () → self::Class7b f7a = #C8;
+ self::Class7b c7a = f7a(){() → self::Class7b};
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7a);
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7b);
+ <T extends core::Object? = dynamic>() → self::Class8b<T%> f8a = #C9;
+ self::Class8b<dynamic> c8a = f8a<dynamic>(){() → self::Class8b<dynamic>};
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8a<dynamic>);
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8b<dynamic>);
+ self::Class8b<core::int> c8b = f8a<core::int>(){() → self::Class8b<core::int>};
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
+ self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
try {
f(){() → dynamic};
}
@@ -232,5 +266,7 @@
#C5 = redirecting-factory-tearoff self::Class4::•
#C6 = redirecting-factory-tearoff self::Class5::•
#C7 = redirecting-factory-tearoff self::Class6::•
- #C8 = false
+ #C8 = redirecting-factory-tearoff self::Class7b::•
+ #C9 = redirecting-factory-tearoff self::Class8b::•
+ #C10 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.transformed.expect
index ccaec42..872ae36 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.transformed.expect
@@ -2,43 +2,43 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f4a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
// f5a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// f5a(42, 87, 123); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
// f6a(42); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f6a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(field1: 87, field2: 87); // error
// ^
//
@@ -55,11 +55,13 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
: super core::Object::•()
;
+ static factory _() → self::Class2
+ return new self::Class2::__();
static factory named() → self::Class2
- let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+ let () → self::Class2 #redirecting_factory = self::Class2::_ in invalid-expression;
}
class Class3 extends core::Object {
final field core::int field;
@@ -100,6 +102,26 @@
static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
let Never #redirecting_factory = self::Class6::_ in invalid-expression;
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ : super core::Object::•()
+ ;
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let Never #redirecting_factory = self::Class7a::• in invalid-expression;
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ : super core::Object::•()
+ ;
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let Never #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+}
static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -127,10 +149,10 @@
self::Class3 c3a = f3a(42){(core::int) → self::Class3};
self::expect(42, c3a.{self::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
@@ -146,7 +168,7 @@
self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
self::expect(42, c4b.{self::Class4::field}{core::int?});
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f4a(42, 87); // error
^" in f4a{<inapplicable>}.(42, 87);
@@ -161,10 +183,10 @@
self::expect(87, c5b.{self::Class5::field1}{core::int});
self::expect(42, c5b.{self::Class5::field2}{core::int?});
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
f5a(); // error
^" in f5a{<inapplicable>}.();
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
f5a(42, 87, 123); // error
^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -178,17 +200,17 @@
self::expect(null, c6a.{self::Class6::field2}{core::int?});
self::expect(87, c6a.{self::Class6::field3}{core::int});
() → Null {
- let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(); // error
^" in f6a{<inapplicable>}.();
- let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
f6a(42); // error
^" in f6a{<inapplicable>}.(42);
- let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f6a(42, 87); // error
^" in f6a{<inapplicable>}.(42, 87);
- let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(field1: 87, field2: 87); // error
^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
};
@@ -205,12 +227,24 @@
self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+ () → self::Class7b f7a = #C8;
+ self::Class7b c7a = f7a(){() → self::Class7b};
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7a);
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7b);
+ <T extends core::Object? = dynamic>() → self::Class8b<T%> f8a = #C9;
+ self::Class8b<dynamic> c8a = f8a<dynamic>(){() → self::Class8b<dynamic>};
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8a<dynamic>);
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8b<dynamic>);
+ self::Class8b<core::int> c8b = f8a<core::int>(){() → self::Class8b<core::int>};
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
+ self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
try {
f(){() → dynamic};
}
@@ -232,5 +266,7 @@
#C5 = redirecting-factory-tearoff self::Class4::•
#C6 = redirecting-factory-tearoff self::Class5::•
#C7 = redirecting-factory-tearoff self::Class6::•
- #C8 = false
+ #C8 = redirecting-factory-tearoff self::Class7b::•
+ #C9 = redirecting-factory-tearoff self::Class8b::•
+ #C10 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline.expect
index 999b5d2..2fa25d6 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline.expect
@@ -7,7 +7,8 @@
}
class Class2 {
- Class2._();
+ Class2.__();
+ factory Class2._() => Class2.__();
factory Class2.named() = Class2._;
}
@@ -40,6 +41,22 @@
factory Class6(int field1, {int? field2, required int field3}) = Class6._;
}
+class Class7a implements Class7b {
+ Class7a();
+}
+
+class Class7b {
+ factory Class7b() = Class7a;
+}
+
+class Class8a<T> implements Class8b<T> {
+ Class8a();
+}
+
+class Class8b<T> {
+ factory Class8b() = Class8a<T>;
+}
+
testArgs() {}
expect(expected, actual) {}
throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
index edb4f68..0500e74 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
@@ -4,7 +4,8 @@
}
class Class2 {
- Class2._();
+ Class2.__();
+ factory Class2._() => Class2.__();
factory Class2.named() = Class2._;
}
@@ -35,6 +36,22 @@
final int field3;
}
+class Class7a implements Class7b {
+ Class7a();
+}
+
+class Class7b {
+ factory Class7b() = Class7a;
+}
+
+class Class8a<T> implements Class8b<T> {
+ Class8a();
+}
+
+class Class8b<T> {
+ factory Class8b() = Class8a<T>;
+}
+
expect(expected, actual) {}
final bool inSoundMode = <int?>[] is! List<int>;
main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.expect
index f2dd642..ce07a22 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.expect
@@ -2,43 +2,43 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f4a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
// f5a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// f5a(42, 87, 123); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
// f6a(42); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f6a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(field1: 87, field2: 87); // error
// ^
//
@@ -55,9 +55,11 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
: super core::Object::•()
;
+ static factory _() → self::Class2
+ return new self::Class2::__();
static factory named() → self::Class2
let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
}
@@ -100,6 +102,26 @@
static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ : super core::Object::•()
+ ;
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let dynamic #redirecting_factory = self::Class7a::• in invalid-expression;
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ : super core::Object::•()
+ ;
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let dynamic #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+}
static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -127,10 +149,10 @@
self::Class3 c3a = f3a(42){(core::int) → self::Class3};
self::expect(42, c3a.{self::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
@@ -146,7 +168,7 @@
self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
self::expect(42, c4b.{self::Class4::field}{core::int?});
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f4a(42, 87); // error
^" in f4a{<inapplicable>}.(42, 87);
@@ -161,10 +183,10 @@
self::expect(87, c5b.{self::Class5::field1}{core::int});
self::expect(42, c5b.{self::Class5::field2}{core::int?});
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
f5a(); // error
^" in f5a{<inapplicable>}.();
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
f5a(42, 87, 123); // error
^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -178,17 +200,17 @@
self::expect(null, c6a.{self::Class6::field2}{core::int?});
self::expect(87, c6a.{self::Class6::field3}{core::int});
() → Null {
- let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(); // error
^" in f6a{<inapplicable>}.();
- let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
f6a(42); // error
^" in f6a{<inapplicable>}.(42);
- let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f6a(42, 87); // error
^" in f6a{<inapplicable>}.(42, 87);
- let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(field1: 87, field2: 87); // error
^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
};
@@ -205,12 +227,24 @@
self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+ () → self::Class7b f7a = #C8;
+ self::Class7b c7a = f7a(){() → self::Class7b};
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7a);
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7b);
+ <T extends core::Object? = dynamic>() → self::Class8b<T%> f8a = #C9;
+ self::Class8b<dynamic> c8a = f8a<dynamic>(){() → self::Class8b<dynamic>};
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8a<dynamic>);
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8b<dynamic>);
+ self::Class8b<core::int> c8b = f8a<core::int>(){() → self::Class8b<core::int>};
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
+ self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
try {
f(){() → dynamic};
}
@@ -232,5 +266,7 @@
#C5 = redirecting-factory-tearoff self::Class4::•
#C6 = redirecting-factory-tearoff self::Class5::•
#C7 = redirecting-factory-tearoff self::Class6::•
- #C8 = false
+ #C8 = redirecting-factory-tearoff self::Class7b::•
+ #C9 = redirecting-factory-tearoff self::Class8b::•
+ #C10 = false
}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.outline.expect
index 44ac319..d972b38 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.outline.expect
@@ -11,7 +11,9 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
+ ;
+ static factory _() → self::Class2
;
static factory named() → self::Class2
let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
@@ -51,6 +53,24 @@
static factory •(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ ;
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let dynamic #redirecting_factory = self::Class7a::• in invalid-expression;
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ ;
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let dynamic #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+}
static final field core::bool inSoundMode;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.transformed.expect
index ccaec42..872ae36 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.transformed.expect
@@ -2,43 +2,43 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
// f3a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f3a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f4a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
// f5a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
// Try removing the extra positional arguments.
// f5a(42, 87, 123); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
// f6a(42); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
// Try removing the extra positional arguments.
// f6a(42, 87); // error
// ^
//
-// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
// f6a(field1: 87, field2: 87); // error
// ^
//
@@ -55,11 +55,13 @@
}
class Class2 extends core::Object {
static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
- constructor _() → self::Class2
+ constructor __() → self::Class2
: super core::Object::•()
;
+ static factory _() → self::Class2
+ return new self::Class2::__();
static factory named() → self::Class2
- let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+ let () → self::Class2 #redirecting_factory = self::Class2::_ in invalid-expression;
}
class Class3 extends core::Object {
final field core::int field;
@@ -100,6 +102,26 @@
static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
let Never #redirecting_factory = self::Class6::_ in invalid-expression;
}
+class Class7a extends core::Object implements self::Class7b {
+ constructor •() → self::Class7a
+ : super core::Object::•()
+ ;
+}
+class Class7b extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class7b::•]/*isLegacy*/;
+ static factory •() → self::Class7b
+ let Never #redirecting_factory = self::Class7a::• in invalid-expression;
+}
+class Class8a<T extends core::Object? = dynamic> extends core::Object implements self::Class8b<self::Class8a::T%> {
+ constructor •() → self::Class8a<self::Class8a::T%>
+ : super core::Object::•()
+ ;
+}
+class Class8b<T extends core::Object? = dynamic> extends core::Object {
+ static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+ static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
+ let Never #redirecting_factory = self::Class8a::• in let self::Class8b::•::T% #typeArg0 = null in invalid-expression;
+}
static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
static method main() → dynamic {
core::print("inSoundMode: ${self::inSoundMode}");
@@ -127,10 +149,10 @@
self::Class3 c3a = f3a(42){(core::int) → self::Class3};
self::expect(42, c3a.{self::Class3::field}{core::int});
() → Null {
- let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
f3a(); // error
^" in f3a{<inapplicable>}.();
- let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f3a(42, 87); // error
^" in f3a{<inapplicable>}.(42, 87);
@@ -146,7 +168,7 @@
self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
self::expect(42, c4b.{self::Class4::field}{core::int?});
() → Null {
- let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f4a(42, 87); // error
^" in f4a{<inapplicable>}.(42, 87);
@@ -161,10 +183,10 @@
self::expect(87, c5b.{self::Class5::field1}{core::int});
self::expect(42, c5b.{self::Class5::field2}{core::int?});
() → Null {
- let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
f5a(); // error
^" in f5a{<inapplicable>}.();
- let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+ let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.
f5a(42, 87, 123); // error
^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -178,17 +200,17 @@
self::expect(null, c6a.{self::Class6::field2}{core::int?});
self::expect(87, c6a.{self::Class6::field3}{core::int});
() → Null {
- let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(); // error
^" in f6a{<inapplicable>}.();
- let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+ let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
f6a(42); // error
^" in f6a{<inapplicable>}.(42);
- let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+ let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
Try removing the extra positional arguments.
f6a(42, 87); // error
^" in f6a{<inapplicable>}.(42, 87);
- let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+ let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
f6a(field1: 87, field2: 87); // error
^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
};
@@ -205,12 +227,24 @@
self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+ () → self::Class7b f7a = #C8;
+ self::Class7b c7a = f7a(){() → self::Class7b};
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7a);
+ self::expect(true, c7a is{ForNonNullableByDefault} self::Class7b);
+ <T extends core::Object? = dynamic>() → self::Class8b<T%> f8a = #C9;
+ self::Class8b<dynamic> c8a = f8a<dynamic>(){() → self::Class8b<dynamic>};
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8a<dynamic>);
+ self::expect(true, c8a is{ForNonNullableByDefault} self::Class8b<dynamic>);
+ self::Class8b<core::int> c8b = f8a<core::int>(){() → self::Class8b<core::int>};
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
+ self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
+ self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
throw "Expected ${expected}, actual ${actual}";
}
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
try {
f(){() → dynamic};
}
@@ -232,5 +266,7 @@
#C5 = redirecting-factory-tearoff self::Class4::•
#C6 = redirecting-factory-tearoff self::Class5::•
#C7 = redirecting-factory-tearoff self::Class6::•
- #C8 = false
+ #C8 = redirecting-factory-tearoff self::Class7b::•
+ #C9 = redirecting-factory-tearoff self::Class8b::•
+ #C10 = false
}
diff --git a/tools/VERSION b/tools/VERSION
index 4038a7d..627df9f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 343
+PRERELEASE 344
PRERELEASE_PATCH 0
\ No newline at end of file