From e55f73ae47dd3b508edaf8403ca26ca9dbb1097e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 9 Mar 2023 21:53:18 +0000 Subject: [PATCH 1/2] Refine error spans for const args in hir typeck --- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 46 +++++++++++-------- compiler/rustc_middle/src/ty/mod.rs | 15 ++++++ .../cross_crate_predicate.stderr | 8 ++-- tests/ui/const-generics/type_mismatch.stderr | 4 +- 4 files changed, 49 insertions(+), 24 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 ec14bd3c6f43e..e0ddb90c33b99 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 @@ -4,7 +4,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::{self, Span}; +use rustc_span::{self, symbol::kw, Span}; use rustc_trait_selection::traits; use std::ops::ControlFlow; @@ -25,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 { @@ -47,21 +58,22 @@ 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 @@ -225,14 +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; }; error.obligation.cause.span = arg .span() diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b17749c1ebafa..e3cd5cca785aa 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1051,6 +1051,21 @@ impl<'tcx> TermKind<'tcx> { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum ParamTerm { + Ty(ParamTy), + Const(ParamConst), +} + +impl ParamTerm { + pub fn index(self) -> usize { + match self { + ParamTerm::Ty(ty) => ty.index as usize, + ParamTerm::Const(ct) => ct.index as usize, + } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// diff --git a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr index 7b4d46b820976..6b3396a25cf97 100644 --- a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr +++ b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr @@ -1,8 +1,8 @@ error: unconstrained generic constant - --> $DIR/cross_crate_predicate.rs:7:13 + --> $DIR/cross_crate_predicate.rs:7:44 | LL | let _ = const_evaluatable_lib::test1::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ | = help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::() - 1]:` note: required by a bound in `test1` @@ -12,10 +12,10 @@ LL | [u8; std::mem::size_of::() - 1]: Sized, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` error: unconstrained generic constant - --> $DIR/cross_crate_predicate.rs:7:13 + --> $DIR/cross_crate_predicate.rs:7:44 | LL | let _ = const_evaluatable_lib::test1::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ | = help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::() - 1]:` note: required by a bound in `test1` diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr index 6d8955e411ec3..2831577b13269 100644 --- a/tests/ui/const-generics/type_mismatch.stderr +++ b/tests/ui/const-generics/type_mismatch.stderr @@ -1,8 +1,8 @@ error: the constant `N` is not of type `u8` - --> $DIR/type_mismatch.rs:2:5 + --> $DIR/type_mismatch.rs:2:11 | LL | bar::() - | ^^^^^^^^ + | ^ | note: required by a bound in `bar` --> $DIR/type_mismatch.rs:6:8 From 6c6bd014210aa4a5cd4a2bb5ab4cc7174e82d74b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 9 Mar 2023 22:08:48 +0000 Subject: [PATCH 2/2] Note type mismatch on ConstArgHasType --- .../src/traits/error_reporting/mod.rs | 14 ++++++++++++-- tests/ui/const-generics/type_mismatch.stderr | 2 +- .../bad-const-wf-doesnt-specialize.stderr | 2 +- tests/ui/transmutability/issue-101739-1.stderr | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 617d53b609dbc..296fd1ed5248f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1282,10 +1282,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ), ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { - self.tcx.sess.struct_span_err( + let mut diag = self.tcx.sess.struct_span_err( span, &format!("the constant `{}` is not of type `{}`", ct, ty), - ) + ); + self.note_type_err( + &mut diag, + &obligation.cause, + None, + None, + TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())), + false, + false, + ); + diag } } } diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr index 2831577b13269..394dd44d40d33 100644 --- a/tests/ui/const-generics/type_mismatch.stderr +++ b/tests/ui/const-generics/type_mismatch.stderr @@ -2,7 +2,7 @@ error: the constant `N` is not of type `u8` --> $DIR/type_mismatch.rs:2:11 | LL | bar::() - | ^ + | ^ expected `u8`, found `usize` | note: required by a bound in `bar` --> $DIR/type_mismatch.rs:6:8 diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr index 6d7028c5e7088..83f311efd39d7 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -2,7 +2,7 @@ error: the constant `N` is not of type `usize` --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29 | LL | impl Copy for S {} - | ^^^^ + | ^^^^ expected `usize`, found `i32` | note: required by a bound in `S` --> $DIR/bad-const-wf-doesnt-specialize.rs:6:10 diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr index f0fa93722b89b..bf947d0ea4a6c 100644 --- a/tests/ui/transmutability/issue-101739-1.stderr +++ b/tests/ui/transmutability/issue-101739-1.stderr @@ -8,7 +8,7 @@ error: the constant `ASSUME_ALIGNMENT` is not of type `Assume` --> $DIR/issue-101739-1.rs:8:14 | LL | Dst: BikeshedIntrinsicFrom, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` | note: required by a bound in `BikeshedIntrinsicFrom` --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL