blob: 821e9f8850df4463a30e8019d375cc355004868b [file] [log] [blame]
// Copyright (c) 2019, 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 '../dart/resolution/context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(InvalidAssignment_ImplicitCallReferenceTest);
defineReflectiveTests(InvalidAssignmentTest);
defineReflectiveTests(InvalidAssignmentWithStrictCastsTest);
});
}
@reflectiveTest
class InvalidAssignment_ImplicitCallReferenceTest
extends PubPackageResolutionTest {
test_invalid_genericBoundedCall_nonGenericContext() async {
await assertErrorsInCode('''
class C {
T call<T extends num>(T t) => t;
}
String Function(String) f = C();
''', [
error(CompileTimeErrorCode.COULD_NOT_INFER, 76, 3),
]);
}
test_invalid_genericCall_genericEnclosingClass_nonGenericContext() async {
await assertErrorsInCode('''
class C<T> {
C(T a);
void call<U>(T t, U u) {}
}
void Function(bool, String) f = C(7);
''', [
// The type arguments of the instance of `C` should be accurate and be
// taken into account when evaluating the assignment of the implicit call
// reference.
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 86, 4),
]);
}
test_invalid_genericCall_nonGenericContext() async {
await assertErrorsInCode('''
class C {
T call<T>(T t) => t;
}
void Function() f = C();
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 56, 3),
]);
}
test_invalid_genericCall_nonGenericContext_withoutConstructorTearoffs() async {
await assertErrorsInCode('''
// @dart=2.12
class C {
T call<T>(T t) => t;
}
int Function(int) f = C();
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 72, 3),
]);
}
test_invalid_interfaceType_enum_interfaces() async {
await assertErrorsInCode('''
class I {}
class J {}
enum E implements J {
v
}
I x = E.v;
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 56, 3),
]);
}
test_invalid_message_preferTypeAlias_functionType() async {
await assertErrorsInCode('''
typedef A<T> = T Function();
void f(A<int> a) {
A<String> b = a;
}
''', [
error(WarningCode.UNUSED_LOCAL_VARIABLE, 61, 1),
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 65, 1,
messageContains: ['A<int>', 'A<String>']),
]);
}
test_invalid_message_preferTypeAlias_interfaceType() async {
await assertErrorsInCode('''
typedef A<T> = List<T>;
void f(A<int> a) {
A<String> b = a;
}
''', [
error(WarningCode.UNUSED_LOCAL_VARIABLE, 56, 1),
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 60, 1,
messageContains: ['A<int>', 'A<String>']),
]);
}
test_invalid_message_preferTypeAlias_recordType() async {
await assertErrorsInCode('''
typedef A<T> = (T, T);
void f(A<int> a) {
A<String> b = a;
}
''', [
error(WarningCode.UNUSED_LOCAL_VARIABLE, 55, 1),
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 59, 1,
messageContains: ['A<int>', 'A<String>']),
]);
}
test_invalid_noCall_functionContext() async {
await assertErrorsInCode('''
class C {}
Function f = C();
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 25, 3),
]);
}
test_invalid_noCall_functionTypeContext() async {
await assertErrorsInCode('''
class C {}
String Function(String) f = C();
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 40, 3),
]);
}
test_invalid_nonGenericCall() async {
await assertErrorsInCode('''
class C {
void call(int a) {}
}
void Function(String) f = C();
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 61, 3),
]);
}
test_invalid_nonGenericCall_typeVariableExtendsFunctionContext() async {
await assertErrorsInCode('''
class C {
void call(int a) {}
}
class D<U extends Function> {
U f = C();
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 72, 3),
]);
}
test_invalid_nonGenericCall_typeVariableExtendsFunctionTypeContext() async {
await assertErrorsInCode('''
class C {
void call(int a) {}
}
class D<U extends void Function(int)> {
U f = C();
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 82, 3),
]);
}
test_valid_genericBoundedCall_nonGenericContext() async {
await assertNoErrorsInCode('''
class C {
T call<T extends num>(T t) => t;
}
int Function(int) f = C();
''');
}
test_valid_genericCall_functionContext() async {
await assertNoErrorsInCode('''
class C {
T call<T>(T t) => t;
}
Function f = C();
''');
}
test_valid_genericCall_futureOrFunctionContext() async {
await assertNoErrorsInCode('''
import 'dart:async';
class C {
T call<T>(T t) => t;
}
FutureOr<Function> f = C();
''');
}
test_valid_genericCall_futureOrFunctionTypeContext_generic() async {
await assertNoErrorsInCode('''
import 'dart:async';
class C {
T call<T>(T t) => t;
}
FutureOr<T Function<T>(T)> f = C();
''');
}
test_valid_genericCall_futureOrFunctionTypeContext_nonGeneric() async {
await assertNoErrorsInCode('''
import 'dart:async';
class C {
T call<T>(T t) => t;
}
FutureOr<int Function(int)> f = C();
''');
}
test_valid_genericCall_genericContext() async {
await assertNoErrorsInCode('''
class C {
T call<T>(T t) => t;
}
T Function<T>(T) f = C();
''');
}
test_valid_genericCall_genericEnclosingClass_nonGenericContext() async {
await assertNoErrorsInCode('''
class C<T> {
C(T a);
void call<U>(T t, U u) {}
}
void Function(int, String) f = C(7);
''');
}
test_valid_genericCall_genericTypedefContext() async {
await assertNoErrorsInCode('''
class C {
T call<T>(T t) => t;
}
typedef Fn<T> = T Function(T);
class D<U> {
Fn<U> f = C();
}
''');
}
test_valid_genericCall_nonGenericContext() async {
await assertNoErrorsInCode('''
class C {
T call<T>(T t) => t;
}
int Function(int) f = C();
''');
}
test_valid_genericCall_nullableFunctionContext() async {
await assertNoErrorsInCode('''
class C {
T call<T>(T t) => t;
}
Function? f = C();
''');
}
test_valid_genericCall_nullableNonGenericContext() async {
await assertNoErrorsInCode('''
class C {
T call<T>(T t) => t;
}
int Function(int)? f = C();
''');
}
test_valid_genericCall_typedefOfGenericContext() async {
await assertNoErrorsInCode('''
class C {
T call<T>(T t) => t;
}
typedef Fn = T Function<T>(T);
Fn f = C();
''');
}
test_valid_interfaceType_enum_interfaces() async {
await assertNoErrorsInCode('''
class I {}
enum E implements I {
v
}
I x = E.v;
''');
}
test_valid_nonGenericCall() async {
await assertNoErrorsInCode('''
class C {
void call(int a) {}
}
void Function(int) f = C();
''');
}
test_valid_nonGenericCall_declaredOnMixin() async {
await assertNoErrorsInCode('''
mixin M {
void call(int a) {}
}
class C with M {}
Function f = C();
''');
}
test_valid_nonGenericCall_inCascade() async {
await assertNoErrorsInCode('''
class C {
void call(int a) {}
}
class D {
late void Function(int) f;
}
void foo() {
D()..f = C();
}
''');
}
test_valid_nonGenericCall_subTypeViaParameter() async {
await assertNoErrorsInCode('''
class C {
void call(num a) {}
}
void Function(int) f = C();
''');
}
test_valid_nonGenericCall_subTypeViaReturnType() async {
await assertNoErrorsInCode('''
class C {
int call() => 7;
}
num Function() f = C();
''');
}
}
@reflectiveTest
class InvalidAssignmentTest extends PubPackageResolutionTest {
test_assignment_to_dynamic() async {
await assertErrorsInCode(r'''
f() {
var g;
g = () => 0;
}
''', [
error(WarningCode.UNUSED_LOCAL_VARIABLE, 12, 1),
]);
}
test_cascadeExpression() async {
await assertErrorsInCode(r'''
void f(int a) {
// ignore:unused_local_variable
String v = (a)..isEven;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 64, 1),
]);
}
test_compoundAssignment() async {
await assertErrorsInCode(r'''
class byte {
int _value;
byte(this._value);
byte operator +(int val) { return this; }
}
void main() {
byte b = new byte(52);
b += 3;
}
''', [
error(WarningCode.UNUSED_FIELD, 19, 6),
error(WarningCode.UNUSED_LOCAL_VARIABLE, 116, 1),
]);
}
test_constructorTearoff_inferredTypeArgs() async {
await assertNoErrorsInCode('''
class C<T> {
C(T a);
}
var g = C<int>.new;
''');
}
test_constructorTearoff_withExplicitTypeArgs() async {
await assertNoErrorsInCode('''
class C<T> {
C(T a);
}
C Function(int) g = C<int>.new;
''');
}
test_constructorTearoff_withExplicitTypeArgs_invalid() async {
await assertErrorsInCode('''
class C<T> {
C(T a);
}
C Function(String) g = C<int>.new;
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 49, 10),
]);
}
test_defaultValue_named() async {
await assertErrorsInCode(r'''
f({String x = 0}) {
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 14, 1),
]);
}
test_defaultValue_named_sameType() async {
await assertNoErrorsInCode(r'''
f({String x = '0'}) {
}''');
}
test_defaultValue_optional() async {
await assertErrorsInCode(r'''
f([String x = 0]) {
}''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 14, 1),
]);
}
test_defaultValue_optional_sameType() async {
await assertNoErrorsInCode(r'''
f([String x = '0']) {
}
''');
}
test_functionExpressionInvocation() async {
await assertErrorsInCode('''
class C {
String x = (() => 5)();
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 23, 11),
]);
}
test_functionInstantiation_topLevelVariable_genericContext_assignable() async {
await assertNoErrorsInCode('''
T f<T>(T a) => a;
U Function<U>(U) foo = f;
''');
}
test_functionInstantiation_topLevelVariable_genericContext_nonAssignable() async {
await assertErrorsInCode('''
T f<T>(T a) => a;
U Function<U>(U, int) foo = f;
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 46, 1),
]);
}
test_functionInstantiation_topLevelVariable_nonGenericContext_assignable() async {
await assertNoErrorsInCode('''
T f<T>(T a) => a;
int Function(int) foo = f;
''');
}
test_functionInstantiation_topLevelVariable_nonGenericContext_nonAssignable() async {
await assertErrorsInCode('''
T f<T>(T a) => a;
int Function(int, int) foo = f;
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 47, 1),
]);
}
test_functionTearoff_genericInstantiation() async {
await assertNoErrorsInCode('''
int Function() foo(int Function<T extends int>() f) {
return f;
}
''');
assertResolvedNodeText(findNode.functionReference('f;'), r'''
FunctionReference
function: SimpleIdentifier
token: f
staticElement: <testLibraryFragment>::@function::foo::@parameter::f
staticType: int Function<T extends int>()
staticType: int Function()
typeArgumentTypes
int
''');
}
test_functionTearoff_inferredTypeArgs() async {
await assertNoErrorsInCode('''
void f<T>(T a) {}
var g = f<int>;
''');
}
test_functionTearoff_withExplicitTypeArgs() async {
await assertNoErrorsInCode('''
void f<T>(T a) {}
void Function(int) g = f<int>;
''');
}
test_functionTearoff_withExplicitTypeArgs_invalid() async {
await assertErrorsInCode('''
void f<T>(T a) {}
void Function(String) g = f<int>;
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 45, 6),
]);
}
test_ifNullAssignment() async {
await assertErrorsInCode('''
void f(int i) {
double? d;
d ??= i;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 37, 1),
]);
}
test_ifNullAssignment_sameType() async {
await assertNoErrorsInCode('''
void f(int i) {
int? j;
j ??= i;
}
''');
}
test_ifNullAssignment_superType() async {
await assertNoErrorsInCode('''
void f(int i) {
num? n;
n ??= i;
}
''');
}
test_implicitlyImplementFunctionViaCall_1() async {
// issue 18341
//
// This test and
// 'test_invalidAssignment_implicitlyImplementFunctionViaCall_2()' are
// closely related: here we see that 'I' checks as a subtype of 'IntToInt'.
await assertNoErrorsInCode(r'''
class I {
int call(int x) => 0;
}
class C implements I {
noSuchMethod(_) => null;
}
typedef int IntToInt(int x);
IntToInt f = new I();
''');
}
test_implicitlyImplementFunctionViaCall_2() async {
// issue 18341
//
// Here 'C' checks as a subtype of 'I', but 'C' does not check as a subtype
// of 'IntToInt'. Together with
// 'test_invalidAssignment_implicitlyImplementFunctionViaCall_1()' we see
// that subtyping is not transitive here.
await assertNoErrorsInCode(r'''
class I {
int call(int x) => 0;
}
class C implements I {
noSuchMethod(_) => null;
}
typedef int IntToInt(int x);
IntToInt f = new C();
''');
}
test_implicitlyImplementFunctionViaCall_3() async {
// issue 18341
//
// Like 'test_invalidAssignment_implicitlyImplementFunctionViaCall_2()', but
// uses type 'Function' instead of more precise type 'IntToInt' for 'f'.
await assertNoErrorsInCode(r'''
class I {
int call(int x) => 0;
}
class C implements I {
noSuchMethod(_) => null;
}
typedef int IntToInt(int x);
Function f = new C();
''');
}
test_implicitlyImplementFunctionViaCall_4() async {
// issue 18341
//
// Like 'test_invalidAssignment_implicitlyImplementFunctionViaCall_2()', but
// uses type 'VoidToInt' instead of more precise type 'IntToInt' for 'f'.
//
// Here 'C <: IntToInt <: VoidToInt', but the spec gives no transitivity
// rule for '<:'. However, many of the :/tools/test.py tests assume this
// transitivity for 'JsBuilder' objects, assigning them to
// '(String) -> dynamic'. The declared type of 'JsBuilder.call' is
// '(String, [dynamic]) -> Expression'.
await assertNoErrorsInCode(r'''
class I {
int call([int x = 7]) => 0;
}
class C implements I {
noSuchMethod(_) => null;
}
typedef int VoidToInt();
VoidToInt f = new C();
''');
}
test_instanceVariable() async {
await assertErrorsInCode(r'''
class A {
int x = 7;
}
f(var y) {
A a = A();
if (y is String) {
a.x = y;
}
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 80, 1),
]);
}
test_invalidAssignment() async {
await assertErrorsInCode(r'''
f() {
var x;
var y;
x = y;
}
''', [
error(WarningCode.UNUSED_LOCAL_VARIABLE, 12, 1),
]);
}
test_localLevelVariable_never_null() async {
await assertErrorsInCode('''
void f(Never x) {
x = null;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 24, 4),
]);
}
test_localVariable() async {
await assertErrorsInCode(r'''
f() {
int x;
x = '0';
}
''', [
error(WarningCode.UNUSED_LOCAL_VARIABLE, 12, 1),
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 21, 3),
]);
}
test_localVariable_promotion() async {
await assertErrorsInCode(r'''
f(var y) {
if (y is String) {
int x = y;
print(x);
}
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 44, 1),
]);
}
test_parenthesizedExpression() async {
await assertErrorsInCode(r'''
void f(int a) {
// ignore:unused_local_variable
String v = (a);
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 64, 1),
]);
}
test_postfixExpression_localVariable() async {
await assertErrorsInCode(r'''
class A {
B operator+(_) => new B();
}
class B {}
f(A a) {
a++;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 65, 3),
]);
}
test_postfixExpression_localVariable_sameType() async {
await assertNoErrorsInCode(r'''
class A {
A operator+(_) => this;
}
f(A a) {
a++;
}
''');
}
test_postfixExpression_property() async {
await assertErrorsInCode(r'''
class A {
B operator+(_) => new B();
}
class B {}
class C {
A a = A();
}
f(C c) {
c.a++;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 91, 5),
]);
}
test_postfixExpression_property_sameType() async {
await assertNoErrorsInCode(r'''
class A {
A operator+(_) => this;
}
class C {
A a = A();
}
f(C c) {
c.a++;
}
''');
}
test_prefixExpression_localVariable() async {
await assertErrorsInCode(r'''
class A {
B operator+(_) => new B();
}
class B {}
f(A a) {
++a;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 65, 3),
]);
}
test_prefixExpression_localVariable_sameType() async {
await assertNoErrorsInCode(r'''
class A {
A operator+(_) => this;
}
f(A a) {
++a;
}
''');
}
test_prefixExpression_property() async {
await assertErrorsInCode(r'''
class A {
B operator+(_) => new B();
}
class B {}
class C {
A a = A();
}
f(C c) {
++c.a;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 91, 5),
]);
}
test_prefixExpression_property_sameType() async {
await assertNoErrorsInCode(r'''
class A {
A operator+(_) => this;
}
class C {
A a = A();
}
f(C c) {
++c.a;
}
''');
}
test_promotedTypeParameter_regress35306() async {
await assertErrorsInCode(r'''
class A {}
class B extends A {}
class C extends D {}
class D {}
void f<X extends A, Y extends B>(X x) {
if (x is Y) {
A a = x;
B b = x;
X x2 = x;
Y y = x;
}
}
''', [
error(WarningCode.UNUSED_LOCAL_VARIABLE, 127, 1),
error(WarningCode.UNUSED_LOCAL_VARIABLE, 140, 1),
error(WarningCode.UNUSED_LOCAL_VARIABLE, 153, 2),
error(WarningCode.UNUSED_LOCAL_VARIABLE, 167, 1),
]);
}
void test_recordType_localVariable_initializer() async {
await assertErrorsInCode('''
void f() {
(int, int) r = (a: 1, b: 2);
print(r);
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 28, 12),
]);
}
void test_recordType_parameter() async {
await assertErrorsInCode('''
void f((int a, int b) r) {
r = (a: 1, b: 2);
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 33, 12),
]);
}
void test_recordType_setter() async {
await assertErrorsInCode('''
void f(C c) {
c.r = (a: 1, b: 2);
}
class C {
(int, int)? r;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 22, 12),
]);
}
test_regressionInIssue18468Fix() async {
// https://code.google.com/p/dart/issues/detail?id=18628
await assertErrorsInCode(r'''
class C<T> {
T t = int;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 21, 3),
]);
}
test_staticVariable() async {
await assertErrorsInCode(r'''
class A {
static int x = 1;
}
f() {
A.x = '0';
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 46, 3),
]);
}
test_staticVariable_promoted() async {
await assertErrorsInCode(r'''
class A {
static int x = 7;
}
f(var y) {
if (y is String) {
A.x = y;
}
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 74, 1),
]);
}
test_topLevelVariable_never_null() async {
await assertErrorsInCode('''
Never x = throw 0;
void f() {
x = null;
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 37, 4),
]);
}
test_topLevelVariableDeclaration() async {
await assertErrorsInCode('''
int x = 'string';
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 8, 8),
]);
}
test_typeParameter() async {
// https://github.com/dart-lang/sdk/issues/14221
await assertErrorsInCode(r'''
class B<T> {
T? value;
void test(num n) {
value = n;
}
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 58, 1),
]);
}
test_typeParameterRecursion_regress35306() async {
await assertErrorsInCode(r'''
class A {}
class B extends A {}
class C extends D {}
class D {}
void f<X extends A, Y extends B>(X x) {
if (x is Y) {
D d = x;
print(d);
}
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 131, 1),
]);
}
test_variableDeclaration() async {
await assertErrorsInCode(r'''
class A {
int x = 'string';
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 20, 8),
]);
}
test_variableDeclaration_overriddenOperator() async {
// https://github.com/dart-lang/sdk/issues/17971
await assertErrorsInCode(r'''
class Point {
final num x, y;
Point(this.x, this.y);
Point operator +(Point other) {
return new Point(x+other.x, y+other.y);
}
}
main() {
var p1 = new Point(0, 0);
var p2 = new Point(10, 10);
int n = p1 + p2;
print(n);
}
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 218, 7),
]);
}
}
@reflectiveTest
class InvalidAssignmentWithStrictCastsTest extends PubPackageResolutionTest
with WithStrictCastsMixin {
test_functionType() async {
await assertErrorsWithStrictCasts('''
dynamic a;
void Function(int i) f = a;
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 36, 1),
]);
}
test_interfaceType() async {
await assertErrorsWithStrictCasts('''
dynamic a;
int b = a;
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 19, 1),
]);
}
test_recordType() async {
await assertErrorsWithStrictCasts('''
dynamic a;
(int i, ) r = a;
''', [
error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 25, 1),
]);
}
}