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

Make adjust_fulfillment_errors work with HostEffectPredicate and const_conditions #133403

Merged
merged 3 commits into from
Dec 1, 2024
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
19 changes: 15 additions & 4 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
use rustc_hir::def::{self, CtorKind, Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, LangItem};
use rustc_hir::{self as hir, HirId, LangItem};
use rustc_hir_analysis::autoderef::Autoderef;
use rustc_infer::infer;
use rustc_infer::traits::{self, Obligation, ObligationCause, ObligationCauseCode};
Expand Down Expand Up @@ -428,7 +428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
let (fn_sig, def_id) = match *callee_ty.kind() {
ty::FnDef(def_id, args) => {
self.enforce_context_effects(call_expr.span, def_id, args);
self.enforce_context_effects(Some(call_expr.hir_id), call_expr.span, def_id, args);
let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args);

// Unit testing: function items annotated with
Expand Down Expand Up @@ -837,6 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[tracing::instrument(level = "debug", skip(self, span))]
pub(super) fn enforce_context_effects(
&self,
call_hir_id: Option<HirId>,
span: Span,
callee_did: DefId,
callee_args: GenericArgsRef<'tcx>,
Expand Down Expand Up @@ -867,10 +868,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.tcx.is_conditionally_const(callee_did) {
let q = self.tcx.const_conditions(callee_did);
// FIXME(const_trait_impl): Use this span with a better cause code.
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
for (cond, _) in q.instantiate(self.tcx, callee_args) {
for (idx, (cond, pred_span)) in
q.instantiate(self.tcx, callee_args).into_iter().enumerate()
{
let cause = self.cause(
span,
if let Some(hir_id) = call_hir_id {
ObligationCauseCode::HostEffectInExpr(callee_did, pred_span, hir_id, idx)
} else {
ObligationCauseCode::WhereClause(callee_did, pred_span)
},
);
self.register_predicate(Obligation::new(
self.tcx,
self.misc(span),
cause,
self.param_env,
cond.to_host_effect_clause(self.tcx, host),
));
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
method: MethodCallee<'tcx>,
) {
self.enforce_context_effects(span, method.def_id, method.args);
self.enforce_context_effects(Some(hir_id), span, method.def_id, method.args);
self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
self.write_args(hir_id, method.args);
}
Expand Down Expand Up @@ -263,6 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
Adjust::Deref(Some(overloaded_deref)) => {
self.enforce_context_effects(
None,
expr.span,
overloaded_deref.method_call(self.tcx),
self.tcx.mk_args(&[a.target.into()]),
Expand Down
230 changes: 166 additions & 64 deletions compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,56 @@ use rustc_trait_selection::traits;

use crate::FnCtxt;

enum ClauseFlavor {
/// Predicate comes from `predicates_of`.
Where,
/// Predicate comes from `const_conditions`.
Const,
}

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn adjust_fulfillment_error_for_expr_obligation(
&self,
error: &mut traits::FulfillmentError<'tcx>,
) -> bool {
let ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx) =
*error.obligation.cause.code().peel_derives()
else {
return false;
let (def_id, hir_id, idx, flavor) = match *error.obligation.cause.code().peel_derives() {
ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx) => {
(def_id, hir_id, idx, ClauseFlavor::Where)
}
ObligationCauseCode::HostEffectInExpr(def_id, _, hir_id, idx) => {
(def_id, hir_id, idx, ClauseFlavor::Const)
}
_ => return false,
};

let Some(uninstantiated_pred) = self
.tcx
.predicates_of(def_id)
.instantiate_identity(self.tcx)
.predicates
.into_iter()
.nth(idx)
else {
return false;
let uninstantiated_pred = match flavor {
ClauseFlavor::Where => {
if let Some(pred) = self
.tcx
.predicates_of(def_id)
.instantiate_identity(self.tcx)
.predicates
.into_iter()
.nth(idx)
{
pred
} else {
return false;
}
}
ClauseFlavor::Const => {
if let Some((pred, _)) = self
.tcx
.const_conditions(def_id)
.instantiate_identity(self.tcx)
.into_iter()
.nth(idx)
{
pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe)
} else {
return false;
}
}
};

let generics = self.tcx.generics_of(def_id);
Expand All @@ -39,6 +69,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::ClauseKind::Trait(pred) => {
(pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
}
ty::ClauseKind::HostEffect(pred) => {
(pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
}
ty::ClauseKind::Projection(pred) => (pred.projection_term.args.to_vec(), None),
ty::ClauseKind::ConstArgHasType(arg, ty) => (vec![ty.into(), arg.into()], None),
ty::ClauseKind::ConstEvaluatable(e) => (vec![e.into()], None),
Expand Down Expand Up @@ -94,39 +127,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
}

let (expr, qpath) = match self.tcx.hir_node(hir_id) {
hir::Node::Expr(expr) => {
if self.closure_span_overlaps_error(error, expr.span) {
return false;
match self.tcx.hir_node(hir_id) {
hir::Node::Expr(expr) => self.point_at_expr_if_possible(
error,
def_id,
expr,
predicate_self_type_to_point_at,
param_to_point_at,
fallback_param_to_point_at,
self_param_to_point_at,
),

hir::Node::Ty(hir::Ty { kind: hir::TyKind::Path(qpath), .. }) => {
for param in [
predicate_self_type_to_point_at,
param_to_point_at,
fallback_param_to_point_at,
self_param_to_point_at,
]
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, def_id, param, &qpath) {
return true;
}
}
let qpath =
if let hir::ExprKind::Path(qpath) = expr.kind { Some(qpath) } else { None };

(Some(&expr.kind), qpath)
false
}
hir::Node::Ty(hir::Ty { kind: hir::TyKind::Path(qpath), .. }) => (None, Some(*qpath)),
_ => return false,
};

if let Some(qpath) = qpath {
// Prefer pointing at the turbofished arg that corresponds to the
// self type of the failing predicate over anything else.
if let Some(param) = predicate_self_type_to_point_at
&& self.point_at_path_if_possible(error, def_id, param, &qpath)
{
return true;
}
_ => false,
}
}

if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Call(callee, args),
hir_id: call_hir_id,
span: call_span,
..
}) = self.tcx.parent_hir_node(hir_id)
&& callee.hir_id == hir_id
{
if self.closure_span_overlaps_error(error, *call_span) {
return false;
fn point_at_expr_if_possible(
&self,
error: &mut traits::FulfillmentError<'tcx>,
callee_def_id: DefId,
expr: &'tcx hir::Expr<'tcx>,
predicate_self_type_to_point_at: Option<ty::GenericArg<'tcx>>,
param_to_point_at: Option<ty::GenericArg<'tcx>>,
fallback_param_to_point_at: Option<ty::GenericArg<'tcx>>,
self_param_to_point_at: Option<ty::GenericArg<'tcx>>,
) -> bool {
if self.closure_span_overlaps_error(error, expr.span) {
return false;
}

match expr.kind {
hir::ExprKind::Call(
hir::Expr { kind: hir::ExprKind::Path(qpath), span: callee_span, .. },
args,
) => {
if let Some(param) = predicate_self_type_to_point_at
&& self.point_at_path_if_possible(error, callee_def_id, param, &qpath)
{
return true;
}

for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
Expand All @@ -135,32 +191,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
if self.blame_specific_arg_if_possible(
error,
def_id,
callee_def_id,
param,
*call_hir_id,
callee.span,
expr.hir_id,
*callee_span,
None,
args,
) {
return true;
}
}

for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, callee_def_id, param, &qpath) {
return true;
}
}
}
hir::ExprKind::Path(qpath) => {
// If the parent is an call, then process this as a call.
//
// This is because the `WhereClauseInExpr` obligations come from
// the well-formedness of the *path* expression, but we care to
// point at the call expression (namely, its args).
if let hir::Node::Expr(
call_expr @ hir::Expr { kind: hir::ExprKind::Call(callee, ..), .. },
) = self.tcx.parent_hir_node(expr.hir_id)
&& callee.hir_id == expr.hir_id
{
return self.point_at_expr_if_possible(
error,
callee_def_id,
call_expr,
predicate_self_type_to_point_at,
param_to_point_at,
fallback_param_to_point_at,
self_param_to_point_at,
);
}

for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, def_id, param, &qpath) {
// Otherwise, just try to point at path components.

if let Some(param) = predicate_self_type_to_point_at
&& self.point_at_path_if_possible(error, callee_def_id, param, &qpath)
{
return true;
}
}
}

match expr {
Some(hir::ExprKind::MethodCall(segment, receiver, args, ..)) => {
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, callee_def_id, param, &qpath) {
return true;
}
}
}
hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
if let Some(param) = predicate_self_type_to_point_at
&& self.point_at_generic_if_possible(error, def_id, param, segment)
&& self.point_at_generic_if_possible(error, callee_def_id, param, segment)
{
// HACK: This is not correct, since `predicate_self_type_to_point_at` might
// not actually correspond to the receiver of the method call. But we
Expand All @@ -170,7 +262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error.obligation.cause.map_code(|parent_code| {
ObligationCauseCode::FunctionArg {
arg_hir_id: receiver.hir_id,
call_hir_id: hir_id,
call_hir_id: expr.hir_id,
parent_code,
}
});
Expand All @@ -183,9 +275,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
if self.blame_specific_arg_if_possible(
error,
def_id,
callee_def_id,
param,
hir_id,
expr.hir_id,
segment.ident.span,
Some(receiver),
args,
Expand All @@ -194,7 +286,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
if let Some(param_to_point_at) = param_to_point_at
&& self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
&& self.point_at_generic_if_possible(
error,
callee_def_id,
param_to_point_at,
segment,
)
{
return true;
}
Expand All @@ -208,17 +305,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return true;
}
}
Some(hir::ExprKind::Struct(qpath, fields, ..)) => {
hir::ExprKind::Struct(qpath, fields, ..) => {
if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
self.typeck_results.borrow().qpath_res(qpath, hir_id)
self.typeck_results.borrow().qpath_res(qpath, expr.hir_id)
{
for param in
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
{
let refined_expr =
self.point_at_field_if_possible(def_id, param, variant_def_id, fields);
let refined_expr = self.point_at_field_if_possible(
callee_def_id,
param,
variant_def_id,
fields,
);

match refined_expr {
None => {}
Expand All @@ -242,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, def_id, param, qpath) {
if self.point_at_path_if_possible(error, callee_def_id, param, qpath) {
return true;
}
}
Expand Down Expand Up @@ -525,7 +626,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &'tcx hir::Expr<'tcx>,
) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
match obligation_cause_code {
traits::ObligationCauseCode::WhereClauseInExpr(_, _, _, _) => {
traits::ObligationCauseCode::WhereClauseInExpr(_, _, _, _)
| ObligationCauseCode::HostEffectInExpr(..) => {
// This is the "root"; we assume that the `expr` is already pointing here.
// Therefore, we return `Ok` so that this `expr` can be refined further.
Ok(expr)
Expand Down
Loading
Loading