Skip to content

Commit

Permalink
Rollup merge of rust-lang#106173 - compiler-errors:deduplicate-op-met…
Browse files Browse the repository at this point in the history
…hods, r=jackh726

Deduplicate `op` methods

There are some operator-checking flavored methods in `FnCtxt` that can be deduplicated.
  • Loading branch information
matthiaskrgr authored Dec 28, 2022
2 parents d40f16e + 8bf7ec7 commit 9dc0474
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 159 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});

if let Some(ok) = self.lookup_method_in_trait(
call_expr.span,
self.misc(call_expr.span),
method_name,
trait_def_id,
adjusted_ty,
Expand Down
140 changes: 18 additions & 122 deletions compiler/rustc_hir_typeck/src/method/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub use self::suggest::SelfSource;
pub use self::MethodError::*;

use crate::errors::OpMethodGenericParams;
use crate::{Expectation, FnCtxt};
use crate::FnCtxt;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
Expand Down Expand Up @@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

pub(super) fn obligation_for_method(
&self,
span: Span,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
Expand All @@ -282,71 +282,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
self.var_for_def(span, param)
});

let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);

// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
(
traits::Obligation::misc(
self.tcx,
span,
self.body_id,
self.param_env,
poly_trait_ref.without_const(),
),
substs,
)
}

pub(super) fn obligation_for_op_method(
&self,
span: Span,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_type: Option<Ty<'tcx>>,
opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
expected: Expectation<'tcx>,
) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
{
// Construct a trait-reference `self_ty : Trait<input_tys>`
let substs = InternalSubsts::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_type) = opt_input_type {
return input_type.into();
}
}
}
self.var_for_def(span, param)
self.var_for_def(cause.span, param)
});

let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);

// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));

(
traits::Obligation::new(
self.tcx,
traits::ObligationCause::new(
span,
self.body_id,
traits::BinOp {
rhs_span: opt_input_expr.map(|expr| expr.span),
is_lit: opt_input_expr
.map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty,
},
),
cause,
self.param_env,
poly_trait_ref,
poly_trait_ref.without_const(),
),
substs,
)
Expand All @@ -357,69 +305,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// In particular, it doesn't really do any probing: it simply constructs
/// an obligation for a particular trait with the given self type and checks
/// whether that trait is implemented.
#[instrument(level = "debug", skip(self, span))]
#[instrument(level = "debug", skip(self))]
pub(super) fn lookup_method_in_trait(
&self,
span: Span,
cause: ObligationCause<'tcx>,
m_name: Ident,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, substs) =
self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
self.construct_obligation_for_trait(
span,
m_name,
trait_def_id,
obligation,
substs,
None,
false,
)
}

pub(super) fn lookup_op_method_in_trait(
&self,
span: Span,
m_name: Ident,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_type: Option<Ty<'tcx>>,
opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
expected: Expectation<'tcx>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, substs) = self.obligation_for_op_method(
span,
trait_def_id,
self_ty,
opt_input_type,
opt_input_expr,
expected,
);
self.construct_obligation_for_trait(
span,
m_name,
trait_def_id,
obligation,
substs,
opt_input_expr,
true,
)
self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs)
}

// 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,
span: Span,
m_name: Ident,
trait_def_id: DefId,
obligation: traits::PredicateObligation<'tcx>,
substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>,
opt_input_expr: Option<&'tcx hir::Expr<'tcx>>,
is_op: bool,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!(?obligation);

Expand All @@ -435,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx;
let Some(method_item) = self.associated_value(trait_def_id, m_name) else {
tcx.sess.delay_span_bug(
span,
obligation.cause.span,
"operator trait does not have corresponding operator method",
);
return None;
Expand All @@ -461,24 +369,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// with bound regions.
let fn_sig = tcx.bound_fn_sig(def_id);
let fn_sig = fn_sig.subst(self.tcx, substs);
let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);

let cause = if is_op {
ObligationCause::new(
span,
self.body_id,
traits::BinOp {
rhs_span: opt_input_expr.map(|expr| expr.span),
is_lit: opt_input_expr
.map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty: None,
},
)
} else {
traits::ObligationCause::misc(span, self.body_id)
};
let fn_sig =
self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);

let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(fn_sig);
let InferOk { value, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(fn_sig);
let fn_sig = {
obligations.extend(o);
value
Expand All @@ -494,15 +389,16 @@ 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, substs);

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

assert!(!bounds.has_escaping_bound_vars());

let predicates_cause = cause.clone();
let predicates_cause = obligation.cause.clone();
obligations.extend(traits::predicates_for_generics(
move |_, _| predicates_cause.clone(),
self.param_env,
Expand All @@ -517,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
obligations.push(traits::Obligation::new(
tcx,
cause,
obligation.cause,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
));
Expand Down
Loading

0 comments on commit 9dc0474

Please sign in to comment.