Skip to content

Commit dac4929

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Migration: propagate nullability inference through override relationships: parameter types.
Change-Id: Ib41ffa388af9688efc59aea2c196d8fdcf713ad8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107101 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Dan Rubel <danrubel@google.com>
1 parent 559e49a commit dac4929

3 files changed

Lines changed: 189 additions & 6 deletions

File tree

pkg/nnbd_migration/lib/src/edge_builder.dart

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -860,13 +860,22 @@ $stackTrace''');
860860
destination.typeArguments.isNotEmpty) {
861861
throw UnimplementedError('TODO(paulberry)');
862862
}
863-
if (source.positionalParameters.isNotEmpty ||
864-
destination.positionalParameters.isNotEmpty) {
865-
throw UnimplementedError('TODO(paulberry)');
863+
for (int i = 0;
864+
i < source.positionalParameters.length &&
865+
i < destination.positionalParameters.length;
866+
i++) {
867+
// Note: source and destination are swapped due to contravariance.
868+
_checkAssignment(expressionChecks,
869+
source: destination.positionalParameters[i],
870+
destination: source.positionalParameters[i],
871+
hard: hard);
866872
}
867-
if (source.namedParameters.isNotEmpty ||
868-
destination.namedParameters.isNotEmpty) {
869-
throw UnimplementedError('TODO(paulberry)');
873+
for (var entry in destination.namedParameters.entries) {
874+
// Note: source and destination are swapped due to contravariance.
875+
_checkAssignment(expressionChecks,
876+
source: entry.value,
877+
destination: source.namedParameters[entry.key],
878+
hard: hard);
870879
}
871880
} else if (destination.type.isDynamic || source.type.isDynamic) {
872881
// ok; nothing further to do.

pkg/nnbd_migration/test/api_test.dart

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,72 @@ main() {
10431043
await _checkSingleFileChanges(content, expected);
10441044
}
10451045

1046+
test_override_parameter_type_non_nullable() async {
1047+
var content = '''
1048+
abstract class Base {
1049+
void f(int i);
1050+
}
1051+
class Derived extends Base {
1052+
void f(int i) {
1053+
assert(i != null);
1054+
}
1055+
}
1056+
void g(int i, bool b, Base base) {
1057+
if (b) {
1058+
base.f(i);
1059+
}
1060+
}
1061+
void h(Base base) {
1062+
g(null, false, base);
1063+
}
1064+
''';
1065+
var expected = '''
1066+
abstract class Base {
1067+
void f(int i);
1068+
}
1069+
class Derived extends Base {
1070+
void f(int i) {
1071+
assert(i != null);
1072+
}
1073+
}
1074+
void g(int? i, bool b, Base base) {
1075+
if (b) {
1076+
base.f(i!);
1077+
}
1078+
}
1079+
void h(Base base) {
1080+
g(null, false, base);
1081+
}
1082+
''';
1083+
await _checkSingleFileChanges(content, expected);
1084+
}
1085+
1086+
test_override_parameter_type_nullable() async {
1087+
var content = '''
1088+
abstract class Base {
1089+
void f(int i);
1090+
}
1091+
class Derived extends Base {
1092+
void f(int i) {}
1093+
}
1094+
void g(int i, Base base) {
1095+
base.f(null);
1096+
}
1097+
''';
1098+
var expected = '''
1099+
abstract class Base {
1100+
void f(int? i);
1101+
}
1102+
class Derived extends Base {
1103+
void f(int? i) {}
1104+
}
1105+
void g(int i, Base base) {
1106+
base.f(null);
1107+
}
1108+
''';
1109+
await _checkSingleFileChanges(content, expected);
1110+
}
1111+
10461112
test_override_return_type_non_nullable() async {
10471113
var content = '''
10481114
abstract class Base {

pkg/nnbd_migration/test/edge_builder_test.dart

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,114 @@ void test(C c) {
12741274
expect(never.isNullable, isFalse);
12751275
}
12761276

1277+
test_override_parameter_type_named() async {
1278+
await analyze('''
1279+
abstract class Base {
1280+
void f({int/*1*/ i});
1281+
}
1282+
class Derived extends Base {
1283+
void f({int/*2*/ i}) {}
1284+
}
1285+
''');
1286+
var int1 = decoratedTypeAnnotation('int/*1*/');
1287+
var int2 = decoratedTypeAnnotation('int/*2*/');
1288+
assertEdge(int1.node, int2.node, hard: true);
1289+
}
1290+
1291+
test_override_parameter_type_named_over_none() async {
1292+
await analyze('''
1293+
abstract class Base {
1294+
void f();
1295+
}
1296+
class Derived extends Base {
1297+
void f({int i}) {}
1298+
}
1299+
''');
1300+
// No assertions; just checking that it doesn't crash.
1301+
}
1302+
1303+
test_override_parameter_type_operator() async {
1304+
await analyze('''
1305+
abstract class Base {
1306+
Base operator+(Base/*1*/ b);
1307+
}
1308+
class Derived extends Base {
1309+
Base operator+(Base/*2*/ b) => this;
1310+
}
1311+
''');
1312+
var base1 = decoratedTypeAnnotation('Base/*1*/');
1313+
var base2 = decoratedTypeAnnotation('Base/*2*/');
1314+
assertEdge(base1.node, base2.node, hard: true);
1315+
}
1316+
1317+
test_override_parameter_type_optional() async {
1318+
await analyze('''
1319+
abstract class Base {
1320+
void f([int/*1*/ i]);
1321+
}
1322+
class Derived extends Base {
1323+
void f([int/*2*/ i]) {}
1324+
}
1325+
''');
1326+
var int1 = decoratedTypeAnnotation('int/*1*/');
1327+
var int2 = decoratedTypeAnnotation('int/*2*/');
1328+
assertEdge(int1.node, int2.node, hard: true);
1329+
}
1330+
1331+
test_override_parameter_type_optional_over_none() async {
1332+
await analyze('''
1333+
abstract class Base {
1334+
void f();
1335+
}
1336+
class Derived extends Base {
1337+
void f([int i]) {}
1338+
}
1339+
''');
1340+
// No assertions; just checking that it doesn't crash.
1341+
}
1342+
1343+
test_override_parameter_type_optional_over_required() async {
1344+
await analyze('''
1345+
abstract class Base {
1346+
void f(int/*1*/ i);
1347+
}
1348+
class Derived extends Base {
1349+
void f([int/*2*/ i]) {}
1350+
}
1351+
''');
1352+
var int1 = decoratedTypeAnnotation('int/*1*/');
1353+
var int2 = decoratedTypeAnnotation('int/*2*/');
1354+
assertEdge(int1.node, int2.node, hard: true);
1355+
}
1356+
1357+
test_override_parameter_type_required() async {
1358+
await analyze('''
1359+
abstract class Base {
1360+
void f(int/*1*/ i);
1361+
}
1362+
class Derived extends Base {
1363+
void f(int/*2*/ i) {}
1364+
}
1365+
''');
1366+
var int1 = decoratedTypeAnnotation('int/*1*/');
1367+
var int2 = decoratedTypeAnnotation('int/*2*/');
1368+
assertEdge(int1.node, int2.node, hard: true);
1369+
}
1370+
1371+
test_override_parameter_type_setter() async {
1372+
await analyze('''
1373+
abstract class Base {
1374+
void set x(int/*1*/ value);
1375+
}
1376+
class Derived extends Base {
1377+
void set x(int/*2*/ value) {}
1378+
}
1379+
''');
1380+
var int1 = decoratedTypeAnnotation('int/*1*/');
1381+
var int2 = decoratedTypeAnnotation('int/*2*/');
1382+
assertEdge(int1.node, int2.node, hard: true);
1383+
}
1384+
12771385
test_override_return_type_getter() async {
12781386
await analyze('''
12791387
abstract class Base {

0 commit comments

Comments
 (0)