use crate::check::FnCtxt;
use crate::ObligationCause;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId;
pub mode: probe::Mode,
}
-impl<'tcx> NoMatchData<'tcx> {
- pub fn new(
- static_candidates: Vec<CandidateSource>,
- unsatisfied_predicates: Vec<(
- ty::Predicate<'tcx>,
- Option<ty::Predicate<'tcx>>,
- Option<ObligationCause<'tcx>>,
- )>,
- out_of_scope_traits: Vec<DefId>,
- lev_candidate: Option<ty::AssocItem>,
- mode: probe::Mode,
- ) -> Self {
- NoMatchData {
- static_candidates,
- unsatisfied_predicates,
- out_of_scope_traits,
- lev_candidate,
- mode,
- }
- }
-}
-
// A pared down enum describing just the places from which a method
// candidate can arise. Used for error reporting only.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[instrument(level = "debug", skip(self, err, call_expr))]
crate fn suggest_method_call(
&self,
- err: &mut DiagnosticBuilder<'a>,
+ err: &mut Diagnostic,
msg: &str,
method_name: Ident,
self_ty: Ty<'tcx>,
)
}
+ 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>>,
+ ) -> (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 = ty::TraitRef::new(trait_def_id, substs);
+
+ // Construct an obligation
+ let poly_trait_ref = ty::Binder::dummy(trait_ref);
+ (
+ traits::Obligation::new(
+ 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(_))),
+ },
+ ),
+ self.param_env,
+ poly_trait_ref.without_const().to_predicate(self.tcx),
+ ),
+ substs,
+ )
+ }
+
/// `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
/// an obligation for a particular trait with the given self type and checks
/// whether that trait is implemented.
- //
- // 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.
#[instrument(level = "debug", skip(self, span, opt_input_types))]
pub(super) fn lookup_method_in_trait(
&self,
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>>,
+ ) -> 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,
+ );
+ 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
+ // 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);
// Now we want to know if this can be matched
// Trait must have a method named `m_name` and it should not have
// type parameters or early-bound regions.
let tcx = self.tcx;
- let method_item = match self.associated_value(trait_def_id, m_name) {
- Some(method_item) => method_item,
- None => {
- tcx.sess.delay_span_bug(
- span,
- "operator trait does not have corresponding operator method",
- );
- return None;
- }
+ let Some(method_item) = self.associated_value(trait_def_id, m_name) else {
+ tcx.sess.delay_span_bug(
+ span,
+ "operator trait does not have corresponding operator method",
+ );
+ return None;
};
let def_id = method_item.def_id;
let generics = tcx.generics_of(def_id);
let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
let fn_sig = fn_sig.subst(self.tcx, substs);
- let InferOk { value, obligations: o } =
- self.normalize_associated_types_in_as_infer_ok(span, fn_sig);
+ let InferOk { value, obligations: o } = if is_op {
+ self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr)
+ } else {
+ self.normalize_associated_types_in_as_infer_ok(span, fn_sig)
+ };
let fn_sig = {
obligations.extend(o);
value
// 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.normalize_associated_types_in_as_infer_ok(span, bounds);
+ let InferOk { value, obligations: o } = if is_op {
+ self.normalize_op_associated_types_in_as_infer_ok(span, bounds, opt_input_expr)
+ } else {
+ self.normalize_associated_types_in_as_infer_ok(span, bounds)
+ };
let bounds = {
obligations.extend(o);
value
assert!(!bounds.has_escaping_bound_vars());
- let cause = traits::ObligationCause::misc(span, self.body_id);
+ 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(_))),
+ },
+ )
+ } else {
+ traits::ObligationCause::misc(span, self.body_id)
+ };
obligations.extend(traits::predicates_for_generics(cause.clone(), self.param_env, bounds));
// Also add an obligation for the method type being well-formed.
if let ty::Adt(adt_def, _) = self_ty.kind() {
if adt_def.is_enum() {
let variant_def = adt_def
- .variants
+ .variants()
.iter()
- .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did));
+ .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did()));
if let Some(variant_def) = variant_def {
// Braced variants generate unusable names in value namespace (reserved for
// possible future use), so variants resolved as associated items may refer to