Skip to content

Commit 2d9e563

Browse files
committed
Handle splatted empty tuples and simplify the code
1 parent 5d1856a commit 2d9e563

7 files changed

Lines changed: 30 additions & 45 deletions

File tree

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,14 +1048,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10481048
expected,
10491049
arg_exprs,
10501050
fn_sig.c_variadic,
1051-
TupleArgumentsFlag::TupleSplattedArguments {
1052-
splatted_arg_index: fn_sig
1053-
.splatted_arg_index()
1054-
.expect("must have a splatted argument"),
1055-
},
1051+
TupleArgumentsFlag::TupleSplattedArguments,
10561052
def_id,
10571053
);
10581054

1055+
// FIXME(splat): is splatting incompatible with RustCall?
10591056
if fn_sig.abi == rustc_abi::ExternAbi::RustCall {
10601057
let sp = arg_exprs.last().map_or(call_expr.span, |expr| expr.span);
10611058
self.dcx().emit_err(errors::RustCallIncorrectArgs { span: sp });

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,17 +1483,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14831483
self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
14841484

14851485
// Handle splatted method arguments
1486-
let tuple_arguments =
1487-
if let Some(meth_splatted_arg) = method.sig.splatted_arg_index() {
1488-
// self is already handled as `rcvr`
1489-
TupleArgumentsFlag::TupleSplattedArguments {
1490-
splatted_arg_index: meth_splatted_arg
1491-
.checked_sub(1)
1492-
.expect("missing splatted arg or self in method call"),
1493-
}
1494-
} else {
1495-
TupleArgumentsFlag::DontTupleArguments
1496-
};
1486+
let tuple_arguments = if method.sig.splatted {
1487+
// self is already handled as `rcvr`, so it's never splatted here
1488+
TupleArgumentsFlag::TupleSplattedArguments
1489+
} else {
1490+
TupleArgumentsFlag::DontTupleArguments
1491+
};
14971492

14981493
self.check_argument_types(
14991494
segment.ident.span,

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -286,15 +286,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
286286
let mut err_code = E0061;
287287

288288
// If the arguments should be wrapped in a tuple (ex: closures, splats), unwrap them here
289-
let (formal_input_tys, expected_input_tys) = if let Some(tupled_arg_index) =
290-
tuple_arguments.tupled_argument_position()
291-
{
292-
let tupled_arg_index = usize::from(tupled_arg_index);
293-
assert_eq!(
294-
Some(tupled_arg_index),
295-
formal_input_tys.len().checked_sub(1),
296-
"only trailing tupled arguments are implemented",
297-
);
289+
let (formal_input_tys, expected_input_tys) = if tuple_arguments.last_argument_is_tupled() {
290+
// An empty argument list should be a single unit type argument in the callee.
291+
// The Fn* traits ensure this by construction, and `#[splat]` can only be applied to an actual argument.
292+
let tupled_arg_index =
293+
formal_input_tys.len().checked_sub(1).expect("must have a tuple argument");
298294
// Keep the type variable if the argument is splatted, so we can force it to be a tuple later.
299295
let tuple_type = if tuple_arguments.is_splatted() {
300296
let tuple_type = self

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -638,16 +638,19 @@ enum TupleArgumentsFlag {
638638
DontTupleArguments,
639639
/// All arguments are tupled before typechecking.
640640
TupleAllArguments,
641-
/// Only the splatted arguments are tupled before typechecking.
642-
TupleSplattedArguments { splatted_arg_index: u16 },
641+
/// Only the splatted final argument is tupled before typechecking.
642+
TupleSplattedArguments,
643643
}
644644

645645
impl TupleArgumentsFlag {
646-
fn tupled_argument_position(&self) -> Option<u16> {
646+
// Is the last argument in the callee tupled?
647+
fn last_argument_is_tupled(&self) -> bool {
647648
match self {
648-
Self::DontTupleArguments => None,
649-
Self::TupleAllArguments => Some(0),
650-
Self::TupleSplattedArguments { splatted_arg_index } => Some(*splatted_arg_index),
649+
Self::DontTupleArguments => false,
650+
// The callee always has a single tuple argument.
651+
Self::TupleAllArguments => true,
652+
// The last argument of the callee is a splatted tuple in the caller.
653+
Self::TupleSplattedArguments { .. } => true,
651654
}
652655
}
653656

compiler/rustc_type_ir/src/ty_kind.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -777,14 +777,6 @@ impl<I: Interner> FnSig<I> {
777777
let FnSig { safety, abi, c_variadic, .. } = self;
778778
!c_variadic && safety.is_safe() && abi.is_rust()
779779
}
780-
781-
pub fn splatted_arg_index(self) -> Option<u16> {
782-
// A function with no inputs behaves the same regardless of splatting.
783-
let last_index = self.inputs().len().checked_sub(1)?;
784-
785-
debug_assert!(last_index <= u16::MAX as usize);
786-
self.splatted.then_some(last_index as u16)
787-
}
788780
}
789781

790782
impl<I: Interner> ty::Binder<I, FnSig<I>> {
@@ -852,16 +844,20 @@ impl<I: Interner> fmt::Debug for FnSig<I> {
852844

853845
write!(f, "fn(")?;
854846
let inputs = sig.inputs();
855-
let splatted_arg_index = sig.splatted_arg_index();
847+
// Always the last argument.
848+
let splatted_arg_index = self.splatted.then(|| inputs.len().checked_sub(1)).flatten();
856849
for (i, ty) in inputs.iter().enumerate() {
857850
if i > 0 {
858851
write!(f, ", ")?;
859852
}
860-
if splatted_arg_index == Some(i as u16) {
853+
if splatted_arg_index == Some(i) {
861854
write!(f, "#[splat] ")?;
862855
}
863856
write!(f, "{ty:?}")?;
864857
}
858+
if self.splatted && inputs.is_empty() {
859+
write!(f, "#[splat] ()")?;
860+
}
865861
if *c_variadic {
866862
if inputs.is_empty() {
867863
write!(f, "...")?;

tests/ui/splat/splat-overload-at-home.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ impl Foo {
3535
fn main() {
3636
let foo = Foo;
3737

38-
// FIXME(splat): incorrectly assumes that splat must have one or more arguments to tuple
39-
//foo.method::<()>();
38+
foo.method::<()>(); //~ ERROR broken MIR
4039

4140
// FIXME(splat): generic tuple trait implementers should work without explicit tuple type parameters.
4241
// actually modify the argument list during typeck, to avoid "broken MIR" errors

tests/ui/splat/splat-tuple.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,5 @@ fn main() {
9595
// FIXME(splat): generic tuple trait implementers should work without explicit tuple type parameters.
9696
splat_generic_tuple::<(u32, i8)>(1u32, 2i8);
9797

98-
// FIXME(splat): incorrectly assumes that splat must have one or more arguments to tuple
99-
//splat_generic_tuple::<()>();
98+
splat_generic_tuple::<()>();
10099
}

0 commit comments

Comments
 (0)