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;
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>]>,
}
}
}
- 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_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'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_rhs {
- 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_rhs.map(|(expr, _)| expr.span),
- is_lit: opt_rhs
- .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,
)
/// 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)
- }
-
- pub(super) fn lookup_op_method_in_trait(
- &self,
- span: Span,
- m_name: Ident,
- trait_def_id: DefId,
- self_ty: Ty<'tcx>,
- opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>,
- expected: Expectation<'tcx>,
- ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
- let (obligation, substs) =
- self.obligation_for_op_method(span, trait_def_id, self_ty, opt_rhs, expected);
- self.construct_obligation_for_trait(span, m_name, trait_def_id, obligation, substs)
+ 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
// 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>,
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;
// 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 fn_sig =
+ self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
let InferOk { value, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(fn_sig);
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
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_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
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::*;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(output_def_id) = output_def_id
&& let Some(trait_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))
} else {
Op::Unary(..) => 0,
},
) {
+ self.tcx
+ .sess
+ .delay_span_bug(span, "operator didn't have the right number of generic args");
return Err(vec![]);
}
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| {
- self.lookup_op_method_in_trait(span, opname, trait_did, lhs_ty, opt_rhs, expected)
+ self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, Some(input_types))
});
match (method, trait_did) {
(None, None) => Err(vec![]),
(None, Some(trait_did)) => {
let (obligation, _) =
- self.obligation_for_op_method(span, trait_did, lhs_ty, opt_rhs, expected);
+ self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation))
}
}