about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs161
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs109
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs72
3 files changed, 161 insertions, 181 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 5f28500389d..1844e766a82 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -11,7 +11,7 @@ use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::CoroutineKind;
 use rustc_index::IndexSlice;
 use rustc_infer::infer::BoundRegionConversionTime;
-use rustc_infer::traits::{FulfillmentErrorCode, SelectionError, TraitEngine, TraitEngineExt};
+use rustc_infer::traits::{FulfillmentErrorCode, SelectionError};
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
     AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
@@ -25,11 +25,9 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, VariantIdx};
-use rustc_trait_selection::solve::FulfillmentCtxt;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{
-    type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause,
-};
+use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
@@ -1175,113 +1173,56 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             } else {
                                 vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
                             };
-                            self.infcx.probe(|_snapshot| {
-                                if let ty::Adt(def, args) = ty.kind()
-                                    && !has_sugg
-                                    && let Some((def_id, _imp)) = tcx
-                                        .all_impls(clone_trait)
-                                        .filter_map(|def_id| {
-                                            tcx.impl_trait_ref(def_id).map(|r| (def_id, r))
-                                        })
-                                        .map(|(def_id, imp)| (def_id, imp.skip_binder()))
-                                        .filter(|(_, imp)| match imp.self_ty().peel_refs().kind() {
-                                            ty::Adt(i_def, _) if i_def.did() == def.did() => true,
-                                            _ => false,
-                                        })
-                                        .next()
-                                {
-                                    let mut fulfill_cx = FulfillmentCtxt::new(self.infcx);
-                                    // We get all obligations from the impl to talk about specific
-                                    // trait bounds.
-                                    let obligations = tcx
-                                        .predicates_of(def_id)
-                                        .instantiate(tcx, args)
-                                        .into_iter()
-                                        .map(|(clause, span)| {
-                                            Obligation::new(
-                                                tcx,
-                                                ObligationCause::misc(
-                                                    span,
-                                                    self.body.source.def_id().expect_local(),
-                                                ),
-                                                self.param_env,
-                                                clause,
-                                            )
-                                        })
-                                        .collect::<Vec<_>>();
-                                    fulfill_cx
-                                        .register_predicate_obligations(self.infcx, obligations);
-                                    // We also register the parent obligation for the type at hand
-                                    // implementing `Clone`, to account for bounds that also need
-                                    // to be evaluated, like ensuring that `Self: Clone`.
-                                    let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty]);
-                                    let obligation = Obligation::new(
-                                        tcx,
-                                        ObligationCause::dummy(),
-                                        self.param_env,
-                                        trait_ref,
-                                    );
-                                    fulfill_cx
-                                        .register_predicate_obligation(self.infcx, obligation);
-                                    let errors = fulfill_cx.select_all_or_error(self.infcx);
-                                    // We remove the last predicate failure, which corresponds to
-                                    // the top-level obligation, because most of the type we only
-                                    // care about the other ones, *except* when it is the only one.
-                                    // This seems to only be relevant for arbitrary self-types.
-                                    // Look at `tests/ui/moves/move-fn-self-receiver.rs`.
-                                    let errors = match &errors[..] {
-                                        errors @ [] | errors @ [_] | [errors @ .., _] => errors,
-                                    };
-                                    let msg = match &errors[..] {
-                                        [] => "you can `clone` the value and consume it, but this \
-                                               might not be your desired behavior"
-                                            .to_string(),
-                                        [error] => {
-                                            format!(
-                                                "you could `clone` the value and consume it, if \
-                                                 the `{}` trait bound could be satisfied",
-                                                error.obligation.predicate,
-                                            )
-                                        }
-                                        [errors @ .., last] => {
-                                            format!(
-                                                "you could `clone` the value and consume it, if \
-                                                 the following trait bounds could be satisfied: {} \
-                                                 and `{}`",
-                                                errors
-                                                    .iter()
-                                                    .map(|e| format!(
-                                                        "`{}`",
-                                                        e.obligation.predicate
-                                                    ))
-                                                    .collect::<Vec<_>>()
-                                                    .join(", "),
-                                                last.obligation.predicate,
-                                            )
-                                        }
-                                    };
-                                    err.multipart_suggestion_verbose(
-                                        msg,
-                                        sugg.clone(),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                    for error in errors {
-                                        if let FulfillmentErrorCode::CodeSelectionError(
-                                            SelectionError::Unimplemented,
-                                        ) = error.code
-                                            && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
-                                                pred,
-                                            )) = error.obligation.predicate.kind().skip_binder()
-                                        {
-                                            self.infcx.err_ctxt().suggest_derive(
-                                                &error.obligation,
-                                                err,
-                                                error.obligation.predicate.kind().rebind(pred),
-                                            );
-                                        }
+                            if let Some(errors) =
+                                self.infcx.could_impl_trait(clone_trait, ty, self.param_env)
+                                && !has_sugg
+                            {
+                                let msg = match &errors[..] {
+                                    [] => "you can `clone` the value and consume it, but this \
+                                            might not be your desired behavior"
+                                        .to_string(),
+                                    [error] => {
+                                        format!(
+                                            "you could `clone` the value and consume it, if \
+                                                the `{}` trait bound could be satisfied",
+                                            error.obligation.predicate,
+                                        )
+                                    }
+                                    [errors @ .., last] => {
+                                        format!(
+                                            "you could `clone` the value and consume it, if \
+                                                the following trait bounds could be satisfied: {} \
+                                                and `{}`",
+                                            errors
+                                                .iter()
+                                                .map(|e| format!("`{}`", e.obligation.predicate))
+                                                .collect::<Vec<_>>()
+                                                .join(", "),
+                                            last.obligation.predicate,
+                                        )
+                                    }
+                                };
+                                err.multipart_suggestion_verbose(
+                                    msg,
+                                    sugg.clone(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                for error in errors {
+                                    if let FulfillmentErrorCode::CodeSelectionError(
+                                        SelectionError::Unimplemented,
+                                    ) = error.code
+                                        && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
+                                            pred,
+                                        )) = error.obligation.predicate.kind().skip_binder()
+                                    {
+                                        self.infcx.err_ctxt().suggest_derive(
+                                            &error.obligation,
+                                            err,
+                                            error.obligation.predicate.kind().rebind(pred),
+                                        );
                                     }
                                 }
-                            });
+                            }
                         }
                     }
                 }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index b61b029813c..2c9942caab2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -21,7 +21,7 @@ use rustc_hir::{
     StmtKind, TyKind, WherePredicate,
 };
 use rustc_hir_analysis::astconv::AstConv;
-use rustc_infer::traits::{self, StatementAsExpression, TraitEngineExt};
+use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -34,7 +34,6 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::solve::FulfillmentCtxt;
 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -1620,78 +1619,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     None,
                 );
             } else {
-                self.infcx.probe(|_snapshot| {
-                    if let ty::Adt(def, args) = expected_ty.kind()
-                        && let Some((def_id, _imp)) = self
-                            .tcx
-                            .all_impls(clone_trait_did)
-                            .filter_map(|def_id| {
-                                self.tcx.impl_trait_ref(def_id).map(|r| (def_id, r))
-                            })
-                            .map(|(def_id, imp)| (def_id, imp.skip_binder()))
-                            .filter(|(_, imp)| match imp.self_ty().peel_refs().kind() {
-                                ty::Adt(i_def, _) if i_def.did() == def.did() => true,
-                                _ => false,
-                            })
-                            .next()
-                    {
-                        let mut fulfill_cx = FulfillmentCtxt::new(&self.infcx);
-                        // We get all obligations from the impl to talk about specific
-                        // trait bounds.
-                        let obligations = self
-                            .tcx
-                            .predicates_of(def_id)
-                            .instantiate(self.tcx, args)
-                            .into_iter()
-                            .map(|(clause, span)| {
-                                traits::Obligation::new(
-                                    self.tcx,
-                                    traits::ObligationCause::misc(span, self.body_id),
-                                    self.param_env,
-                                    clause,
-                                )
-                            })
-                            .collect::<Vec<_>>();
-                        fulfill_cx.register_predicate_obligations(&self.infcx, obligations);
-                        let errors = fulfill_cx.select_all_or_error(&self.infcx);
-                        match &errors[..] {
-                            [] => {}
-                            [error] => {
-                                diag.help(format!(
-                                    "`Clone` is not implemented because the trait bound `{}` is \
-                                     not satisfied",
-                                    error.obligation.predicate,
-                                ));
-                            }
-                            [errors @ .., last] => {
-                                diag.help(format!(
-                                    "`Clone` is not implemented because the following trait bounds \
-                                     could not be satisfied: {} and `{}`",
-                                    errors
-                                        .iter()
-                                        .map(|e| format!("`{}`", e.obligation.predicate))
-                                        .collect::<Vec<_>>()
-                                        .join(", "),
-                                    last.obligation.predicate,
-                                ));
-                            }
+                if let Some(errors) =
+                    self.could_impl_trait(clone_trait_did, expected_ty, self.param_env)
+                {
+                    match &errors[..] {
+                        [] => {}
+                        [error] => {
+                            diag.help(format!(
+                                "`Clone` is not implemented because the trait bound `{}` is \
+                                 not satisfied",
+                                error.obligation.predicate,
+                            ));
                         }
-                        for error in errors {
-                            if let traits::FulfillmentErrorCode::CodeSelectionError(
-                                traits::SelectionError::Unimplemented,
-                            ) = error.code
-                                && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
-                                    error.obligation.predicate.kind().skip_binder()
-                            {
-                                self.infcx.err_ctxt().suggest_derive(
-                                    &error.obligation,
-                                    diag,
-                                    error.obligation.predicate.kind().rebind(pred),
-                                );
-                            }
+                        [errors @ .., last] => {
+                            diag.help(format!(
+                                "`Clone` is not implemented because the following trait bounds \
+                                 could not be satisfied: {} and `{}`",
+                                errors
+                                    .iter()
+                                    .map(|e| format!("`{}`", e.obligation.predicate))
+                                    .collect::<Vec<_>>()
+                                    .join(", "),
+                                last.obligation.predicate,
+                            ));
                         }
                     }
-                });
+                    for error in errors {
+                        if let traits::FulfillmentErrorCode::CodeSelectionError(
+                            traits::SelectionError::Unimplemented,
+                        ) = error.code
+                            && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
+                                error.obligation.predicate.kind().skip_binder()
+                        {
+                            self.infcx.err_ctxt().suggest_derive(
+                                &error.obligation,
+                                diag,
+                                error.obligation.predicate.kind().rebind(pred),
+                            );
+                        }
+                    }
+                }
                 self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
             }
         }
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 38153cccfdd..992bfd97e0e 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -1,8 +1,10 @@
+use crate::solve::FulfillmentCtxt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::{self, DefiningAnchor, ObligationCtxt};
 
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
+use rustc_infer::traits::{TraitEngine, TraitEngineExt};
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
 use rustc_middle::traits::query::NoSolution;
@@ -35,6 +37,13 @@ pub trait InferCtxtExt<'tcx> {
         params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> traits::EvaluationResult;
+
+    fn could_impl_trait(
+        &self,
+        trait_def_id: DefId,
+        ty: Ty<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Option<Vec<traits::FulfillmentError<'tcx>>>;
 }
 
 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
@@ -76,6 +85,69 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         };
         self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
     }
+
+    fn could_impl_trait(
+        &self,
+        trait_def_id: DefId,
+        ty: Ty<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Option<Vec<traits::FulfillmentError<'tcx>>> {
+        self.probe(|_snapshot| {
+            if let ty::Adt(def, args) = ty.kind()
+                && let Some((impl_def_id, _)) = self
+                    .tcx
+                    .all_impls(trait_def_id)
+                    .filter_map(|impl_def_id| {
+                        self.tcx.impl_trait_ref(impl_def_id).map(|r| (impl_def_id, r))
+                    })
+                    .map(|(impl_def_id, imp)| (impl_def_id, imp.skip_binder()))
+                    .filter(|(_, imp)| match imp.self_ty().peel_refs().kind() {
+                        ty::Adt(i_def, _) if i_def.did() == def.did() => true,
+                        _ => false,
+                    })
+                    .next()
+            {
+                let mut fulfill_cx = FulfillmentCtxt::new(self);
+                // We get all obligations from the impl to talk about specific
+                // trait bounds.
+                let obligations = self
+                    .tcx
+                    .predicates_of(impl_def_id)
+                    .instantiate(self.tcx, args)
+                    .into_iter()
+                    .map(|(clause, span)| {
+                        traits::Obligation::new(
+                            self.tcx,
+                            traits::ObligationCause::dummy_with_span(span),
+                            param_env,
+                            clause,
+                        )
+                    })
+                    .collect::<Vec<_>>();
+                fulfill_cx.register_predicate_obligations(self, obligations);
+                let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty]);
+                let obligation = traits::Obligation::new(
+                    self.tcx,
+                    traits::ObligationCause::dummy(),
+                    param_env,
+                    trait_ref,
+                );
+                fulfill_cx.register_predicate_obligation(self, obligation);
+                let mut errors = fulfill_cx.select_all_or_error(self);
+                // We remove the last predicate failure, which corresponds to
+                // the top-level obligation, because most of the type we only
+                // care about the other ones, *except* when it is the only one.
+                // This seems to only be relevant for arbitrary self-types.
+                // Look at `tests/ui/moves/move-fn-self-receiver.rs`.
+                if errors.len() > 1 {
+                    errors.truncate(errors.len() - 1);
+                }
+                Some(errors)
+            } else {
+                None
+            }
+        })
+    }
 }
 
 pub trait InferCtxtBuilderExt<'tcx> {