Skip to content

Commit 84cab65

Browse files
committed
Fix splat ICEs in arg mismatch checks
1 parent a28d527 commit 84cab65

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
@@ -739,12 +739,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
739739
compatibility_diagonal,
740740
formal_and_expected_inputs,
741741
provided_args,
742-
fn_sig_kind.c_variadic(),
743742
err_code,
744743
fn_def_id,
745744
call_span,
746745
call_expr,
747746
tuple_arguments,
747+
fn_sig_kind,
748748
);
749749
}
750750
}
@@ -769,14 +769,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
769769
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
770770
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
771771
provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
772-
// FIXME(splat): when the feature design is settled, replace this with FnSigKind, and
773-
// improve the errors here
774-
c_variadic: bool,
775772
err_code: ErrCode,
776773
fn_def_id: Option<DefId>,
777774
call_span: Span,
778775
call_expr: &'tcx hir::Expr<'tcx>,
779776
tuple_arguments: TupleArgumentsFlag,
777+
// FIXME(splat): when the feature design is settled, improve the errors here
778+
fn_sig_kind: FnSigKind,
780779
) -> ErrorGuaranteed {
781780
// Next, let's construct the error
782781

@@ -785,12 +784,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
785784
compatibility_diagonal,
786785
formal_and_expected_inputs,
787786
provided_args,
788-
c_variadic,
789787
err_code,
790788
fn_def_id,
791789
call_span,
792790
call_expr,
793791
tuple_arguments,
792+
fn_sig_kind,
794793
);
795794

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

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

21302147
// The algorithm here is inspired by levenshtein distance and longest common subsequence.
@@ -2207,7 +2224,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
22072224
self.arg_matching_ctxt.args_ctxt.call_metadata.full_call_span,
22082225
format!(
22092226
"{call_name} takes {}{} but {} {} supplied",
2210-
if self.c_variadic { "at least " } else { "" },
2227+
if self.fn_sig_kind.c_variadic() { "at least " } else { "" },
22112228
potentially_plural_count(
22122229
self.formal_and_expected_inputs.len(),
22132230
"argument"
@@ -2237,6 +2254,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
22372254
&self.formal_and_expected_inputs,
22382255
self.call_metadata.is_method,
22392256
self.tuple_arguments,
2257+
self.fn_sig_kind,
22402258
);
22412259
self.suggest_confusable(&mut err);
22422260
Some(err.emit())
@@ -2402,6 +2420,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
24022420
&self.formal_and_expected_inputs,
24032421
self.call_metadata.is_method,
24042422
self.tuple_arguments,
2423+
self.fn_sig_kind,
24052424
);
24062425
self.arg_matching_ctxt.suggest_confusable(&mut err);
24072426
self.detect_dotdot(&mut err, provided_ty, self.provided_args[provided_idx]);
@@ -2440,7 +2459,7 @@ impl<'a, 'tcx> FnCallDiagCtxt<'a, 'tcx> {
24402459
format!(
24412460
"this {} takes {}{} but {} {} supplied",
24422461
self.call_metadata.call_name,
2443-
if self.c_variadic { "at least " } else { "" },
2462+
if self.fn_sig_kind.c_variadic() { "at least " } else { "" },
24442463
potentially_plural_count(self.formal_and_expected_inputs.len(), "argument"),
24452464
potentially_plural_count(self.provided_args.len(), "argument"),
24462465
pluralize!("was", self.provided_args.len())
@@ -3004,24 +3023,24 @@ impl<'a, 'tcx> ArgMatchingCtxt<'a, 'tcx> {
30043023
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
30053024
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
30063025
provided_args: IndexVec<ProvidedIdx, &'tcx Expr<'tcx>>,
3007-
c_variadic: bool,
30083026
err_code: ErrCode,
30093027
fn_def_id: Option<DefId>,
30103028
call_span: Span,
30113029
call_expr: &'tcx Expr<'tcx>,
30123030
tuple_arguments: TupleArgumentsFlag,
3031+
fn_sig_kind: FnSigKind,
30133032
) -> Self {
30143033
let args_ctxt = ArgsCtxt::new(
30153034
arg,
30163035
compatibility_diagonal,
30173036
formal_and_expected_inputs,
30183037
provided_args,
3019-
c_variadic,
30203038
err_code,
30213039
fn_def_id,
30223040
call_span,
30233041
call_expr,
30243042
tuple_arguments,
3043+
fn_sig_kind,
30253044
);
30263045
let provided_arg_tys = args_ctxt.provided_arg_tys();
30273046

@@ -3151,24 +3170,24 @@ impl<'a, 'tcx> ArgsCtxt<'a, 'tcx> {
31513170
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
31523171
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
31533172
provided_args: IndexVec<ProvidedIdx, &'tcx Expr<'tcx>>,
3154-
c_variadic: bool,
31553173
err_code: ErrCode,
31563174
fn_def_id: Option<DefId>,
31573175
call_span: Span,
31583176
call_expr: &'tcx Expr<'tcx>,
31593177
tuple_arguments: TupleArgumentsFlag,
3178+
fn_sig_kind: FnSigKind,
31603179
) -> Self {
31613180
let call_ctxt: CallCtxt<'_, '_> = CallCtxt::new(
31623181
arg,
31633182
compatibility_diagonal,
31643183
formal_and_expected_inputs,
31653184
provided_args,
3166-
c_variadic,
31673185
err_code,
31683186
fn_def_id,
31693187
call_span,
31703188
call_expr,
31713189
tuple_arguments,
3190+
fn_sig_kind,
31723191
);
31733192

31743193
let call_metadata = call_ctxt.call_metadata();
@@ -3270,12 +3289,12 @@ struct CallCtxt<'a, 'tcx> {
32703289
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
32713290
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
32723291
provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
3273-
c_variadic: bool,
32743292
err_code: ErrCode,
32753293
fn_def_id: Option<DefId>,
32763294
call_span: Span,
32773295
call_expr: &'tcx hir::Expr<'tcx>,
32783296
tuple_arguments: TupleArgumentsFlag,
3297+
fn_sig_kind: FnSigKind,
32793298
callee_expr: Option<&'tcx Expr<'tcx>>,
32803299
callee_ty: Option<Ty<'tcx>>,
32813300
}
@@ -3294,12 +3313,12 @@ impl<'a, 'tcx> CallCtxt<'a, 'tcx> {
32943313
compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
32953314
formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
32963315
provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
3297-
c_variadic: bool,
32983316
err_code: ErrCode,
32993317
fn_def_id: Option<DefId>,
33003318
call_span: Span,
33013319
call_expr: &'tcx hir::Expr<'tcx>,
33023320
tuple_arguments: TupleArgumentsFlag,
3321+
fn_sig_kind: FnSigKind,
33033322
) -> CallCtxt<'a, 'tcx> {
33043323
let callee_expr = match &call_expr.peel_blocks().kind {
33053324
hir::ExprKind::Call(callee, _) => Some(*callee),
@@ -3326,12 +3345,12 @@ impl<'a, 'tcx> CallCtxt<'a, 'tcx> {
33263345
compatibility_diagonal,
33273346
formal_and_expected_inputs,
33283347
provided_args,
3329-
c_variadic,
33303348
err_code,
33313349
fn_def_id,
33323350
call_span,
33333351
call_expr,
33343352
tuple_arguments,
3353+
fn_sig_kind,
33353354
callee_expr,
33363355
callee_ty,
33373356
}

0 commit comments

Comments
 (0)