Skip to content

Commit

Permalink
Rollup merge of #132274 - compiler-errors:cleanup-op-lookup, r=nnethe…
Browse files Browse the repository at this point in the history
…rcote

Cleanup op lookup in HIR typeck

Minor cleanup for some redundant methods involved with looking up the `Operator::operator` methods for operators.
  • Loading branch information
matthiaskrgr authored Oct 29, 2024
2 parents f9fdd63 + 3240fe2 commit 1e3c0da
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 83 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/autoderef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
base_ty: Ty<'tcx>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
self.try_overloaded_place_op(span, base_ty, None, PlaceOp::Deref)
}

/// Returns the adjustment steps.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{iter, slice};
use std::iter;

use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
Expand Down Expand Up @@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ident::with_dummy_span(method_name),
trait_def_id,
adjusted_ty,
opt_input_type.as_ref().map(slice::from_ref),
opt_input_type,
) {
let method = self.register_infer_ok_obligations(ok);
let mut autoref = None;
Expand Down
91 changes: 31 additions & 60 deletions compiler/rustc_hir_typeck/src/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,35 +324,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(pick)
}

pub(super) fn obligation_for_method(
&self,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
) -> (traits::PredicateObligation<'tcx>, ty::GenericArgsRef<'tcx>) {
// Construct a trait-reference `self_ty : Trait<input_tys>`
let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| {
match param.kind {
GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
GenericParamDefKind::Type { .. } => {
if param.index == 0 {
return self_ty.into();
} else if let Some(input_types) = opt_input_types {
return input_types[param.index as usize - 1].into();
}
}
}
self.var_for_def(cause.span, param)
});

let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, args);

// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
(traits::Obligation::new(self.tcx, cause, self.param_env, poly_trait_ref), args)
}

/// `lookup_method_in_trait` is used for overloaded operators.
/// It does a very narrow slice of what the normal probe/confirm path does.
/// In particular, it doesn't really do any probing: it simply constructs
Expand All @@ -365,24 +336,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
m_name: Ident,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
opt_rhs_ty: Option<Ty<'tcx>>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, args) =
self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args)
}
// Construct a trait-reference `self_ty : Trait<input_tys>`
let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| match param.kind {
GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {
unreachable!("did not expect operator trait to have lifetime/const")
}
GenericParamDefKind::Type { .. } => {
if param.index == 0 {
self_ty.into()
} else if let Some(rhs_ty) = opt_rhs_ty {
assert_eq!(param.index, 1, "did not expect >1 param on operator trait");
rhs_ty.into()
} else {
// FIXME: We should stop passing `None` for the failure case
// when probing for call exprs. I.e. `opt_rhs_ty` should always
// be set when it needs to be.
self.var_for_def(cause.span, param)
}
}
});

// FIXME(#18741): it seems likely that we can consolidate some of this
// code with the other method-lookup code. In particular, the second half
// of this method is basically the same as confirmation.
fn construct_obligation_for_trait(
&self,
m_name: Ident,
trait_def_id: DefId,
obligation: traits::PredicateObligation<'tcx>,
args: ty::GenericArgsRef<'tcx>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!(?obligation);
let obligation = traits::Obligation::new(
self.tcx,
cause,
self.param_env,
ty::TraitRef::new_from_args(self.tcx, trait_def_id, args),
);

// Now we want to know if this can be matched
if !self.predicate_may_hold(&obligation) {
Expand All @@ -406,8 +387,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
let mut obligations = PredicateObligations::new();

// FIXME(effects): revisit when binops get `#[const_trait]`

// Instantiate late-bound regions and instantiate the trait
// parameters into the method type to get the actual method type.
//
Expand All @@ -418,12 +397,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let fn_sig =
self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);

let InferOk { value, obligations: o } =
let InferOk { value: fn_sig, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(fn_sig);
let fn_sig = {
obligations.extend(o);
value
};
obligations.extend(o);

// Register obligations for the parameters. This will include the
// `Self` parameter, which in turn has a bound of the main trait,
Expand All @@ -435,13 +411,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// any late-bound regions appearing in its bounds.
let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args);

let InferOk { value, obligations: o } =
let InferOk { value: bounds, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(bounds);
let bounds = {
obligations.extend(o);
value
};

obligations.extend(o);
assert!(!bounds.has_escaping_bound_vars());

let predicates_cause = obligation.cause.clone();
Expand All @@ -454,7 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Also add an obligation for the method type being well-formed.
let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig));
debug!(
"lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
"lookup_method_in_trait: matched method method_ty={:?} obligation={:?}",
method_ty, obligation
);
obligations.push(traits::Obligation::new(
Expand All @@ -467,7 +439,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
));

let callee = MethodCallee { def_id, args, sig: fn_sig };

debug!("callee = {:?}", callee);

Some(InferOk { obligations, value: callee })
Expand Down
36 changes: 24 additions & 12 deletions compiler/rustc_hir_typeck/src/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc_span::Span;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{Ident, sym};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt};
use rustc_trait_selection::traits::{FulfillmentError, Obligation, ObligationCtxt};
use rustc_type_ir::TyKind::*;
use tracing::debug;
use {rustc_ast as ast, rustc_hir as hir};
Expand Down Expand Up @@ -895,7 +895,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let opname = Ident::with_dummy_span(opname);
let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip();
let input_types = opt_rhs_ty.as_slice();
let cause = self.cause(span, ObligationCauseCode::BinOp {
lhs_hir_id: lhs_expr.hir_id,
rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id),
Expand All @@ -904,13 +903,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
output_ty: expected.only_has_type(self),
});

let method = self.lookup_method_in_trait(
cause.clone(),
opname,
trait_did,
lhs_ty,
Some(input_types),
);
let method =
self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, opt_rhs_ty);
match method {
Some(ok) => {
let method = self.register_infer_ok_obligations(ok);
Expand All @@ -931,9 +925,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_coercible_to_type(rhs_expr, rhs_ty, None);
}

let (obligation, _) =
self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
// FIXME: This should potentially just add the obligation to the `FnCtxt`
// Construct an obligation `self_ty : Trait<input_tys>`
let args =
ty::GenericArgs::for_item(self.tcx, trait_did, |param, _| match param.kind {
ty::GenericParamDefKind::Lifetime
| ty::GenericParamDefKind::Const { .. } => {
unreachable!("did not expect operand trait to have lifetime/const args")
}
ty::GenericParamDefKind::Type { .. } => {
if param.index == 0 {
lhs_ty.into()
} else {
opt_rhs_ty.expect("expected RHS for binop").into()
}
}
});
let obligation = Obligation::new(
self.tcx,
cause,
self.param_env,
ty::TraitRef::new_from_args(self.tcx, trait_did, args),
);
let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx);
ocx.register_obligation(obligation);
Err(ocx.select_all_or_error())
Expand Down
15 changes: 7 additions & 8 deletions compiler/rustc_hir_typeck/src/place_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If some lookup succeeded, install method in table
let input_ty = self.next_ty_var(base_expr.span);
let method =
self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index);
self.try_overloaded_place_op(expr.span, self_ty, Some(input_ty), PlaceOp::Index);

if let Some(result) = method {
debug!("try_index_step: success, using overloaded indexing");
Expand Down Expand Up @@ -189,7 +189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
span: Span,
base_ty: Ty<'tcx>,
arg_tys: &[Ty<'tcx>],
opt_rhs_ty: Option<Ty<'tcx>>,
op: PlaceOp,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
Expand All @@ -207,15 +207,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ident::with_dummy_span(imm_op),
imm_tr,
base_ty,
Some(arg_tys),
opt_rhs_ty,
)
}

fn try_mutable_overloaded_place_op(
&self,
span: Span,
base_ty: Ty<'tcx>,
arg_tys: &[Ty<'tcx>],
opt_rhs_ty: Option<Ty<'tcx>>,
op: PlaceOp,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
Expand All @@ -233,7 +233,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ident::with_dummy_span(mut_op),
mut_tr,
base_ty,
Some(arg_tys),
opt_rhs_ty,
)
}

Expand Down Expand Up @@ -284,7 +284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let Some(ok) = self.try_mutable_overloaded_place_op(
expr.span,
source,
&[],
None,
PlaceOp::Deref,
)
{
Expand Down Expand Up @@ -359,8 +359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(self.typeck_results.borrow().node_args(expr.hir_id).type_at(1))
}
};
let arg_tys = arg_ty.as_slice();
let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op);
let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_ty, op);
let method = match method {
Some(ok) => self.register_infer_ok_obligations(ok),
// Couldn't find the mutable variant of the place op, keep the
Expand Down

0 comments on commit 1e3c0da

Please sign in to comment.