blob: 08ac1e9c2898518a7a7ceaded36d629662a5851c [file] [edit]
// Copyright (c) 2026, 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.
// Since dynamic downcasts can fail, their evaluation order is observable. This
// test verifies that in an invocation with multiple arguments, each argument is
// evaluated and then (if necessary) downcast prior to evaluating the next
// argument.
// The test pays special attention to the situation where a named argument
// precedes a positional argument, since the front end is known to re-order such
// arguments when converting to the kernel representation.
// This test only makes sense to run on platforms that check implicit downcasts.
// Requirements=checked-implicit-downcasts
import 'package:expect/expect.dart';
final List<String> log = [];
void f(int x, int y) {
log.add('f($x, $y) called');
}
void g(int x, {required int y}) {
log.add('g($x, y: $y) called');
}
void h({required int x, required int y}) {
log.add('h(x: $x, y: $y) called');
}
T compute<T>(T t) {
log.add('computed $t');
return t;
}
void testTwoPositionalArgs() {
log.clear();
Expect.throws<TypeError>(() => f(compute<dynamic>('bad'), compute<int>(1)));
Expect.listEquals(['computed bad'], log);
log.clear();
Expect.throws<TypeError>(() => f(compute<int>(0), compute<dynamic>('bad')));
Expect.listEquals(['computed 0', 'computed bad'], log);
log.clear();
f(compute<int>(0), compute<int>(1));
Expect.listEquals(['computed 0', 'computed 1', 'f(0, 1) called'], log);
}
void testPositionalThenNamedArg() {
log.clear();
Expect.throws<TypeError>(
() => g(compute<dynamic>('bad'), y: compute<int>(1)),
);
Expect.listEquals(['computed bad'], log);
log.clear();
Expect.throws<TypeError>(
() => g(compute<int>(0), y: compute<dynamic>('bad')),
);
Expect.listEquals(['computed 0', 'computed bad'], log);
log.clear();
g(compute<int>(0), y: compute<int>(1));
Expect.listEquals(['computed 0', 'computed 1', 'g(0, y: 1) called'], log);
}
void testNamedThenPositionalArg() {
log.clear();
Expect.throws<TypeError>(
() => g(y: compute<dynamic>('bad'), compute<int>(1)),
);
Expect.listEquals(['computed bad'], log);
log.clear();
Expect.throws<TypeError>(
() => g(y: compute<int>(0), compute<dynamic>('bad')),
);
Expect.listEquals(['computed 0', 'computed bad'], log);
log.clear();
g(y: compute<int>(0), compute<int>(1));
Expect.listEquals(['computed 0', 'computed 1', 'g(1, y: 0) called'], log);
}
void testTwoNamedArgsInOrder() {
log.clear();
Expect.throws<TypeError>(
() => h(x: compute<dynamic>('bad'), y: compute<int>(1)),
);
Expect.listEquals(['computed bad'], log);
log.clear();
Expect.throws<TypeError>(
() => h(x: compute<int>(0), y: compute<dynamic>('bad')),
);
Expect.listEquals(['computed 0', 'computed bad'], log);
log.clear();
h(x: compute<int>(0), y: compute<int>(1));
Expect.listEquals(['computed 0', 'computed 1', 'h(x: 0, y: 1) called'], log);
}
void testTwoNamedArgsOutOfOrder() {
log.clear();
Expect.throws<TypeError>(
() => h(y: compute<dynamic>('bad'), x: compute<int>(1)),
);
Expect.listEquals(['computed bad'], log);
log.clear();
Expect.throws<TypeError>(
() => h(y: compute<int>(0), x: compute<dynamic>('bad')),
);
Expect.listEquals(['computed 0', 'computed bad'], log);
log.clear();
h(y: compute<int>(0), x: compute<int>(1));
Expect.listEquals(['computed 0', 'computed 1', 'h(x: 1, y: 0) called'], log);
}
void main() {
testTwoPositionalArgs();
testPositionalThenNamedArg();
testNamedThenPositionalArg();
testTwoNamedArgsInOrder();
testTwoNamedArgsOutOfOrder();
}