blob: 7c2d1598b259d4ada747efcbf1e81aa240ecefce [file]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/results.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../src/dart/resolution/context_collection_resolution.dart';
import '../src/dart/resolution/node_text_expectations.dart';
import '../utils.dart';
import 'resolver_test_case.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(StrongModeLocalInferenceTest);
defineReflectiveTests(StrongModeStaticTypeAnalyzer2Test);
defineReflectiveTests(StrongModeTypePropagationTest);
defineReflectiveTests(UpdateNodeTextExpectations);
});
}
/// Strong mode static analyzer local type inference tests.
@reflectiveTest
class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
TypeAssertions? _assertions;
late final Asserter<DartType> _isDynamic;
late final Asserter<DartType> _isInvalidType;
late final Asserter<InterfaceType> _isFutureOfDynamic;
late final Asserter<InterfaceType> _isFutureOfInt;
late final Asserter<InterfaceType> _isFutureOfNull;
late final Asserter<InterfaceType> _isFutureOrOfInt;
late final Asserter<DartType> _isInt;
late final Asserter<DartType> _isNever;
late final Asserter<DartType> _isNull;
late final Asserter<DartType> _isNum;
late final Asserter<DartType> _isObject;
late final Asserter<DartType> _isString;
late final AsserterBuilder2<Asserter<DartType>, Asserter<DartType>, DartType>
_isFunction2Of;
late final AsserterBuilder<List<Asserter<DartType>>, InterfaceType>
_isFutureOf;
late final AsserterBuilder<List<Asserter<DartType>>, InterfaceType>
_isFutureOrOf;
late final AsserterBuilderBuilder<
Asserter<DartType>,
List<Asserter<DartType>>,
DartType
>
_isInstantiationOf;
late final AsserterBuilder<Asserter<DartType>, InterfaceType> _isListOf;
late final AsserterBuilder2<
Asserter<DartType>,
Asserter<DartType>,
InterfaceType
>
_isMapOf;
late final AsserterBuilder<DartType, DartType> _isType;
late final AsserterBuilder<Element, DartType> _hasElement;
@override
Future<ResolvedUnitResultImpl> resolveFile(File file) async {
var result = await super.resolveFile(file);
_initAssertions(result.typeProvider);
return result;
}
test_async_method_propagation() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
Future f0() => new Future.value(3);
Future f1() async => new Future.value(3);
Future f2() async => await new Future.value(3);
Future<int> f3() => new Future.value(3);
Future<int> f4() async => new Future.value(3);
Future<int> f5() async => await new Future.value(3);
Future g0() { return new Future.value(3); }
Future g1() async { return new Future.value(3); }
Future g2() async { return await new Future.value(3); }
Future<int> g3() { return new Future.value(3); }
Future<int> g4() async { return new Future.value(3); }
Future<int> g5() async { return await new Future.value(3); }
}
''');
void check(String name, Asserter<InterfaceType> typeTest) {
MethodDeclaration test = AstFinder.getMethodInClass(
result.unit,
"A",
name,
);
FunctionBody body = test.body;
Expression returnExp;
if (body is ExpressionFunctionBody) {
returnExp = body.expression2;
} else {
var stmt =
(body as BlockFunctionBody).block.statements[0] as ReturnStatement;
returnExp = stmt.expression2!;
}
DartType type = returnExp.typeOrThrow;
if (returnExp is AwaitExpression) {
type = returnExp.expression2.typeOrThrow;
}
typeTest(type as InterfaceType);
}
check("f0", _isFutureOfDynamic);
check("f1", _isFutureOfDynamic);
check("f2", _isFutureOfDynamic);
check("f3", _isFutureOfInt);
check("f4", _isFutureOfInt);
check("f5", _isFutureOfInt);
check("g0", _isFutureOfDynamic);
check("g1", _isFutureOfDynamic);
check("g2", _isFutureOfDynamic);
check("g3", _isFutureOfInt);
check("g4", _isFutureOfInt);
check("g5", _isFutureOfInt);
}
test_async_propagation() async {
var result = await resolveTestCodeWithDiagnostics(r'''
Future f0() => new Future.value(3);
Future f1() async => new Future.value(3);
Future f2() async => await new Future.value(3);
Future<int> f3() => new Future.value(3);
Future<int> f4() async => new Future.value(3);
Future<int> f5() async => await new Future.value(3);
Future g0() { return new Future.value(3); }
Future g1() async { return new Future.value(3); }
Future g2() async { return await new Future.value(3); }
Future<int> g3() { return new Future.value(3); }
Future<int> g4() async { return new Future.value(3); }
Future<int> g5() async { return await new Future.value(3); }
''');
void check(String name, Asserter<InterfaceType> typeTest) {
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
name,
);
var body = test.functionExpression.body;
Expression returnExp;
if (body is ExpressionFunctionBody) {
returnExp = body.expression2;
} else {
var stmt =
(body as BlockFunctionBody).block.statements[0] as ReturnStatement;
returnExp = stmt.expression2!;
}
DartType type = returnExp.typeOrThrow;
if (returnExp is AwaitExpression) {
type = returnExp.expression2.typeOrThrow;
}
typeTest(type as InterfaceType);
}
check("f0", _isFutureOfDynamic);
check("f1", _isFutureOfDynamic);
check("f2", _isFutureOfDynamic);
check("f3", _isFutureOfInt);
check("f4", _isFutureOfInt);
check("f5", _isFutureOfInt);
check("g0", _isFutureOfDynamic);
check("g1", _isFutureOfDynamic);
check("g2", _isFutureOfDynamic);
check("g3", _isFutureOfInt);
check("g4", _isFutureOfInt);
check("g5", _isFutureOfInt);
}
test_cascadeExpression() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A<T> {
List<T> map(T a, List<T> mapper(T x)) => mapper(a);
}
void main () {
A<int> a = new A()..map(0, (x) => [x]);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'a' isn't used.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
CascadeExpression fetch(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as CascadeExpression;
return exp;
}
var elementA = AstFinder.getClass(
result.unit,
"A",
).declaredFragment!.element;
CascadeExpression cascade = fetch(0);
_isInstantiationOf(_hasElement(elementA))([_isInt])(cascade.typeOrThrow);
var invoke = cascade.cascadeSections2[0] as MethodInvocation;
var function = invoke.argumentList.arguments2[1] as FunctionExpression;
ExecutableElement f0 = function.declaredFragment!.element;
_isListOf(_isInt)(f0.type.returnType as InterfaceType);
expect(f0.type.normalParameterTypes[0], result.typeProvider.intType);
}
test_constrainedByBounds1() async {
// Test that upwards inference with two type variables correctly
// propagates from the constrained variable to the unconstrained
// variable if they are ordered left to right.
var result = await resolveTestCodeWithDiagnostics(r'''
T f<S, T extends S>(S x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'T'.
void test() { var x = f(3); }
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test",
);
var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer2!;
_isInt(call.typeOrThrow);
}
test_constrainedByBounds2() async {
// Test that upwards inference with two type variables does
// propagate from the constrained variable to the unconstrained
// variable if they are ordered right to left.
var result = await resolveTestCodeWithDiagnostics(r'''
T f<T extends S, S>(S x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'T'.
void test() { var x = f(3); }
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test",
);
var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer2!;
_isInt(call.typeOrThrow);
}
test_constrainedByBounds3() async {
var result = await resolveTestCodeWithDiagnostics(r'''
T f<T extends S, S extends int>(S x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'T'.
void test() { var x = f(3); }
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test",
);
var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer2!;
_isInt(call.typeOrThrow);
}
test_constrainedByBounds4() async {
// Test that upwards inference with two type variables correctly
// propagates from the constrained variable to the unconstrained
// variable if they are ordered left to right, when the variable
// appears co and contra variantly
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
T f<S, T extends Func1<S, S>>(S x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'T'.
void test() { var x = f(3)(4); }
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test",
);
var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer2!;
_isInt(call.typeOrThrow);
}
test_constrainedByBounds5() async {
// Test that upwards inference with two type variables does not
// propagate from the constrained variable to the unconstrained
// variable if they are ordered right to left, when the variable
// appears co- and contra-variantly, and that an error is issued
// for the non-matching bound.
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
T f<T extends Func1<S, S>, S>(S x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'T'.
void test() { var x = f(3)(null); }
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T'.\n\nTried to infer 'Object? Function(Never)' for 'T' which doesn't work:\n Type parameter 'T' is declared to extend 'S Function(S)' producing 'int Function(int)'.\n\nConsider passing explicit type argument(s) to the generic.
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'Never'.
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test",
);
var stmt = statements[0] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression call = decl.initializer2!;
_isType(call.typeOrThrow);
}
test_constructorInitializer_propagation() async {
String code = r'''
class A {
List<String> x;
A() : this.x = [];
}
''';
var result = await resolveTestCodeWithDiagnostics(code);
ConstructorDeclaration constructor = AstFinder.getConstructorInClass(
result.unit,
"A",
null,
);
var assignment = constructor.initializers[0] as ConstructorFieldInitializer;
Expression exp = assignment.expression2;
_isListOf(_isString)(exp.staticType as InterfaceType);
}
test_factoryConstructor_propagation() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A<T> {
factory A() { return new B(); }
}
class B<S> extends A<S> {}
// ^^^^
// [diag.noGenerativeConstructorsInSuperclass] The class 'B' can't extend 'A' because 'A' only has factory constructors (no generative constructors), and 'B' has at least one generative constructor.
''');
ConstructorDeclaration constructor = AstFinder.getConstructorInClass(
result.unit,
"A",
null,
);
var body = constructor.body as BlockFunctionBody;
var stmt = body.block.statements[0] as ReturnStatement;
var exp = stmt.expression2 as InstanceCreationExpression;
ClassElement elementB = AstFinder.getClass(
result.unit,
"B",
).declaredFragment!.element;
ClassElement elementA = AstFinder.getClass(
result.unit,
"A",
).declaredFragment!.element;
var type = exp.constructorName.type.typeOrThrow as InterfaceType;
expect(type.element, elementB);
_isInstantiationOf(_hasElement(elementB))([
_isType(
elementA.typeParameters[0].instantiate(
nullabilitySuffix: NullabilitySuffix.none,
),
),
])(exp.typeOrThrow);
}
test_fieldDeclaration_propagation() async {
String code = r'''
class A {
List<String> f0 = ["hello"];
}
''';
var result = await resolveTestCodeWithDiagnostics(code);
VariableDeclaration field = AstFinder.getFieldInClass(
result.unit,
"A",
"f0",
);
_isListOf(_isString)(field.initializer2!.staticType as InterfaceType);
}
test_functionDeclaration_body_propagation() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef T Function2<S, T>(S x);
List<int> test1() => [];
Function2<int, int> test2 (int x) {
Function2<String, int> inner() {
// ^^^^^
// [diag.unusedElement] The declaration 'inner' isn't referenced.
return (x) => x.length;
}
return (x) => x;
}
''');
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
FunctionDeclaration test1 = AstFinder.getTopLevelFunction(
result.unit,
"test1",
);
var body = test1.functionExpression.body as ExpressionFunctionBody;
assertListOfInt(body.expression2.staticType as InterfaceType);
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test2",
);
FunctionDeclaration inner =
(statements[0] as FunctionDeclarationStatement).functionDeclaration;
var body0 = inner.functionExpression.body as BlockFunctionBody;
var return0 = body0.block.statements[0] as ReturnStatement;
Expression anon0 = return0.expression2!;
var type0 = anon0.staticType as FunctionType;
expect(type0.returnType, result.typeProvider.intType);
expect(type0.normalParameterTypes[0], result.typeProvider.stringType);
var anon1 =
(statements[1] as ReturnStatement).expression2 as FunctionExpression;
FunctionType type1 = anon1.declaredFragment!.element.type;
expect(type1.returnType, result.typeProvider.intType);
expect(type1.normalParameterTypes[0], result.typeProvider.intType);
}
test_functionLiteral_assignment_typedArguments() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef T Function2<S, T>(S x);
void main () {
Function2<int, String> l0 = (int x) => null;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
// ^^^^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'Null' isn't returnable from a 'String' function, as required by the closure's context.
Function2<int, String> l1 = (int x) => "hello";
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
Function2<int, String> l2 = (String x) => "hello";
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'String Function(String)' can't be assigned to a variable of type 'Function2<int, String>'.
Function2<int, String> l3 = (int x) => 3;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
Function2<int, String> l4 = (int x) {return 3;};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l4' isn't used.
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as FunctionExpression;
return exp.declaredFragment!.element.type;
}
_isFunction2Of(_isInt, _isString)(literal(0));
_isFunction2Of(_isInt, _isString)(literal(1));
_isFunction2Of(_isString, _isString)(literal(2));
_isFunction2Of(_isInt, _isString)(literal(3));
_isFunction2Of(_isInt, _isString)(literal(4));
}
test_functionLiteral_assignment_unTypedArguments() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef T Function2<S, T>(S x);
void main () {
Function2<int, String> l0 = (x) => null;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
// ^^^^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'Null' isn't returnable from a 'String' function, as required by the closure's context.
Function2<int, String> l1 = (x) => "hello";
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
Function2<int, String> l2 = (x) => "hello";
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
Function2<int, String> l3 = (x) => 3;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
Function2<int, String> l4 = (x) {return 3;};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l4' isn't used.
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as FunctionExpression;
return exp.declaredFragment!.element.type;
}
_isFunction2Of(_isInt, _isString)(literal(0));
_isFunction2Of(_isInt, _isString)(literal(1));
_isFunction2Of(_isInt, _isString)(literal(2));
_isFunction2Of(_isInt, _isString)(literal(3));
_isFunction2Of(_isInt, _isString)(literal(4));
}
test_functionLiteral_body_propagation() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef T Function2<S, T>(S x);
void main () {
Function2<int, List<String>> l0 = (int x) => ["hello"];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
Function2<int, List<String>> l1 = (String x) => ["hello"];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'List<String> Function(String)' can't be assigned to a variable of type 'Function2<int, List<String>>'.
Function2<int, List<String>> l2 = (int x) => [3];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
// ^
// [diag.listElementTypeNotAssignable] The element type 'int' can't be assigned to the list type 'String'.
Function2<int, List<String>> l3 = (int x) {return [3];};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^
// [diag.listElementTypeNotAssignable] The element type 'int' can't be assigned to the list type 'String'.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
Expression functionReturnValue(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as FunctionExpression;
FunctionBody body = exp.body;
if (body is ExpressionFunctionBody) {
return body.expression2;
} else {
Statement stmt = (body as BlockFunctionBody).block.statements[0];
return (stmt as ReturnStatement).expression2!;
}
}
Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
assertListOfString(functionReturnValue(0).staticType as InterfaceType);
assertListOfString(functionReturnValue(1).staticType as InterfaceType);
assertListOfString(functionReturnValue(2).staticType as InterfaceType);
assertListOfString(functionReturnValue(3).staticType as InterfaceType);
}
test_functionLiteral_functionExpressionInvocation_typedArguments() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class Mapper<F, T> {
T map(T mapper(F x)) => mapper(null);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'F'.
}
void main () {
(new Mapper<int, String>().map)((int x) => null);
// ^^^^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'Null' isn't returnable from a 'String' function, as required by the closure's context.
(new Mapper<int, String>().map)((int x) => "hello");
(new Mapper<int, String>().map)((String x) => "hello");
// ^^^^^^^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String Function(String)' can't be assigned to the parameter type 'String Function(int)'.
(new Mapper<int, String>().map)((int x) => 3);
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
(new Mapper<int, String>().map)((int x) {return 3;});
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as ExpressionStatement;
var invk = stmt.expression2 as FunctionExpressionInvocation;
var exp = invk.argumentList.arguments2[0] as FunctionExpression;
return exp.declaredFragment!.element.type;
}
_isFunction2Of(_isInt, _isString)(literal(0));
_isFunction2Of(_isInt, _isString)(literal(1));
_isFunction2Of(_isString, _isString)(literal(2));
_isFunction2Of(_isInt, _isString)(literal(3));
_isFunction2Of(_isInt, _isString)(literal(4));
}
test_functionLiteral_functionExpressionInvocation_unTypedArguments() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class Mapper<F, T> {
T map(T mapper(F x)) => mapper(null);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'F'.
}
void main () {
(new Mapper<int, String>().map)((x) => null);
// ^^^^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'Null' isn't returnable from a 'String' function, as required by the closure's context.
(new Mapper<int, String>().map)((x) => "hello");
(new Mapper<int, String>().map)((x) => "hello");
(new Mapper<int, String>().map)((x) => 3);
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
(new Mapper<int, String>().map)((x) {return 3;});
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as ExpressionStatement;
var invk = stmt.expression2 as FunctionExpressionInvocation;
var exp = invk.argumentList.arguments2[0] as FunctionExpression;
return exp.declaredFragment!.element.type;
}
_isFunction2Of(_isInt, _isString)(literal(0));
_isFunction2Of(_isInt, _isString)(literal(1));
_isFunction2Of(_isInt, _isString)(literal(2));
_isFunction2Of(_isInt, _isString)(literal(3));
_isFunction2Of(_isInt, _isString)(literal(4));
}
test_functionLiteral_functionInvocation_typedArguments() async {
var result = await resolveTestCodeWithDiagnostics(r'''
String map(String mapper(int x)) => mapper(null);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'int'.
void main () {
map((int x) => null);
// ^^^^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'Null' isn't returnable from a 'String' function, as required by the closure's context.
map((int x) => "hello");
map((String x) => "hello");
// ^^^^^^^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String Function(String)' can't be assigned to the parameter type 'String Function(int)'.
map((int x) => 3);
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
map((int x) {return 3;});
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as ExpressionStatement;
var invk = stmt.expression2 as MethodInvocation;
var exp = invk.argumentList.arguments2[0] as FunctionExpression;
return exp.declaredFragment!.element.type;
}
_isFunction2Of(_isInt, _isString)(literal(0));
_isFunction2Of(_isInt, _isString)(literal(1));
_isFunction2Of(_isString, _isString)(literal(2));
_isFunction2Of(_isInt, _isString)(literal(3));
_isFunction2Of(_isInt, _isString)(literal(4));
}
test_functionLiteral_functionInvocation_unTypedArguments() async {
var result = await resolveTestCodeWithDiagnostics(r'''
String map(String mapper(int x)) => mapper(null);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'int'.
void main () {
map((x) => null);
// ^^^^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'Null' isn't returnable from a 'String' function, as required by the closure's context.
map((x) => "hello");
map((x) => "hello");
map((x) => 3);
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
map((x) {return 3;});
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as ExpressionStatement;
var invk = stmt.expression2 as MethodInvocation;
var exp = invk.argumentList.arguments2[0] as FunctionExpression;
return exp.declaredFragment!.element.type;
}
_isFunction2Of(_isInt, _isString)(literal(0));
_isFunction2Of(_isInt, _isString)(literal(1));
_isFunction2Of(_isInt, _isString)(literal(2));
_isFunction2Of(_isInt, _isString)(literal(3));
_isFunction2Of(_isInt, _isString)(literal(4));
}
test_functionLiteral_methodInvocation_typedArguments() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class Mapper<F, T> {
T map(T mapper(F x)) => mapper(null);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'F'.
}
void main () {
new Mapper<int, String>().map((int x) => null);
// ^^^^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'Null' isn't returnable from a 'String' function, as required by the closure's context.
new Mapper<int, String>().map((int x) => "hello");
new Mapper<int, String>().map((String x) => "hello");
// ^^^^^^^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String Function(String)' can't be assigned to the parameter type 'String Function(int)'.
new Mapper<int, String>().map((int x) => 3);
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
new Mapper<int, String>().map((int x) {return 3;});
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as ExpressionStatement;
var invk = stmt.expression2 as MethodInvocation;
var exp = invk.argumentList.arguments2[0] as FunctionExpression;
return exp.declaredFragment!.element.type;
}
_isFunction2Of(_isInt, _isString)(literal(0));
_isFunction2Of(_isInt, _isString)(literal(1));
_isFunction2Of(_isString, _isString)(literal(2));
_isFunction2Of(_isInt, _isString)(literal(3));
_isFunction2Of(_isInt, _isString)(literal(4));
}
test_functionLiteral_methodInvocation_unTypedArguments() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class Mapper<F, T> {
T map(T mapper(F x)) => mapper(null);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'F'.
}
void main () {
new Mapper<int, String>().map((x) => null);
// ^^^^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'Null' isn't returnable from a 'String' function, as required by the closure's context.
new Mapper<int, String>().map((x) => "hello");
new Mapper<int, String>().map((x) => "hello");
new Mapper<int, String>().map((x) => 3);
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
new Mapper<int, String>().map((x) {return 3;});
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as ExpressionStatement;
var invk = stmt.expression2 as MethodInvocation;
var exp = invk.argumentList.arguments2[0] as FunctionExpression;
return exp.declaredFragment!.element.type;
}
_isFunction2Of(_isInt, _isString)(literal(0));
_isFunction2Of(_isInt, _isString)(literal(1));
_isFunction2Of(_isInt, _isString)(literal(2));
_isFunction2Of(_isInt, _isString)(literal(3));
_isFunction2Of(_isInt, _isString)(literal(4));
}
test_functionLiteral_unTypedArgument_propagation() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef T Function2<S, T>(S x);
void main () {
Function2<int, int> l0 = (x) => x;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
Function2<int, int> l1 = (x) => x+1;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
Function2<int, String> l2 = (x) => x;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
// ^
// [diag.returnOfInvalidTypeFromClosure] The returned type 'int' isn't returnable from a 'String' function, as required by the closure's context.
Function2<int, String> l3 = (x) => x.toLowerCase();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^^^^^^^^^^^
// [diag.undefinedMethod] The method 'toLowerCase' isn't defined for the type 'int'.
Function2<String, String> l4 = (x) => x.toLowerCase();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l4' isn't used.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
Expression functionReturnValue(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as FunctionExpression;
FunctionBody body = exp.body;
if (body is ExpressionFunctionBody) {
return body.expression2;
} else {
Statement stmt = (body as BlockFunctionBody).block.statements[0];
return (stmt as ReturnStatement).expression2!;
}
}
expect(functionReturnValue(0).staticType, result.typeProvider.intType);
expect(functionReturnValue(1).staticType, result.typeProvider.intType);
expect(functionReturnValue(2).staticType, result.typeProvider.intType);
expect(functionReturnValue(3).staticType, InvalidTypeImpl.instance);
expect(functionReturnValue(4).staticType, result.typeProvider.stringType);
}
test_futureOr_assignFromFuture() async {
// Test a Future<T> can be assigned to FutureOr<T>.
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
test() => mk(new Future<int>.value(42));
''');
_isFutureOrOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_assignFromValue() async {
// Test a T can be assigned to FutureOr<T>.
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(T x) => x;
test() => mk(42);
''');
_isFutureOrOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_asyncExpressionBody() async {
// A FutureOr<T> can be used as the expression body for an async function
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) async => x;
test() => mk(42);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_asyncReturn() async {
// A FutureOr<T> can be used as the return value for an async function
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) async { return x; }
test() => mk(42);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_await() async {
// Test a FutureOr<T> can be awaited.
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) async => await x;
test() => mk(42);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_downwards1() async {
// Test that downwards inference interacts correctly with FutureOr
// parameters.
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
Future<int> test() => mk(new Future<int>.value(42));
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_downwards2() async {
// Test that downwards inference interacts correctly with FutureOr
// parameters when the downwards context is FutureOr
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
FutureOr<int> test() => mk(new Future<int>.value(42));
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_downwards3() async {
// Test that downwards inference correctly propagates into
// arguments.
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
Future<int> test() => mk(new Future.value(42));
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments2[0].argumentExpression2.staticType
as InterfaceType,
);
}
test_futureOr_downwards4() async {
// Test that downwards inference interacts correctly with FutureOr
// parameters when the downwards context is FutureOr
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
FutureOr<int> test() => mk(new Future.value(42));
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments2[0].argumentExpression2.staticType
as InterfaceType,
);
}
test_futureOr_downwards5() async {
// Test that downwards inference correctly pins the type when it
// comes from a FutureOr
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
FutureOr<num> test() => mk(new Future.value(42));
''');
_isFutureOf([_isNum])(invoke.staticType as InterfaceType);
_isFutureOf([_isNum])(
invoke.argumentList.arguments2[0].argumentExpression2.staticType
as InterfaceType,
);
}
test_futureOr_downwards6() async {
// Test that downwards inference doesn't decompose FutureOr
// when instantiating type variables.
MethodInvocation invoke = await _testFutureOr(r'''
T mk<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'T'.
FutureOr<int> test() => mk(new Future.value(42));
''');
_isFutureOrOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments2[0].argumentExpression2.staticType
as InterfaceType,
);
}
test_futureOr_downwards7() async {
// Test that downwards inference incorporates bounds correctly
// when instantiating type variables.
MethodInvocation invoke = await _testFutureOr(r'''
T mk<T extends Future<int>>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'T'.
FutureOr<int> test() => mk(new Future.value(42));
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments2[0].argumentExpression2.staticType
as InterfaceType,
);
}
test_futureOr_downwards8() async {
// Test that downwards inference incorporates bounds correctly
// when instantiating type variables.
// TODO(leafp): I think this should pass once the inference changes
// that jmesserly is adding are landed.
MethodInvocation invoke = await _testFutureOr(r'''
T mk<T extends Future<Object>>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'T'.
FutureOr<int> test() => mk(new Future.value(42));
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments2[0].argumentExpression2.staticType
as InterfaceType,
);
}
test_futureOr_downwards9() async {
// Test that downwards inference decomposes correctly with
// other composite types
MethodInvocation invoke = await _testFutureOr(r'''
List<T> mk<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'List<T>'.
FutureOr<List<int>> test() => mk(3);
''');
_isListOf(_isInt)(invoke.staticType as InterfaceType);
_isInt(invoke.argumentList.arguments2[0].argumentExpression2.typeOrThrow);
}
test_futureOr_methods1() async {
// Test that FutureOr has the Object methods
MethodInvocation invoke = await _testFutureOr(r'''
dynamic test(FutureOr<int> x) => x.toString();
''');
_isString(invoke.typeOrThrow);
}
test_futureOr_methods2() async {
// Test that FutureOr does not have the constituent type methods
MethodInvocation invoke = await _testFutureOr(r'''
dynamic test(FutureOr<int> x) => x.abs();
// ^^^
// [diag.undefinedMethod] The method 'abs' isn't defined for the type 'FutureOr'.
''');
_isInvalidType(invoke.typeOrThrow);
}
test_futureOr_methods3() async {
// Test that FutureOr does not have the Future type methods
MethodInvocation invoke = await _testFutureOr(r'''
dynamic test(FutureOr<int> x) => x.then((x) => x);
// ^^^^
// [diag.undefinedMethod] The method 'then' isn't defined for the type 'FutureOr'.
''');
_isInvalidType(invoke.typeOrThrow);
}
test_futureOr_methods4() async {
// Test that FutureOr<dynamic> does not have all methods
MethodInvocation invoke = await _testFutureOr(r'''
dynamic test(FutureOr<dynamic> x) => x.abs();
// ^^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'abs' can't be unconditionally invoked because the receiver can be 'null'.
''');
_isInvalidType(invoke.typeOrThrow);
}
test_futureOr_no_return() async {
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then((int x) {});
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments2[0].argumentExpression2.typeOrThrow,
);
_isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOr_no_return_value() async {
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then((int x) {return;});
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments2[0].argumentExpression2.typeOrThrow,
);
_isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOr_return_null() async {
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then((int x) {return null;});
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments2[0].argumentExpression2.typeOrThrow,
);
_isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOr_upwards1() async {
// Test that upwards inference correctly prefers to instantiate type
// variables with the "smaller" solution when both are possible.
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
dynamic test() => mk(new Future<int>.value(42));
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_upwards2() async {
// Test that upwards inference fails when the solution doesn't
// match the bound.
MethodInvocation invoke = await _testFutureOr(r'''
T mk<T extends Future<Object>>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'T'.
dynamic test() => mk(new Future<int>.value(42));
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOrNull_no_return() async {
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then<Null>((int x) {});
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments2[0].argumentExpression2.typeOrThrow,
);
_isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOrNull_no_return_value() async {
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then<Null>((int x) {return;});
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments2[0].argumentExpression2.typeOrThrow,
);
_isFutureOfNull(invoke.staticType as InterfaceType);
}
test_futureOrNull_return_null() async {
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then<Null>((int x) { return null;});
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments2[0].argumentExpression2.typeOrThrow,
);
_isFutureOfNull(invoke.staticType as InterfaceType);
}
test_generic_partial() async {
// Test that upward and downward type inference handles partial
// type schemas correctly. Downwards inference in a partial context
// (e.g. Map<String, ?>) should still allow upwards inference to fill
// in the missing information.
var result = await resolveTestCodeWithDiagnostics(r'''
class A<T> {
A(T x);
A.fromA(A<T> a) {}
A.fromMap(Map<String, T> m) {}
A.fromList(List<T> m) {}
A.fromT(T t) {}
A.fromB(B<T, String> a) {}
}
class B<S, T> {
B(S s);
}
void test() {
var a0 = new A.fromA(new A(3));
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
var a1 = new A.fromMap({'hello' : 3});
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
var a2 = new A.fromList([3]);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a2' isn't used.
var a3 = new A.fromT(3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a3' isn't used.
var a4 = new A.fromB(new B(3));
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a4' isn't used.
}
''');
Element elementA = AstFinder.getClass(
result.unit,
"A",
).declaredFragment!.element;
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test",
);
void check(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression init = decl.initializer2!;
_isInstantiationOf(_hasElement(elementA))([_isInt])(init.typeOrThrow);
}
for (var i = 0; i < 5; i++) {
check(i);
}
}
test_inferConstructor_unknownTypeLowerBound() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T> {
C(void callback(List<T> a));
}
test() {
// downwards inference pushes List<?> and in parameter position this
// becomes inferred as List<Null>.
var c = new C((items) {});
// ^
// [diag.unusedLocalVariable] The value of the local variable 'c' isn't used.
}
''');
DartType cType = result.findElement.localVar('c').type;
Element elementC = AstFinder.getClass(
result.unit,
"C",
).declaredFragment!.element;
_isInstantiationOf(_hasElement(elementC))([_isType])(cType);
}
test_inference_error_arguments() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef R F<T, R>(T t);
F<T, T> g<T>(F<T, T> f) => (x) => f(f(x));
test() {
var h = g((int x) => 42.0);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'h' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T'.\n\nTried to infer 'double' for 'T' which doesn't work:\n Parameter 'f' declared as 'T Function(T)'\n but argument is 'double Function(int)'.\n\nConsider passing explicit type argument(s) to the generic.
// ^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'double Function(int)' can't be assigned to the parameter type 'F<double, double>'.
}
''');
_expectInferenceError(result, r'''
Couldn't infer type parameter 'T'.
Tried to infer 'double' for 'T' which doesn't work:
Parameter 'f' declared as 'T Function(T)'
but argument is 'double Function(int)'.
Consider passing explicit type argument(s) to the generic.
''');
}
test_inference_error_arguments2() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef R F<T, R>(T t);
F<T, T> g<T>(F<T, T> a, F<T, T> b) => (x) => a(b(x));
test() {
var h = g((int x) => 42.0, (double x) => 42);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'h' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T'.\n\nTried to infer 'num' for 'T' which doesn't work:\n Parameter 'a' declared as 'T Function(T)'\n but argument is 'double Function(int)'.\n Parameter 'b' declared as 'T Function(T)'\n but argument is 'int Function(double)'.\n\nConsider passing explicit type argument(s) to the generic.
// ^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'double Function(int)' can't be assigned to the parameter type 'F<num, num>'.
// ^^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'int Function(double)' can't be assigned to the parameter type 'F<num, num>'.
}
''');
_expectInferenceError(result, r'''
Couldn't infer type parameter 'T'.
Tried to infer 'num' for 'T' which doesn't work:
Parameter 'a' declared as 'T Function(T)'
but argument is 'double Function(int)'.
Parameter 'b' declared as 'T Function(T)'
but argument is 'int Function(double)'.
Consider passing explicit type argument(s) to the generic.
''');
}
test_inference_error_extendsFromReturn() async {
// This is not an inference error because we successfully infer Null.
var result = await resolveTestCodeWithDiagnostics(r'''
T max<T extends num>(T x, T y) => x;
test() {
String hello = max(1, 2);
// ^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'hello' isn't used.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'Never'.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'Never'.
}
''');
var node = result.findNode.singleMethodInvocation;
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: max
element: <testLibrary>::@function::max
staticType: T Function<T extends num>(T, T)
argumentList: ArgumentList
leftParenthesis: (
arguments2
IntegerLiteral
literal: 1
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::max::@formalParameter::x
substitution: {T: Never}
staticType: int
IntegerLiteral
literal: 2
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::max::@formalParameter::y
substitution: {T: Never}
staticType: int
rightParenthesis: )
staticInvokeType: Never Function(Never, Never)
staticType: Never
typeArgumentTypes
Never
''');
}
test_inference_error_extendsFromReturn2() async {
await resolveTestCodeWithDiagnostics(r'''
typedef R F<T, R>(T t);
F<T, T> g<T extends num>() => (y) => y;
test() {
F<String, String> hello = g();
// ^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'hello' isn't used.
// ^^^
// [diag.invalidAssignment] A value of type 'F<num, num>' can't be assigned to a variable of type 'F<String, String>'.
}
''');
}
test_inference_error_genericFunction() async {
await resolveTestCodeWithDiagnostics(r'''
T max<T extends num>(T x, T y) => x < y ? y : x;
abstract class Iterable<T> {
T get first;
S fold<S>(S s, S f(S s, T t));
}
test(Iterable values) {
num n = values.fold(values.first as num, max);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'n' isn't used.
// ^^^
// [diag.argumentTypeNotAssignable] The argument type 'num Function(num, num)' can't be assigned to the parameter type 'num Function(num, dynamic)'.
}
''');
}
test_inference_error_returnContext() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef R F<T, R>(T t);
F<T, T> g<T>(T t) => (x) => t;
test() {
F<num, int> h = g(42);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'h' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T'.\n\nTried to infer 'num' for 'T' which doesn't work:\n Return type declared as 'T Function(T)'\n used where 'int Function(num)' is required.\n\nConsider passing explicit type argument(s) to the generic.
// ^^^^^
// [diag.invalidAssignment] A value of type 'F<num, num>' can't be assigned to a variable of type 'F<num, int>'.
}
''');
_expectInferenceError(result, r'''
Couldn't infer type parameter 'T'.
Tried to infer 'num' for 'T' which doesn't work:
Return type declared as 'T Function(T)'
used where 'int Function(num)' is required.
Consider passing explicit type argument(s) to the generic.
''');
}
test_inference_hints() async {
await resolveTestCodeWithDiagnostics(r'''
void main () {
var x = 3;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
List<int> l0 = [];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
}
''');
}
test_inference_simplePolymorphicRecursion_function() async {
// Regression test for https://github.com/dart-lang/sdk/issues/30980
// Check that inference works properly when inferring the type argument
// for a self-recursive call with a function type
var result = await resolveTestCodeWithDiagnostics(r'''
void _mergeSort<T>(T Function(T) list, int compare(T a, T b), T Function(T) target) {
// ^^^^^^^^^^
// [diag.unusedElement] The declaration '_mergeSort' isn't referenced.
_mergeSort(list, compare, target);
_mergeSort(list, compare, list);
_mergeSort(target, compare, target);
_mergeSort(target, compare, list);
}
''');
var node = result.findNode.singleBlock;
assertResolvedNodeText(node, r'''
Block
leftBracket: {
statements
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(T Function(T), int Function(T, T), T Function(T))
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: T Function(T)
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: T Function(T)
rightParenthesis: )
staticInvokeType: void Function(T Function(T), int Function(T, T), T Function(T))
staticType: void
typeArgumentTypes
T
semicolon: ;
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(T Function(T), int Function(T, T), T Function(T))
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: T Function(T)
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: T Function(T)
rightParenthesis: )
staticInvokeType: void Function(T Function(T), int Function(T, T), T Function(T))
staticType: void
typeArgumentTypes
T
semicolon: ;
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(T Function(T), int Function(T, T), T Function(T))
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: T Function(T)
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: T Function(T)
rightParenthesis: )
staticInvokeType: void Function(T Function(T), int Function(T, T), T Function(T))
staticType: void
typeArgumentTypes
T
semicolon: ;
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(T Function(T), int Function(T, T), T Function(T))
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: T Function(T)
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: T Function(T)
rightParenthesis: )
staticInvokeType: void Function(T Function(T), int Function(T, T), T Function(T))
staticType: void
typeArgumentTypes
T
semicolon: ;
rightBracket: }
''');
}
test_inference_simplePolymorphicRecursion_interface() async {
// Regression test for https://github.com/dart-lang/sdk/issues/30980
// Check that inference works properly when inferring the type argument
// for a self-recursive call with an interface type
var result = await resolveTestCodeWithDiagnostics(r'''
void _mergeSort<T>(List<T> list, int compare(T a, T b), List<T> target) {
// ^^^^^^^^^^
// [diag.unusedElement] The declaration '_mergeSort' isn't referenced.
_mergeSort(list, compare, target);
_mergeSort(list, compare, list);
_mergeSort(target, compare, target);
_mergeSort(target, compare, list);
}
''');
var node = result.findNode.singleBlock;
assertResolvedNodeText(node, r'''
Block
leftBracket: {
statements
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(List<T>, int Function(T, T), List<T>)
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: List<T>
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: List<T>
rightParenthesis: )
staticInvokeType: void Function(List<T>, int Function(T, T), List<T>)
staticType: void
typeArgumentTypes
T
semicolon: ;
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(List<T>, int Function(T, T), List<T>)
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: List<T>
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: List<T>
rightParenthesis: )
staticInvokeType: void Function(List<T>, int Function(T, T), List<T>)
staticType: void
typeArgumentTypes
T
semicolon: ;
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(List<T>, int Function(T, T), List<T>)
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: List<T>
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: List<T>
rightParenthesis: )
staticInvokeType: void Function(List<T>, int Function(T, T), List<T>)
staticType: void
typeArgumentTypes
T
semicolon: ;
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(List<T>, int Function(T, T), List<T>)
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: List<T>
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: List<T>
rightParenthesis: )
staticInvokeType: void Function(List<T>, int Function(T, T), List<T>)
staticType: void
typeArgumentTypes
T
semicolon: ;
rightBracket: }
''');
}
test_inference_simplePolymorphicRecursion_simple() async {
// Regression test for https://github.com/dart-lang/sdk/issues/30980
// Check that inference works properly when inferring the type argument
// for a self-recursive call with a simple type parameter
var result = await resolveTestCodeWithDiagnostics(r'''
void _mergeSort<T>(T list, int compare(T a, T b), T target) {
// ^^^^^^^^^^
// [diag.unusedElement] The declaration '_mergeSort' isn't referenced.
_mergeSort(list, compare, target);
_mergeSort(list, compare, list);
_mergeSort(target, compare, target);
_mergeSort(target, compare, list);
}
''');
var node = result.findNode.singleBlock;
assertResolvedNodeText(node, r'''
Block
leftBracket: {
statements
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(T, int Function(T, T), T)
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: T
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: T
rightParenthesis: )
staticInvokeType: void Function(T, int Function(T, T), T)
staticType: void
typeArgumentTypes
T
semicolon: ;
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(T, int Function(T, T), T)
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: T
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: T
rightParenthesis: )
staticInvokeType: void Function(T, int Function(T, T), T)
staticType: void
typeArgumentTypes
T
semicolon: ;
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(T, int Function(T, T), T)
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: T
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: T
rightParenthesis: )
staticInvokeType: void Function(T, int Function(T, T), T)
staticType: void
typeArgumentTypes
T
semicolon: ;
ExpressionStatement
expression2: MethodInvocation
methodName: SimpleIdentifier
token: _mergeSort
element: <testLibrary>::@function::_mergeSort
staticType: void Function<T>(T, int Function(T, T), T)
argumentList: ArgumentList
leftParenthesis: (
arguments2
SimpleIdentifier
token: target
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::list
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::target
staticType: T
SimpleIdentifier
token: compare
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::compare
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::compare
staticType: int Function(T, T)
SimpleIdentifier
token: list
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::_mergeSort::@formalParameter::target
substitution: {T: T}
element: <testLibrary>::@function::_mergeSort::@formalParameter::list
staticType: T
rightParenthesis: )
staticInvokeType: void Function(T, int Function(T, T), T)
staticType: void
typeArgumentTypes
T
semicolon: ;
rightBracket: }
''');
}
test_inferGenericInstantiation() async {
// Verify that we don't infer '?` when we instantiate a generic function.
var result = await resolveTestCodeWithDiagnostics(r'''
T f<T>(T x(T t)) => x(null);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'T'.
S g<S>(S s) => s;
test() {
var h = f(g);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'h' isn't used.
}
''');
var node = result.findNode.methodInvocation('f(g)');
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: f
element: <testLibrary>::@function::f
staticType: T Function<T>(T Function(T))
argumentList: ArgumentList
leftParenthesis: (
arguments2
FunctionReference
function2: SimpleIdentifier
token: g
element: <testLibrary>::@function::g
staticType: S Function<S>(S)
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: <testLibrary>::@function::f::@formalParameter::x
substitution: {T: dynamic}
staticType: dynamic Function(dynamic)
typeArgumentTypes
dynamic
rightParenthesis: )
staticInvokeType: dynamic Function(dynamic Function(dynamic))
staticType: dynamic
typeArgumentTypes
dynamic
''');
}
test_inferGenericInstantiation2() async {
// Verify the behavior when we cannot infer an instantiation due to invalid
// constraints from an outer generic method.
var result = await resolveTestCodeWithDiagnostics(r'''
T max<T extends num>(T x, T y) => x < y ? y : x;
abstract class Iterable<T> {
T get first;
S fold<S>(S s, S f(S s, T t));
}
num test(Iterable values) => values.fold(values.first as num, max);
// ^^^
// [diag.argumentTypeNotAssignable] The argument type 'num Function(num, num)' can't be assigned to the parameter type 'num Function(num, dynamic)'.
''');
var node = result.findNode.methodInvocation('values.fold');
assertResolvedNodeText(node, r'''
MethodInvocation
target2: SimpleIdentifier
token: values
element: <testLibrary>::@function::test::@formalParameter::values
staticType: Iterable<dynamic>
operator: .
methodName: SimpleIdentifier
token: fold
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::Iterable::@method::fold
substitution: {T: dynamic, S: S}
staticType: S Function<S>(S, S Function(S, dynamic))
argumentList: ArgumentList
leftParenthesis: (
arguments2
AsExpression
expression2: PrefixedIdentifier
prefix: SimpleIdentifier
token: values
element: <testLibrary>::@function::test::@formalParameter::values
staticType: Iterable<dynamic>
period: .
identifier: SimpleIdentifier
token: first
element: SubstitutedGetterElementImpl
baseElement: <testLibrary>::@class::Iterable::@getter::first
substitution: {T: dynamic}
staticType: dynamic
element: SubstitutedGetterElementImpl
baseElement: <testLibrary>::@class::Iterable::@getter::first
substitution: {T: dynamic}
staticType: dynamic
asOperator: as
type: NamedType
name: num
element: dart:core::@class::num
type: num
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: s@null
substitution: {S: num}
staticType: num
FunctionReference
function2: SimpleIdentifier
token: max
element: <testLibrary>::@function::max
staticType: T Function<T extends num>(T, T)
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: f@null
substitution: {S: num}
staticType: num Function(num, num)
typeArgumentTypes
num
rightParenthesis: )
staticInvokeType: num Function(num, num Function(num, dynamic))
staticType: num
typeArgumentTypes
num
''');
}
test_inferredFieldDeclaration_propagation() async {
// Regression test for https://github.com/dart-lang/sdk/issues/25546
String code = r'''
abstract class A {
Map<int, List<int>> get map;
}
class B extends A {
var map = { 42: [] };
}
class C extends A {
get map => { 43: [] };
}
''';
var result = await resolveTestCodeWithDiagnostics(code);
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
Asserter<InterfaceType> assertMapOfIntToListOfInt = _isMapOf(
_isInt,
(DartType type) => assertListOfInt(type as InterfaceType),
);
VariableDeclaration mapB = AstFinder.getFieldInClass(
result.unit,
"B",
"map",
);
MethodDeclaration mapC = AstFinder.getMethodInClass(
result.unit,
"C",
"map",
);
assertMapOfIntToListOfInt(
mapB.declaredFragment!.element.type as InterfaceType,
);
assertMapOfIntToListOfInt(
mapC.declaredFragment!.element.returnType as InterfaceType,
);
var mapLiteralB = mapB.initializer2 as SetOrMapLiteral;
var mapLiteralC =
(mapC.body as ExpressionFunctionBody).expression2 as SetOrMapLiteral;
assertMapOfIntToListOfInt(mapLiteralB.staticType as InterfaceType);
assertMapOfIntToListOfInt(mapLiteralC.staticType as InterfaceType);
var listLiteralB =
(mapLiteralB.elements2[0] as MapLiteralEntry).value2 as ListLiteral;
var listLiteralC =
(mapLiteralC.elements2[0] as MapLiteralEntry).value2 as ListLiteral;
assertListOfInt(listLiteralB.staticType as InterfaceType);
assertListOfInt(listLiteralC.staticType as InterfaceType);
}
test_instanceCreation() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A<S, T> {
S x;
T y;
A(this.x, this.y);
A.named(this.x, this.y);
}
class B<S, T> extends A<T, S> {
B(S y, T x) : super(x, y);
B.named(S y, T x) : super.named(x, y);
}
class C<S> extends B<S, S> {
C(S a) : super(a, a);
C.named(S a) : super.named(a, a);
}
class D<S, T> extends B<T, int> {
D(T a) : super(a, 3);
D.named(T a) : super.named(a, 3);
}
class E<S, T> extends A<C<S>, T> {
E(T a) : super(null, a);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'C<S>'.
}
class F<S, T> extends A<S, T> {
F(S x, T y, {List<S> a, List<T> b}) : super(x, y);
// ^
// [diag.missingDefaultValueForParameter] The parameter 'a' can't have a value of 'null' because of its type, but the implicit default value is 'null'.
// ^
// [diag.missingDefaultValueForParameter] The parameter 'b' can't have a value of 'null' because of its type, but the implicit default value is 'null'.
F.named(S x, T y, [S a, T b]) : super(a, b);
// ^
// [diag.missingDefaultValueForParameterPositional] The parameter 'a' can't have a value of 'null' because of its type, but the implicit default value is 'null'.
// ^
// [diag.missingDefaultValueForParameterPositional] The parameter 'b' can't have a value of 'null' because of its type, but the implicit default value is 'null'.
}
void test0() {
A<int, String> a0 = new A(3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
A<int, String> a1 = new A.named(3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
A<int, String> a2 = new A<int, String>(3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a2' isn't used.
A<int, String> a3 = new A<int, String>.named(3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a3' isn't used.
A<int, String> a4 = new A<int, dynamic>(3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a4' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'A<int, dynamic>' can't be assigned to a variable of type 'A<int, String>'.
A<int, String> a5 = new A<dynamic, dynamic>.named(3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a5' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'A<dynamic, dynamic>' can't be assigned to a variable of type 'A<int, String>'.
}
void test1() {
A<int, String> a0 = new A("hello", 3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
// ^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String' can't be assigned to the parameter type 'int'.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'String'.
A<int, String> a1 = new A.named("hello", 3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
// ^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String' can't be assigned to the parameter type 'int'.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'String'.
}
void test2() {
A<int, String> a0 = new B("hello", 3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
A<int, String> a1 = new B.named("hello", 3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
A<int, String> a2 = new B<String, int>("hello", 3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a2' isn't used.
A<int, String> a3 = new B<String, int>.named("hello", 3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a3' isn't used.
A<int, String> a4 = new B<String, dynamic>("hello", 3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a4' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'B<String, dynamic>' can't be assigned to a variable of type 'A<int, String>'.
A<int, String> a5 = new B<dynamic, dynamic>.named("hello", 3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a5' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'B<dynamic, dynamic>' can't be assigned to a variable of type 'A<int, String>'.
}
void test3() {
A<int, String> a0 = new B(3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'String'.
// ^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String' can't be assigned to the parameter type 'int'.
A<int, String> a1 = new B.named(3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'String'.
// ^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String' can't be assigned to the parameter type 'int'.
}
void test4() {
A<int, int> a0 = new C(3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
A<int, int> a1 = new C.named(3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
A<int, int> a2 = new C<int>(3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a2' isn't used.
A<int, int> a3 = new C<int>.named(3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a3' isn't used.
A<int, int> a4 = new C<dynamic>(3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a4' isn't used.
// ^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'C<dynamic>' can't be assigned to a variable of type 'A<int, int>'.
A<int, int> a5 = new C<dynamic>.named(3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a5' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'C<dynamic>' can't be assigned to a variable of type 'A<int, int>'.
}
void test5() {
A<int, int> a0 = new C("hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
// ^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String' can't be assigned to the parameter type 'int'.
A<int, int> a1 = new C.named("hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
// ^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String' can't be assigned to the parameter type 'int'.
}
void test6() {
A<int, String> a0 = new D("hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
A<int, String> a1 = new D.named("hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
A<int, String> a2 = new D<int, String>("hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a2' isn't used.
A<int, String> a3 = new D<String, String>.named("hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a3' isn't used.
A<int, String> a4 = new D<num, dynamic>("hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a4' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'D<num, dynamic>' can't be assigned to a variable of type 'A<int, String>'.
A<int, String> a5 = new D<dynamic, dynamic>.named("hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a5' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'D<dynamic, dynamic>' can't be assigned to a variable of type 'A<int, String>'.
}
void test7() {
A<int, String> a0 = new D(3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'String'.
A<int, String> a1 = new D.named(3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'String'.
}
void test8() {
A<C<int>, String> a0 = new E("hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
}
void test9() { // Check named and optional arguments
A<int, String> a0 = new F(3, "hello", a: [3], b: ["hello"]);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a0' isn't used.
A<int, String> a1 = new F(3, "hello", a: ["hello"], b:[3]);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a1' isn't used.
// ^^^^^^^
// [diag.listElementTypeNotAssignable] The element type 'String' can't be assigned to the list type 'int'.
// ^
// [diag.listElementTypeNotAssignable] The element type 'int' can't be assigned to the list type 'String'.
A<int, String> a2 = new F.named(3, "hello", 3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a2' isn't used.
A<int, String> a3 = new F.named(3, "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a3' isn't used.
A<int, String> a4 = new F.named(3, "hello", "hello", 3);
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a4' isn't used.
// ^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String' can't be assigned to the parameter type 'int'.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'String'.
A<int, String> a5 = new F.named(3, "hello", "hello");
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'a5' isn't used.
// ^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'String' can't be assigned to the parameter type 'int'.
}''');
Expression rhs(AstNode stmt) {
stmt as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
Expression exp = decl.initializer2!;
return exp;
}
void hasType(Asserter<DartType> assertion, Expression exp) =>
assertion(exp.typeOrThrow);
Element elementA = AstFinder.getClass(
result.unit,
"A",
).declaredFragment!.element;
Element elementB = AstFinder.getClass(
result.unit,
"B",
).declaredFragment!.element;
Element elementC = AstFinder.getClass(
result.unit,
"C",
).declaredFragment!.element;
Element elementD = AstFinder.getClass(
result.unit,
"D",
).declaredFragment!.element;
Element elementE = AstFinder.getClass(
result.unit,
"E",
).declaredFragment!.element;
Element elementF = AstFinder.getClass(
result.unit,
"F",
).declaredFragment!.element;
AsserterBuilder<List<Asserter<DartType>>, DartType> assertAOf =
_isInstantiationOf(_hasElement(elementA));
AsserterBuilder<List<Asserter<DartType>>, DartType> assertBOf =
_isInstantiationOf(_hasElement(elementB));
AsserterBuilder<List<Asserter<DartType>>, DartType> assertCOf =
_isInstantiationOf(_hasElement(elementC));
AsserterBuilder<List<Asserter<DartType>>, DartType> assertDOf =
_isInstantiationOf(_hasElement(elementD));
AsserterBuilder<List<Asserter<DartType>>, DartType> assertEOf =
_isInstantiationOf(_hasElement(elementE));
AsserterBuilder<List<Asserter<DartType>>, DartType> assertFOf =
_isInstantiationOf(_hasElement(elementF));
{
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test0",
).cast<VariableDeclarationStatement>();
hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
hasType(assertAOf([_isInt, _isString]), rhs(statements[1]));
hasType(assertAOf([_isInt, _isString]), rhs(statements[2]));
hasType(assertAOf([_isInt, _isString]), rhs(statements[3]));
hasType(assertAOf([_isInt, _isDynamic]), rhs(statements[4]));
hasType(assertAOf([_isDynamic, _isDynamic]), rhs(statements[5]));
}
{
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test1",
).cast<VariableDeclarationStatement>();
hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
hasType(assertAOf([_isInt, _isString]), rhs(statements[1]));
}
{
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test2",
).cast<VariableDeclarationStatement>();
hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
hasType(assertBOf([_isString, _isInt]), rhs(statements[2]));
hasType(assertBOf([_isString, _isInt]), rhs(statements[3]));
hasType(assertBOf([_isString, _isDynamic]), rhs(statements[4]));
hasType(assertBOf([_isDynamic, _isDynamic]), rhs(statements[5]));
}
{
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test3",
).cast<VariableDeclarationStatement>();
hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
}
{
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test4",
).cast<VariableDeclarationStatement>();
hasType(assertCOf([_isInt]), rhs(statements[0]));
hasType(assertCOf([_isInt]), rhs(statements[1]));
hasType(assertCOf([_isInt]), rhs(statements[2]));
hasType(assertCOf([_isInt]), rhs(statements[3]));
hasType(assertCOf([_isDynamic]), rhs(statements[4]));
hasType(assertCOf([_isDynamic]), rhs(statements[5]));
}
{
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test5",
).cast<VariableDeclarationStatement>();
hasType(assertCOf([_isInt]), rhs(statements[0]));
hasType(assertCOf([_isInt]), rhs(statements[1]));
}
{
// The first type parameter is not constrained by the
// context. We could choose a tighter type, but currently
// we just use dynamic.
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test6",
).cast<VariableDeclarationStatement>();
hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
hasType(assertDOf([_isInt, _isString]), rhs(statements[2]));
hasType(assertDOf([_isString, _isString]), rhs(statements[3]));
hasType(assertDOf([_isNum, _isDynamic]), rhs(statements[4]));
hasType(assertDOf([_isDynamic, _isDynamic]), rhs(statements[5]));
}
{
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test7",
).cast<VariableDeclarationStatement>();
hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
}
{
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test8",
).cast<VariableDeclarationStatement>();
hasType(assertEOf([_isInt, _isString]), rhs(statements[0]));
}
{
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"test9",
).cast<VariableDeclarationStatement>();
hasType(assertFOf([_isInt, _isString]), rhs(statements[0]));
hasType(assertFOf([_isInt, _isString]), rhs(statements[1]));
hasType(assertFOf([_isInt, _isString]), rhs(statements[2]));
hasType(assertFOf([_isInt, _isString]), rhs(statements[3]));
hasType(assertFOf([_isInt, _isString]), rhs(statements[4]));
hasType(assertFOf([_isInt, _isString]), rhs(statements[5]));
}
}
test_listLiteral_nested() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void main () {
List<List<int>> l0 = [[]];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
Iterable<List<int>> l1 = [[3]];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
Iterable<List<int>> l2 = [[3], [4]];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
List<List<int>> l3 = [["hello", 3], []];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^^^^^^^
// [diag.listElementTypeNotAssignable] The element type 'String' can't be assigned to the list type 'int'.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
ListLiteral literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as ListLiteral;
return exp;
}
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
Asserter<InterfaceType> assertListOfListOfInt = _isListOf(
(DartType type) => assertListOfInt(type as InterfaceType),
);
assertListOfListOfInt(literal(0).staticType as InterfaceType);
assertListOfListOfInt(literal(1).staticType as InterfaceType);
assertListOfListOfInt(literal(2).staticType as InterfaceType);
assertListOfListOfInt(literal(3).staticType as InterfaceType);
assertListOfInt(
(literal(1).elements2[0] as Expression).staticType as InterfaceType,
);
assertListOfInt(
(literal(2).elements2[0] as Expression).staticType as InterfaceType,
);
assertListOfInt(
(literal(3).elements2[0] as Expression).staticType as InterfaceType,
);
}
test_listLiteral_simple() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void main () {
List<int> l0 = [];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
List<int> l1 = [3];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
List<int> l2 = ["hello"];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
// ^^^^^^^
// [diag.listElementTypeNotAssignable] The element type 'String' can't be assigned to the list type 'int'.
List<int> l3 = ["hello", 3];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^^^^^^^
// [diag.listElementTypeNotAssignable] The element type 'String' can't be assigned to the list type 'int'.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as ListLiteral;
return exp.typeOrThrow;
}
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
assertListOfInt(literal(0) as InterfaceType);
assertListOfInt(literal(1) as InterfaceType);
assertListOfInt(literal(2) as InterfaceType);
assertListOfInt(literal(3) as InterfaceType);
}
test_listLiteral_simple_const() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void main () {
const List<int> c0 = const [];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'c0' isn't used.
const List<int> c1 = const [3];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'c1' isn't used.
const List<int> c2 = const ["hello"];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'c2' isn't used.
// ^^^^^^^
// [diag.listElementTypeNotAssignable] The element type 'String' can't be assigned to the list type 'int'.
const List<int> c3 = const ["hello", 3];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'c3' isn't used.
// ^^^^^^^
// [diag.listElementTypeNotAssignable] The element type 'String' can't be assigned to the list type 'int'.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as ListLiteral;
return exp.typeOrThrow;
}
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
assertListOfInt(literal(0) as InterfaceType);
assertListOfInt(literal(1) as InterfaceType);
assertListOfInt(literal(2) as InterfaceType);
assertListOfInt(literal(3) as InterfaceType);
}
test_listLiteral_simple_disabled() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void main () {
List<int> l0 = <num>[];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
// ^^^^^^^
// [diag.invalidAssignment] A value of type 'List<num>' can't be assigned to a variable of type 'List<int>'.
List<int> l1 = <num>[3];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
// ^^^^^^^^
// [diag.invalidAssignment] A value of type 'List<num>' can't be assigned to a variable of type 'List<int>'.
List<int> l2 = <String>["hello"];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
// ^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'List<String>' can't be assigned to a variable of type 'List<int>'.
List<int> l3 = <dynamic>["hello", 3];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'List<dynamic>' can't be assigned to a variable of type 'List<int>'.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
DartType literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as ListLiteral;
return exp.typeOrThrow;
}
_isListOf(_isNum)(literal(0) as InterfaceType);
_isListOf(_isNum)(literal(1) as InterfaceType);
_isListOf(_isString)(literal(2) as InterfaceType);
_isListOf(_isDynamic)(literal(3) as InterfaceType);
}
test_listLiteral_simple_subtype() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void main () {
Iterable<int> l0 = [];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
Iterable<int> l1 = [3];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
Iterable<int> l2 = ["hello"];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
// ^^^^^^^
// [diag.listElementTypeNotAssignable] The element type 'String' can't be assigned to the list type 'int'.
Iterable<int> l3 = ["hello", 3];
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^^^^^^^
// [diag.listElementTypeNotAssignable] The element type 'String' can't be assigned to the list type 'int'.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
InterfaceType literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as ListLiteral;
return exp.staticType as InterfaceType;
}
Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
assertListOfInt(literal(0));
assertListOfInt(literal(1));
assertListOfInt(literal(2));
assertListOfInt(literal(3));
}
test_mapLiteral_nested() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void main () {
Map<int, List<String>> l0 = {};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
Map<int, List<String>> l1 = {3: ["hello"]};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
Map<int, List<String>> l2 = {"hello": ["hello"]};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
// ^^^^^^^
// [diag.mapKeyTypeNotAssignable] The element type 'String' can't be assigned to the map key type 'int'.
Map<int, List<String>> l3 = {3: [3]};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^
// [diag.listElementTypeNotAssignable] The element type 'int' can't be assigned to the list type 'String'.
Map<int, List<String>> l4 = {3:["hello"], "hello": [3]};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l4' isn't used.
// ^^^^^^^
// [diag.mapKeyTypeNotAssignable] The element type 'String' can't be assigned to the map key type 'int'.
// ^
// [diag.listElementTypeNotAssignable] The element type 'int' can't be assigned to the list type 'String'.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
SetOrMapLiteral literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as SetOrMapLiteral;
return exp;
}
Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
Asserter<InterfaceType> assertMapOfIntToListOfString = _isMapOf(
_isInt,
(DartType type) => assertListOfString(type as InterfaceType),
);
assertMapOfIntToListOfString(literal(0).staticType as InterfaceType);
assertMapOfIntToListOfString(literal(1).staticType as InterfaceType);
assertMapOfIntToListOfString(literal(2).staticType as InterfaceType);
assertMapOfIntToListOfString(literal(3).staticType as InterfaceType);
assertMapOfIntToListOfString(literal(4).staticType as InterfaceType);
assertListOfString(
(literal(1).elements2[0] as MapLiteralEntry).value2.staticType
as InterfaceType,
);
assertListOfString(
(literal(2).elements2[0] as MapLiteralEntry).value2.staticType
as InterfaceType,
);
assertListOfString(
(literal(3).elements2[0] as MapLiteralEntry).value2.staticType
as InterfaceType,
);
assertListOfString(
(literal(4).elements2[0] as MapLiteralEntry).value2.staticType
as InterfaceType,
);
}
test_mapLiteral_simple() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void main () {
Map<int, String> l0 = {};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
Map<int, String> l1 = {3: "hello"};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
Map<int, String> l2 = {"hello": "hello"};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
// ^^^^^^^
// [diag.mapKeyTypeNotAssignable] The element type 'String' can't be assigned to the map key type 'int'.
Map<int, String> l3 = {3: 3};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^
// [diag.mapValueTypeNotAssignable] The element type 'int' can't be assigned to the map value type 'String'.
Map<int, String> l4 = {3:"hello", "hello": 3};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l4' isn't used.
// ^^^^^^^
// [diag.mapKeyTypeNotAssignable] The element type 'String' can't be assigned to the map key type 'int'.
// ^
// [diag.mapValueTypeNotAssignable] The element type 'int' can't be assigned to the map value type 'String'.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
InterfaceType literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as SetOrMapLiteral;
return exp.staticType as InterfaceType;
}
Asserter<InterfaceType> assertMapOfIntToString = _isMapOf(
_isInt,
_isString,
);
assertMapOfIntToString(literal(0));
assertMapOfIntToString(literal(1));
assertMapOfIntToString(literal(2));
assertMapOfIntToString(literal(3));
}
test_mapLiteral_simple_disabled() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void main () {
Map<int, String> l0 = <int, dynamic>{};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l0' isn't used.
// ^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'Map<int, dynamic>' can't be assigned to a variable of type 'Map<int, String>'.
Map<int, String> l1 = <int, dynamic>{3: "hello"};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l1' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'Map<int, dynamic>' can't be assigned to a variable of type 'Map<int, String>'.
Map<int, String> l2 = <int, dynamic>{"hello": "hello"};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l2' isn't used.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'Map<int, dynamic>' can't be assigned to a variable of type 'Map<int, String>'.
// ^^^^^^^
// [diag.mapKeyTypeNotAssignable] The element type 'String' can't be assigned to the map key type 'int'.
Map<int, String> l3 = <int, dynamic>{3: 3};
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'l3' isn't used.
// ^^^^^^^^^^^^^^^^^^^^
// [diag.invalidAssignment] A value of type 'Map<int, dynamic>' can't be assigned to a variable of type 'Map<int, String>'.
}
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
"main",
);
InterfaceType literal(int i) {
var stmt = statements[i] as VariableDeclarationStatement;
VariableDeclaration decl = stmt.variables.variables[0];
var exp = decl.initializer2 as SetOrMapLiteral;
return exp.staticType as InterfaceType;
}
Asserter<InterfaceType> assertMapOfIntToDynamic = _isMapOf(
_isInt,
_isDynamic,
);
assertMapOfIntToDynamic(literal(0));
assertMapOfIntToDynamic(literal(1));
assertMapOfIntToDynamic(literal(2));
assertMapOfIntToDynamic(literal(3));
}
test_methodDeclaration_body_propagation() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
List<String> m0(int x) => ["hello"];
List<String> m1(int x) {return [3];}
// ^
// [diag.listElementTypeNotAssignable] The element type 'int' can't be assigned to the list type 'String'.
}
''');
Expression methodReturnValue(String methodName) {
MethodDeclaration method = AstFinder.getMethodInClass(
result.unit,
"A",
methodName,
);
FunctionBody body = method.body;
if (body is ExpressionFunctionBody) {
return body.expression2;
} else {
Statement stmt = (body as BlockFunctionBody).block.statements[0];
return (stmt as ReturnStatement).expression2!;
}
}
Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
assertListOfString(methodReturnValue("m0").staticType as InterfaceType);
assertListOfString(methodReturnValue("m1").staticType as InterfaceType);
}
test_partialTypes1() async {
// Test that downwards inference with a partial type
// correctly uses the partial information to fill in subterm
// types
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
S f<S, T>(Func1<S, T> g) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'S'.
String test() => f((l) => l.length);
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
_isString(body.expression2.typeOrThrow);
var invoke = body.expression2 as MethodInvocation;
var function = invoke.argumentList.arguments2[0] as FunctionExpression;
ExecutableElement f0 = function.declaredFragment!.element;
FunctionType type = f0.type;
_isFunction2Of(_isString, _isInt)(type);
}
test_pinning_multipleConstraints1() async {
// Test that downwards inference with two different downwards covariant
// constraints on the same parameter correctly fails to infer when
// the types do not share a common subtype
var result = await resolveTestCodeWithDiagnostics(r'''
class A<S, T> {
S s;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 's' must be initialized.
T t;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 't' must be initialized.
}
class B<S> extends A<S, S> { B(S s); }
A<int, String> test() => new B(3);
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'Never'.
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
DartType type = body.expression2.typeOrThrow;
Element elementB = AstFinder.getClass(
result.unit,
"B",
).declaredFragment!.element;
_isInstantiationOf(_hasElement(elementB))([_isNever])(type);
}
test_pinning_multipleConstraints2() async {
// Test that downwards inference with two identical downwards covariant
// constraints on the same parameter correctly infers and pins the type
var result = await resolveTestCodeWithDiagnostics(r'''
class A<S, T> {
S s;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 's' must be initialized.
T t;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 't' must be initialized.
}
class B<S> extends A<S, S> { B(S s); }
A<num, num> test() => new B(3);
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
DartType type = body.expression2.typeOrThrow;
Element elementB = AstFinder.getClass(
result.unit,
"B",
).declaredFragment!.element;
_isInstantiationOf(_hasElement(elementB))([_isNum])(type);
}
test_pinning_multipleConstraints3() async {
// Test that downwards inference with two different downwards covariant
// constraints on the same parameter correctly fails to infer when
// the types do not share a common subtype, but do share a common supertype
var result = await resolveTestCodeWithDiagnostics(r'''
class A<S, T> {
S s;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 's' must be initialized.
T t;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 't' must be initialized.
}
class B<S> extends A<S, S> { B(S s); }
A<int, double> test() => new B(3);
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'Never'.
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
DartType type = body.expression2.typeOrThrow;
Element elementB = AstFinder.getClass(
result.unit,
"B",
).declaredFragment!.element;
_isInstantiationOf(_hasElement(elementB))([_isNever])(type);
}
test_pinning_multipleConstraints4() async {
// Test that downwards inference with two subtype related downwards
// covariant constraints on the same parameter correctly infers and pins
// the type
var result = await resolveTestCodeWithDiagnostics(r'''
class A<S, T> {
S s;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 's' must be initialized.
T t;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 't' must be initialized.
}
class B<S> extends A<S, S> {}
A<int, num> test() => new B();
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
DartType type = body.expression2.typeOrThrow;
Element elementB = AstFinder.getClass(
result.unit,
"B",
).declaredFragment!.element;
_isInstantiationOf(_hasElement(elementB))([_isInt])(type);
}
test_pinning_multipleConstraints_contravariant1() async {
// Test that downwards inference with two different downwards contravariant
// constraints on the same parameter chooses the upper bound
// when the only supertype is Object
var result = await resolveTestCodeWithDiagnostics(r'''
class A<S, T> {
S s;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 's' must be initialized.
T t;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 't' must be initialized.
}
class B<S> extends A<S, S> {}
typedef void Contra1<T>(T x);
Contra1<A<S, S>> mkA<S>() => (A<S, S> x) {};
Contra1<A<int, String>> test() => mkA();
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var functionType = body.expression2.staticType as FunctionType;
DartType type = functionType.normalParameterTypes[0];
Element elementA = AstFinder.getClass(
result.unit,
"A",
).declaredFragment!.element;
_isInstantiationOf(_hasElement(elementA))([_isObject, _isObject])(type);
}
test_pinning_multipleConstraints_contravariant2() async {
// Test that downwards inference with two identical downwards contravariant
// constraints on the same parameter correctly pins the type
var result = await resolveTestCodeWithDiagnostics(r'''
class A<S, T> {
S s;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 's' must be initialized.
T t;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 't' must be initialized.
}
class B<S> extends A<S, S> {}
typedef void Contra1<T>(T x);
Contra1<A<S, S>> mkA<S>() => (A<S, S> x) {};
Contra1<A<num, num>> test() => mkA();
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var functionType = body.expression2.staticType as FunctionType;
DartType type = functionType.normalParameterTypes[0];
Element elementA = AstFinder.getClass(
result.unit,
"A",
).declaredFragment!.element;
_isInstantiationOf(_hasElement(elementA))([_isNum, _isNum])(type);
}
test_pinning_multipleConstraints_contravariant3() async {
// Test that downwards inference with two different downwards contravariant
// constraints on the same parameter correctly choose the least upper bound
// when they share a common supertype
var result = await resolveTestCodeWithDiagnostics(r'''
class A<S, T> {
S s;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 's' must be initialized.
T t;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 't' must be initialized.
}
class B<S> extends A<S, S> {}
typedef void Contra1<T>(T x);
Contra1<A<S, S>> mkA<S>() => (A<S, S> x) {};
Contra1<A<int, double>> test() => mkA();
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var functionType = body.expression2.staticType as FunctionType;
DartType type = functionType.normalParameterTypes[0];
Element elementA = AstFinder.getClass(
result.unit,
"A",
).declaredFragment!.element;
_isInstantiationOf(_hasElement(elementA))([_isNum, _isNum])(type);
}
test_pinning_multipleConstraints_contravariant4() async {
// Test that downwards inference with two different downwards contravariant
// constraints on the same parameter correctly choose the least upper bound
// when one is a subtype of the other
var result = await resolveTestCodeWithDiagnostics(r'''
class A<S, T> {
S s;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 's' must be initialized.
T t;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 't' must be initialized.
}
class B<S> extends A<S, S> {}
typedef void Contra1<T>(T x);
Contra1<A<S, S>> mkA<S>() => (A<S, S> x) {};
Contra1<A<int, num>> test() => mkA();
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var functionType = body.expression2.staticType as FunctionType;
DartType type = functionType.normalParameterTypes[0];
Element elementA = AstFinder.getClass(
result.unit,
"A",
).declaredFragment!.element;
_isInstantiationOf(_hasElement(elementA))([_isNum, _isNum])(type);
}
test_redirectedConstructor_named() async {
var code = r'''
class A<T, U> implements B<T, U> {
A.named();
}
class B<T2, U2> {
factory B() = A.named;
}
''';
var result = await resolveTestCodeWithDiagnostics(code);
var b = result.unit.declarations[1] as ClassDeclaration;
var classBody = b.body as BlockClassBody;
var bConstructor = classBody.members[0] as ConstructorDeclaration;
var redirected = bConstructor.redirectedConstructor as ConstructorName;
var typeName = redirected.type;
assertType(typeName.type, 'A<T2, U2>');
assertType(typeName.type, 'A<T2, U2>');
var constructorMember = redirected.element!;
expect(constructorMember.displayString(), 'A<T2, U2>.named()');
expect(redirected.name!.element, constructorMember);
}
test_redirectedConstructor_self() async {
await resolveTestCodeWithDiagnostics(r'''
class A<T> {
A();
factory A.redirected() = A;
}
''');
}
test_redirectedConstructor_unnamed() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A<T, U> implements B<T, U> {
A();
}
class B<T2, U2> {
factory B() = A;
}
''');
var b = result.unit.declarations[1] as ClassDeclaration;
var classBody = b.body as BlockClassBody;
var bConstructor = classBody.members[0] as ConstructorDeclaration;
var redirected = bConstructor.redirectedConstructor as ConstructorName;
var typeName = redirected.type;
assertType(typeName.type, 'A<T2, U2>');
assertType(typeName.type, 'A<T2, U2>');
expect(redirected.name, isNull);
expect(redirected.element!.displayString(), 'A<T2, U2>()');
}
test_redirectingConstructor_propagation() async {
String code = r'''
class A {
A() : this.named([]);
A.named(List<String> x);
}
''';
var result = await resolveTestCodeWithDiagnostics(code);
ConstructorDeclaration constructor = AstFinder.getConstructorInClass(
result.unit,
"A",
null,
);
var invocation =
constructor.initializers[0] as RedirectingConstructorInvocation;
var exp = invocation.argumentList.arguments2[0].argumentExpression2;
_isListOf(_isString)(exp.staticType as InterfaceType);
}
test_returnType_variance1() async {
// Check that downwards inference correctly pins a type parameter
// when the parameter is constrained in a contravariant position
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
Func1<T, String> f<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'Func1<T, String>'.
Func1<num, String> test() => f(42);
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var invoke = body.expression2 as MethodInvocation;
_isFunction2Of(_isNum, _isFunction2Of(_isNum, _isString))(
invoke.staticInvokeType!,
);
}
test_returnType_variance2() async {
// Check that downwards inference correctly pins a type parameter
// when the parameter is constrained in a covariant position
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
Func1<String, T> f<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'Func1<String, T>'.
Func1<String, num> test() => f(42);
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var invoke = body.expression2 as MethodInvocation;
_isFunction2Of(_isNum, _isFunction2Of(_isString, _isNum))(
invoke.staticInvokeType!,
);
}
test_returnType_variance3() async {
// Check that the variance heuristic chooses the most precise type
// when the return type uses the variable in a contravariant position
// and there is no downwards constraint.
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
Func1<T, String> f<T>(T x, g(T x)) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'Func1<T, String>'.
dynamic test() => f(42, (num x) => x);
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var functionType = body.expression2.staticType as FunctionType;
DartType type = functionType.normalParameterTypes[0];
_isInt(type);
}
test_returnType_variance4() async {
// Check that the variance heuristic chooses the more precise type
// when the return type uses the variable in a covariant position
// and there is no downwards constraint
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
Func1<String, T> f<T>(T x, g(T x)) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'Func1<String, T>'.
dynamic test() => f(42, (num x) => x);
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var functionType = body.expression2.staticType as FunctionType;
DartType type = functionType.returnType;
_isInt(type);
}
test_returnType_variance5() async {
// Check that pinning works correctly with a partial type
// when the return type uses the variable in a contravariant position
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
Func1<T, String> f<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'Func1<T, String>'.
T g<T, S>(Func1<T, S> f) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'g' because it has a return type of 'T'.
num test() => g(f(3));
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var call = body.expression2 as MethodInvocation;
_isNum(call.typeOrThrow);
_isFunction2Of(_isFunction2Of(_isNum, _isString), _isNum)(
call.staticInvokeType!,
);
}
test_returnType_variance6() async {
// Check that pinning works correctly with a partial type
// when the return type uses the variable in a covariant position
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
Func1<String, T> f<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'Func1<String, T>'.
T g<T, S>(Func1<S, T> f) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'g' because it has a return type of 'T'.
num test() => g(f(3));
''');
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
var call = body.expression2 as MethodInvocation;
_isNum(call.typeOrThrow);
_isFunction2Of(_isFunction2Of(_isString, _isNum), _isNum)(
call.staticInvokeType!,
);
}
test_superConstructorInvocation_propagation() async {
String code = r'''
class B {
B(List<String> p);
}
class A extends B {
A() : super([]);
}
''';
var result = await resolveTestCodeWithDiagnostics(code);
ConstructorDeclaration constructor = AstFinder.getConstructorInClass(
result.unit,
"A",
null,
);
var invocation = constructor.initializers[0] as SuperConstructorInvocation;
var exp = invocation.argumentList.arguments2[0].argumentExpression2;
_isListOf(_isString)(exp.staticType as InterfaceType);
}
/// Verifies the result has a `could_not_infer` diagnostic with
/// the expected [errorMessage].
void _expectInferenceError(
TestResolvedUnitResult result,
String errorMessage,
) {
var errors = result.diagnostics
.where((e) => e.diagnosticCode.lowerCaseUniqueName == 'could_not_infer')
.map((e) => e.message)
.toList();
expect(errors.length, 1);
var actual = errors[0];
expect(
actual,
errorMessage, // Print the literal error message for easy copy+paste:
reason: 'Actual error did not match expected error:\n$actual',
);
}
void _initAssertions(TypeProvider typeProvider) {
var assertions = _assertions;
if (assertions == null) {
assertions = _assertions = TypeAssertions(typeProvider);
_isType = assertions.isType;
_hasElement = assertions.hasElement;
_isInstantiationOf = assertions.isInstantiationOf;
_isInt = assertions.isInt;
_isNever = assertions.isNever;
_isNull = assertions.isNull;
_isNum = assertions.isNum;
_isObject = assertions.isObject;
_isString = assertions.isString;
_isDynamic = assertions.isDynamic;
_isInvalidType = assertions.isInvalidType;
_isListOf = assertions.isListOf;
_isMapOf = assertions.isMapOf;
_isFunction2Of = assertions.isFunction2Of;
_isFutureOf = _isInstantiationOf(_hasElement(typeProvider.futureElement));
_isFutureOrOf = _isInstantiationOf(
_hasElement(typeProvider.futureOrElement),
);
_isFutureOfDynamic = _isFutureOf([_isDynamic]);
_isFutureOfInt = _isFutureOf([_isInt]);
_isFutureOfNull = _isFutureOf([_isNull]);
_isFutureOrOfInt = _isFutureOrOf([_isInt]);
}
}
/// Helper method for testing `FutureOr<T>`.
///
/// Validates that [code] defines a function "test", whose body is an
/// expression that invokes a method. Returns that invocation.
Future<MethodInvocation> _testFutureOr(String code) async {
var fullCode =
"""
import "dart:async";
$code
""";
var result = await resolveTestCodeWithDiagnostics(fullCode);
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
"test",
);
var body = test.functionExpression.body as ExpressionFunctionBody;
return body.expression2 as MethodInvocation;
}
}
@reflectiveTest
class StrongModeStaticTypeAnalyzer2Test extends StaticTypeAnalyzer2TestShared {
test_dynamicObjectGetter_hashCode() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
dynamic a = null;
var foo = a.hashCode;
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
}
''');
expectInitializerType(result, 'foo =', 'int');
}
test_futureOr_promotion1() async {
// Test that promotion from FutureOr<T> to T works for concrete types
String code = r'''
import "dart:async";
dynamic test(FutureOr<int> x) => (x is int) && (x.abs() == 0);
''';
await resolveTestCodeWithDiagnostics(code);
}
test_futureOr_promotion2() async {
// Test that promotion from FutureOr<T> to Future<T> works for concrete
// types
await resolveTestCodeWithDiagnostics(r'''
import "dart:async";
dynamic test(FutureOr<int> x) => (x is Future<int>) &&
(x.then((x) => x) == null);
// ^^^^^^^
// [diag.unnecessaryNullComparisonNeverNullFalse] The operand can't be 'null', so the condition is always 'false'.
''');
}
test_futureOr_promotion3() async {
// Test that promotion from FutureOr<T> to T works for type
// parameters T
String code = r'''
import "dart:async";
dynamic test<T extends num>(FutureOr<T> x) => (x is T) &&
(x.abs() == 0);
''';
await resolveTestCodeWithDiagnostics(code);
}
test_futureOr_promotion4() async {
// Test that promotion from FutureOr<T> to Future<T> works for type
// parameters T
await resolveTestCodeWithDiagnostics(r'''
import "dart:async";
dynamic test<T extends num>(FutureOr<T> x) => (x is Future<T>) &&
(x.then((x) => x) == null);
// ^^^^^^^
// [diag.unnecessaryNullComparisonNeverNullFalse] The operand can't be 'null', so the condition is always 'false'.
''');
}
test_generalizedVoid_assignToVoidOk() async {
await resolveTestCodeWithDiagnostics(r'''
void main() {
void x;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
x = 42;
}
''');
}
test_genericFunction() async {
var result = await resolveTestCodeWithDiagnostics(r'''
T f<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'T'.
''');
var node = result.findNode.functionDeclaration('f<T>');
assertResolvedNodeText(node, r'''
FunctionDeclaration
returnType: NamedType
name: T
element: #E0 T
type: T
name: f
functionExpression: FunctionExpression
typeParameters: TypeParameterList
leftBracket: <
typeParameters
TypeParameter
name: T
declaredFragment: <testLibraryFragment> T@4
defaultType: dynamic
rightBracket: >
parameters: FormalParameterList
leftParenthesis: (
requiredPositionalFormalParameters
RegularFormalParameter
type: NamedType
name: T
element: #E0 T
type: T
name: x
declaredFragment: <testLibraryFragment> x@9
element: isPublic
type: T
rightParenthesis: )
parameters(v1): FormalParameterList
leftParenthesis: (
parameter: RegularFormalParameter
type: NamedType
name: T
element: #E0 T
type: T
name: x
declaredFragment: <testLibraryFragment> x@9
element: isPublic
type: T
rightParenthesis: )
body: ExpressionFunctionBody
functionDefinition: =>
expression2: NullLiteral
literal: null
staticType: Null
semicolon: ;
declaredFragment: <testLibraryFragment> f@2
element: <testLibrary>::@function::f
type: T Function<T>(T)
staticType: T Function<T>(T)
declaredFragment: <testLibraryFragment> f@2
element: <testLibrary>::@function::f
type: T Function<T>(T)
''');
}
test_genericFunction_bounds() async {
var result = await resolveTestCodeWithDiagnostics(r'''
T f<T extends num>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'T'.
''');
var node = result.findNode.functionDeclaration('f<T');
assertResolvedNodeText(node, r'''
FunctionDeclaration
returnType: NamedType
name: T
element: #E0 T
type: T
name: f
functionExpression: FunctionExpression
typeParameters: TypeParameterList
leftBracket: <
typeParameters
TypeParameter
name: T
extendsKeyword: extends
bound: NamedType
name: num
element: dart:core::@class::num
type: num
declaredFragment: <testLibraryFragment> T@4
defaultType: num
rightBracket: >
parameters: FormalParameterList
leftParenthesis: (
requiredPositionalFormalParameters
RegularFormalParameter
type: NamedType
name: T
element: #E0 T
type: T
name: x
declaredFragment: <testLibraryFragment> x@21
element: isPublic
type: T
rightParenthesis: )
parameters(v1): FormalParameterList
leftParenthesis: (
parameter: RegularFormalParameter
type: NamedType
name: T
element: #E0 T
type: T
name: x
declaredFragment: <testLibraryFragment> x@21
element: isPublic
type: T
rightParenthesis: )
body: ExpressionFunctionBody
functionDefinition: =>
expression2: NullLiteral
literal: null
staticType: Null
semicolon: ;
declaredFragment: <testLibraryFragment> f@2
element: <testLibrary>::@function::f
type: T Function<T extends num>(T)
staticType: T Function<T extends num>(T)
declaredFragment: <testLibraryFragment> f@2
element: <testLibrary>::@function::f
type: T Function<T extends num>(T)
''');
}
test_genericFunction_parameter() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void g(T f<T>(T x)) {}
''');
var fType = result.findElement.parameter('f').type;
fType as FunctionType;
assertType(fType, 'T Function<T>(T)');
}
test_genericFunction_static() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
static T f<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
''');
var node = result.findNode.methodDeclaration('f<T>');
assertResolvedNodeText(node, r'''
MethodDeclaration
modifierKeyword: static
returnType: NamedType
name: T
element: #E0 T
type: T
name: f
typeParameters: TypeParameterList
leftBracket: <
typeParameters
TypeParameter
name: T
declaredFragment: <testLibraryFragment> T@26
defaultType: dynamic
rightBracket: >
parameters: FormalParameterList
leftParenthesis: (
requiredPositionalFormalParameters
RegularFormalParameter
type: NamedType
name: T
element: #E0 T
type: T
name: x
declaredFragment: <testLibraryFragment> x@31
element: isPublic
type: T
rightParenthesis: )
parameters(v1): FormalParameterList
leftParenthesis: (
parameter: RegularFormalParameter
type: NamedType
name: T
element: #E0 T
type: T
name: x
declaredFragment: <testLibraryFragment> x@31
element: isPublic
type: T
rightParenthesis: )
body: ExpressionFunctionBody
functionDefinition: =>
expression2: NullLiteral
literal: null
staticType: Null
semicolon: ;
declaredFragment: <testLibraryFragment> f@24
element: <testLibrary>::@class::C::@method::f
type: T Function<T>(T)
''');
}
test_genericFunction_typedef() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef T F<T>(T x);
F f0;
//^^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f0' must be initialized.
class C {
static F f1;
// ^^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f1' must be initialized.
F f2;
// ^^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 'f2' must be initialized.
void g(F f3) { // C
F f4;
f0(3);
f1(3);
f2(3);
f3(3);
f4(3);
// ^^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f4' must be assigned before it can be used.
}
}
class D<S> {
static F f1;
// ^^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f1' must be initialized.
F f2;
// ^^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 'f2' must be initialized.
void g(F f3) { // D
F f4;
f0(3);
f1(3);
f2(3);
f3(3);
f4(3);
// ^^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f4' must be assigned before it can be used.
}
}
''');
checkBody(String className) {
var statements = result.findNode.block('{ // $className').statements;
for (int i = 1; i <= 5; i++) {
Expression exp = (statements[i] as ExpressionStatement).expression2;
expect(exp.staticType, result.typeProvider.dynamicType);
}
}
checkBody("C");
checkBody("D");
}
test_genericFunction_upwardsAndDownwards() async {
// Regression tests for https://github.com/dart-lang/sdk/issues/27586.
var result = await resolveTestCodeWithDiagnostics(r'List<num> x = [1, 2];');
expectInitializerType(result, 'x =', 'List<num>');
}
test_genericFunction_upwardsAndDownwards_Object() async {
// Regression tests for https://github.com/dart-lang/sdk/issues/27625.
var result = await resolveTestCodeWithDiagnostics(r'''
List<Object> aaa = [];
List<Object> bbb = [1, 2, 3];
List<Object> ccc = [null];
// ^^^^
// [diag.listElementTypeNotAssignableNullability] The element type 'Null' can't be assigned to the list type 'Object'.
List<Object> ddd = [1 as dynamic];
List<Object> eee = [new Object()];
''');
expectInitializerType(result, 'aaa =', 'List<Object>');
expectInitializerType(result, 'bbb =', 'List<Object>');
expectInitializerType(result, 'ccc =', 'List<Object>');
expectInitializerType(result, 'ddd =', 'List<Object>');
expectInitializerType(result, 'eee =', 'List<Object>');
}
test_genericMethod() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
List<T> f<T>(E e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'List<T>'.
}
main() {
C<String> cOfString;
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'cOfString' isn't used.
}
''');
assertType(result.findElement.method('f').type, 'List<T> Function<T>(E)');
var cOfString = result.findElement.localVar('cOfString');
var ft = result.inheritanceManager
.getMember3(cOfString.type as InterfaceType, Name(null, 'f'))!
.type;
assertType(ft, 'List<T> Function<T>(String)');
assertType(
ft.instantiate([result.typeProvider.intType]),
'List<int> Function(String)',
);
}
test_genericMethod_explicitTypeParams() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
List<T> f<T>(E e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'List<T>'.
}
main() {
C<String> cOfString;
var x = cOfString.f<int>('hi');
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
// ^^^^^^^^^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'cOfString' must be assigned before it can be used.
}
''');
var f = result.findNode.simple('f<int>').parent2 as MethodInvocation;
var ft = f.staticInvokeType as FunctionType;
assertType(ft, 'List<int> Function(String)');
var x = result.findElement.localVar('x');
expect(x.type, result.typeProvider.listType(result.typeProvider.intType));
}
test_genericMethod_functionExpressionInvocation_explicit() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
T f<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
static T g<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'g' because it has a return type of 'T'.
static T Function<T>(T) h = null;
// ^^^^
// [diag.invalidAssignment] A value of type 'Null' can't be assigned to a variable of type 'T Function<T>(T)'.
}
T topF<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'topF' because it has a return type of 'T'.
var topG = topF;
void test<S>(T Function<T>(T) pf) {
var c = new C<int>();
T lf<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'lf' because it has a return type of 'T'.
var lambdaCall = (<E>(E e) => e)<int>(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'lambdaCall' isn't used.
var methodCall = (c.f)<int>(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'methodCall' isn't used.
var staticCall = (C.g)<int>(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticCall' isn't used.
var staticFieldCall = (C.h)<int>(3);
// ^^^^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticFieldCall' isn't used.
var topFunCall = (topF)<int>(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFunCall' isn't used.
var topFieldCall = (topG)<int>(3);
// ^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFieldCall' isn't used.
var localCall = (lf)<int>(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'localCall' isn't used.
var paramCall = (pf)<int>(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramCall' isn't used.
}
''');
_assertLocalVarType(result, 'lambdaCall', "int");
_assertLocalVarType(result, 'methodCall', "int");
_assertLocalVarType(result, 'staticCall', "int");
_assertLocalVarType(result, 'staticFieldCall', "int");
_assertLocalVarType(result, 'topFunCall', "int");
_assertLocalVarType(result, 'topFieldCall', "int");
_assertLocalVarType(result, 'localCall', "int");
_assertLocalVarType(result, 'paramCall', "int");
}
test_genericMethod_functionExpressionInvocation_functionTypedParameter_explicit() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void test<S>(T pf<T>(T e)) {
var paramCall = (pf)<int>(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramCall' isn't used.
}
''');
_assertLocalVarType(result, 'paramCall', "int");
}
test_genericMethod_functionExpressionInvocation_functionTypedParameter_inferred() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void test<S>(T pf<T>(T e)) {
var paramCall = (pf)(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramCall' isn't used.
}
''');
_assertLocalVarType(result, 'paramCall', "int");
}
test_genericMethod_functionExpressionInvocation_inferred() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
T f<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
static T g<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'g' because it has a return type of 'T'.
static T Function<T>(T) h = null;
// ^^^^
// [diag.invalidAssignment] A value of type 'Null' can't be assigned to a variable of type 'T Function<T>(T)'.
}
T topF<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'topF' because it has a return type of 'T'.
var topG = topF;
void test<S>(T Function<T>(T) pf) {
var c = new C<int>();
T lf<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'lf' because it has a return type of 'T'.
var lambdaCall = (<E>(E e) => e)(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'lambdaCall' isn't used.
var methodCall = (c.f)(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'methodCall' isn't used.
var staticCall = (C.g)(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticCall' isn't used.
var staticFieldCall = (C.h)(3);
// ^^^^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticFieldCall' isn't used.
var topFunCall = (topF)(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFunCall' isn't used.
var topFieldCall = (topG)(3);
// ^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFieldCall' isn't used.
var localCall = (lf)(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'localCall' isn't used.
var paramCall = (pf)(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramCall' isn't used.
}
''');
_assertLocalVarType(result, 'lambdaCall', "int");
_assertLocalVarType(result, 'methodCall', "int");
_assertLocalVarType(result, 'staticCall', "int");
_assertLocalVarType(result, 'staticFieldCall', "int");
_assertLocalVarType(result, 'topFunCall', "int");
_assertLocalVarType(result, 'topFieldCall', "int");
_assertLocalVarType(result, 'localCall', "int");
_assertLocalVarType(result, 'paramCall', "int");
}
test_genericMethod_functionInvocation_explicit() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
T f<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
static T g<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'g' because it has a return type of 'T'.
static T Function<T>(T) h = null;
// ^^^^
// [diag.invalidAssignment] A value of type 'Null' can't be assigned to a variable of type 'T Function<T>(T)'.
}
T topF<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'topF' because it has a return type of 'T'.
var topG = topF;
void test<S>(T Function<T>(T) pf) {
var c = new C<int>();
T lf<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'lf' because it has a return type of 'T'.
var methodCall = c.f<int>(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'methodCall' isn't used.
var staticCall = C.g<int>(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticCall' isn't used.
var staticFieldCall = C.h<int>(3);
// ^^^^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticFieldCall' isn't used.
var topFunCall = topF<int>(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFunCall' isn't used.
var topFieldCall = topG<int>(3);
// ^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFieldCall' isn't used.
var localCall = lf<int>(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'localCall' isn't used.
var paramCall = pf<int>(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramCall' isn't used.
}
''');
_assertLocalVarType(result, 'methodCall', "int");
_assertLocalVarType(result, 'staticCall', "int");
_assertLocalVarType(result, 'staticFieldCall', "int");
_assertLocalVarType(result, 'topFunCall', "int");
_assertLocalVarType(result, 'topFieldCall', "int");
_assertLocalVarType(result, 'localCall', "int");
_assertLocalVarType(result, 'paramCall', "int");
}
test_genericMethod_functionInvocation_functionTypedParameter_explicit() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void test<S>(T pf<T>(T e)) {
var paramCall = pf<int>(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramCall' isn't used.
}
''');
_assertLocalVarType(result, 'paramCall', "int");
}
test_genericMethod_functionInvocation_functionTypedParameter_inferred() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void test<S>(T pf<T>(T e)) {
var paramCall = pf(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramCall' isn't used.
}
''');
_assertLocalVarType(result, 'paramCall', "int");
}
test_genericMethod_functionInvocation_inferred() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
T f<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
static T g<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'g' because it has a return type of 'T'.
static T Function<T>(T) h = null;
// ^^^^
// [diag.invalidAssignment] A value of type 'Null' can't be assigned to a variable of type 'T Function<T>(T)'.
}
T topF<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'topF' because it has a return type of 'T'.
var topG = topF;
void test<S>(T Function<T>(T) pf) {
var c = new C<int>();
T lf<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'lf' because it has a return type of 'T'.
var methodCall = c.f(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'methodCall' isn't used.
var staticCall = C.g(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticCall' isn't used.
var staticFieldCall = C.h(3);
// ^^^^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticFieldCall' isn't used.
var topFunCall = topF(3);
// ^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFunCall' isn't used.
var topFieldCall = topG(3);
// ^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFieldCall' isn't used.
var localCall = lf(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'localCall' isn't used.
var paramCall = pf(3);
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramCall' isn't used.
}
''');
_assertLocalVarType(result, 'methodCall', "int");
_assertLocalVarType(result, 'staticCall', "int");
_assertLocalVarType(result, 'staticFieldCall', "int");
_assertLocalVarType(result, 'topFunCall', "int");
_assertLocalVarType(result, 'topFieldCall', "int");
_assertLocalVarType(result, 'localCall', "int");
_assertLocalVarType(result, 'paramCall', "int");
}
test_genericMethod_functionTypedParameter() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
List<T> f<T>(T f(E e)) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'List<T>'.
}
main() {
C<String> cOfString;
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'cOfString' isn't used.
}
''');
assertType(
result.findElement.method('f').type,
'List<T> Function<T>(T Function(E))',
);
var cOfString = result.findElement.localVar('cOfString');
var ft = result.inheritanceManager
.getMember3(cOfString.type as InterfaceType, Name(null, 'f'))!
.type;
assertType(ft, 'List<T> Function<T>(T Function(String))');
assertType(
ft.instantiate([result.typeProvider.intType]),
'List<int> Function(int Function(String))',
);
}
test_genericMethod_functionTypedParameter_tearoff() async {
var result = await resolveTestCodeWithDiagnostics(r'''
void test<S>(T pf<T>(T e)) {
var paramTearOff = pf;
// ^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramTearOff' isn't used.
}
''');
_assertLocalVarType(result, 'paramTearOff', "T Function<T>(T)");
}
test_genericMethod_implicitDynamic() async {
// Regression test for:
// https://github.com/dart-lang/sdk/issues/25100#issuecomment-162047588
// These should not cause any hints or warnings.
var result = await resolveTestCodeWithDiagnostics(r'''
class List<E> {
T map<T>(T f(E e)) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'map' because it has a return type of 'T'.
}
void foo() {
List list = null;
// ^^^^
// [diag.invalidAssignment] A value of type 'Null' can't be assigned to a variable of type 'List<dynamic>'.
list.map((e) => e);
list.map((e) => 3);
}''');
var node1 = result.findNode.methodInvocation('map((e) => e);');
assertResolvedNodeText(node1, r'''
MethodInvocation
target2: SimpleIdentifier
token: list
element: list@68
staticType: List<dynamic>
operator: .
methodName: SimpleIdentifier
token: map
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::List::@method::map
substitution: {E: dynamic, T: T}
staticType: T Function<T>(T Function(dynamic))
argumentList: ArgumentList
leftParenthesis: (
arguments2
FunctionExpression
parameters: FormalParameterList
leftParenthesis: (
requiredPositionalFormalParameters
RegularFormalParameter
name: e
declaredFragment: <testLibraryFragment> e@93
element: hasImplicitType isPublic
type: dynamic
rightParenthesis: )
parameters(v1): FormalParameterList
leftParenthesis: (
parameter: RegularFormalParameter
name: e
declaredFragment: <testLibraryFragment> e@93
element: hasImplicitType isPublic
type: dynamic
rightParenthesis: )
body: ExpressionFunctionBody
functionDefinition: =>
expression2: SimpleIdentifier
token: e
element: e@93
staticType: dynamic
declaredFragment: <testLibraryFragment> null@null
element: null@null
type: dynamic Function(dynamic)
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: f@null
substitution: {T: dynamic}
staticType: dynamic Function(dynamic)
rightParenthesis: )
staticInvokeType: dynamic Function(dynamic Function(dynamic))
staticType: dynamic
typeArgumentTypes
dynamic
''');
var node2 = result.findNode.methodInvocation('map((e) => 3);');
assertResolvedNodeText(node2, r'''
MethodInvocation
target2: SimpleIdentifier
token: list
element: list@68
staticType: List<dynamic>
operator: .
methodName: SimpleIdentifier
token: map
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::List::@method::map
substitution: {E: dynamic, T: T}
staticType: T Function<T>(T Function(dynamic))
argumentList: ArgumentList
leftParenthesis: (
arguments2
FunctionExpression
parameters: FormalParameterList
leftParenthesis: (
requiredPositionalFormalParameters
RegularFormalParameter
name: e
declaredFragment: <testLibraryFragment> e@115
element: hasImplicitType isPublic
type: dynamic
rightParenthesis: )
parameters(v1): FormalParameterList
leftParenthesis: (
parameter: RegularFormalParameter
name: e
declaredFragment: <testLibraryFragment> e@115
element: hasImplicitType isPublic
type: dynamic
rightParenthesis: )
body: ExpressionFunctionBody
functionDefinition: =>
expression2: IntegerLiteral
literal: 3
staticType: int
declaredFragment: <testLibraryFragment> null@null
element: null@null
type: int Function(dynamic)
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: f@null
substitution: {T: int}
staticType: int Function(dynamic)
rightParenthesis: )
staticInvokeType: int Function(int Function(dynamic))
staticType: int
typeArgumentTypes
int
''');
}
test_genericMethod_max_doubleDouble() async {
var result = await resolveTestCodeWithDiagnostics(r'''
import 'dart:math';
main() {
var foo = max(1.0, 2.0);
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
}
''');
expectInitializerType(result, 'foo =', 'double');
}
test_genericMethod_max_doubleDouble_prefixed() async {
var result = await resolveTestCodeWithDiagnostics(r'''
import 'dart:math' as math;
main() {
var foo = math.max(1.0, 2.0);
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
}
''');
expectInitializerType(result, 'foo =', 'double');
}
test_genericMethod_max_doubleInt() async {
var result = await resolveTestCodeWithDiagnostics(r'''
import 'dart:math';
main() {
var foo = max(1.0, 2);
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
}
''');
expectInitializerType(result, 'foo =', 'num');
}
test_genericMethod_max_intDouble() async {
var result = await resolveTestCodeWithDiagnostics(r'''
import 'dart:math';
main() {
var foo = max(1, 2.0);
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
}
''');
expectInitializerType(result, 'foo =', 'num');
}
test_genericMethod_max_intInt() async {
var result = await resolveTestCodeWithDiagnostics(r'''
import 'dart:math';
main() {
var foo = max(1, 2);
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
}
''');
expectInitializerType(result, 'foo =', 'int');
}
test_genericMethod_nestedBound() async {
// Just validate that there is no warning on the call to `.abs()`.
await resolveTestCodeWithDiagnostics(r'''
class Foo<T extends num> {
void method<U extends T>(U u) {
u.abs();
}
}
''');
}
test_genericMethod_nestedCapture() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T> {
T f<S>(S x) {
new C<S>().f<int>(3);
new C<S>().f; // tear-off
return null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
}
''');
var node1 = result.findNode.methodInvocation('f<int>(3);');
assertResolvedNodeText(node1, r'''
MethodInvocation
target2: InstanceCreationExpression
keyword: new
constructorName: ConstructorName
type: NamedType
name: C
typeArguments: TypeArgumentList
leftBracket: <
arguments
NamedType
name: S
element: #E0 S
type: S
rightBracket: >
element: <testLibrary>::@class::C
type: C<S>
element: SubstitutedConstructorElementImpl
baseElement: <testLibrary>::@class::C::@constructor::new
substitution: {T: S}
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticType: C<S>
operator: .
methodName: SimpleIdentifier
token: f
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::C::@method::f
substitution: {T: S, S: S}
staticType: S Function<Sâ‚€>(Sâ‚€)
typeArguments: TypeArgumentList
leftBracket: <
arguments
NamedType
name: int
element: dart:core::@class::int
type: int
rightBracket: >
argumentList: ArgumentList
leftParenthesis: (
arguments2
IntegerLiteral
literal: 3
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: x@null
substitution: {S: int}
staticType: int
rightParenthesis: )
staticInvokeType: S Function(int)
staticType: S
typeArgumentTypes
int
''');
}
test_genericMethod_nestedCaptureBounds() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T> {
T f<S extends T>(S x) {
new C<S>().f<int>(3);
// ^^^
// [diag.typeArgumentNotMatchingBounds] 'int' doesn't conform to the bound 'S' of the type parameter 'S'.
new C<S>().f; // tear-off
return null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
}
''');
var node1 = result.findNode.methodInvocation('f<int>(3);');
assertResolvedNodeText(node1, r'''
MethodInvocation
target2: InstanceCreationExpression
keyword: new
constructorName: ConstructorName
type: NamedType
name: C
typeArguments: TypeArgumentList
leftBracket: <
arguments
NamedType
name: S
element: #E0 S
type: S
rightBracket: >
element: <testLibrary>::@class::C
type: C<S>
element: SubstitutedConstructorElementImpl
baseElement: <testLibrary>::@class::C::@constructor::new
substitution: {T: S}
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticType: C<S>
operator: .
methodName: SimpleIdentifier
token: f
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::C::@method::f
substitution: {T: S, S: S}
staticType: S Function<Sâ‚€ extends S>(Sâ‚€)
typeArguments: TypeArgumentList
leftBracket: <
arguments
NamedType
name: int
element: dart:core::@class::int
type: int
rightBracket: >
argumentList: ArgumentList
leftParenthesis: (
arguments2
IntegerLiteral
literal: 3
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: x@null
substitution: {S: int}
staticType: int
rightParenthesis: )
staticInvokeType: S Function(int)
staticType: S
typeArgumentTypes
int
''');
var node2 = result.findNode.simple('f;');
assertResolvedNodeText(node2, r'''
SimpleIdentifier
token: f
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::C::@method::f
substitution: {T: S, S: S}
staticType: S Function<Sâ‚€ extends S>(Sâ‚€)
''');
}
test_genericMethod_nestedFunctions() async {
var result = await resolveTestCodeWithDiagnostics(r'''
S f<S>(S x) {
g<S>(S x) => f;
//^
// [diag.unusedElement] The declaration 'g' isn't referenced.
return null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'S'.
}
''');
assertType(result.findElement.topFunction('f').type, 'S Function<S>(S)');
assertType(
result.findElement.localFunction('g').type,
'S Function<S>(S) Function<Sâ‚€>(Sâ‚€)',
);
}
test_genericMethod_override() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C {
T f<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
class D extends C {
T f<T>(T y) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
''');
var node = result.findNode.methodDeclaration('f<T>(T y)');
assertResolvedNodeText(node, r'''
MethodDeclaration
returnType: NamedType
name: T
element: #E0 T
type: T
name: f
typeParameters: TypeParameterList
leftBracket: <
typeParameters
TypeParameter
name: T
declaredFragment: <testLibraryFragment> T@61
defaultType: dynamic
rightBracket: >
parameters: FormalParameterList
leftParenthesis: (
requiredPositionalFormalParameters
RegularFormalParameter
type: NamedType
name: T
element: #E0 T
type: T
name: y
declaredFragment: <testLibraryFragment> y@66
element: isPublic
type: T
rightParenthesis: )
parameters(v1): FormalParameterList
leftParenthesis: (
parameter: RegularFormalParameter
type: NamedType
name: T
element: #E0 T
type: T
name: y
declaredFragment: <testLibraryFragment> y@66
element: isPublic
type: T
rightParenthesis: )
body: ExpressionFunctionBody
functionDefinition: =>
expression2: NullLiteral
literal: null
staticType: Null
semicolon: ;
declaredFragment: <testLibraryFragment> f@59
element: <testLibrary>::@class::D::@method::f
type: T Function<T>(T)
''');
}
test_genericMethod_override_bounds() async {
await resolveTestCodeWithDiagnostics(r'''
class A {}
class B {
T f<T extends A>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
// override with the same bound is OK
class C extends B {
T f<T extends A>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
// override with new name and the same bound is OK
class D extends B {
Q f<Q extends A>(Q x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'Q'.
}
''');
}
test_genericMethod_override_covariant_field() async {
await resolveTestCodeWithDiagnostics(r'''
abstract class A {
num get x;
set x(covariant num _);
}
class B extends A {
int x;
// ^
// [diag.notInitializedNonNullableInstanceField] Non-nullable instance field 'x' must be initialized.
}
''');
}
test_genericMethod_override_differentContextsSameBounds() async {
await resolveTestCodeWithDiagnostics(r'''
class GenericMethodBounds<T> {
Type get t => T;
GenericMethodBounds<E> foo<E extends T>() => new GenericMethodBounds<E>();
GenericMethodBounds<E> bar<E extends void Function(T)>() =>
new GenericMethodBounds<E>();
}
class GenericMethodBoundsDerived extends GenericMethodBounds<num> {
GenericMethodBounds<E> foo<E extends num>() => new GenericMethodBounds<E>();
GenericMethodBounds<E> bar<E extends void Function(num)>() =>
new GenericMethodBounds<E>();
}
''');
}
test_genericMethod_override_invalidContravariantTypeParamBounds() async {
await resolveTestCodeWithDiagnostics(r'''
class A {}
class B extends A {}
class C {
T f<T extends A>(T x) => null;
// ^
// [context 1] The member being overridden.
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
class D extends C {
T f<T extends B>(T x) => null;
// ^
// [diag.invalidOverride][context 1] 'D.f' ('T Function<T extends B>(T)') isn't a valid override of 'C.f' ('T Function<T extends A>(T)').
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}''');
}
test_genericMethod_override_invalidCovariantTypeParamBounds() async {
await resolveTestCodeWithDiagnostics(r'''
class A {}
class B extends A {}
class C {
T f<T extends B>(T x) => null;
// ^
// [context 1] The member being overridden.
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
class D extends C {
T f<T extends A>(T x) => null;
// ^
// [diag.invalidOverride][context 1] 'D.f' ('T Function<T extends A>(T)') isn't a valid override of 'C.f' ('T Function<T extends B>(T)').
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}''');
}
test_genericMethod_override_invalidReturnType() async {
await resolveTestCodeWithDiagnostics(r'''
class C {
Iterable<T> f<T>(T x) => null;
// ^
// [context 1] The member being overridden.
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'Iterable<T>'.
}
class D extends C {
String f<S>(S x) => null;
// ^
// [diag.invalidOverride][context 1] 'D.f' ('String Function<S>(S)') isn't a valid override of 'C.f' ('Iterable<T> Function<T>(T)').
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'String'.
}''');
}
test_genericMethod_override_invalidTypeParamCount() async {
await resolveTestCodeWithDiagnostics(r'''
class C {
T f<T>(T x) => null;
// ^
// [context 1] The member being overridden.
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
}
class D extends C {
S f<T, S>(T x) => null;
// ^
// [diag.invalidOverride][context 1] 'D.f' ('S Function<T, S>(T)') isn't a valid override of 'C.f' ('T Function<T>(T)').
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'S'.
}''');
}
test_genericMethod_propagatedType_promotion() async {
// Regression test for:
// https://github.com/dart-lang/sdk/issues/25340
// Note, after https://github.com/dart-lang/sdk/issues/25486 the original
// example won't work, as we now compute a static type and therefore discard
// the propagated type. So a new test was created that doesn't run under
// strong mode.
var result = await resolveTestCodeWithDiagnostics(r'''
abstract class Iter {
List<S> map<S>(S f(x));
}
class C {}
C toSpan(dynamic element) {
if (element is Iter) {
var y = element.map(toSpan);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'y' isn't used.
}
return null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'toSpan' because it has a return type of 'C'.
}
''');
_assertLocalVarType(result, 'y', 'List<C>');
}
test_genericMethod_tearoff() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
T f<T>(E e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'f' because it has a return type of 'T'.
static T g<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'g' because it has a return type of 'T'.
static T Function<T>(T) h = null;
// ^^^^
// [diag.invalidAssignment] A value of type 'Null' can't be assigned to a variable of type 'T Function<T>(T)'.
}
T topF<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'topF' because it has a return type of 'T'.
var topG = topF;
void test<S>(T Function<T>(T) pf) {
var c = new C<int>();
T lf<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'lf' because it has a return type of 'T'.
var methodTearOff = c.f;
// ^^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'methodTearOff' isn't used.
var staticTearOff = C.g;
// ^^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticTearOff' isn't used.
var staticFieldTearOff = C.h;
// ^^^^^^^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'staticFieldTearOff' isn't used.
var topFunTearOff = topF;
// ^^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFunTearOff' isn't used.
var topFieldTearOff = topG;
// ^^^^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'topFieldTearOff' isn't used.
var localTearOff = lf;
// ^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'localTearOff' isn't used.
var paramTearOff = pf;
// ^^^^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'paramTearOff' isn't used.
}
''');
_assertLocalVarType(result, 'methodTearOff', "T Function<T>(int)");
_assertLocalVarType(result, 'staticTearOff', "T Function<T>(T)");
_assertLocalVarType(result, 'staticFieldTearOff', "T Function<T>(T)");
_assertLocalVarType(result, 'topFunTearOff', "T Function<T>(T)");
_assertLocalVarType(result, 'topFieldTearOff', "T Function<T>(T)");
_assertLocalVarType(result, 'localTearOff', "T Function<T>(T)");
_assertLocalVarType(result, 'paramTearOff', "T Function<T>(T)");
}
@FailingTest() // TODO(scheglov): fix it
test_genericMethod_tearoff_instantiated() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
T f<T>(E e) => null;
static T g<T>(T e) => null;
static T Function<T>(T) h = null;
}
T topF<T>(T e) => null;
var topG = topF;
void test<S>(T pf<T>(T e)) {
var c = new C<int>();
T lf<T>(T e) => null;
var methodTearOffInst = c.f<int>;
var staticTearOffInst = C.g<int>;
var staticFieldTearOffInst = C.h<int>;
var topFunTearOffInst = topF<int>;
var topFieldTearOffInst = topG<int>;
var localTearOffInst = lf<int>;
var paramTearOffInst = pf<int>;
}
''');
expectIdentifierType(result, 'methodTearOffInst', "int Function(int)");
expectIdentifierType(result, 'staticTearOffInst', "int Function(int)");
expectIdentifierType(result, 'staticFieldTearOffInst', "int Function(int)");
expectIdentifierType(result, 'topFunTearOffInst', "int Function(int)");
expectIdentifierType(result, 'topFieldTearOffInst', "int Function(int)");
expectIdentifierType(result, 'localTearOffInst', "int Function(int)");
expectIdentifierType(result, 'paramTearOffInst', "int Function(int)");
}
test_genericMethod_then() async {
var result = await resolveTestCodeWithDiagnostics(r'''
String toString(int x) => x.toString();
main() {
Future<int> bar = null;
// ^^^^
// [diag.invalidAssignment] A value of type 'Null' can't be assigned to a variable of type 'Future<int>'.
var foo = bar.then(toString);
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
}
''');
expectInitializerType(result, 'foo =', 'Future<String>');
}
test_genericMethod_then_prefixed() async {
var result = await resolveTestCodeWithDiagnostics(r'''
import 'dart:async' as async;
String toString(int x) => x.toString();
main() {
async.Future<int> bar = null;
// ^^^^
// [diag.invalidAssignment] A value of type 'Null' can't be assigned to a variable of type 'Future<int>'.
var foo = bar.then(toString);
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
}
''');
expectInitializerType(result, 'foo =', 'Future<String>');
}
test_genericMethod_then_propagatedType() async {
// Regression test for https://github.com/dart-lang/sdk/issues/25482.
var result = await resolveTestCodeWithDiagnostics(r'''
void main() {
Future<String> p;
var foo = p.then((r) => new Future<String>.value(3));
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'p' must be assigned before it can be used.
// ^
// [diag.argumentTypeNotAssignable] The argument type 'int' can't be assigned to the parameter type 'FutureOr<String>?'.
}
''');
// Note: this correctly reports the error
// CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE when run with the driver;
// when run without the driver, it reports no errors. So we don't bother
// checking whether the correct errors were reported.
expectInitializerType(result, 'foo =', 'Future<String>');
}
test_genericMethod_toplevel_field_staticTearoff() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<E> {
static T g<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'g' because it has a return type of 'T'.
static T Function<T>(T) h = null;
// ^^^^
// [diag.invalidAssignment] A value of type 'Null' can't be assigned to a variable of type 'T Function<T>(T)'.
}
void test() {
var fieldRead = C.h;
// ^^^^^^^^^
// [diag.unusedLocalVariable] The value of the local variable 'fieldRead' isn't used.
}
''');
_assertLocalVarType(result, 'fieldRead', "T Function<T>(T)");
}
test_implicitBounds() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A<T> {}
class B<T extends num> {}
class C<S extends int, T extends B<S>, U extends A> {}
void test() {
A ai;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'ai' isn't used.
B bi;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'bi' isn't used.
C ci;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'ci' isn't used.
var aa = new A();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'aa' isn't used.
var bb = new B();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'bb' isn't used.
var cc = new C();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 'cc' isn't used.
}
''');
_assertLocalVarType(result, 'ai', "A<dynamic>");
_assertLocalVarType(result, 'bi', "B<num>");
_assertLocalVarType(result, 'ci', "C<int, B<int>, A<dynamic>>");
_assertLocalVarType(result, 'aa', "A<dynamic>");
_assertLocalVarType(result, 'bb', "B<num>");
_assertLocalVarType(result, 'cc', "C<int, B<int>, A<dynamic>>");
}
test_instantiateToBounds_class_error_extension_malbounded() async {
// Test that superclasses are strictly checked for malbounded default
// types
await resolveTestCodeWithDiagnostics(r'''
class C<T0 extends List<T1>, T1 extends List<T0>> {}
class D extends C {}
// ^
// [context 1] The raw type was instantiated as 'C<List<dynamic>, List<dynamic>>', and is not regular-bounded.
// [context 2] The raw type was instantiated as 'C<List<dynamic>, List<dynamic>>', and is not regular-bounded.
// [diag.typeArgumentNotMatchingBounds][context 1] 'List<dynamic>' doesn't conform to the bound 'List<List<dynamic>>' of the type parameter 'T0'.
// [diag.typeArgumentNotMatchingBounds][context 2] 'List<dynamic>' doesn't conform to the bound 'List<List<dynamic>>' of the type parameter 'T1'.
''');
}
test_instantiateToBounds_class_error_instantiation_malbounded() async {
// Test that instance creations are strictly checked for malbounded default
// types
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T0 extends List<T1>, T1 extends List<T0>> {}
void test() {
var c = new C();
// ^
// [diag.unusedLocalVariable] The value of the local variable 'c' isn't used.
// ^
// [context 1] The raw type was instantiated as 'C<List<Object?>, List<List<Object?>>>', and is not regular-bounded.
// [diag.couldNotInfer] Couldn't infer type parameter 'T0'.\n\nTried to infer 'List<Object?>' for 'T0' which doesn't work:\n Type parameter 'T0' is declared to extend 'List<T1>' producing 'List<List<List<Object?>>>'.\n\nConsider passing explicit type argument(s) to the generic.
// [diag.typeArgumentNotMatchingBounds][context 1] 'List<Object?>' doesn't conform to the bound 'List<List<List<Object?>>>' of the type parameter 'T0'.
}
''');
_assertLocalVarType(result, 'c', 'C<List<Object?>, List<List<Object?>>>');
}
test_instantiateToBounds_class_error_recursion() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T0 extends List<T1>, T1 extends List<T0>> {}
C c;
//^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'c' must be initialized.
''');
_assertTopVarType(result, 'c', 'C<List<dynamic>, List<dynamic>>');
}
test_instantiateToBounds_class_error_recursion_self() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T extends C<T>> {}
C c;
//^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'c' must be initialized.
''');
_assertTopVarType(result, 'c', 'C<C<dynamic>>');
}
test_instantiateToBounds_class_error_recursion_self2() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A<E> {}
class C<T extends A<T>> {}
C c;
//^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'c' must be initialized.
''');
_assertTopVarType(result, 'c', 'C<A<dynamic>>');
}
test_instantiateToBounds_class_error_typedef() async {
var result = await resolveTestCodeWithDiagnostics(r'''
typedef T F<T>(T x);
class C<T extends F<T>> {}
C c;
// [context 1][column 1][length 1] The raw type was instantiated as 'C<dynamic Function(dynamic)>', and is not regular-bounded.
// [context 2][column 1][length 1] The inverted type 'C<Never Function(Never)>' is also not regular-bounded, so the type is not well-bounded.
// [diag.typeArgumentNotMatchingBounds][column 1][length 1][context 1][context 2] 'F<Never>' doesn't conform to the bound 'F<F<Never>>' of the type parameter 'T'.
//^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'c' must be initialized.
''');
_assertTopVarType(result, 'c', 'C<dynamic Function(dynamic)>');
}
test_instantiateToBounds_class_ok_implicitDynamic_multi() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T0 extends Map<T1, T2>, T1 extends List, T2 extends int> {}
C c;
//^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'c' must be initialized.
''');
_assertTopVarType(
result,
'c',
'C<Map<List<dynamic>, int>, List<dynamic>, int>',
);
}
test_instantiateToBounds_class_ok_referenceOther_after() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T0 extends T1, T1 extends int> {}
C c;
//^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'c' must be initialized.
''');
_assertTopVarType(result, 'c', 'C<int, int>');
}
test_instantiateToBounds_class_ok_referenceOther_after2() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T0 extends Map<T1, T1>, T1 extends int> {}
C c;
//^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'c' must be initialized.
''');
_assertTopVarType(result, 'c', 'C<Map<int, int>, int>');
}
test_instantiateToBounds_class_ok_referenceOther_before() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T0 extends int, T1 extends T0> {}
C c;
//^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'c' must be initialized.
''');
_assertTopVarType(result, 'c', 'C<int, int>');
}
test_instantiateToBounds_class_ok_referenceOther_multi() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T0 extends Map<T1, T2>, T1 extends List<T2>, T2 extends int> {}
C c;
//^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'c' must be initialized.
''');
_assertTopVarType(result, 'c', 'C<Map<List<int>, int>, List<int>, int>');
}
test_instantiateToBounds_class_ok_simpleBounds() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A<T> {}
class B<T extends num> {}
class C<T extends List<int>> {}
class D<T extends A> {}
void main() {
A a;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'a' isn't used.
B b;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'b' isn't used.
C c;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'c' isn't used.
D d;
// ^
// [diag.unusedLocalVariable] The value of the local variable 'd' isn't used.
}
''');
_assertLocalVarType(result, 'a', 'A<dynamic>');
_assertLocalVarType(result, 'b', 'B<num>');
_assertLocalVarType(result, 'c', 'C<List<int>>');
_assertLocalVarType(result, 'd', 'D<A<dynamic>>');
}
test_instantiateToBounds_generic_function_error_malbounded() async {
// Test that generic methods are strictly checked for malbounded default
// types
var result = await resolveTestCodeWithDiagnostics(r'''
T0 f<T0 extends List<T1>, T1 extends List<T0>>() {}
// ^
// [diag.bodyMightCompleteNormally] The body might complete normally, causing 'null' to be returned, but the return type, 'T0', is a potentially non-nullable type.
void g() {
var c = f();
// ^
// [diag.unusedLocalVariable] The value of the local variable 'c' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T0'.\n\nTried to infer 'List<Object?>' for 'T0' which doesn't work:\n Type parameter 'T0' is declared to extend 'List<T1>' producing 'List<List<List<Object?>>>'.\n\nConsider passing explicit type argument(s) to the generic.
return;
}
''');
_assertLocalVarType(result, 'c', 'List<Object?>');
}
test_instantiateToBounds_method_ok_referenceOther_before() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T> {
void m<S0 extends T, S1 extends List<S0>>(S0 p0, S1 p1) {}
void main() {
m(null, null);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'T'.
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'List<T>'.
}
}
''');
var node = result.findNode.singleMethodInvocation;
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: m
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::C::@method::m
substitution: {T: T, S0: S0, S1: S1}
staticType: void Function<S0 extends T, S1 extends List<S0>>(S0, S1)
argumentList: ArgumentList
leftParenthesis: (
arguments2
NullLiteral
literal: null
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: p0@null
substitution: {S0: T, S1: List<T>}
staticType: Null
NullLiteral
literal: null
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: p1@null
substitution: {S0: T, S1: List<T>}
staticType: Null
rightParenthesis: )
staticInvokeType: void Function(T, List<T>)
staticType: void
typeArgumentTypes
T
List<T>
''');
}
test_instantiateToBounds_method_ok_referenceOther_before2() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T> {
Map<S0, S1> m<S0 extends T, S1 extends List<S0>>() => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'm' because it has a return type of 'Map<S0, S1>'.
void main() {
m();
}
}
''');
var node = result.findNode.singleMethodInvocation;
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: m
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::C::@method::m
substitution: {T: T, S0: S0, S1: S1}
staticType: Map<S0, S1> Function<S0 extends T, S1 extends List<S0>>()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: Map<T, List<T>> Function()
staticType: Map<T, List<T>>
typeArgumentTypes
T
List<T>
''');
}
test_instantiateToBounds_method_ok_simpleBounds() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T> {
void m<S extends T>(S p0) {}
void main() {
m(null);
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'T'.
}
}
''');
var node = result.findNode.singleMethodInvocation;
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: m
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::C::@method::m
substitution: {T: T, S: S}
staticType: void Function<S extends T>(S)
argumentList: ArgumentList
leftParenthesis: (
arguments2
NullLiteral
literal: null
correspondingParameter: SubstitutedFormalParameterElementImpl
baseElement: p0@null
substitution: {S: T}
staticType: Null
rightParenthesis: )
staticInvokeType: void Function(T)
staticType: void
typeArgumentTypes
T
''');
}
test_instantiateToBounds_method_ok_simpleBounds2() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T> {
S m<S extends T>() => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'm' because it has a return type of 'S'.
void main() {
m();
}
}
''');
var node = result.findNode.singleMethodInvocation;
assertResolvedNodeText(node, r'''
MethodInvocation
methodName: SimpleIdentifier
token: m
element: SubstitutedMethodElementImpl
baseElement: <testLibrary>::@class::C::@method::m
substitution: {T: T, S: S}
staticType: S Function<S extends T>()
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
staticInvokeType: T Function()
staticType: T
typeArgumentTypes
T
''');
}
test_issue32396() async {
await resolveTestCodeWithDiagnostics(r'''
class C<E> {
static T g<T>(T e) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromMethod] A value of type 'Null' can't be returned from the method 'g' because it has a return type of 'T'.
static final h = g;
}
''');
}
test_objectMethodOnFunctions_Anonymous() async {
await _objectMethodOnFunctions_helper2(r'''
void main() {
var f = (x) => 3;
// No errors, correct type
var t0 = f.toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't0' isn't used.
var t1 = f.toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't1' isn't used.
var t2 = f.hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't2' isn't used.
// Expressions, no errors, correct type
var t3 = (f).toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't3' isn't used.
var t4 = (f).toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't4' isn't used.
var t5 = (f).hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't5' isn't used.
// Cascades, no errors
f..toString();
f..toString;
f..hashCode;
// Expression cascades, no errors
(f)..toString();
(f)..toString;
(f)..hashCode;
}
''');
}
test_objectMethodOnFunctions_Function() async {
await _objectMethodOnFunctions_helper2(r'''
void main() {
Function f;
// No errors, correct type
var t0 = f.toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't0' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t1 = f.toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't1' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t2 = f.hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't2' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Expressions, no errors, correct type
var t3 = (f).toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't3' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t4 = (f).toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't4' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t5 = (f).hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't5' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Cascades, no errors
f..toString();
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
f..toString;
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
f..hashCode;
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Expression cascades, no errors
(f)..toString();
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
(f)..toString;
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
(f)..hashCode;
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
}
''');
}
test_objectMethodOnFunctions_Static() async {
await _objectMethodOnFunctions_helper2(r'''
int f(int x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'int'.
void main() {
// No errors, correct type
var t0 = f.toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't0' isn't used.
var t1 = f.toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't1' isn't used.
var t2 = f.hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't2' isn't used.
// Expressions, no errors, correct type
var t3 = (f).toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't3' isn't used.
var t4 = (f).toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't4' isn't used.
var t5 = (f).hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't5' isn't used.
// Cascades, no errors
f..toString();
f..toString;
f..hashCode;
// Expression cascades, no errors
(f)..toString();
(f)..toString;
(f)..hashCode;
}
''');
}
test_objectMethodOnFunctions_Typedef() async {
await _objectMethodOnFunctions_helper2(r'''
typedef bool Predicate<T>(T object);
void main() {
Predicate<int> f;
// No errors, correct type
var t0 = f.toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't0' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t1 = f.toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't1' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t2 = f.hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't2' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Expressions, no errors, correct type
var t3 = (f).toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't3' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t4 = (f).toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't4' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t5 = (f).hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't5' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Cascades, no errors
f..toString();
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
f..toString;
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
f..hashCode;
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Expression cascades, no errors
(f)..toString();
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
(f)..toString;
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
(f)..hashCode;
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
}
''');
}
test_returnOfInvalidType_object_void() async {
await resolveTestCodeWithDiagnostics(r'''
Object f() { void voidFn() => null; return voidFn(); }
// ^^^^^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'void' can't be returned from the function 'f' because it has a return type of 'Object'.
''');
}
test_setterWithDynamicTypeIsError() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
dynamic set f(String s) => null;
//^^^^^^^
// [diag.nonVoidReturnForSetter] The return type of the setter must be 'void' or absent.
}
dynamic set g(int x) => null;
// [diag.nonVoidReturnForSetter][column 1][length 7] The return type of the setter must be 'void' or absent.
''');
}
test_setterWithExplicitVoidType_returningVoid() async {
await resolveTestCodeWithDiagnostics(r'''
void returnsVoid() {}
class A {
void set f(String s) => returnsVoid();
}
void set g(int x) => returnsVoid();
''');
}
test_setterWithNoVoidType() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
set f(String s) {
return '42';
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'String' can't be returned from the function 'f' because it has a return type of 'void'.
}
}
set g(int x) => 42;
''');
}
test_setterWithNoVoidType_returningVoid() async {
await resolveTestCodeWithDiagnostics(r'''
void returnsVoid() {}
class A {
set f(String s) => returnsVoid();
}
set g(int x) => returnsVoid();
''');
}
test_setterWithOtherTypeIsError() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
String set f(String s) => null;
//^^^^^^
// [diag.nonVoidReturnForSetter] The return type of the setter must be 'void' or absent.
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'String'.
}
Object set g(x) => null;
// [diag.nonVoidReturnForSetter][column 1][length 6] The return type of the setter must be 'void' or absent.
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'g' because it has a return type of 'Object'.
''');
}
test_ternaryOperator_null_left() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
var foo = (true) ? null : 3;
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
// ^
// [diag.deadCode] Dead code.
}
''');
expectInitializerType(result, 'foo =', 'int?');
}
test_ternaryOperator_null_right() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
var foo = (true) ? 3 : null;
// ^^^
// [diag.unusedLocalVariable] The value of the local variable 'foo' isn't used.
// ^^^^
// [diag.deadCode] Dead code.
}
''');
expectInitializerType(result, 'foo =', 'int?');
}
void _assertLocalVarType(
TestResolvedUnitResult result,
String name,
String expectedType,
) {
var element = result.findElement.localVar(name);
assertType(element.type, expectedType);
}
void _assertTopVarType(
TestResolvedUnitResult result,
String name,
String expectedType,
) {
var element = result.findElement.topVar(name);
assertType(element.type, expectedType);
}
Future<void> _objectMethodOnFunctions_helper2(String code) async {
var result = await resolveTestCodeWithDiagnostics(code);
_assertLocalVarType(result, 't0', "String");
_assertLocalVarType(result, 't1', "String Function()");
_assertLocalVarType(result, 't2', "int");
_assertLocalVarType(result, 't3', "String");
_assertLocalVarType(result, 't4', "String Function()");
_assertLocalVarType(result, 't5', "int");
}
}
@reflectiveTest
class StrongModeTypePropagationTest extends PubPackageResolutionTest {
test_inconsistentMethodInheritance_inferFunctionTypeFromTypedef() async {
await resolveTestCodeWithDiagnostics(r'''
typedef bool F<E>(E argument);
abstract class Base {
f<E extends int>(F<int> x);
}
abstract class BaseCopy extends Base {
}
abstract class Override implements Base, BaseCopy {
f<E extends int>(x) => null;
}
class C extends Override implements Base {}
''');
}
test_localVariableInference_bottom_disabled() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
var v = null;
v; // marker
}''');
assertTypeDynamic(result.findElement.localVar('v').type);
assertTypeDynamic(result.findNode.simple('v; // marker'));
}
test_localVariableInference_constant() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
var v = 3;
v; // marker
}''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_declaredType_disabled() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
dynamic v = 3;
v; // marker
}''');
assertTypeDynamic(result.findElement.localVar('v').type);
assertTypeDynamic(result.findNode.simple('v; // marker'));
}
test_localVariableInference_noInitializer_disabled() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
var v;
v = 3;
v; // marker
}''');
var node = result.findNode.assignment('= 3');
assertResolvedNodeText(node, r'''
AssignmentExpression
leftHandSide2: SimpleIdentifier
token: v
element: v@15
staticType: null
operator: =
rightHandSide2: IntegerLiteral
literal: 3
correspondingParameter: <null>
staticType: int
readElement: <null>
readType: null
writeElement: v@15
writeType: dynamic
element: <null>
staticType: int
''');
assertTypeDynamic(result.findNode.simple('v; // marker'));
}
test_localVariableInference_transitive_field_inferred_lexical() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
final x = 3;
f() {
var v = x;
return v; // marker
}
}
main() {
}
''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_transitive_field_inferred_reversed() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
f() {
var v = x;
return v; // marker
}
final x = 3;
}
main() {
}
''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_transitive_field_lexical() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
int x = 3;
f() {
var v = x;
return v; // marker
}
}
main() {
}
''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_transitive_field_reversed() async {
var result = await resolveTestCodeWithDiagnostics(r'''
class A {
f() {
var v = x;
return v; // marker
}
int x = 3;
}
main() {
}
''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_transitive_list_local() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
var x = <int>[3];
var v = x[0];
v; // marker
}''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_transitive_local() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
var x = 3;
var v = x;
v; // marker
}''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_transitive_topLevel_inferred_lexical() async {
var result = await resolveTestCodeWithDiagnostics(r'''
final x = 3;
main() {
var v = x;
v; // marker
}
''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_transitive_toplevel_inferred_reversed() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
var v = x;
v; // marker
}
final x = 3;
''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_transitive_topLevel_lexical() async {
var result = await resolveTestCodeWithDiagnostics(r'''
int x = 3;
main() {
var v = x;
v; // marker
}
''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
test_localVariableInference_transitive_topLevel_reversed() async {
var result = await resolveTestCodeWithDiagnostics(r'''
main() {
var v = x;
v; // marker
}
int x = 3;
''');
assertType(result.findElement.localVar('v').type, 'int');
assertType(result.findNode.simple('v; // marker'), 'int');
}
}