diff options
Diffstat (limited to 'compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs')
-rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs | 121 |
1 files changed, 63 insertions, 58 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index b09886fe3..f879ccbb3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -3,10 +3,8 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_infer::traits::ObligationCauseCode; -use rustc_middle::ty::{ - self, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, -}; -use rustc_span::{self, Span}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_span::{self, symbol::kw, Span}; use rustc_trait_selection::traits; use std::ops::ControlFlow; @@ -27,17 +25,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generics = self.tcx.generics_of(def_id); let predicate_substs = match unsubstituted_pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs, - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs, - _ => ty::List::empty(), + ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs.to_vec(), + ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + pred.projection_ty.substs.to_vec() + } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => { + vec![ty.into(), arg.into()] + } + ty::PredicateKind::ConstEvaluatable(e) => vec![e.into()], + _ => return false, }; - let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| { - predicate_substs.types().find_map(|ty| { - ty.walk().find_map(|arg| { + let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| { + predicate_substs.iter().find_map(|arg| { + arg.walk().find_map(|arg| { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Param(param_ty) = ty.kind() - && matches(param_ty) + && let ty::Param(param_ty) = *ty.kind() + && matches(ty::ParamTerm::Ty(param_ty)) + { + Some(arg) + } else if let ty::GenericArgKind::Const(ct) = arg.unpack() + && let ty::ConstKind::Param(param_ct) = ct.kind() + && matches(ty::ParamTerm::Const(param_ct)) { Some(arg) } else { @@ -49,26 +58,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Prefer generics that are local to the fn item, since these are likely // to be the cause of the unsatisfied predicate. - let mut param_to_point_at = find_param_matching(&|param_ty| { - self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id + let mut param_to_point_at = find_param_matching(&|param_term| { + self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) == def_id }); // Fall back to generic that isn't local to the fn item. This will come // from a trait or impl, for example. - let mut fallback_param_to_point_at = find_param_matching(&|param_ty| { - self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id - && param_ty.name != rustc_span::symbol::kw::SelfUpper + let mut fallback_param_to_point_at = find_param_matching(&|param_term| { + self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id + && !matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper) }); // Finally, the `Self` parameter is possibly the reason that the predicate // is unsatisfied. This is less likely to be true for methods, because // method probe means that we already kinda check that the predicates due // to the `Self` type are true. - let mut self_param_to_point_at = - find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper); + let mut self_param_to_point_at = find_param_matching( + &|param_term| matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper), + ); // Finally, for ambiguity-related errors, we actually want to look // for a parameter that is the source of the inference type left // over in this predicate. - if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code { + if let traits::FulfillmentErrorCode::CodeAmbiguity { .. } = error.code { fallback_param_to_point_at = None; self_param_to_point_at = None; param_to_point_at = @@ -227,15 +237,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id)); let Some((index, _)) = own_substs .iter() - .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_))) .enumerate() .find(|(_, arg)| **arg == param_to_point_at) else { return false }; let Some(arg) = segment .args() .args - .iter() - .filter(|arg| matches!(arg, hir::GenericArg::Type(_))) - .nth(index) else { return false; }; + .get(index) else { return false; }; error.obligation.cause.span = arg .span() .find_ancestor_in_same_ctxt(error.obligation.cause.span) @@ -302,7 +309,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .filter(|field| { let field_ty = field.ty(self.tcx, identity_substs); - Self::find_param_in_ty(field_ty.into(), param_to_point_at) + find_param_in_ty(field_ty.into(), param_to_point_at) }) .collect(); @@ -348,7 +355,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .inputs() .iter() .enumerate() - .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at)) + .filter(|(_, ty)| find_param_in_ty((**ty).into(), param_to_point_at)) .collect(); // If there's one field that references the given generic, great! if let [(idx, _)] = args_referencing_param.as_slice() @@ -459,7 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// obligation. Hence we refine the `expr` "outwards-in" and bail at the first kind of expression/impl we don't recognize. /// /// This function returns a `Result<&Expr, &Expr>` - either way, it returns the `Expr` whose span should be - /// reported as an error. If it is `Ok`, then it means it refined successfull. If it is `Err`, then it may be + /// reported as an error. If it is `Ok`, then it means it refined successful. If it is `Err`, then it may be /// only a partial success - but it cannot be refined even further. fn blame_specific_expr_if_possible_for_derived_predicate_obligation( &self, @@ -527,7 +534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - in_ty: `(Option<Vec<T>, bool)` /// we would drill until we arrive at `vec![1, 2, 3]`. /// - /// If successful, we return `Ok(refined_expr)`. If unsuccesful, we return `Err(partially_refined_expr`), + /// If successful, we return `Ok(refined_expr)`. If unsuccessful, we return `Err(partially_refined_expr`), /// which will go as far as possible. For example, given `(foo(), false)` instead, we would drill to /// `foo()` and then return `Err("foo()")`. /// @@ -571,8 +578,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find out which of `in_ty_elements` refer to `param`. // FIXME: It may be better to take the first if there are multiple, // just so that the error points to a smaller expression. - let Some((drill_expr, drill_ty)) = Self::is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| { - Self::find_param_in_ty((*in_ty_elem).into(), param) + let Some((drill_expr, drill_ty)) = is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| { + find_param_in_ty((*in_ty_elem).into(), param) })) else { // The param is not mentioned, or it is mentioned in multiple indexes. return Err(expr); @@ -620,10 +627,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We need to know which of the generic parameters mentions our target param. // We expect that at least one of them does, since it is expected to be mentioned. let Some((drill_generic_index, generic_argument_type)) = - Self::is_iterator_singleton( + is_iterator_singleton( in_ty_adt_generic_args.iter().enumerate().filter( |(_index, in_ty_generic)| { - Self::find_param_in_ty(*in_ty_generic, param) + find_param_in_ty(*in_ty_generic, param) }, ), ) else { @@ -743,10 +750,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We need to know which of the generic parameters mentions our target param. // We expect that at least one of them does, since it is expected to be mentioned. let Some((drill_generic_index, generic_argument_type)) = - Self::is_iterator_singleton( + is_iterator_singleton( in_ty_adt_generic_args.iter().enumerate().filter( |(_index, in_ty_generic)| { - Self::find_param_in_ty(*in_ty_generic, param) + find_param_in_ty(*in_ty_generic, param) }, ), ) else { @@ -785,14 +792,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // outer contextual information. // (1) Find the (unique) field index which mentions the type in our constraint: - let Some((field_index, field_type)) = Self::is_iterator_singleton( + let Some((field_index, field_type)) = is_iterator_singleton( in_ty_adt .variant_with_id(variant_def_id) .fields .iter() .map(|field| field.ty(self.tcx, *in_ty_adt_generic_args)) .enumerate() - .filter(|(_index, field_type)| Self::find_param_in_ty((*field_type).into(), param)) + .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)) ) else { return Err(expr); }; @@ -825,20 +832,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(expr) } +} - // FIXME: This can be made into a private, non-impl function later. - /// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references - /// to the given `param_to_point_at`. Returns `true` if it finds any use of the param. - pub fn find_param_in_ty( - ty: ty::GenericArg<'tcx>, - param_to_point_at: ty::GenericArg<'tcx>, - ) -> bool { - let mut walk = ty.walk(); - while let Some(arg) = walk.next() { - if arg == param_to_point_at { - return true; - } - if let ty::GenericArgKind::Type(ty) = arg.unpack() +/// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references +/// to the given `param_to_point_at`. Returns `true` if it finds any use of the param. +fn find_param_in_ty<'tcx>( + ty: ty::GenericArg<'tcx>, + param_to_point_at: ty::GenericArg<'tcx>, +) -> bool { + let mut walk = ty.walk(); + while let Some(arg) = walk.next() { + if arg == param_to_point_at { + return true; + } + if let ty::GenericArgKind::Type(ty) = arg.unpack() && let ty::Alias(ty::Projection, ..) = ty.kind() { // This logic may seem a bit strange, but typically when @@ -849,16 +856,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in some UI tests. walk.skip_current_subtree(); } - } - false } + false +} - // FIXME: This can be made into a private, non-impl function later. - /// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise. - pub fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> { - match (iterator.next(), iterator.next()) { - (_, Some(_)) => None, - (first, _) => first, - } +/// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise. +fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> { + match (iterator.next(), iterator.next()) { + (_, Some(_)) => None, + (first, _) => first, } } |