diff options
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 172 |
1 files changed, 77 insertions, 95 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index bbe65371496..7ee246e0774 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -13,7 +13,7 @@ use rustc_hir::{ExprKind, HirId, Node, QPath}; use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; -use rustc_index::IndexVec; +use rustc_index::{Idx, IndexVec}; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace}; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::TypeError; @@ -2374,11 +2374,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let check_for_matched_generics = || { if matched_inputs.iter().any(|x| x.is_some()) - && params_with_generics.iter().any(|x| x.1.is_some()) + && params_with_generics.iter().any(|(x, _)| x.is_some()) { - for &(idx, generic, _) in ¶ms_with_generics { + for (idx, (generic, _)) in params_with_generics.iter_enumerated() { // Param has to have a generic and be matched to be relevant - if matched_inputs[idx.into()].is_none() { + if matched_inputs[idx].is_none() { continue; } @@ -2386,10 +2386,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; }; - for unmatching_idx in idx + 1..params_with_generics.len() { - if matched_inputs[unmatching_idx.into()].is_none() + for unmatching_idx in + idx.plus(1)..ExpectedIdx::from_usize(params_with_generics.len()) + { + if matched_inputs[unmatching_idx].is_none() && let Some(unmatched_idx_param_generic) = - params_with_generics[unmatching_idx].1 + params_with_generics[unmatching_idx].0 && unmatched_idx_param_generic.name.ident() == generic.name.ident() { @@ -2404,10 +2406,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let check_for_matched_generics = check_for_matched_generics(); - for &(idx, generic_param, param) in - params_with_generics.iter().filter(|&(idx, _, _)| { + for (idx, &(generic_param, param)) in + params_with_generics.iter_enumerated().filter(|&(idx, _)| { check_for_matched_generics - || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) + || expected_idx + .is_none_or(|expected_idx| expected_idx == idx.as_usize()) }) { let Some(generic_param) = generic_param else { @@ -2415,29 +2418,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; }; - let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics - .iter() - .filter(|(other_idx, other_generic_param, _)| { - if *other_idx == idx { - return false; - } - let Some(other_generic_param) = other_generic_param else { - return false; - }; - if matched_inputs[idx.into()].is_none() - && matched_inputs[(*other_idx).into()].is_none() - { - return false; - } - if matched_inputs[idx.into()].is_some() - && matched_inputs[(*other_idx).into()].is_some() - { - return false; - } - other_generic_param.name.ident() == generic_param.name.ident() - }) - .map(|&(other_idx, _, other_param)| (other_idx, other_param)) - .collect(); + let other_params_matched: Vec<(ExpectedIdx, &hir::Param<'_>)> = + params_with_generics + .iter_enumerated() + .filter(|&(other_idx, &(other_generic_param, _))| { + if other_idx == idx { + return false; + } + let Some(other_generic_param) = other_generic_param else { + return false; + }; + if matched_inputs[idx].is_none() + && matched_inputs[other_idx].is_none() + { + return false; + } + if matched_inputs[idx].is_some() + && matched_inputs[other_idx].is_some() + { + return false; + } + other_generic_param.name.ident() == generic_param.name.ident() + }) + .map(|(other_idx, &(_, other_param))| (other_idx, other_param)) + .collect(); if !other_params_matched.is_empty() { let other_param_matched_names: Vec<String> = other_params_matched @@ -2447,16 +2451,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { format!("`{ident}`") } else { - format!("parameter #{}", idx + 1) + format!("parameter #{}", idx.as_u32() + 1) } }) .collect(); let matched_ty = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .resolve_vars_if_possible(formal_and_expected_inputs[idx].1) .sort_string(self.tcx); - if matched_inputs[idx.into()].is_some() { + if matched_inputs[idx].is_some() { spans.push_span_label( param.span, format!( @@ -2502,19 +2506,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) { let param_idents_matching: Vec<String> = params_with_generics - .iter() - .filter(|(_, generic, _)| { + .iter_enumerated() + .filter(|&(_, &(generic, _))| { if let Some(generic) = generic { generic.name.ident() == generic_param.name.ident() } else { false } }) - .map(|(idx, _, param)| { + .map(|(idx, &(_, param))| { if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { format!("`{ident}`") } else { - format!("parameter #{}", idx + 1) + format!("parameter #{}", idx.as_u32() + 1) } }) .collect(); @@ -2607,12 +2611,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) { debug_assert_eq!(params_with_generics.len(), matched_inputs.len()); - for &(idx, generic_param, _) in ¶ms_with_generics { - if matched_inputs[idx.into()].is_none() { + for (idx, (generic_param, _)) in params_with_generics.iter_enumerated() { + if matched_inputs[idx].is_none() { continue; } - let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else { + let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.to_provided_idx()) + else { continue; }; @@ -2620,32 +2625,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; }; - let mut idxs_matched: Vec<usize> = vec![]; - for &(other_idx, _, _) in - params_with_generics.iter().filter(|&&(other_idx, other_generic_param, _)| { + let idxs_matched = params_with_generics + .iter_enumerated() + .filter(|&(other_idx, (other_generic_param, _))| { if other_idx == idx { return false; } let Some(other_generic_param) = other_generic_param else { return false; }; - if matched_inputs[other_idx.into()].is_some() { + if matched_inputs[other_idx].is_some() { return false; } other_generic_param.name.ident() == generic_param.name.ident() }) - { - idxs_matched.push(other_idx); - } + .count(); - if idxs_matched.is_empty() { + if idxs_matched == 0 { continue; } let expected_display_type = self .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) .sort_string(self.tcx); - let label = if idxs_matched.len() == params_with_generics.len() - 1 { + let label = if idxs_matched == params_with_generics.len() - 1 { format!( "expected all arguments to be this {} type because they need to match the type of this parameter", expected_display_type @@ -2664,60 +2667,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Returns the parameters of a function, with their generic parameters if those are the full - /// type of that parameter. Returns `None` if the function body is unavailable (eg is an instrinsic). + /// type of that parameter. Returns `None` if the function has no generics or the body is + /// unavailable (eg is an instrinsic). fn get_hir_params_with_generics( &self, def_id: DefId, is_method: bool, - ) -> Option<Vec<(usize, Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> { + ) -> Option<IndexVec<ExpectedIdx, (Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> { let fn_node = self.tcx.hir().get_if_local(def_id)?; let fn_decl = fn_node.fn_decl()?; + let generic_params = fn_node.generics()?.params; - let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_decl - .inputs - .into_iter() - .skip(if is_method { 1 } else { 0 }) - .map(|param| { - if let hir::TyKind::Path(QPath::Resolved( - _, - hir::Path { res: Res::Def(_, res_def_id), .. }, - )) = param.kind - { - fn_node - .generics() - .into_iter() - .flat_map(|generics| generics.params) - .find(|param| ¶m.def_id.to_def_id() == res_def_id) - } else { - None - } - }) - .collect(); + // Remove both the receiver and variadic arguments. Neither can have an unmatched generic + // parameter. + let params = self.tcx.hir().body(fn_node.body_id()?).params; + let params = params.get(is_method as usize..params.len() - fn_decl.c_variadic as usize)?; + let fn_inputs = fn_decl.inputs.get(is_method as usize..)?; + debug_assert_eq!(params.len(), fn_inputs.len()); - let mut params: Vec<&hir::Param<'_>> = self - .tcx - .hir() - .body(fn_node.body_id()?) - .params - .into_iter() - .skip(if is_method { 1 } else { 0 }) - .collect(); - - // The surrounding code expects variadic functions to not have a parameter representing - // the "..." parameter. This is already true of the FnDecl but not of the body params, so - // we drop it if it exists. - - if fn_decl.c_variadic { - params.pop(); - } - - debug_assert_eq!(params.len(), generic_params.len()); Some( - generic_params + fn_inputs .into_iter() + .map(|param| { + if let hir::TyKind::Path(QPath::Resolved( + _, + &hir::Path { res: Res::Def(_, res_def_id), .. }, + )) = param.kind + { + generic_params.iter().find(|param| param.def_id.to_def_id() == res_def_id) + } else { + None + } + }) .zip(params) - .enumerate() - .map(|(a, (b, c))| (a, b, c)) .collect(), ) } |
