]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_hir_typeck/src/method/mod.rs
Rollup merge of #106867 - sunfishcode:sunfishcode/std-os-fd-stable-version, r=m-ou-se
[rust.git] / compiler / rustc_hir_typeck / src / method / mod.rs
index fddb8a458a7d5f0716a6ba25f7339849a1196eb4..146d5e60c2f388c2bfd7257c66af6b91414ed12f 100644 (file)
@@ -11,7 +11,7 @@
 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;
@@ -57,7 +57,12 @@ pub enum MethodError<'tcx> {
     PrivateMatch(DefKind, DefId, Vec<DefId>),
 
     // Found a `Self: Sized` bound where `Self` is a trait object.
-    IllegalSizedBound(Vec<DefId>, bool, Span),
+    IllegalSizedBound {
+        candidates: Vec<DefId>,
+        needs_mut: bool,
+        bound_span: Span,
+        self_expr: &'tcx hir::Expr<'tcx>,
+    },
 
     // Found a match, but the return type is wrong
     BadReturnType,
@@ -92,10 +97,12 @@ pub fn method_exists(
         self_ty: Ty<'tcx>,
         call_expr_id: hir::HirId,
         allow_private: bool,
+        return_type: Option<Ty<'tcx>>,
     ) -> bool {
         match self.probe_for_name(
             probe::Mode::MethodCall,
             method_name,
+            return_type,
             IsSuggestion(false),
             self_ty,
             call_expr_id,
@@ -112,8 +119,8 @@ pub fn method_exists(
             Err(NoMatch(..)) => false,
             Err(Ambiguity(..)) => true,
             Err(PrivateMatch(..)) => allow_private,
-            Err(IllegalSizedBound(..)) => true,
-            Err(BadReturnType) => bug!("no return type expectations but got BadReturnType"),
+            Err(IllegalSizedBound { .. }) => true,
+            Err(BadReturnType) => false,
         }
     }
 
@@ -125,17 +132,16 @@ pub(crate) fn suggest_method_call(
         msg: &str,
         method_name: Ident,
         self_ty: Ty<'tcx>,
-        call_expr: &hir::Expr<'_>,
+        call_expr: &hir::Expr<'tcx>,
         span: Option<Span>,
     ) {
         let params = self
-            .probe_for_name(
-                probe::Mode::MethodCall,
+            .lookup_probe_for_diagnostic(
                 method_name,
-                IsSuggestion(true),
                 self_ty,
-                call_expr.hir_id,
+                call_expr,
                 ProbeScope::TraitsInScope,
+                None,
             )
             .map(|pick| {
                 let sig = self.tcx.fn_sig(pick.item.def_id);
@@ -216,27 +222,32 @@ pub fn lookup_method(
             }
 
             // We probe again, taking all traits into account (not only those in scope).
-            let candidates =
-                match self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::AllTraits) {
-                    // If we find a different result the caller probably forgot to import a trait.
-                    Ok(ref new_pick) if pick.differs_from(new_pick) => {
-                        vec![new_pick.item.container_id(self.tcx)]
-                    }
-                    Err(Ambiguity(ref sources)) => sources
-                        .iter()
-                        .filter_map(|source| {
-                            match *source {
-                                // Note: this cannot come from an inherent impl,
-                                // because the first probing succeeded.
-                                CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
-                                CandidateSource::Trait(_) => None,
-                            }
-                        })
-                        .collect(),
-                    _ => Vec::new(),
-                };
-
-            return Err(IllegalSizedBound(candidates, needs_mut, span));
+            let candidates = match self.lookup_probe_for_diagnostic(
+                segment.ident,
+                self_ty,
+                call_expr,
+                ProbeScope::AllTraits,
+                None,
+            ) {
+                // If we find a different result the caller probably forgot to import a trait.
+                Ok(ref new_pick) if pick.differs_from(new_pick) => {
+                    vec![new_pick.item.container_id(self.tcx)]
+                }
+                Err(Ambiguity(ref sources)) => sources
+                    .iter()
+                    .filter_map(|source| {
+                        match *source {
+                            // Note: this cannot come from an inherent impl,
+                            // because the first probing succeeded.
+                            CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
+                            CandidateSource::Trait(_) => None,
+                        }
+                    })
+                    .collect(),
+                _ => Vec::new(),
+            };
+
+            return Err(IllegalSizedBound { candidates, needs_mut, bound_span: span, self_expr });
         }
 
         Ok(result.callee)
@@ -247,12 +258,13 @@ pub fn lookup_probe(
         &self,
         method_name: Ident,
         self_ty: Ty<'tcx>,
-        call_expr: &'tcx hir::Expr<'tcx>,
+        call_expr: &hir::Expr<'_>,
         scope: ProbeScope,
     ) -> probe::PickResult<'tcx> {
         let pick = self.probe_for_name(
             probe::Mode::MethodCall,
             method_name,
+            None,
             IsSuggestion(false),
             self_ty,
             call_expr.hir_id,
@@ -262,53 +274,32 @@ pub fn lookup_probe(
         Ok(pick)
     }
 
-    pub(super) fn obligation_for_method(
+    pub fn lookup_probe_for_diagnostic(
         &self,
-        span: Span,
-        trait_def_id: DefId,
+        method_name: Ident,
         self_ty: Ty<'tcx>,
-        opt_input_types: Option<&[Ty<'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_types) = opt_input_types {
-                        return input_types[param.index as usize - 1].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);
-        (
-            traits::Obligation::misc(
-                self.tcx,
-                span,
-                self.body_id,
-                self.param_env,
-                poly_trait_ref.without_const(),
-            ),
-            substs,
-        )
+        call_expr: &hir::Expr<'_>,
+        scope: ProbeScope,
+        return_type: Option<Ty<'tcx>>,
+    ) -> probe::PickResult<'tcx> {
+        let pick = self.probe_for_name(
+            probe::Mode::MethodCall,
+            method_name,
+            return_type,
+            IsSuggestion(true),
+            self_ty,
+            call_expr.hir_id,
+            scope,
+        )?;
+        Ok(pick)
     }
 
-    pub(super) fn obligation_for_op_method(
+    pub(super) fn obligation_for_method(
         &self,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         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>,
+        opt_input_types: Option<&[Ty<'tcx>]>,
     ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
     {
         // Construct a trait-reference `self_ty : Trait<input_tys>`
@@ -318,35 +309,24 @@ pub(super) fn obligation_for_op_method(
                 GenericParamDefKind::Type { .. } => {
                     if param.index == 0 {
                         return self_ty.into();
-                    } else if let Some(input_type) = opt_input_type {
-                        return input_type.into();
+                    } else if let Some(input_types) = opt_input_types {
+                        return input_types[param.index as usize - 1].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,
         )
@@ -357,55 +337,18 @@ pub(super) fn obligation_for_op_method(
     /// 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
@@ -413,13 +356,10 @@ pub(super) fn lookup_op_method_in_trait(
     // 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);
 
@@ -435,7 +375,7 @@ fn construct_obligation_for_trait(
         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;
@@ -461,24 +401,11 @@ fn construct_obligation_for_trait(
         // 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
@@ -494,7 +421,8 @@ fn construct_obligation_for_trait(
         // 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
@@ -502,7 +430,7 @@ fn construct_obligation_for_trait(
 
         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,
@@ -517,7 +445,7 @@ fn construct_obligation_for_trait(
         );
         obligations.push(traits::Obligation::new(
             tcx,
-            cause,
+            obligation.cause,
             self.param_env,
             ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())),
         ));
@@ -583,6 +511,7 @@ pub fn resolve_fully_qualified_call(
         let pick = self.probe_for_name(
             probe::Mode::Path,
             method_name,
+            None,
             IsSuggestion(false),
             self_ty,
             expr_id,