diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart index 280326c7936a..a67288425cba 100644 --- a/pkg/analyzer/lib/src/error/codes.g.dart +++ b/pkg/analyzer/lib/src/error/codes.g.dart @@ -258,7 +258,9 @@ class CompileTimeErrorCode extends AnalyzerErrorCode { 'AWAIT_OF_EXTENSION_TYPE_NOT_FUTURE', "The 'await' expression can't be used for an expression with an extension " "type that is not a subtype of 'Future'.", - correctionMessage: "Try updating the extension type to implement 'Future'.", + correctionMessage: + "Try removing the `await`, or updating the extension type to implement " + "'Future'.", ); /// Parameters: @@ -1672,8 +1674,8 @@ class CompileTimeErrorCode extends AnalyzerErrorCode { static const CompileTimeErrorCode EXTENSION_TYPE_CONSTRUCTOR_WITH_SUPER_INVOCATION = CompileTimeErrorCode( 'EXTENSION_TYPE_CONSTRUCTOR_WITH_SUPER_INVOCATION', - "Extension type constructors can't include superinitializers.", - correctionMessage: "Try removing the superconstructor invocation.", + "Extension type constructors can't include super initializers.", + correctionMessage: "Try removing the super constructor invocation.", ); /// No parameters. diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml index ff769bf9117e..0e9e5f88cd5b 100644 --- a/pkg/analyzer/messages.yaml +++ b/pkg/analyzer/messages.yaml @@ -1170,7 +1170,51 @@ CompileTimeErrorCode: await expression.) AWAIT_OF_EXTENSION_TYPE_NOT_FUTURE: problemMessage: "The 'await' expression can't be used for an expression with an extension type that is not a subtype of 'Future'." - correctionMessage: Try updating the extension type to implement 'Future'. + correctionMessage: Try removing the `await`, or updating the extension type to implement 'Future'. + documentation: |- + #### Description + + The analyzer produces this diagnostic when the type of the expression in + an `await` expression is an extension type, and the extension type isn't a + subclass of `Future`. + + #### Example + + The following code produces this diagnostic because the extension type `E` + isn't a subclass of `Future`: + + ```dart + extension type E(int i) {} + + void f(E e) async { + [!await!] e; + } + ``` + + #### Common fixes + + If the extension type is correctly defined, then remove the `await`: + + ```dart + extension type E(int i) {} + + void f(E e) { + e; + } + ``` + + If the extension type is intended to be awaitable, then add `Future` (or a + subtype of `Future`) to the `implements` clause (adding an `implements` + clause if there isn't one already), and make the representation type + match: + + ```dart + extension type E(Future i) implements Future {} + + void f(E e) async { + await e; + } + ``` BASE_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY: sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY problemMessage: "The class '{0}' can't be implemented outside of its library because it's a base class." @@ -5139,28 +5183,222 @@ CompileTimeErrorCode: problemMessage: "Extension type constructors can't declare super formal parameters." correctionMessage: Try removing the super formal parameter declaration. comment: No parameters. + documentation: |- + #### Description + + The analyzer produces this diagnostic when a constructor in an extension + type has a super parameter. Super parameters aren't valid because + extension types don't have a superclass. + + #### Example + + The following code produces this diagnostic because the named constructor + `n` contains a super parameter: + + ```dart + extension type E(int i) { + E.n(this.i, [!super!].foo); + } + ``` + + #### Common fixes + + If you need the parameter, replace the super parameter with a normal + parameter: + + ```dart + extension type E(int i) { + E.n(this.i, String foo); + } + ``` + + If you don't need the parameter, remove the super parameter: + + ```dart + extension type E(int i) { + E.n(this.i); + } + ``` EXTENSION_TYPE_CONSTRUCTOR_WITH_SUPER_INVOCATION: - problemMessage: "Extension type constructors can't include superinitializers." - correctionMessage: Try removing the superconstructor invocation. + problemMessage: Extension type constructors can't include super initializers. + correctionMessage: Try removing the super constructor invocation. comment: No parameters. + documentation: |- + #### Description + + The analyzer produces this diagnostic when a constructor in an extension + type includes an invocation of a super constructor in the initializer + list. Because extension types don't have a superclass, there's no + constructor to invoke. + + #### Example + + The following code produces this diagnostic because the constructor `E.n` + invokes a super constructor in its initializer list: + + ```dart + extension type E(int i) { + E.n() : i = 0, [!super!].n(); + } + ``` + + #### Common fixes + + Remove the invocation of the super constructor: + + ```dart + extension type E(int i) { + E.n() : i = 0; + } + ``` EXTENSION_TYPE_DECLARES_INSTANCE_FIELD: problemMessage: "Extension types can't declare instance fields." correctionMessage: Try replacing the field with a getter. comment: No parameters. + documentation: |- + #### Description + + The analyzer produces this diagnostic when there's a field declaration in + the body of an extension type declaration. + + #### Example + + The following code produces this diagnostic because the extension type `E` + declares a field named `f`: + + ```dart + extension type E(int i) { + final int [!f!] = 0; + } + ``` + + #### Common fixes + + If you don't need the field, then remove it or replace it with a getter + and/or setter: + + ```dart + extension type E(int i) { + int get f => 0; + } + ``` + + If you need the field, then convert the extension type into a class: + + ```dart + class E { + final int i; + + final int f = 0; + + E(this.i); + } + ``` EXTENSION_TYPE_DECLARES_MEMBER_OF_OBJECT: problemMessage: "Extension types can't declare members with the same name as a member declared by 'Object'." correctionMessage: Try specifying a different name for the member. comment: No parameters. + documentation: |- + #### Description + + The analyzer produces this diagnostic when the body of an extension type + declaration contains a member with the same name as one of the members + declared by `Object`. + + #### Example + + The following code produces this diagnostic because the class `Object` + already defines a member named `hashCode`: + + ```dart + extension type E(int i) { + int get [!hashCode!] => 0; + } + ``` + + #### Common fixes + + If you need a member with the implemented semantics, then rename the + member: + + ```dart + extension type E(int i) { + int get myHashCode => 0; + } + ``` + + If you don't need a member with the implemented semantics, then remove the + member: + + ```dart + extension type E(int i) {} + ``` EXTENSION_TYPE_IMPLEMENTS_DISALLOWED_TYPE: problemMessage: "Extension types can't implement '{0}'." correctionMessage: Try specifying a different type, or remove the type from the list. comment: |- Parameters: 0: the display string of the disallowed type + documentation: |- + #### Description + + The analyzer produces this diagnostic when an extension type implements a + type that it isn't allowed to implement. + + #### Example + + The following code produces this diagnostic because extension types can't + implement the type `dynamic`: + + ```dart + extension type A(int i) implements [!dynamic!] {} + ``` + + #### Common fixes + + Remove the disallowed type from the implements clause: + + ```dart + extension type A(int i) {} + ``` EXTENSION_TYPE_IMPLEMENTS_ITSELF: problemMessage: "The extension type can't implement itself." correctionMessage: Try removing the superinterface that references this extension type. comment: No parameters. + documentation: |- + #### Description + + The analyzer produces this diagnostic when an extension type implements + itself, either directly or indirectly. + + #### Example + + The following code produces this diagnostic because the extension type `A` + directly implements itself: + + ```dart + extension type [!A!](int i) implements A {} + ``` + + The following code produces this diagnostic because the extension type `A` + indirectly implements itself (through `B`): + + ```dart + extension type [!A!](int i) implements B {} + + extension type [!B!](int i) implements A {} + ``` + + #### Common fixes + + Break the cycle by removing a type from the implements clause of at least + one of the types involved in the cycle: + + ```dart + extension type A(int i) implements B {} + + extension type B(int i) {} + ``` EXTENSION_TYPE_IMPLEMENTS_NOT_SUPERTYPE: problemMessage: "'{0}' is not a supertype of '{1}', the representation type." correctionMessage: Try specifying a different type, or remove the type from the list. @@ -5168,6 +5406,37 @@ CompileTimeErrorCode: Parameters: 0: the implemented not extension type 1: the ultimate representation type + documentation: |- + #### Description + + The analyzer produces this diagnostic when an extension type implements a + type that isn't a supertype of the representation type. + + #### Example + + The following code produces this diagnostic because the extension type `A` + implements `String`, but `String` isn't a supertype of the representation + type `int`: + + ```dart + extension type A(int i) implements [!String!] {} + ``` + + #### Common fixes + + If the representation type is correct, then remove or replace the type in + the implements clause: + + ```dart + extension type A(int i) {} + ``` + + If the representation type isn't correct, then replace it with the correct + type: + + ```dart + extension type A(String s) implements String {} + ``` EXTENSION_TYPE_IMPLEMENTS_REPRESENTATION_NOT_SUPERTYPE: problemMessage: "'{0}', the representation type of '{1}', is not a supertype of '{2}', the representation type of '{3}'." correctionMessage: Try specifying a different type, or remove the type from the list. @@ -5177,6 +5446,45 @@ CompileTimeErrorCode: 1: the name of the implemented extension type 2: the representation type of the this extension type 3: the name of the this extension type + documentation: |- + #### Description + + The analyzer produces this diagnostic when an extension type implements + another extension type, and the representation type of the implemented + extension type isn't a subtype of the representation type of the implementing + extension type. + + #### Example + + The following code produces this diagnostic because the extension type `B` + implements `A`, but the representation type of `A` (`num`) isn't a + subtype of the representation type of `B` (`String`): + + ```dart + extension type A(num i) {} + + extension type B(String s) implements [!A!] {} + ``` + + #### Common fixes + + Either change the representation types of the two extension types so that + the representation type of the implemented type is a supertype of the + representation type of the implementing type: + + ```dart + extension type A(num i) {} + + extension type B(int n) implements A {} + ``` + + Or remove the implemented type from the implements clause: + + ```dart + extension type A(num i) {} + + extension type B(String s) {} + ``` EXTENSION_TYPE_INHERITED_MEMBER_CONFLICT: problemMessage: "The extension type '{0}' has more than one distinct member named '{1}' from implemented types." correctionMessage: Try redeclaring the corresponding member in this extension type. @@ -5184,10 +5492,106 @@ CompileTimeErrorCode: Parameters: 0: the name of the extension type 1: the name of the conflicting member + documentation: |- + #### Description + + The analyzer produces this diagnostic when an extension type implements + two or more other types, and at least two of those types declare a member + with the same name. + + #### Example + + The following code produces this diagnostic because the extension type `C` + implements both `A` and `B`, and both declare a member named `m`: + + ```dart + class A { + void m() {} + } + + extension type B(A a) { + void m() {} + } + + extension type [!C!](A a) implements A, B {} + ``` + + #### Common fixes + + If the extension type doesn't need to implement all of the listed types, + then remove all but one of the types introducing the conflicting members: + + ```dart + class A { + void m() {} + } + + extension type B(A a) { + void m() {} + } + + extension type C(A a) implements A {} + ``` + + If the extension type needs to implement all of the listed types but you + can rename the members in those types, then give the conflicting members + unique names: + + ```dart + class A { + void m() {} + } + + extension type B(A a) { + void n() {} + } + + extension type C(A a) implements A, B {} + ``` EXTENSION_TYPE_REPRESENTATION_DEPENDS_ON_ITSELF: problemMessage: "The extension type representation can't depend on itself." correctionMessage: Try specifying a different type. comment: No parameters. + documentation: |- + #### Description + + The analyzer produces this diagnostic when an extension type has a + representation type that depends on the extension type itself, either + directly or indirectly. + + #### Example + + The following code produces this diagnostic because the representation + type of the extension type `A` depends on `A` directly: + + ```dart + extension type [!A!](A a) {} + ``` + + The following two code examples produce this diagnostic because the + representation type of the extension type `A` depends on `A` + indirectly through the extension type `B`: + + ```dart + extension type [!A!](B b) {} + + extension type [!B!](A a) {} + ``` + + ```dart + extension type [!A!](List b) {} + + extension type [!B!](List a) {} + ``` + + #### Common fixes + + Remove the dependency by choosing a different representation type for at + least one of the types in the cycle: + + ```dart + extension type A(String s) {} + ``` EXTENSION_TYPE_REPRESENTATION_TYPE_BOTTOM: problemMessage: "The representation type can't be a bottom type." correctionMessage: Try specifying a different type. @@ -11101,6 +11505,30 @@ CompileTimeErrorCode: problemMessage: "An extension type parameter can't be used in a non-covariant position of its representation type." correctionMessage: "Try removing the type parameters from function parameter types and type parameter bounds." comment: No parameters. + documentation: |- + #### Description + + The analyzer produces this diagnostic when a type parameter of an + extension type is used in a non-covariant position in the representation + type of that extension type. + + #### Example + + The following code produces this diagnostic because the type parameter `T` + is used as a parameter type in the function type `void Function(T)`, and + parameters are not covariant: + + ```dart + extension type A<[!T!]>(void Function(T) f) {} + ``` + + #### Common fixes + + Remove the use of the type parameter: + + ```dart + extension type A(void Function(String) f) {} + ``` NON_EXHAUSTIVE_SWITCH_EXPRESSION: problemMessage: "The type '{0}' is not exhaustively matched by the switch cases since it doesn't match '{1}'." correctionMessage: "Try adding a wildcard pattern or cases that match '{2}'." @@ -20861,7 +21289,7 @@ PubspecWarningCode: #### Common fixes If you can rely on automatic platform detection, then omit the - top-level `platforms` field. + top-level `platforms` field. ```yaml %uri="pubspec.yaml" @@ -24234,6 +24662,62 @@ WarningCode: Parameters: 0: the kind of member + documentation: |- + #### Description + + The analyzer produces this diagnostic when a member of an extension type + is annotated with `@redeclare`, but none of the implemented interfaces + has a member with the same name. + + #### Example + + The following code produces this diagnostic because the member `n` + declared by the extension type `E` is annotated with `@redeclare`, but `C` + doesn't have a member named `n`: + + ```dart + import 'package:meta/meta.dart'; + + class C { + void m() {} + } + + extension type E(C c) implements C { + @redeclare + void [!n!]() {} + } + ``` + + #### Common fixes + + If the annotated member has the right name, then remove the annotation: + + ```dart + class C { + void m() {} + } + + extension type E(C c) implements C { + void n() {} + } + ``` + + If the annotated member is suppose to replace a member from the + implemented interfaces, then change the name of the annotated member to + match the member being replaced: + + ```dart + import 'package:meta/meta.dart'; + + class C { + void m() {} + } + + extension type E(C c) implements C { + @redeclare + void m() {} + } + ``` REMOVED_LINT_USE: problemMessage: "'{0}' was removed in Dart '{1}'" correctionMessage: "Remove the reference to '{0}'." diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart index da14118aa083..a341c59e600f 100644 --- a/pkg/analyzer/test/generated/non_error_resolver_test.dart +++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart @@ -16,158 +16,11 @@ import '../src/dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(NonErrorResolverTest); - defineReflectiveTests(NonErrorResolverWithoutNullSafetyTest); }); } @reflectiveTest -class NonErrorResolverTest extends PubPackageResolutionTest - with NonErrorResolverTestCases { - test_async_callback_in_with_unknown_return_type_context() async { - await assertNoErrorsInCode(''' -abstract class C { - R run(R Function() action); -} -f(C c) { - c.run(() async {}); -} -'''); - } - - test_await_flattened() async { - await assertNoErrorsInCode(''' -Future>? ffi() => null; -f() async { - Future? b = await ffi(); - b; -} -'''); - } - - test_conflictingStaticGetterAndInstanceSetter_thisClass() async { - await assertErrorsInCode(r''' -class A { - static get x => 0; - static set x(int p) {} -} -''', [ - error(CompileTimeErrorCode.GETTER_NOT_SUBTYPE_SETTER_TYPES, 23, 1), - ]); - } - - test_const_constructor_with_named_generic_parameter() async { - await assertNoErrorsInCode(''' -class C { - const C({required T t}); -} -const c = const C(t: 1); -'''); - } - - test_generic_staticParameterElement_annotation() async { - await assertNoErrorsInCode(''' -class C { - const C.named({arg}); -} -@C.named(arg: true) -test() {} -'''); - var x = findNode.namedExpression('arg: true'); - var y = x.staticParameterElement!; - expect(y, TypeMatcher()); - expect(y.declaration, findElement.parameter('arg')); - } - - test_inconsistentMethodInheritance_accessors_typeParameters1() async { - await assertNoErrorsInCode(r''' -abstract class A { - E? get x; -} -abstract class B { - E? get x; -} -class C implements A, B { - E? get x => null; -} -'''); - } - - test_inconsistentMethodInheritance_accessors_typeParameters2() async { - await assertNoErrorsInCode(r''' -abstract class A { - E? get x {return null;} -} -class B { - E? get x {return null;} -} -class C extends A implements B {} -'''); - } - - test_inconsistentMethodInheritance_accessors_typeParameters_diamond() async { - await assertNoErrorsInCode(r''' -abstract class F extends B {} -class D extends F { - external E? get g; -} -abstract class C { - E? get g; -} -abstract class B implements C { - E? get g { return null; } -} -class A extends B implements D { -} -'''); - } - - test_mixinDeclaresConstructor() async { - await assertNoErrorsInCode(r''' -mixin class A { - m() {} -} -class B extends Object with A {} -'''); - } - - test_mixinDeclaresConstructor_factory() async { - await assertNoErrorsInCode(r''' -mixin class A { - factory A() => throw 0; -} -class B extends Object with A {} -'''); - } - - test_no_call_tearoff_on_promoted_var() async { - await assertNoErrorsInCode(''' -class B { - Object call() => ''; -} -void test(Object x) { - x as Object Function(); - x; // promoted - x = B(); // No implicit tearoff of `.call`, demotes x - x; // demoted -} -'''); - assertType(findNode.simple('x; // promoted'), 'Object Function()'); - assertType(findNode.assignment('x = B()'), 'B'); - assertType(findNode.simple('x; // demoted'), 'Object'); - } - - test_typedef_not_function() async { - newFile('$testPackageLibPath/a.dart', ''' -typedef F = int; -'''); - await assertNoErrorsInCode(''' -import 'a.dart'; -F f = 0; -'''); - } -} - -mixin NonErrorResolverTestCases on PubPackageResolutionTest { +class NonErrorResolverTest extends PubPackageResolutionTest { test_ambiguousExport() async { newFile("$testPackageLibPath/lib1.dart", r''' library lib1; @@ -538,6 +391,17 @@ main() { '''); } + test_async_callback_in_with_unknown_return_type_context() async { + await assertNoErrorsInCode(''' +abstract class C { + R run(R Function() action); +} +f(C c) { + c.run(() async {}); +} +'''); + } + test_async_dynamic_with_return() async { await assertNoErrorsInCode(''' dynamic f() async { @@ -709,6 +573,16 @@ f(list) async* { ]); } + test_await_flattened() async { + await assertNoErrorsInCode(''' +Future>? ffi() => null; +f() async { + Future? b = await ffi(); + b; +} +'''); + } + test_await_simple() async { await assertNoErrorsInCode(''' Future fi() => Future.value(0); @@ -792,6 +666,24 @@ f() { ]); } + test_castFrom() async { + // This test exercises a corner case of legacy erasure: due to the type + // substitution in the `newSet` parameter of `Set.castFrom`, we wind up with + // a synthetic `ParameterMember` that belongs to no library. We need to + // make sure this doesn't lead to a crash. + await assertErrorsInCode(''' +class C {} + +void testNewSet(Set setEls) { + var customNewSet; + Set.castFrom(setEls, + newSet: () => customNewSet = new Set()); +} +''', [ + error(WarningCode.UNUSED_LOCAL_VARIABLE, 51, 12), + ]); + } + test_class_type_alias_documentationComment() async { await assertNoErrorsInCode(''' /** @@ -845,6 +737,26 @@ set x(_) {} '''); } + test_conflictingStaticGetterAndInstanceSetter_thisClass() async { + await assertErrorsInCode(r''' +class A { + static get x => 0; + static set x(int p) {} +} +''', [ + error(CompileTimeErrorCode.GETTER_NOT_SUBTYPE_SETTER_TYPES, 23, 1), + ]); + } + + test_const_constructor_with_named_generic_parameter() async { + await assertNoErrorsInCode(''' +class C { + const C({required T t}); +} +const c = const C(t: 1); +'''); + } + test_const_dynamic() async { await assertNoErrorsInCode(''' const Type d = dynamic; @@ -1010,6 +922,18 @@ class B { '''); } + test_constEvalTypeBoolNumString_equal_null() async { + await assertNoErrorsInCode(r''' +class B { + final v; + const B.n1(num? p) : v = p == null; + const B.n2(num? p) : v = null == p; + const B.n3(Object? p) : v = p == null; + const B.n4(Object? p) : v = null == p; +} +'''); + } + test_constEvalTypeBoolNumString_notEqual() async { await assertNoErrorsInCode(r''' class B { @@ -1033,6 +957,18 @@ class B { '''); } + test_constEvalTypeBoolNumString_notEqual_null() async { + await assertNoErrorsInCode(''' +class B { + final v; + const B.n1(num? p) : v = p != null; + const B.n2(num? p) : v = null != p; + const B.n3(Object? p) : v = p != null; + const B.n4(Object? p) : v = null != p; +} +'''); + } + test_constEvAlTypeNum_String() async { await assertNoErrorsInCode(r''' const String A = 'a'; @@ -1417,6 +1353,20 @@ typedef int f(@app int app); '''); } + test_generic_staticParameterElement_annotation() async { + await assertNoErrorsInCode(''' +class C { + const C.named({arg}); +} +@C.named(arg: true) +test() {} +'''); + var x = findNode.namedExpression('arg: true'); + var y = x.staticParameterElement!; + expect(y, TypeMatcher()); + expect(y.declaration, findElement.parameter('arg')); + } + test_generic_staticParameterElement_annotation_implicitTypeArg() async { var required = isNullSafetyEnabled ? 'required' : ''; await assertNoErrorsInCode(''' @@ -1598,6 +1548,15 @@ class A { '''); } + test_genericTypeAlias_invalidGenericFunctionType() async { + await assertNoErrorsInCode(''' +typedef F = int; +main(p) { + p is F; +} +'''); + } + test_genericTypeAlias_noTypeParameters() async { await assertNoErrorsInCode(r''' typedef Foo = int Function(T x); @@ -1728,16 +1687,59 @@ main() { '''); } - test_inconsistentMethodInheritance_methods_typeParameter2() async { + test_inconsistentMethodInheritance_accessors_typeParameters1() async { await assertNoErrorsInCode(r''' -class A { - x(E e) {} +abstract class A { + E? get x; } -class B { - x(E e) {} +abstract class B { + E? get x; } -class C extends A implements B { - x(E e) {} +class C implements A, B { + E? get x => null; +} +'''); + } + + test_inconsistentMethodInheritance_accessors_typeParameters2() async { + await assertNoErrorsInCode(r''' +abstract class A { + E? get x {return null;} +} +class B { + E? get x {return null;} +} +class C extends A implements B {} +'''); + } + + test_inconsistentMethodInheritance_accessors_typeParameters_diamond() async { + await assertNoErrorsInCode(r''' +abstract class F extends B {} +class D extends F { + external E? get g; +} +abstract class C { + E? get g; +} +abstract class B implements C { + E? get g { return null; } +} +class A extends B implements D { +} +'''); + } + + test_inconsistentMethodInheritance_methods_typeParameter2() async { + await assertNoErrorsInCode(r''' +class A { + x(E e) {} +} +class B { + x(E e) {} +} +class C extends A implements B { + x(E e) {} } '''); } @@ -2405,6 +2407,24 @@ class C { '''); } + test_mixinDeclaresConstructor() async { + await assertNoErrorsInCode(r''' +mixin class A { + m() {} +} +class B extends Object with A {} +'''); + } + + test_mixinDeclaresConstructor_factory() async { + await assertNoErrorsInCode(r''' +mixin class A { + factory A() => throw 0; +} +class B extends Object with A {} +'''); + } + test_multipleSuperInitializers_no() async { await assertNoErrorsInCode(r''' class A {} @@ -2437,6 +2457,23 @@ A f() { '''); } + test_no_call_tearoff_on_promoted_var() async { + await assertNoErrorsInCode(''' +class B { + Object call() => ''; +} +void test(Object x) { + x as Object Function(); + x; // promoted + x = B(); // No implicit tearoff of `.call`, demotes x + x; // demoted +} +'''); + assertType(findNode.simple('x; // promoted'), 'Object Function()'); + assertType(findNode.assignment('x = B()'), 'B'); + assertType(findNode.simple('x; // demoted'), 'Object'); + } + test_nonBoolExpression_interfaceType() async { await assertNoErrorsInCode(r''' f() { @@ -3021,6 +3058,16 @@ class A{} '''); } + test_typedef_not_function() async { + newFile('$testPackageLibPath/a.dart', ''' +typedef F = int; +'''); + await assertNoErrorsInCode(''' +import 'a.dart'; +F f = 0; +'''); + } + test_typePromotion_booleanAnd_useInRight() async { await assertNoErrorsInCode(r''' main(Object p) { @@ -3054,6 +3101,46 @@ main(Object p) { '''); } + test_typePromotion_functionType_arg_ignoreIfNotMoreSpecific() async { + await assertNoErrorsInCode(r''' +typedef FuncB(B b); +typedef FuncA(A a); +class A {} +class B {} +void f(FuncA f) { + if (f is FuncB) { + f(new A()); + } +} +'''); + } + + test_typePromotion_functionType_return_ignoreIfNotMoreSpecific() async { + await assertNoErrorsInCode(r''' +class A {} +typedef FuncAtoDyn(A a); +typedef FuncDynToDyn(x); +void f(FuncAtoDyn f, A a) { + if (f is FuncDynToDyn) { + a = f(new A()); + } +} +'''); + } + + test_typePromotion_functionType_return_voidToDynamic() async { + await assertNoErrorsInCode(r''' +typedef FuncDynToDyn(x); +typedef void FuncDynToVoid(x); +class A {} +void f(FuncDynToVoid? f, A a) { + if (f is FuncDynToDyn) { + a = f(null); + } +} +'''); + } + test_typePromotion_if_accessedInClosure_noAssignment() async { await assertNoErrorsInCode(r''' callMe(f()) { f(); } @@ -3067,6 +3154,23 @@ main(Object p) { '''); } + test_typePromotion_if_extends_moreSpecific() async { + await assertNoErrorsInCode(r''' +class V {} +class VP extends V {} +class A {} +class B extends A { + var b; +} + +void f(A p) { + if (p is B) { + p.b; + } +} +'''); + } + test_typePromotion_if_hasAssignment_outsideAfter() async { await assertNoErrorsInCode(r''' main(Object p) { @@ -3088,6 +3192,23 @@ main(Object p, Object p2) { }'''); } + test_typePromotion_if_implements_moreSpecific() async { + await assertNoErrorsInCode(r''' +class V {} +class VP extends V {} +class A {} +class B implements A { + var b; +} + +void f(A p) { + if (p is B) { + p.b; + } +} +'''); + } + test_typePromotion_if_inClosure_assignedAfter_inSameFunction() async { await assertErrorsInCode(r''' main() { @@ -3252,183 +3373,6 @@ class B extends A { import 'dart:core' as core; core.dynamic dynamicVariable; -'''); - } -} - -@reflectiveTest -class NonErrorResolverWithoutNullSafetyTest extends PubPackageResolutionTest - with WithoutNullSafetyMixin, NonErrorResolverTestCases { - test_castFrom() async { - // This test exercises a corner case of legacy erasure: due to the type - // substitution in the `newSet` parameter of `Set.castFrom`, we wind up with - // a synthetic `ParameterMember` that belongs to no library. We need to - // make sure this doesn't lead to a crash. - await assertErrorsInCode(''' -class C {} - -void testNewSet(Set setEls) { - var customNewSet; - Set.castFrom(setEls, - newSet: () => customNewSet = new Set()); -} -''', [ - error(WarningCode.UNUSED_LOCAL_VARIABLE, 51, 12), - ]); - } - - test_conflictingStaticGetterAndInstanceSetter_thisClass() async { - await assertNoErrorsInCode(r''' -class A { - static get x => 0; - static set x(int p) {} -} -'''); - } - - test_constEvalTypeBoolNumString_equal_null() async { - await assertNoErrorsInCode(r''' -class B { - final v; - const B.n1(num p) : v = p == null; - const B.n2(num p) : v = null == p; - const B.n3(Object p) : v = p == null; - const B.n4(Object p) : v = null == p; -} -'''); - } - - test_constEvalTypeBoolNumString_notEqual_null() async { - await assertNoErrorsInCode(''' -class B { - final v; - const B.n1(num p) : v = p != null; - const B.n2(num p) : v = null != p; - const B.n3(Object p) : v = p != null; - const B.n4(Object p) : v = null != p; -} -'''); - } - - test_genericTypeAlias_invalidGenericFunctionType() async { - // There is a parse error, but no crashes. - await assertErrorsInCode(''' -typedef F = int; -main(p) { - p is F; -} -''', [ - error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 10, 1), - ]); - } - - test_mixinDeclaresConstructor() async { - await assertNoErrorsInCode(r''' -class A { - m() {} -} -class B extends Object with A {} -'''); - } - - test_mixinDeclaresConstructor_factory() async { - await assertNoErrorsInCode(r''' -class A { - factory A() => throw 0; -} -class B extends Object with A {} -'''); - } - - test_typePromotion_conditional_issue14655() async { - await assertNoErrorsInCode(r''' -class A {} -class B extends A {} -class C extends B { - mc() {} -} -print(_) {} -main(A p) { - (p is C) && (print(() => p) && (p is B)) ? p.mc() : p = null; -} -'''); - } - - test_typePromotion_functionType_arg_ignoreIfNotMoreSpecific() async { - await assertNoErrorsInCode(r''' -typedef FuncB(B b); -typedef FuncA(A a); -class A {} -class B {} -main(FuncA f) { - if (f is FuncB) { - f(new A()); - } -} -'''); - } - - test_typePromotion_functionType_return_ignoreIfNotMoreSpecific() async { - await assertErrorsInCode(r''' -class A {} -typedef FuncAtoDyn(A a); -typedef FuncDynToDyn(x); -main(FuncAtoDyn f) { - if (f is FuncDynToDyn) { - A a = f(new A()); - } -} -''', [ - error(WarningCode.UNUSED_LOCAL_VARIABLE, 115, 1), - ]); - } - - test_typePromotion_functionType_return_voidToDynamic() async { - await assertErrorsInCode(r''' -typedef FuncDynToDyn(x); -typedef void FuncDynToVoid(x); -class A {} -main(FuncDynToVoid f) { - if (f is FuncDynToDyn) { - A a = f(null); - } -} -''', [ - error(WarningCode.UNUSED_LOCAL_VARIABLE, 124, 1), - ]); - } - - test_typePromotion_if_extends_moreSpecific() async { - await assertNoErrorsInCode(r''' -class V {} -class VP extends V {} -class A {} -class B extends A { - var b; -} - -main(A p) { - if (p is B) { - p.b; - } -} -'''); - } - - test_typePromotion_if_implements_moreSpecific() async { - await assertNoErrorsInCode(r''' -class V {} -class VP extends V {} -class A {} -class B implements A { - var b; -} - -main(A p) { - if (p is B) { - p.b; - } -} '''); } diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart index 5029fa828795..8b4d753eb1fa 100644 --- a/pkg/analyzer/test/generated/strong_mode_test.dart +++ b/pkg/analyzer/test/generated/strong_mode_test.dart @@ -20,19 +20,14 @@ import 'test_support.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(StrongModeLocalInferenceTest); - defineReflectiveTests(StrongModeLocalInferenceWithoutNullSafetyTest); defineReflectiveTests(StrongModeStaticTypeAnalyzer2Test); - defineReflectiveTests(StrongModeStaticTypeAnalyzer2WithoutNullSafetyTest); defineReflectiveTests(StrongModeTypePropagationTest); }); } /// Strong mode static analyzer local type inference tests. @reflectiveTest -class StrongModeLocalInferenceTest extends PubPackageResolutionTest - with StrongModeLocalInferenceTestCases {} - -mixin StrongModeLocalInferenceTestCases on PubPackageResolutionTest { +class StrongModeLocalInferenceTest extends PubPackageResolutionTest { TypeAssertions? _assertions; late final Asserter _isDynamic; @@ -4049,17 +4044,8 @@ $code } } -/// Strong mode static analyzer local type inference tests. -@reflectiveTest -class StrongModeLocalInferenceWithoutNullSafetyTest - extends PubPackageResolutionTest - with StrongModeLocalInferenceTestCases, WithoutNullSafetyMixin {} - @reflectiveTest -class StrongModeStaticTypeAnalyzer2Test extends StaticTypeAnalyzer2TestShared - with StrongModeStaticTypeAnalyzer2TestCases {} - -mixin StrongModeStaticTypeAnalyzer2TestCases on StaticTypeAnalyzer2TestShared { +class StrongModeStaticTypeAnalyzer2Test extends StaticTypeAnalyzer2TestShared { test_dynamicObjectGetter_hashCode() async { await assertErrorsInCode(r''' main() { @@ -6746,11 +6732,6 @@ main() { } } -@reflectiveTest -class StrongModeStaticTypeAnalyzer2WithoutNullSafetyTest - extends StaticTypeAnalyzer2TestShared - with StrongModeStaticTypeAnalyzer2TestCases, WithoutNullSafetyMixin {} - @reflectiveTest class StrongModeTypePropagationTest extends PubPackageResolutionTest { test_inconsistentMethodInheritance_inferFunctionTypeFromTypedef() async { diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart index 01bde789fe49..51c8da57ac4e 100644 --- a/pkg/analyzer/test/verify_diagnostics_test.dart +++ b/pkg/analyzer/test/verify_diagnostics_test.dart @@ -44,6 +44,10 @@ class DocumentationValidator { 'CompileTimeErrorCode.EXPORT_INTERNAL_LIBRARY', // Also reports CompileTimeErrorCode.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED 'CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS', + // The following codes produce two diagnostics because they illustrate a + // cycle. + 'CompileTimeErrorCode.EXTENSION_TYPE_IMPLEMENTS_ITSELF', + 'CompileTimeErrorCode.EXTENSION_TYPE_REPRESENTATION_DEPENDS_ON_ITSELF', // Has code in the example section that needs to be skipped (because it's // part of the explanatory text not part of the example), but there's // currently no way to do that. diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md index ab9875e3a50d..87fd16f527c2 100644 --- a/pkg/analyzer/tool/diagnostics/diagnostics.md +++ b/pkg/analyzer/tool/diagnostics/diagnostics.md @@ -1473,6 +1473,55 @@ Future f() async { } {% endprettify %} +### await_of_extension_type_not_future + +_The 'await' expression can't be used for an expression with an extension type +that is not a subtype of 'Future'._ + +#### Description + +The analyzer produces this diagnostic when the type of the expression in +an `await` expression is an extension type, and the extension type isn't a +subclass of `Future`. + +#### Example + +The following code produces this diagnostic because the extension type `E` +isn't a subclass of `Future`: + +{% prettify dart tag=pre+code %} +extension type E(int i) {} + +void f(E e) async { + [!await!] e; +} +{% endprettify %} + +#### Common fixes + +If the extension type is correctly defined, then remove the `await`: + +{% prettify dart tag=pre+code %} +extension type E(int i) {} + +void f(E e) { + e; +} +{% endprettify %} + +If the extension type is intended to be awaitable, then add `Future` (or a +subtype of `Future`) to the `implements` clause (adding an `implements` +clause if there isn't one already), and make the representation type +match: + +{% prettify dart tag=pre+code %} +extension type E(Future i) implements Future {} + +void f(E e) async { + await e; +} +{% endprettify %} + ### body_might_complete_normally _The body might complete normally, causing 'null' to be returned, but the return @@ -6139,6 +6188,409 @@ f() { If there are multiple cascaded accesses, you'll need to duplicate the extension override for each one. +### extension_type_constructor_with_super_formal_parameter + +_Extension type constructors can't declare super formal parameters._ + +#### Description + +The analyzer produces this diagnostic when a constructor in an extension +type has a super parameter. Super parameters aren't valid because +extension types don't have a superclass. + +#### Example + +The following code produces this diagnostic because the named constructor +`n` contains a super parameter: + +{% prettify dart tag=pre+code %} +extension type E(int i) { + E.n(this.i, [!super!].foo); +} +{% endprettify %} + +#### Common fixes + +If you need the parameter, replace the super parameter with a normal +parameter: + +{% prettify dart tag=pre+code %} +extension type E(int i) { + E.n(this.i, String foo); +} +{% endprettify %} + +If you don't need the parameter, remove the super parameter: + +{% prettify dart tag=pre+code %} +extension type E(int i) { + E.n(this.i); +} +{% endprettify %} + +### extension_type_constructor_with_super_invocation + +_Extension type constructors can't include super initializers._ + +#### Description + +The analyzer produces this diagnostic when a constructor in an extension +type includes an invocation of a super constructor in the initializer +list. Because extension types don't have a superclass, there's no +constructor to invoke. + +#### Example + +The following code produces this diagnostic because the constructor `E.n` +invokes a super constructor in its initializer list: + +{% prettify dart tag=pre+code %} +extension type E(int i) { + E.n() : i = 0, [!super!].n(); +} +{% endprettify %} + +#### Common fixes + +Remove the invocation of the super constructor: + +{% prettify dart tag=pre+code %} +extension type E(int i) { + E.n() : i = 0; +} +{% endprettify %} + +### extension_type_declares_instance_field + +_Extension types can't declare instance fields._ + +#### Description + +The analyzer produces this diagnostic when there's a field declaration in +the body of an extension type declaration. + +#### Example + +The following code produces this diagnostic because the extension type `E` +declares a field named `f`: + +{% prettify dart tag=pre+code %} +extension type E(int i) { + final int [!f!] = 0; +} +{% endprettify %} + +#### Common fixes + +If you don't need the field, then remove it or replace it with a getter +and/or setter: + +{% prettify dart tag=pre+code %} +extension type E(int i) { + int get f => 0; +} +{% endprettify %} + +If you need the field, then convert the extension type into a class: + +{% prettify dart tag=pre+code %} +class E { + final int i; + + final int f = 0; + + E(this.i); +} +{% endprettify %} + +### extension_type_declares_member_of_object + +_Extension types can't declare members with the same name as a member declared +by 'Object'._ + +#### Description + +The analyzer produces this diagnostic when the body of an extension type +declaration contains a member with the same name as one of the members +declared by `Object`. + +#### Example + +The following code produces this diagnostic because the class `Object` +already defines a member named `hashCode`: + +{% prettify dart tag=pre+code %} +extension type E(int i) { + int get [!hashCode!] => 0; +} +{% endprettify %} + +#### Common fixes + +If you need a member with the implemented semantics, then rename the +member: + +{% prettify dart tag=pre+code %} +extension type E(int i) { + int get myHashCode => 0; +} +{% endprettify %} + +If you don't need a member with the implemented semantics, then remove the +member: + +{% prettify dart tag=pre+code %} +extension type E(int i) {} +{% endprettify %} + +### extension_type_implements_disallowed_type + +_Extension types can't implement '{0}'._ + +#### Description + +The analyzer produces this diagnostic when an extension type implements a +type that it isn't allowed to implement. + +#### Example + +The following code produces this diagnostic because extension types can't +implement the type `dynamic`: + +{% prettify dart tag=pre+code %} +extension type A(int i) implements [!dynamic!] {} +{% endprettify %} + +#### Common fixes + +Remove the disallowed type from the implements clause: + +{% prettify dart tag=pre+code %} +extension type A(int i) {} +{% endprettify %} + +### extension_type_implements_itself + +_The extension type can't implement itself._ + +#### Description + +The analyzer produces this diagnostic when an extension type implements +itself, either directly or indirectly. + +#### Example + +The following code produces this diagnostic because the extension type `A` +directly implements itself: + +{% prettify dart tag=pre+code %} +extension type [!A!](int i) implements A {} +{% endprettify %} + +The following code produces this diagnostic because the extension type `A` +indirectly implements itself (through `B`): + +{% prettify dart tag=pre+code %} +extension type [!A!](int i) implements B {} + +extension type [!B!](int i) implements A {} +{% endprettify %} + +#### Common fixes + +Break the cycle by removing a type from the implements clause of at least +one of the types involved in the cycle: + +{% prettify dart tag=pre+code %} +extension type A(int i) implements B {} + +extension type B(int i) {} +{% endprettify %} + +### extension_type_implements_not_supertype + +_'{0}' is not a supertype of '{1}', the representation type._ + +#### Description + +The analyzer produces this diagnostic when an extension type implements a +type that isn't a supertype of the representation type. + +#### Example + +The following code produces this diagnostic because the extension type `A` +implements `String`, but `String` isn't a supertype of the representation +type `int`: + +{% prettify dart tag=pre+code %} +extension type A(int i) implements [!String!] {} +{% endprettify %} + +#### Common fixes + +If the representation type is correct, then remove or replace the type in +the implements clause: + +{% prettify dart tag=pre+code %} +extension type A(int i) {} +{% endprettify %} + +If the representation type isn't correct, then replace it with the correct +type: + +{% prettify dart tag=pre+code %} +extension type A(String s) implements String {} +{% endprettify %} + +### extension_type_implements_representation_not_supertype + +_'{0}', the representation type of '{1}', is not a supertype of '{2}', the +representation type of '{3}'._ + +#### Description + +The analyzer produces this diagnostic when an extension type implements +another extension type, and the representation type of the implemented +extension type isn't a subtype of the representation type of the implementing +extension type. + +#### Example + +The following code produces this diagnostic because the extension type `B` +implements `A`, but the representation type of `A` (`num`) isn't a +subtype of the representation type of `B` (`String`): + +{% prettify dart tag=pre+code %} +extension type A(num i) {} + +extension type B(String s) implements [!A!] {} +{% endprettify %} + +#### Common fixes + +Either change the representation types of the two extension types so that +the representation type of the implemented type is a supertype of the +representation type of the implementing type: + +{% prettify dart tag=pre+code %} +extension type A(num i) {} + +extension type B(int n) implements A {} +{% endprettify %} + +Or remove the implemented type from the implements clause: + +{% prettify dart tag=pre+code %} +extension type A(num i) {} + +extension type B(String s) {} +{% endprettify %} + +### extension_type_inherited_member_conflict + +_The extension type '{0}' has more than one distinct member named '{1}' from +implemented types._ + +#### Description + +The analyzer produces this diagnostic when an extension type implements +two or more other types, and at least two of those types declare a member +with the same name. + +#### Example + +The following code produces this diagnostic because the extension type `C` +implements both `A` and `B`, and both declare a member named `m`: + +{% prettify dart tag=pre+code %} +class A { + void m() {} +} + +extension type B(A a) { + void m() {} +} + +extension type [!C!](A a) implements A, B {} +{% endprettify %} + +#### Common fixes + +If the extension type doesn't need to implement all of the listed types, +then remove all but one of the types introducing the conflicting members: + +{% prettify dart tag=pre+code %} +class A { + void m() {} +} + +extension type B(A a) { + void m() {} +} + +extension type C(A a) implements A {} +{% endprettify %} + +If the extension type needs to implement all of the listed types but you +can rename the members in those types, then give the conflicting members +unique names: + +{% prettify dart tag=pre+code %} +class A { + void m() {} +} + +extension type B(A a) { + void n() {} +} + +extension type C(A a) implements A, B {} +{% endprettify %} + +### extension_type_representation_depends_on_itself + +_The extension type representation can't depend on itself._ + +#### Description + +The analyzer produces this diagnostic when an extension type has a +representation type that depends on the extension type itself, either +directly or indirectly. + +#### Example + +The following code produces this diagnostic because the representation +type of the extension type `A` depends on `A` directly: + +{% prettify dart tag=pre+code %} +extension type [!A!](A a) {} +{% endprettify %} + +The following two code examples produce this diagnostic because the +representation type of the extension type `A` depends on `A` +indirectly through the extension type `B`: + +{% prettify dart tag=pre+code %} +extension type [!A!](B b) {} + +extension type [!B!](A a) {} +{% endprettify %} + +{% prettify dart tag=pre+code %} +extension type [!A!](List b) {} + +extension type [!B!](List a) {} +{% endprettify %} + +#### Common fixes + +Remove the dependency by choosing a different representation type for at +least one of the types in the cycle: + +{% prettify dart tag=pre+code %} +extension type A(String s) {} +{% endprettify %} + ### external_with_initializer _External fields can't have initializers._ @@ -10186,7 +10638,7 @@ platforms: #### Common fixes If you can rely on automatic platform detection, then omit the -top-level `platforms` field. +top-level `platforms` field. {% prettify yaml tag=pre+code %} name: example @@ -14219,6 +14671,35 @@ enum E { } {% endprettify %} +### non_covariant_type_parameter_position_in_representation_type + +_An extension type parameter can't be used in a non-covariant position of its +representation type._ + +#### Description + +The analyzer produces this diagnostic when a type parameter of an +extension type is used in a non-covariant position in the representation +type of that extension type. + +#### Example + +The following code produces this diagnostic because the type parameter `T` +is used as a parameter type in the function type `void Function(T)`, and +parameters are not covariant: + +{% prettify dart tag=pre+code %} +extension type A<[!T!]>(void Function(T) f) {} +{% endprettify %} + +#### Common fixes + +Remove the use of the type parameter: + +{% prettify dart tag=pre+code %} +extension type A(void Function(String) f) {} +{% endprettify %} + ### non_exhaustive_switch_expression _The type '{0}' is not exhaustively matched by the switch cases since it doesn't @@ -16891,6 +17372,66 @@ class B implements A {} Change the type hierarchy so that there's no circularity. +### redeclare_on_non_redeclaring_member + +_The {0} doesn't redeclare a {0} declared in a superinterface._ + +#### Description + +The analyzer produces this diagnostic when a member of an extension type +is annotated with `@redeclare`, but none of the implemented interfaces +has a member with the same name. + +#### Example + +The following code produces this diagnostic because the member `n` +declared by the extension type `E` is annotated with `@redeclare`, but `C` +doesn't have a member named `n`: + +{% prettify dart tag=pre+code %} +import 'package:meta/meta.dart'; + +class C { + void m() {} +} + +extension type E(C c) implements C { + @redeclare + void [!n!]() {} +} +{% endprettify %} + +#### Common fixes + +If the annotated member has the right name, then remove the annotation: + +{% prettify dart tag=pre+code %} +class C { + void m() {} +} + +extension type E(C c) implements C { + void n() {} +} +{% endprettify %} + +If the annotated member is suppose to replace a member from the +implemented interfaces, then change the name of the annotated member to +match the member being replaced: + +{% prettify dart tag=pre+code %} +import 'package:meta/meta.dart'; + +class C { + void m() {} +} + +extension type E(C c) implements C { + @redeclare + void m() {} +} +{% endprettify %} + ### redirect_generative_to_missing_constructor _The constructor '{0}' couldn't be found in '{1}'._ diff --git a/tools/VERSION b/tools/VERSION index 583f7610a9d7..e92b6feddf92 100644 --- a/tools/VERSION +++ b/tools/VERSION @@ -27,5 +27,5 @@ CHANNEL dev MAJOR 3 MINOR 3 PATCH 0 -PRERELEASE 171 +PRERELEASE 172 PRERELEASE_PATCH 0