1
Fork 0

Rollup merge of #106173 - compiler-errors:deduplicate-op-methods, r=jackh726

Deduplicate `op` methods

There are some operator-checking flavored methods in `FnCtxt` that can be deduplicated.
This commit is contained in:
Matthias Krüger 2022-12-28 14:40:01 +01:00 committed by GitHub
commit c991c243b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 159 deletions

View file

@ -241,7 +241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}); });
if let Some(ok) = self.lookup_method_in_trait( if let Some(ok) = self.lookup_method_in_trait(
call_expr.span, self.misc(call_expr.span),
method_name, method_name,
trait_def_id, trait_def_id,
adjusted_ty, adjusted_ty,

View file

@ -11,7 +11,7 @@ pub use self::suggest::SelfSource;
pub use self::MethodError::*; pub use self::MethodError::*;
use crate::errors::OpMethodGenericParams; use crate::errors::OpMethodGenericParams;
use crate::{Expectation, FnCtxt}; use crate::FnCtxt;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic}; use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir; use rustc_hir as hir;
@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(super) fn obligation_for_method( pub(super) fn obligation_for_method(
&self, &self,
span: Span, cause: ObligationCause<'tcx>,
trait_def_id: DefId, trait_def_id: DefId,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>, opt_input_types: Option<&[Ty<'tcx>]>,
@ -282,71 +282,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
} }
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); let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
// Construct an obligation // Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref); 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)
});
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( traits::Obligation::new(
self.tcx, self.tcx,
traits::ObligationCause::new( cause,
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,
},
),
self.param_env, self.param_env,
poly_trait_ref, poly_trait_ref.without_const(),
), ),
substs, substs,
) )
@ -357,55 +305,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// In particular, it doesn't really do any probing: it simply constructs /// 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 /// an obligation for a particular trait with the given self type and checks
/// whether that trait is implemented. /// whether that trait is implemented.
#[instrument(level = "debug", skip(self, span))] #[instrument(level = "debug", skip(self))]
pub(super) fn lookup_method_in_trait( pub(super) fn lookup_method_in_trait(
&self, &self,
span: Span, cause: ObligationCause<'tcx>,
m_name: Ident, m_name: Ident,
trait_def_id: DefId, trait_def_id: DefId,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>, opt_input_types: Option<&[Ty<'tcx>]>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
let (obligation, substs) = let (obligation, substs) =
self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types); self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
self.construct_obligation_for_trait( self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs)
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,
)
} }
// FIXME(#18741): it seems likely that we can consolidate some of this // FIXME(#18741): it seems likely that we can consolidate some of this
@ -413,13 +324,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// of this method is basically the same as confirmation. // of this method is basically the same as confirmation.
fn construct_obligation_for_trait( fn construct_obligation_for_trait(
&self, &self,
span: Span,
m_name: Ident, m_name: Ident,
trait_def_id: DefId, trait_def_id: DefId,
obligation: traits::PredicateObligation<'tcx>, obligation: traits::PredicateObligation<'tcx>,
substs: &'tcx ty::List<ty::subst::GenericArg<'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>>> { ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!(?obligation); debug!(?obligation);
@ -435,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let Some(method_item) = self.associated_value(trait_def_id, m_name) else { let Some(method_item) = self.associated_value(trait_def_id, m_name) else {
tcx.sess.delay_span_bug( tcx.sess.delay_span_bug(
span, obligation.cause.span,
"operator trait does not have corresponding operator method", "operator trait does not have corresponding operator method",
); );
return None; return None;
@ -461,24 +369,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// with bound regions. // with bound regions.
let fn_sig = tcx.bound_fn_sig(def_id); let fn_sig = tcx.bound_fn_sig(def_id);
let fn_sig = fn_sig.subst(self.tcx, substs); 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 fn_sig =
self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
let cause = if is_op { let InferOk { value, obligations: o } =
ObligationCause::new( self.at(&obligation.cause, self.param_env).normalize(fn_sig);
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 InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(fn_sig);
let fn_sig = { let fn_sig = {
obligations.extend(o); obligations.extend(o);
value value
@ -494,7 +389,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// any late-bound regions appearing in its bounds. // any late-bound regions appearing in its bounds.
let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); 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 = { let bounds = {
obligations.extend(o); obligations.extend(o);
value value
@ -502,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
assert!(!bounds.has_escaping_bound_vars()); assert!(!bounds.has_escaping_bound_vars());
let predicates_cause = cause.clone(); let predicates_cause = obligation.cause.clone();
obligations.extend(traits::predicates_for_generics( obligations.extend(traits::predicates_for_generics(
move |_, _| predicates_cause.clone(), move |_, _| predicates_cause.clone(),
self.param_env, self.param_env,
@ -517,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
); );
obligations.push(traits::Obligation::new( obligations.push(traits::Obligation::new(
tcx, tcx,
cause, obligation.cause,
self.param_env, self.param_env,
ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())), ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
)); ));

View file

@ -12,14 +12,16 @@ use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
}; };
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; use rustc_middle::ty::{
self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable,
};
use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident}; use rustc_span::symbol::{sym, Ident};
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::FulfillmentError; use rustc_trait_selection::traits::{self, FulfillmentError};
use rustc_type_ir::sty::TyKind::*; use rustc_type_ir::sty::TyKind::*;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -48,8 +50,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self if self
.lookup_op_method( .lookup_op_method(
lhs_deref_ty, lhs_deref_ty,
Some(rhs_ty), Some((rhs, rhs_ty)),
Some(rhs),
Op::Binary(op, IsAssign::Yes), Op::Binary(op, IsAssign::Yes),
expected, expected,
) )
@ -60,8 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self if self
.lookup_op_method( .lookup_op_method(
lhs_ty, lhs_ty,
Some(rhs_ty), Some((rhs, rhs_ty)),
Some(rhs),
Op::Binary(op, IsAssign::Yes), Op::Binary(op, IsAssign::Yes),
expected, expected,
) )
@ -248,8 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let result = self.lookup_op_method( let result = self.lookup_op_method(
lhs_ty, lhs_ty,
Some(rhs_ty_var), Some((rhs_expr, rhs_ty_var)),
Some(rhs_expr),
Op::Binary(op, is_assign), Op::Binary(op, is_assign),
expected, expected,
); );
@ -382,8 +381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self if self
.lookup_op_method( .lookup_op_method(
lhs_deref_ty, lhs_deref_ty,
Some(rhs_ty), Some((rhs_expr, rhs_ty)),
Some(rhs_expr),
Op::Binary(op, is_assign), Op::Binary(op, is_assign),
expected, expected,
) )
@ -410,8 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let is_compatible = |lhs_ty, rhs_ty| { let is_compatible = |lhs_ty, rhs_ty| {
self.lookup_op_method( self.lookup_op_method(
lhs_ty, lhs_ty,
Some(rhs_ty), Some((rhs_expr, rhs_ty)),
Some(rhs_expr),
Op::Binary(op, is_assign), Op::Binary(op, is_assign),
expected, expected,
) )
@ -471,8 +468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let errors = self let errors = self
.lookup_op_method( .lookup_op_method(
lhs_ty, lhs_ty,
Some(rhs_ty), Some((rhs_expr, rhs_ty)),
Some(rhs_expr),
Op::Binary(op, is_assign), Op::Binary(op, is_assign),
expected, expected,
) )
@ -492,6 +488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(output_def_id) = output_def_id if let Some(output_def_id) = output_def_id
&& let Some(trait_def_id) = trait_def_id && let Some(trait_def_id) = trait_def_id
&& self.tcx.parent(output_def_id) == trait_def_id && self.tcx.parent(output_def_id) == trait_def_id
&& output_ty.is_suggestable(self.tcx, false)
{ {
Some(("Output", *output_ty)) Some(("Output", *output_ty))
} else { } else {
@ -625,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Expectation<'tcx>, expected: Expectation<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
assert!(op.is_by_value()); assert!(op.is_by_value());
match self.lookup_op_method(operand_ty, None, None, Op::Unary(op, ex.span), expected) { match self.lookup_op_method(operand_ty, None, Op::Unary(op, ex.span), expected) {
Ok(method) => { Ok(method) => {
self.write_method_call(ex.hir_id, method); self.write_method_call(ex.hir_id, method);
method.sig.output() method.sig.output()
@ -712,8 +709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn lookup_op_method( fn lookup_op_method(
&self, &self,
lhs_ty: Ty<'tcx>, lhs_ty: Ty<'tcx>,
other_ty: Option<Ty<'tcx>>, opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>,
other_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
op: Op, op: Op,
expected: Expectation<'tcx>, expected: Expectation<'tcx>,
) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> { ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> {
@ -742,20 +738,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Op::Unary(..) => 0, Op::Unary(..) => 0,
}, },
) { ) {
self.tcx
.sess
.delay_span_bug(span, "operator didn't have the right number of generic args");
return Err(vec![]); return Err(vec![]);
} }
let opname = Ident::with_dummy_span(opname); let opname = Ident::with_dummy_span(opname);
let input_types =
opt_rhs.as_ref().map(|(_, ty)| std::slice::from_ref(ty)).unwrap_or_default();
let cause = self.cause(
span,
traits::BinOp {
rhs_span: opt_rhs.map(|(expr, _)| expr.span),
is_lit: opt_rhs
.map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty: expected.only_has_type(self),
},
);
let method = trait_did.and_then(|trait_did| { let method = trait_did.and_then(|trait_did| {
self.lookup_op_method_in_trait( self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, Some(input_types))
span,
opname,
trait_did,
lhs_ty,
other_ty,
other_ty_expr,
expected,
)
}); });
match (method, trait_did) { match (method, trait_did) {
@ -766,14 +769,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
(None, None) => Err(vec![]), (None, None) => Err(vec![]),
(None, Some(trait_did)) => { (None, Some(trait_did)) => {
let (obligation, _) = self.obligation_for_op_method( let (obligation, _) =
span, self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
trait_did,
lhs_ty,
other_ty,
other_ty_expr,
expected,
);
Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation)) Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation))
} }
} }

View file

@ -225,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
imm_tr.and_then(|trait_did| { imm_tr.and_then(|trait_did| {
self.lookup_method_in_trait( self.lookup_method_in_trait(
span, self.misc(span),
Ident::with_dummy_span(imm_op), Ident::with_dummy_span(imm_op),
trait_did, trait_did,
base_ty, base_ty,
@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mut_tr.and_then(|trait_did| { mut_tr.and_then(|trait_did| {
self.lookup_method_in_trait( self.lookup_method_in_trait(
span, self.misc(span),
Ident::with_dummy_span(mut_op), Ident::with_dummy_span(mut_op),
trait_did, trait_did,
base_ty, base_ty,