From 51003df5c326853c2f7ebbfeb4fc46371ec92aed Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Tue, 3 Feb 2026 11:38:23 -0800 Subject: [PATCH] CQ. Move constructor body diagnostics into ErrorVerifier Centralize diagnostics for illegal constructor/method bodies in ErrorVerifier instead of reporting them from the AST builder and Fasta error conversion. This consolidates several overlapping checks and fixes inconsistent error locations (for example, reporting at `external`/`const` instead of at `{`/`=>`). Key changes: - Remove constructor-body validation from AstBuilder (const bodies, const factories) and stop converting the corresponding Fasta codes to analyzer diagnostics to avoid duplicate reporting. - Add a single verifier entry point that validates whether a body is allowed based on: - factory vs generative - const vs non-const - external vs non-external - redirecting vs non-redirecting - Reuse the same validation for both regular constructors and primary constructors, and report at the body token for stable source ranges. - Add a shared check for `external` functions/methods with block or expression bodies, and apply it consistently to top-level functions and class members. - Align expectation files to the new, body-based error ranges and remove formatter-crash classification where the new reporting no longer triggers it. Change-Id: Ie91ea08a7b5505d3e6443b12317c45359bac1c2d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/477780 Reviewed-by: Johnni Winther Reviewed-by: Paul Berry Commit-Queue: Konstantin Shcheglov --- pkg/analyzer/lib/src/fasta/ast_builder.dart | 12 - .../lib/src/fasta/error_converter.dart | 13 +- .../lib/src/generated/error_verifier.dart | 115 ++++++- .../generated/class_member_parser_test.dart | 8 +- .../test/generated/error_parser_test.dart | 11 +- .../external_method_with_body_test.dart | 4 +- ..._body.dart.textual_outline_modelled.expect | 3 + ...uctor.dart.textual_outline_modelled.expect | 10 + .../various.dart.textual_outline.expect | 75 +++-- ...rious.dart.textual_outline_modelled.expect | 299 ++++++++++++++++++ .../testcases/textual_outline.status | 3 - tests/language/unsorted/external_test.dart | 6 +- 12 files changed, 480 insertions(+), 79 deletions(-) create mode 100644 pkg/front_end/testcases/extension_types/const_constructor_body.dart.textual_outline_modelled.expect create mode 100644 pkg/front_end/testcases/general/constants/non_const_constructor.dart.textual_outline_modelled.expect create mode 100644 pkg/front_end/testcases/general/constants/various.dart.textual_outline_modelled.expect diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart index d3bcdff106b..490b370e399 100644 --- a/pkg/analyzer/lib/src/fasta/ast_builder.dart +++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart @@ -3896,7 +3896,6 @@ class AstBuilder extends StackListener { void handleConstFactory(Token constKeyword) { debugEvent("ConstFactory"); // TODO(kallentu): Removal of const factory error for const function feature - handleRecoverableError(fe_diag.constFactory, constKeyword, constKeyword); } @override @@ -5872,17 +5871,6 @@ class AstBuilder extends StackListener { typeParameters.endToken, ); } - if (modifiers?.constKeyword != null && - (body.length > 1 || body.beginToken.lexeme != ';')) { - // This error is also reported in BodyBuilder.finishFunction - Token bodyToken = body.beginToken; - // Token bodyToken = body.beginToken ?? modifiers.constKeyword; - handleRecoverableError( - fe_diag.constConstructorWithBody, - bodyToken, - bodyToken, - ); - } if (modifiers?.externalKeyword != null) { for (var formalParameter in parameters.parameters) { diff --git a/pkg/analyzer/lib/src/fasta/error_converter.dart b/pkg/analyzer/lib/src/fasta/error_converter.dart index ffd12d76f32..f73ea6e3e4d 100644 --- a/pkg/analyzer/lib/src/fasta/error_converter.dart +++ b/pkg/analyzer/lib/src/fasta/error_converter.dart @@ -57,12 +57,7 @@ class FastaErrorReporter { ); return; case PseudoSharedCode.constConstructorWithBody: - diagnosticReporter?.report( - diag.constConstructorWithBody.atOffset( - offset: offset, - length: length, - ), - ); + // Reported by [ErrorVerifier] return; case PseudoSharedCode.constNotInitialized: // Reported by [ErrorVerifier] @@ -362,6 +357,12 @@ class FastaErrorReporter { void reportMessage(Message message, int offset, int length) { Code code = message.code; if (code.sharedCode case var sharedCode?) { + // Reported by [ErrorVerifier]. + if (sharedCode == SharedCode.externalFactoryWithBody || + sharedCode == SharedCode.redirectingConstructorWithBody || + sharedCode == SharedCode.externalMethodWithBody) { + return; + } var diagnosticCode = sharedAnalyzerCodes[sharedCode.index]; diagnosticReporter!.reportError( Diagnostic.tmp( diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index 12e4f41e655..fe3a106cf48 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart @@ -644,6 +644,17 @@ class ErrorVerifier extends RecursiveAstVisitor constructorElement: element, errorRange: node.errorRange, ); + _validateConstructorBodyAllowed( + element: element, + constKeyword: node.constKeyword, + externalKeyword: node.externalKeyword, + isRedirecting: + node.redirectedConstructor != null || + node.initializers + .whereType() + .isNotEmpty, + body: node.body, + ); } _checkForRedirectingConstructorErrorCodes(node); _checkForConflictingInitializerErrorCodes(node); @@ -1025,6 +1036,10 @@ class ErrorVerifier extends RecursiveAstVisitor _returnTypeVerifier.verifyReturnType(returnType); _checkForMainFunction1(node.name, fragment); _checkForMainFunction2(node); + _checkForExternalMethodWithBody( + externalKeyword: node.externalKeyword, + body: node.functionExpression.body, + ); super.visitFunctionDeclaration(node); }, isAsynchronous: fragment.isAsynchronous, @@ -1274,6 +1289,10 @@ class ErrorVerifier extends RecursiveAstVisitor _checkForTypeAnnotationDeferredClass(returnType); _returnTypeVerifier.verifyReturnType(returnType); _checkForWrongTypeParameterVarianceInMethod(node); + _checkForExternalMethodWithBody( + externalKeyword: node.externalKeyword, + body: node.body, + ); super.visitMethodDeclaration(node); }, isAsynchronous: fragment.isAsynchronous, @@ -1484,7 +1503,15 @@ class ErrorVerifier extends RecursiveAstVisitor constructorElement: element, errorRange: node.errorRange, ); - _checkForConstConstructorWithBodyPrimary(node); + if (body != null) { + _validateConstructorBodyAllowed( + element: element, + constKeyword: node.constKeyword, + externalKeyword: null, + isRedirecting: false, + body: body.body, + ); + } } _checkForUndefinedConstructorInInitializerImplicit( @@ -2964,21 +2991,6 @@ class ErrorVerifier extends RecursiveAstVisitor } } - void _checkForConstConstructorWithBodyPrimary( - PrimaryConstructorDeclaration node, - ) { - var element = node.declaredFragment!.element; - if (!element.isConst) { - return; - } - - if (node.body?.body case BlockFunctionBody blockBody) { - diagnosticReporter.report( - diag.constConstructorWithBody.at(blockBody.block.leftBracket), - ); - } - } - /// Verify that if the given [element] is 'const' constructor, then there are /// no invocations of non-'const' super constructors, and that there are no /// instance variables mixed in. @@ -3852,6 +3864,26 @@ class ErrorVerifier extends RecursiveAstVisitor } } + bool _checkForExternalMethodWithBody({ + required Token? externalKeyword, + required FunctionBody body, + }) { + if (externalKeyword != null) { + if (body is BlockFunctionBody) { + diagnosticReporter.report( + diag.externalMethodWithBody.at(body.block.leftBracket), + ); + return true; + } else if (body is ExpressionFunctionBody) { + diagnosticReporter.report( + diag.externalMethodWithBody.at(body.functionDefinition), + ); + return true; + } + } + return false; + } + /// Verify that the given field formal [parameter] is in a constructor /// declaration. /// @@ -6774,6 +6806,57 @@ class ErrorVerifier extends RecursiveAstVisitor } } + void _validateConstructorBodyAllowed({ + required ConstructorElement element, + required Token? constKeyword, + required Token? externalKeyword, + required bool isRedirecting, + required FunctionBody body, + }) { + if (element.isFactory) { + if (externalKeyword != null) { + if (body is BlockFunctionBody) { + diagnosticReporter.report( + diag.externalFactoryWithBody.at(body.block.leftBracket), + ); + } else if (body is ExpressionFunctionBody) { + diagnosticReporter.report( + diag.externalFactoryWithBody.at(body.functionDefinition), + ); + } + } else if (constKeyword != null && !isRedirecting) { + diagnosticReporter.report(diag.constFactory.at(constKeyword)); + } + } else { + _checkForExternalMethodWithBody( + externalKeyword: externalKeyword, + body: body, + ); + if (isRedirecting) { + if (body is BlockFunctionBody) { + diagnosticReporter.report( + diag.redirectingConstructorWithBody.at(body.block.leftBracket), + ); + } else if (body is ExpressionFunctionBody) { + diagnosticReporter.report( + diag.redirectingConstructorWithBody.at(body.functionDefinition), + ); + } + } + if (element.isConst) { + if (body is BlockFunctionBody) { + diagnosticReporter.report( + diag.constConstructorWithBody.at(body.block.leftBracket), + ); + } else if (body is ExpressionFunctionBody) { + diagnosticReporter.report( + diag.constConstructorWithBody.at(body.functionDefinition), + ); + } + } + } + } + void _withEnclosingExecutable( InternalExecutableElement element, void Function() operation, { diff --git a/pkg/analyzer/test/generated/class_member_parser_test.dart b/pkg/analyzer/test/generated/class_member_parser_test.dart index 067e33976c7..80496ed7fb9 100644 --- a/pkg/analyzer/test/generated/class_member_parser_test.dart +++ b/pkg/analyzer/test/generated/class_member_parser_test.dart @@ -1018,17 +1018,14 @@ void Function(core.List x) m() => null; void test_parseClassMember_method_native_with_body_allowed() { allowNativeClause = true; _parseClassMember_method_native_with_body(); - listener.assertErrors([expectedError(diag.externalMethodWithBody, 17, 1)]); + assertNoErrors(); } void test_parseClassMember_method_native_with_body_not_allowed() { allowNativeClause = false; _parseClassMember_method_native_with_body(); // TODO(brianwilkerson): Convert codes to errors when highlighting is fixed. - assertErrorsWithCodes([ - diag.nativeClauseShouldBeAnnotation, - diag.externalMethodWithBody, - ]); + assertErrorsWithCodes([diag.nativeClauseShouldBeAnnotation]); } void test_parseClassMember_method_operator_noType() { @@ -1561,7 +1558,6 @@ void Function(core.List x) m() => null; expectedError(diag.invalidConstructorName, 11, 1), expectedError(diag.missingIdentifier, 20, 1), expectedError(diag.expectedToken, 20, 1), - expectedError(diag.constConstructorWithBody, 20, 1), expectedError(diag.expectedToken, 21, 1), expectedError(diag.expectedToken, 22, 1), expectedError(diag.expectedToken, 22, 1), diff --git a/pkg/analyzer/test/generated/error_parser_test.dart b/pkg/analyzer/test/generated/error_parser_test.dart index bd47712ee5c..ec3b6dc2e02 100644 --- a/pkg/analyzer/test/generated/error_parser_test.dart +++ b/pkg/analyzer/test/generated/error_parser_test.dart @@ -263,7 +263,7 @@ main() { // missing async createParser('const factory C() {}'); ClassMember member = parser.parseClassMember('C'); expectNotNullIfNoErrors(member); - listener.assertErrors([expectedError(diag.constFactory, 0, 5)]); + listener.assertErrors([]); } void test_constMethod() { @@ -1319,14 +1319,9 @@ class Wrong { createParser('String get m native "str" => 0;'); parser.parseClassMember('C') as MethodDeclaration; if (!allowNativeClause) { - assertErrorsWithCodes([ - diag.nativeClauseShouldBeAnnotation, - diag.externalMethodWithBody, - ]); + assertErrorsWithCodes([diag.nativeClauseShouldBeAnnotation]); } else { - listener.assertErrors([ - expectedError(diag.externalMethodWithBody, 26, 1), - ]); + assertNoErrors(); } } diff --git a/pkg/analyzer/test/src/diagnostics/external_method_with_body_test.dart b/pkg/analyzer/test/src/diagnostics/external_method_with_body_test.dart index f7b9be2fbc7..62f0d5b23a2 100644 --- a/pkg/analyzer/test/src/diagnostics/external_method_with_body_test.dart +++ b/pkg/analyzer/test/src/diagnostics/external_method_with_body_test.dart @@ -92,7 +92,7 @@ class A { r''' external void foo() {} ''', - [error(diag.externalMethodWithBody, 0, 8)], + [error(diag.externalMethodWithBody, 20, 1)], ); } @@ -101,7 +101,7 @@ external void foo() {} r''' external void foo() => null; ''', - [error(diag.externalMethodWithBody, 0, 8)], + [error(diag.externalMethodWithBody, 20, 2)], ); } } diff --git a/pkg/front_end/testcases/extension_types/const_constructor_body.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/extension_types/const_constructor_body.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..4c7a6bf8cc3 --- /dev/null +++ b/pkg/front_end/testcases/extension_types/const_constructor_body.dart.textual_outline_modelled.expect @@ -0,0 +1,3 @@ +extension type ET(int i) { + const ET.named(this.i) {} +} diff --git a/pkg/front_end/testcases/general/constants/non_const_constructor.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/constants/non_const_constructor.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..4ba7c65c22a --- /dev/null +++ b/pkg/front_end/testcases/general/constants/non_const_constructor.dart.textual_outline_modelled.expect @@ -0,0 +1,10 @@ +class Class { + Class(); + const Class.named() {} +} + +const a = const Class(); + +const b = const Class.named(); + +main() {} diff --git a/pkg/front_end/testcases/general/constants/various.dart.textual_outline.expect b/pkg/front_end/testcases/general/constants/various.dart.textual_outline.expect index 8cdaa8aaeef..8a52e93a3bf 100644 --- a/pkg/front_end/testcases/general/constants/various.dart.textual_outline.expect +++ b/pkg/front_end/testcases/general/constants/various.dart.textual_outline.expect @@ -2,7 +2,8 @@ const bool barFromEnv = const bool.fromEnvironment("bar"); const bool hasBarEnv = const bool.hasEnvironment("bar"); -const bool barFromEnvOrNull = const bool.fromEnvironment("bar", defaultValue: null); +const bool barFromEnvOrNull = + const bool.fromEnvironment("bar", defaultValue: null); const bool notBarFromEnvOrNull = !barFromEnvOrNull; @@ -30,25 +31,32 @@ const bool orOnNull4 = false || barFromEnvOrNull; const String barFromEnvString = const String.fromEnvironment("bar"); -const String barFromEnvOrNullString = const String.fromEnvironment("bar", defaultValue: null); +const String barFromEnvOrNullString = + const String.fromEnvironment("bar", defaultValue: null); -const String barFromEnvOrActualString = const String.fromEnvironment("bar", defaultValue: "hello"); +const String barFromEnvOrActualString = + const String.fromEnvironment("bar", defaultValue: "hello"); -const String nullFromEnvString = const String.fromEnvironment(barFromEnvOrNullString); +const String nullFromEnvString = + const String.fromEnvironment(barFromEnvOrNullString); const bool barFromEnvBool = const bool.fromEnvironment("bar"); -const bool barFromEnvOrNullBool = const bool.fromEnvironment("bar", defaultValue: null); +const bool barFromEnvOrNullBool = + const bool.fromEnvironment("bar", defaultValue: null); -const bool barFromEnvOrActualBool = const bool.fromEnvironment("bar", defaultValue: true); +const bool barFromEnvOrActualBool = + const bool.fromEnvironment("bar", defaultValue: true); const bool nullFromEnvBool = const bool.fromEnvironment(barFromEnvOrNullString); const int barFromEnvInt = const int.fromEnvironment("bar"); -const int barFromEnvOrNullInt = const int.fromEnvironment("bar", defaultValue: null); +const int barFromEnvOrNullInt = + const int.fromEnvironment("bar", defaultValue: null); -const int barFromEnvOrActualInt = const int.fromEnvironment("bar", defaultValue: 42); +const int barFromEnvOrActualInt = + const int.fromEnvironment("bar", defaultValue: 42); const int nullFromEnvInt = const int.fromEnvironment(barFromEnvOrNullString); @@ -88,7 +96,8 @@ const binaryOnIntWithDoubleOK = willBeInt + willBeDouble; const binaryOnIntWithString = willBeInt << "hello"; -const dynamic willBeString = const bool.fromEnvironment("foo") ? 42.42 : "hello"; +const dynamic willBeString = + const bool.fromEnvironment("foo") ? 42.42 : "hello"; const binaryOnStringWithStringOK = willBeString + " world"; @@ -123,7 +132,8 @@ abstract class AbstractClassWithConstructor { int foo(); } -AbstractClassWithConstructor abstractClassWithConstructor = const AbstractClassWithConstructor(); +AbstractClassWithConstructor abstractClassWithConstructor = + const AbstractClassWithConstructor(); class NotAbstractClass { @AbstractClass() @@ -135,14 +145,19 @@ class NotAbstractClass { class Foo { final int x; final int y; - const Foo(int x) : this.x = x, this.y = "hello".length; + const Foo(int x) + : this.x = x, + this.y = "hello".length; } class FooWithHashCodeField { final int x; final int y; final int hashCode; - const FooWithHashCodeField(int x) : this.x = x, this.y = "hello".length, this.hashCode = x * 42; + const FooWithHashCodeField(int x) + : this.x = x, + this.y = "hello".length, + this.hashCode = x * 42; } class ExtendsFoo1 extends Foo {} @@ -163,13 +178,17 @@ const bool foosIdentical = identical(foo1, foo2); const bool foosEqual = foo1 == foo2; -const FooWithHashCodeField fooWithHashCodeField1 = const FooWithHashCodeField(42); +const FooWithHashCodeField fooWithHashCodeField1 = + const FooWithHashCodeField(42); -const FooWithHashCodeField fooWithHashCodeField2 = const FooWithHashCodeField(42); +const FooWithHashCodeField fooWithHashCodeField2 = + const FooWithHashCodeField(42); -const bool fooWithHashCodeFieldIdentical = identical(fooWithHashCodeField1, fooWithHashCodeField2); +const bool fooWithHashCodeFieldIdentical = + identical(fooWithHashCodeField1, fooWithHashCodeField2); -const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2; +const bool fooWithHashCodeFieldEqual = + fooWithHashCodeField1 == fooWithHashCodeField2; const Symbol barFoo = const Symbol("Foo"); @@ -195,23 +214,28 @@ class ConstClassWithFailingAssertWithEmptyMessage { const ConstClassWithFailingAssertWithEmptyMessage() : assert(false, ""); } -ConstClassWithFailingAssertWithEmptyMessage failedAssertEmptyMessage = const ConstClassWithFailingAssertWithEmptyMessage(); +ConstClassWithFailingAssertWithEmptyMessage failedAssertEmptyMessage = + const ConstClassWithFailingAssertWithEmptyMessage(); class ClassWithTypeArguments { const ClassWithTypeArguments(E e, F f, G g); } -const ClassWithTypeArguments classWithTypeArguments1 = const ClassWithTypeArguments(42, 42, 42); +const ClassWithTypeArguments classWithTypeArguments1 = + const ClassWithTypeArguments(42, 42, 42); -const ClassWithTypeArguments classWithTypeArguments2 = const ClassWithTypeArguments(42, 42, 42); +const ClassWithTypeArguments classWithTypeArguments2 = + const ClassWithTypeArguments(42, 42, 42); -const bool classWithTypeArgumentsIdentical = identical(classWithTypeArguments1, classWithTypeArguments2); +const bool classWithTypeArgumentsIdentical = + identical(classWithTypeArguments1, classWithTypeArguments2); class ClassWithNonEmptyConstConstructor { const ClassWithNonEmptyConstConstructor() {} } -ClassWithNonEmptyConstConstructor classWithNonEmptyConstConstructor = const ClassWithNonEmptyConstConstructor(); +ClassWithNonEmptyConstConstructor classWithNonEmptyConstConstructor = + const ClassWithNonEmptyConstConstructor(); class ConstClassWithFinalFields1 { const ConstClassWithFinalFields1(); @@ -225,7 +249,8 @@ class ConstClassWithFinalFields2 { final z2 = x; } -ConstClassWithFinalFields2 constClassWithFinalFields = const ConstClassWithFinalFields2(); +ConstClassWithFinalFields2 constClassWithFinalFields = + const ConstClassWithFinalFields2(); const zeroPointZeroIdentical = identical(0.0, 0.0); @@ -249,9 +274,11 @@ T id2(T t) => t; const dynamic willBecomeNull = const bool.fromEnvironment("foo") ? id1 : null; -const int Function(int) willBecomeNullToo = const bool.fromEnvironment("foo") ? id1 : willBecomeNull; +const int Function(int) willBecomeNullToo = + const bool.fromEnvironment("foo") ? id1 : willBecomeNull; -const int Function(int) partialInstantiation = const bool.fromEnvironment("foo") ? willBecomeNull : id1; +const int Function(int) partialInstantiation = + const bool.fromEnvironment("foo") ? willBecomeNull : id1; const bool yBool = true; diff --git a/pkg/front_end/testcases/general/constants/various.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/constants/various.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..b40a7e18613 --- /dev/null +++ b/pkg/front_end/testcases/general/constants/various.dart.textual_outline_modelled.expect @@ -0,0 +1,299 @@ +AbstractClassWithConstructor abstractClassWithConstructor = + const AbstractClassWithConstructor(); + +ClassWithNonEmptyConstConstructor classWithNonEmptyConstConstructor = + const ClassWithNonEmptyConstConstructor(); + +ConstClassWithFailingAssertWithEmptyMessage failedAssertEmptyMessage = + const ConstClassWithFailingAssertWithEmptyMessage(); + +ConstClassWithFinalFields2 constClassWithFinalFields = + const ConstClassWithFinalFields2(); + +T id1(T t) => t; + +T id2(T t) => t; + +abstract class AbstractClass {} + +abstract class AbstractClassWithConstructor { + const AbstractClassWithConstructor(); + int foo(); +} + +class ClassWithNonEmptyConstConstructor { + const ClassWithNonEmptyConstConstructor() {} +} + +class ClassWithTypeArguments { + const ClassWithTypeArguments(E e, F f, G g); +} + +class ConstClassWithFailingAssertWithEmptyMessage { + const ConstClassWithFailingAssertWithEmptyMessage() : assert(false, ""); +} + +class ConstClassWithFinalFields1 { + const ConstClassWithFinalFields1(); + final x = 1; +} + +class ConstClassWithFinalFields2 { + const ConstClassWithFinalFields2(); + final y = 1; + final z1 = y; + final z2 = x; +} + +class ExtendsFoo1 extends Foo {} + +class ExtendsFoo2 extends Foo { + const ExtendsFoo2(); +} + +class Foo { + const Foo(int x) + : this.x = x, + this.y = "hello".length; + final int x; + final int y; +} + +class FooWithHashCodeField { + const FooWithHashCodeField(int x) + : this.x = x, + this.y = "hello".length, + this.hashCode = x * 42; + final int hashCode; + final int x; + final int y; +} + +class NotAbstractClass { + @AbstractClassWithConstructor() + Object bar; + @AbstractClass() + Object foo; +} + +const ClassWithTypeArguments classWithTypeArguments1 = + const ClassWithTypeArguments(42, 42, 42); + +const ClassWithTypeArguments classWithTypeArguments2 = + const ClassWithTypeArguments(42, 42, 42); + +const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1(); + +const ExtendsFoo2 extendsFoo2 = const ExtendsFoo2(); + +const Foo foo1 = const Foo(42); + +const Foo foo2 = const Foo(42); + +const FooWithHashCodeField fooWithHashCodeField1 = + const FooWithHashCodeField(42); + +const FooWithHashCodeField fooWithHashCodeField2 = + const FooWithHashCodeField(42); + +const String barFromEnvOrActualString = + const String.fromEnvironment("bar", defaultValue: "hello"); + +const String barFromEnvOrNullString = + const String.fromEnvironment("bar", defaultValue: null); + +const String barFromEnvString = const String.fromEnvironment("bar"); + +const String bazFromEnvAsString = const String.fromEnvironment("baz"); + +const String nullFromEnvString = + const String.fromEnvironment(barFromEnvOrNullString); + +const Symbol barFoo = const Symbol("Foo"); + +const Symbol barFooEqual = const Symbol("Foo="); + +const Symbol symbolWithDots = const Symbol("I.Have.Dots"); + +const Symbol tripleShiftSymbol = const Symbol(">>>"); + +const binaryOnDouble = willBeDouble << 2; + +const binaryOnIntWithDoubleBad = willBeInt << willBeDouble; + +const binaryOnIntWithDoubleOK = willBeInt + willBeDouble; + +const binaryOnIntWithString = willBeInt << "hello"; + +const binaryOnStringWithInt = willBeString + willBeInt; + +const binaryOnStringWithStringBad = willBeString - " world"; + +const binaryOnStringWithStringOK = willBeString + " world"; + +const bool andOnFalse = nullAwareOnNullFalse && nullAwareOnNullTrue; + +const bool andOnFalse2 = nullAwareOnNullTrue && nullAwareOnNullFalse; + +const bool andOnNull = barFromEnvOrNull && true; + +const bool andOnNull2 = true && barFromEnvOrNull; + +const bool barFromEnv = const bool.fromEnvironment("bar"); + +const bool barFromEnvBool = const bool.fromEnvironment("bar"); + +const bool barFromEnvOrActualBool = + const bool.fromEnvironment("bar", defaultValue: true); + +const bool barFromEnvOrNull = + const bool.fromEnvironment("bar", defaultValue: null); + +const bool barFromEnvOrNullBool = + const bool.fromEnvironment("bar", defaultValue: null); + +const bool bazFalseFromEnv = const bool.fromEnvironment("bazFalse"); + +const bool bazFromEnv = const bool.fromEnvironment("baz"); + +const bool bazTrueFromEnv = const bool.fromEnvironment("bazTrue"); + +const bool binaryOnBoolAmpersand = trueBool & falseBool; + +const bool binaryOnBoolBar = trueBool | falseBool; + +const bool binaryOnBoolBar2 = falseBool | trueBool; + +const bool binaryOnBoolCaret = trueBool ^ falseBool; + +const bool classWithTypeArgumentsIdentical = + identical(classWithTypeArguments1, classWithTypeArguments2); + +const bool conditionalOnNull = barFromEnvOrNull ? true : false; + +const bool falseBool = false; + +const bool fooWithHashCodeFieldEqual = + fooWithHashCodeField1 == fooWithHashCodeField2; + +const bool fooWithHashCodeFieldIdentical = + identical(fooWithHashCodeField1, fooWithHashCodeField2); + +const bool foosEqual = foo1 == foo2; + +const bool foosIdentical = identical(foo1, foo2); + +const bool hasBarEnv = const bool.hasEnvironment("bar"); + +const bool hasBazEnv = const bool.hasEnvironment("baz"); + +const bool isItInt = maybeInt is int ? true : false; + +const bool isItInt2 = maybeInt2 is int ? true : false; + +const bool isItInt3 = maybeInt3 is int ? true : false; + +const bool notBarFromEnvOrNull = !barFromEnvOrNull; + +const bool nullAwareOnNullFalse = barFromEnvOrNull ?? false; + +const bool nullAwareOnNullTrue = barFromEnvOrNull ?? true; + +const bool nullFromEnvBool = const bool.fromEnvironment(barFromEnvOrNullString); + +const bool orOnNull = barFromEnvOrNull || true; + +const bool orOnNull2 = barFromEnvOrNull || false; + +const bool orOnNull3 = true || barFromEnvOrNull; + +const bool orOnNull4 = false || barFromEnvOrNull; + +const bool trueBool = true; + +const bool yBool = true; + +const bool zBool = !yBool; + +const dynamic willBeDouble = const bool.fromEnvironment("foo") ? 42 : 42.42; + +const dynamic willBeInt = const bool.fromEnvironment("foo") ? 42.42 : 42; + +const dynamic willBeString = + const bool.fromEnvironment("foo") ? 42.42 : "hello"; + +const dynamic willBecomeNull = const bool.fromEnvironment("foo") ? id1 : null; + +const function_const = () {}; + +const int Function(int) partialInstantiation = + const bool.fromEnvironment("foo") ? willBecomeNull : id1; + +const int Function(int) willBecomeNullToo = + const bool.fromEnvironment("foo") ? id1 : willBecomeNull; + +const int barFromEnvInt = const int.fromEnvironment("bar"); + +const int barFromEnvOrActualInt = + const int.fromEnvironment("bar", defaultValue: 42); + +const int barFromEnvOrNullInt = + const int.fromEnvironment("bar", defaultValue: null); + +const int bazFromEnvAsInt = const int.fromEnvironment("baz"); + +const int circularity1 = circularity2; + +const int circularity2 = circularity3; + +const int circularity3 = circularity4; + +const int circularity4 = circularity1; + +const int nullFromEnvInt = const int.fromEnvironment(barFromEnvOrNullString); + +const maybeInt = bool.fromEnvironment("foo") ? 42 : true; + +const maybeInt2 = zBool ? 42 : true; + +const maybeInt3 = zBool ? 42 : null; + +const nanEqual = 0 / 0 == 0 / 0; + +const nanIdentical = identical(0 / 0, 0 / 0); + +const x1 = --x; + +const x2 = ++x; + +const x3 = x--; + +const x4 = x++; + +const y = 1; + +const y1 = --y; + +const y2 = ++y; + +const y3 = y--; + +const y4 = y++; + +const zeroEqualToZeroPointZero = 0 == 0.0; + +const zeroIdenticalToZeroPointZero = identical(0, 0.0); + +const zeroPointZeroEqual = 0.0 == 0.0; + +const zeroPointZeroEqualToZero = 0.0 == 0; + +const zeroPointZeroIdentical = identical(0.0, 0.0); + +const zeroPointZeroIdenticalToZero = identical(0.0, 0); + +main() {} + +var function_var = () {}; + +var x = 1; diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status index ea7ee903dee..74a500e549e 100644 --- a/pkg/front_end/testcases/textual_outline.status +++ b/pkg/front_end/testcases/textual_outline.status @@ -10,9 +10,6 @@ regress/annotation_on_type_parameter_name_clash_on_constructor: FormatterCrash regress/annotation_on_type_parameter_name_extension_type_constructor: FormatterCrash enhanced_enums/external_constructor: FormatterCrash -extension_types/const_constructor_body: FormatterCrash -general/constants/non_const_constructor: FormatterCrash -general/constants/various: FormatterCrash general/invalid_operator: FormatterCrash general/invalid_super_initializer: FormatterCrash general/issue45700.crash: FormatterCrash diff --git a/tests/language/unsorted/external_test.dart b/tests/language/unsorted/external_test.dart index ac1e9a4c0af..a81aa3dd3e1 100644 --- a/tests/language/unsorted/external_test.dart +++ b/tests/language/unsorted/external_test.dart @@ -70,14 +70,16 @@ class Foo { } external int t06(int i) { return 1; } -// [error column 1, length 8] +// ^ // [analyzer] SYNTACTIC_ERROR.EXTERNAL_METHOD_WITH_BODY +// [error column 1, length 8] // [cfe] An external or native method can't have a body. // ^ // [cfe] An external or native method can't have a body. external int t07(int i) => i + 1; -// [error column 1, length 8] +// ^^ // [analyzer] SYNTACTIC_ERROR.EXTERNAL_METHOD_WITH_BODY +// [error column 1, length 8] // [cfe] An external or native method can't have a body. // ^ // [cfe] An external or native method can't have a body.