Skip to content

Commit d83e6d9

Browse files
committed
Fix splat ICEs in arg mismatch checks
1 parent fbecb23 commit d83e6d9

2 files changed

Lines changed: 64 additions & 32 deletions

File tree

compiler/rustc_hir_typeck/src/demand.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ use rustc_hir::def::Res;
33
use rustc_hir::intravisit::Visitor;
44
use rustc_hir::{self as hir, find_attr};
55
use rustc_infer::infer::DefineOpaqueTypes;
6-
use rustc_middle::bug;
76
use rustc_middle::ty::adjustment::AllowTwoPhase;
87
use rustc_middle::ty::error::{ExpectedFound, TypeError};
98
use rustc_middle::ty::print::with_no_trimmed_paths;
109
use rustc_middle::ty::{self, AssocItem, BottomUpFolder, Ty, TypeFoldable, TypeVisitableExt};
10+
use rustc_middle::{bug, span_bug};
1111
use rustc_span::{DUMMY_SP, Ident, Span, sym};
1212
use rustc_trait_selection::infer::InferCtxtExt;
1313
use rustc_trait_selection::traits::ObligationCause;
@@ -405,9 +405,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
405405
// Unify the method signature with our incompatible arg, to
406406
// do inference in the *opposite* direction and to find out
407407
// what our ideal rcvr ty would look like.
408+
let Some(input_arg) = method.sig.inputs().get(idx + 1) else {
409+
if method.sig.splatted().is_some() {
410+
// FIXME(splat): when the arg is splatted, adjust its index
411+
return None;
412+
} else {
413+
span_bug!(
414+
self.tcx.def_span(method.def_id),
415+
"arg index {} out of bounds for method with {} inputs",
416+
idx + 1,
417+
method.sig.inputs().len(),
418+
);
419+
}
420+
};
408421
let _ = self
409422
.at(&ObligationCause::dummy(), self.param_env)
410-
.eq(DefineOpaqueTypes::Yes, method.sig.inputs()[idx + 1], arg_ty)
423+
.eq(DefineOpaqueTypes::Yes, *input_arg, arg_ty)
411424
.ok()?;
412425
self.select_obligations_where_possible(|errs| {
413426
// Yeet the errors, we're already reporting errors.

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -740,12 +740,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
740740
compatibility_diagonal,
741741
formal_and_expected_inputs,
742742
provided_args,
743-
fn_sig_kind.c_variadic(),
744743
err_code,
745744
fn_def_id,
746745
call_span,
747746
call_expr,
748747
tuple_arguments,
748+
fn_sig_kind,
749749
);
750750
}
751751
}
@@ -770,14 +770,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
770770
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
771771
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
772772
provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
773-
// FIXME(splat): when the feature design is settled, replace this with FnSigKind, and
774-
// improve the errors here
775-
c_variadic: bool,
776773
err_code: ErrCode,
777774
fn_def_id: Option<DefId>,
778775
call_span: Span,
779776
call_expr: &'tcx hir::Expr<'tcx>,
780777
tuple_arguments: TupleArgumentsFlag,
778+
// FIXME(splat): when the feature design is settled, improve the errors here
779+
fn_sig_kind: FnSigKind,
781780
) -> ErrorGuaranteed {
782781
// Next, let's construct the error
783782

@@ -786,12 +785,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
786785
compatibility_diagonal,
787786
formal_and_expected_inputs,
788787
provided_args,
789-
c_variadic,
790788
err_code,
791789
fn_def_id,
792790
call_span,
793791
call_expr,
794792
tuple_arguments,
793+
fn_sig_kind,
795794
);
796795

797796
// First, check if we just need to wrap some arguments in a tuple.
@@ -871,6 +870,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
871870
&fn_call_diag_ctxt.formal_and_expected_inputs,
872871
fn_call_diag_ctxt.call_metadata.is_method,
873872
tuple_arguments,
873+
fn_sig_kind,
874874
);
875875

876876
// And add a suggestion block for all of the parameters
@@ -1549,6 +1549,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15491549
formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
15501550
is_method: bool,
15511551
tuple_arguments: TupleArgumentsFlag,
1552+
fn_sig_kind: FnSigKind,
15521553
) {
15531554
let Some(mut def_id) = callable_def_id else {
15541555
return;
@@ -1649,22 +1650,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16491650
debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
16501651
// Gather all mismatched parameters with generics.
16511652
let mut mismatched_params = Vec::<MismatchedParam<'_>>::new();
1653+
let mut use_splat_fallback = false;
16521654
if let Some(expected_idx) = expected_idx {
16531655
let expected_idx = ExpectedIdx::from_usize(expected_idx);
1654-
let &(expected_generic, ref expected_param) =
1655-
&params_with_generics[expected_idx];
1656-
if let Some(expected_generic) = expected_generic {
1657-
mismatched_params.push(MismatchedParam {
1658-
idx: expected_idx,
1659-
generic: expected_generic,
1660-
param: expected_param,
1661-
deps: SmallVec::new(),
1662-
});
1663-
} else {
1664-
// Still mark the mismatched parameter
1665-
spans.push_span_label(expected_param.span(), "");
1666-
}
1667-
} else {
1656+
match params_with_generics.get(expected_idx) {
1657+
Some(&(Some(expected_generic), ref expected_param)) => mismatched_params
1658+
.push(MismatchedParam {
1659+
idx: expected_idx,
1660+
generic: expected_generic,
1661+
param: expected_param,
1662+
deps: SmallVec::new(),
1663+
}),
1664+
Some((None, expected_param)) => {
1665+
// Still mark the mismatched parameter
1666+
spans.push_span_label(expected_param.span(), "");
1667+
}
1668+
None => {
1669+
if fn_sig_kind.splatted().is_none() {
1670+
// FIXME(splat): when the arg is splatted, adjust its index
1671+
use_splat_fallback = true;
1672+
} else {
1673+
span_bug!(
1674+
self.tcx.def_span(def_id),
1675+
"arg index {} out of bounds for method with {} inputs",
1676+
expected_idx.as_usize(),
1677+
params_with_generics.len(),
1678+
);
1679+
}
1680+
}
1681+
};
1682+
}
1683+
1684+
if expected_idx.is_none() || use_splat_fallback {
16681685
mismatched_params.extend(
16691686
params_with_generics.iter_enumerated().zip(matched_inputs).filter_map(
16701687
|((idx, &(generic, ref param)), matched_idx)| {
@@ -2108,24 +2125,24 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
21082125
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
21092126
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
21102127
provided_args: IndexVec<ProvidedIdx, &'tcx Expr<'tcx>>,
2111-
c_variadic: bool,
21122128
err_code: ErrCode,
21132129
fn_def_id: Option<DefId>,
21142130
call_span: Span,
21152131
call_expr: &'tcx Expr<'tcx>,
21162132
tuple_arguments: TupleArgumentsFlag,
2133+
fn_sig_kind: FnSigKind,
21172134
) -> Self {
21182135
let arg_matching_ctxt = ArgMatchingCtxt::new(
21192136
arg,
21202137
compatibility_diagonal,
21212138
formal_and_expected_inputs,
21222139
provided_args,
2123-
c_variadic,
21242140
err_code,
21252141
fn_def_id,
21262142
call_span,
21272143
call_expr,
21282144
tuple_arguments,
2145+
fn_sig_kind,
21292146
);
21302147

21312148
// The algorithm here is inspired by levenshtein distance and longest common subsequence.
@@ -2208,7 +2225,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
22082225
self.arg_matching_ctxt.args_ctxt.call_metadata.full_call_span,
22092226
format!(
22102227
"{call_name} takes {}{} but {} {} supplied",
2211-
if self.c_variadic { "at least " } else { "" },
2228+
if self.fn_sig_kind.c_variadic() { "at least " } else { "" },
22122229
potentially_plural_count(
22132230
self.formal_and_expected_inputs.len(),
22142231
"argument"
@@ -2238,6 +2255,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
22382255
&self.formal_and_expected_inputs,
22392256
self.call_metadata.is_method,
22402257
self.tuple_arguments,
2258+
self.fn_sig_kind,
22412259
);
22422260
self.suggest_confusable(&mut err);
22432261
Some(err.emit())
@@ -2403,6 +2421,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
24032421
&self.formal_and_expected_inputs,
24042422
self.call_metadata.is_method,
24052423
self.tuple_arguments,
2424+
self.fn_sig_kind,
24062425
);
24072426
self.arg_matching_ctxt.suggest_confusable(&mut err);
24082427
self.detect_dotdot(&mut err, provided_ty, self.provided_args[provided_idx]);
@@ -2441,7 +2460,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
24412460
format!(
24422461
"this {} takes {}{} but {} {} supplied",
24432462
self.call_metadata.call_name,
2444-
if self.c_variadic { "at least " } else { "" },
2463+
if self.fn_sig_kind.c_variadic() { "at least " } else { "" },
24452464
potentially_plural_count(self.formal_and_expected_inputs.len(), "argument"),
24462465
potentially_plural_count(self.provided_args.len(), "argument"),
24472466
pluralize!("was", self.provided_args.len())
@@ -3005,24 +3024,24 @@ impl<'a, 'tcx> ArgMatchingCtxt<'a, 'tcx> {
30053024
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
30063025
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
30073026
provided_args: IndexVec<ProvidedIdx, &'tcx Expr<'tcx>>,
3008-
c_variadic: bool,
30093027
err_code: ErrCode,
30103028
fn_def_id: Option<DefId>,
30113029
call_span: Span,
30123030
call_expr: &'tcx Expr<'tcx>,
30133031
tuple_arguments: TupleArgumentsFlag,
3032+
fn_sig_kind: FnSigKind,
30143033
) -> Self {
30153034
let args_ctxt = ArgsCtxt::new(
30163035
arg,
30173036
compatibility_diagonal,
30183037
formal_and_expected_inputs,
30193038
provided_args,
3020-
c_variadic,
30213039
err_code,
30223040
fn_def_id,
30233041
call_span,
30243042
call_expr,
30253043
tuple_arguments,
3044+
fn_sig_kind,
30263045
);
30273046
let provided_arg_tys = args_ctxt.provided_arg_tys();
30283047

@@ -3152,24 +3171,24 @@ impl<'a, 'tcx> ArgsCtxt<'a, 'tcx> {
31523171
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
31533172
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
31543173
provided_args: IndexVec<ProvidedIdx, &'tcx Expr<'tcx>>,
3155-
c_variadic: bool,
31563174
err_code: ErrCode,
31573175
fn_def_id: Option<DefId>,
31583176
call_span: Span,
31593177
call_expr: &'tcx Expr<'tcx>,
31603178
tuple_arguments: TupleArgumentsFlag,
3179+
fn_sig_kind: FnSigKind,
31613180
) -> Self {
31623181
let call_ctxt: CallCtxt<'_, '_> = CallCtxt::new(
31633182
arg,
31643183
compatibility_diagonal,
31653184
formal_and_expected_inputs,
31663185
provided_args,
3167-
c_variadic,
31683186
err_code,
31693187
fn_def_id,
31703188
call_span,
31713189
call_expr,
31723190
tuple_arguments,
3191+
fn_sig_kind,
31733192
);
31743193

31753194
let call_metadata = call_ctxt.call_metadata();
@@ -3271,12 +3290,12 @@ struct CallCtxt<'a, 'tcx> {
32713290
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
32723291
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
32733292
provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
3274-
c_variadic: bool,
32753293
err_code: ErrCode,
32763294
fn_def_id: Option<DefId>,
32773295
call_span: Span,
32783296
call_expr: &'tcx hir::Expr<'tcx>,
32793297
tuple_arguments: TupleArgumentsFlag,
3298+
fn_sig_kind: FnSigKind,
32803299
callee_expr: Option<&'tcx Expr<'tcx>>,
32813300
callee_ty: Option<Ty<'tcx>>,
32823301
}
@@ -3295,12 +3314,12 @@ impl<'a, 'tcx> CallCtxt<'a, 'tcx> {
32953314
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
32963315
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
32973316
provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
3298-
c_variadic: bool,
32993317
err_code: ErrCode,
33003318
fn_def_id: Option<DefId>,
33013319
call_span: Span,
33023320
call_expr: &'tcx hir::Expr<'tcx>,
33033321
tuple_arguments: TupleArgumentsFlag,
3322+
fn_sig_kind: FnSigKind,
33043323
) -> CallCtxt<'a, 'tcx> {
33053324
let callee_expr = match &call_expr.peel_blocks().kind {
33063325
hir::ExprKind::Call(callee, _) => Some(*callee),
@@ -3327,12 +3346,12 @@ impl<'a, 'tcx> CallCtxt<'a, 'tcx> {
33273346
compatibility_diagonal,
33283347
formal_and_expected_inputs,
33293348
provided_args,
3330-
c_variadic,
33313349
err_code,
33323350
fn_def_id,
33333351
call_span,
33343352
call_expr,
33353353
tuple_arguments,
3354+
fn_sig_kind,
33363355
callee_expr,
33373356
callee_ty,
33383357
}

0 commit comments

Comments
 (0)