Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine error spans for const args in hir typeck #108961

Merged
merged 2 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 28 additions & 18 deletions compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
///
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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::<T>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^
|
= help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:`
note: required by a bound in `test1`
Expand All @@ -12,10 +12,10 @@ LL | [u8; std::mem::size_of::<T>() - 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::<T>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^
|
= help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:`
note: required by a bound in `test1`
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/const-generics/type_mismatch.stderr
Original file line number Diff line number Diff line change
@@ -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::<N>()
| ^^^^^^^^
| ^ expected `u8`, found `usize`
|
note: required by a bound in `bar`
--> $DIR/type_mismatch.rs:6:8
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error: the constant `N` is not of type `usize`
--> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
|
LL | impl<const N: i32> Copy for S<N> {}
| ^^^^
| ^^^^ expected `usize`, found `i32`
|
note: required by a bound in `S`
--> $DIR/bad-const-wf-doesnt-specialize.rs:6:10
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/transmutability/issue-101739-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ error: the constant `ASSUME_ALIGNMENT` is not of type `Assume`
--> $DIR/issue-101739-1.rs:8:14
|
LL | Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME_ALIGNMENT>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Assume`, found `bool`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have the "machinery" in rustc to do the same thing as with exprs, for other paths so that this has a nicer span?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this has to do with wfcheck which notoriously has bad spans, e.g. playground. I've looked into it, doesn't seem to have a good solution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sad :(

|
note: required by a bound in `BikeshedIntrinsicFrom`
--> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL
Expand Down