1
Fork 0

Add traits::fully_solve_obligation that acts like traits::fully_normalize

It spawns up a trait engine, registers the single obligation, then fully
solves it
This commit is contained in:
Michael Goulet 2022-08-02 06:02:04 +00:00
parent 3e48434cc7
commit fe894756f8
10 changed files with 78 additions and 97 deletions

View file

@ -5,12 +5,11 @@
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir::LangItem; use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::TraitEngine;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{
self, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngineExt, self, ImplSource, Obligation, ObligationCause, SelectionContext,
}; };
use super::ConstCx; use super::ConstCx;
@ -189,15 +188,8 @@ impl Qualif for NeedsNonConstDrop {
return false; return false;
} }
// If we successfully found one, then select all of the predicates
// implied by our const drop impl.
let mut fcx = <dyn TraitEngine<'tcx>>::new(cx.tcx);
for nested in impl_src.nested_obligations() {
fcx.register_predicate_obligation(&infcx, nested);
}
// If we had any errors, then it's bad // If we had any errors, then it's bad
!fcx.select_all_or_error(&infcx).is_empty() !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
}) })
} }

View file

@ -205,10 +205,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// At this point, we already have all of the bounds we need. FulfillmentContext is used // At this point, we already have all of the bounds we need. FulfillmentContext is used
// to store all of the necessary region/lifetime bounds in the InferContext, as well as // to store all of the necessary region/lifetime bounds in the InferContext, as well as
// an additional sanity check. // an additional sanity check.
let mut fulfill = <dyn TraitEngine<'tcx>>::new(tcx); let errors =
fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy()); super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
let errors = fulfill.select_all_or_error(&infcx);
if !errors.is_empty() { if !errors.is_empty() {
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
} }

View file

@ -10,14 +10,14 @@ use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::util::impl_subject_and_oblig; use crate::traits::util::impl_subject_and_oblig;
use crate::traits::SkipLeakCheck; use crate::traits::SkipLeakCheck;
use crate::traits::{ use crate::traits::{
self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation, self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
PredicateObligations, SelectionContext, TraitEngineExt, SelectionContext,
}; };
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic; use rustc_errors::Diagnostic;
use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{util, TraitEngine}; use rustc_infer::traits::util;
use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::Subst;
@ -384,16 +384,11 @@ fn resolve_negative_obligation<'cx, 'tcx>(
return false; return false;
}; };
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); let errors = super::fully_solve_obligation(infcx, o);
fulfillment_cx.register_predicate_obligation(infcx, o);
let errors = fulfillment_cx.select_all_or_error(infcx);
if !errors.is_empty() { if !errors.is_empty() {
return false; return false;
} }
// FIXME -- also add "assumed to be well formed" types into the `outlives_env`
let outlives_env = OutlivesEnvironment::new(param_env); let outlives_env = OutlivesEnvironment::new(param_env);
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);

View file

@ -30,6 +30,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::visit::TypeVisitable;
@ -161,22 +162,20 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
// this function's result remains infallible, we must confirm // this function's result remains infallible, we must confirm
// that guess. While imperfect, I believe this is sound. // that guess. While imperfect, I believe this is sound.
// The handling of regions in this area of the code is terrible,
// see issue #29149. We should be able to improve on this with
// NLL.
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
// We can use a dummy node-id here because we won't pay any mind // We can use a dummy node-id here because we won't pay any mind
// to region obligations that arise (there shouldn't really be any // to region obligations that arise (there shouldn't really be any
// anyhow). // anyhow).
let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID); let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID);
fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause); // The handling of regions in this area of the code is terrible,
// see issue #29149. We should be able to improve on this with
// NLL.
let errors = fully_solve_bound(infcx, cause, param_env, ty, def_id);
// Note: we only assume something is `Copy` if we can // Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise, // *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok. // assume it is move; linear is always ok.
match fulfill_cx.select_all_or_error(infcx).as_slice() { match &errors[..] {
[] => { [] => {
debug!( debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
@ -413,6 +412,36 @@ where
Ok(resolved_value) Ok(resolved_value)
} }
pub fn fully_solve_obligation<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
obligation: PredicateObligation<'tcx>,
) -> Vec<FulfillmentError<'tcx>> {
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
engine.register_predicate_obligation(infcx, obligation);
engine.select_all_or_error(infcx)
}
pub fn fully_solve_obligations<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
) -> Vec<FulfillmentError<'tcx>> {
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
engine.register_predicate_obligations(infcx, obligations);
engine.select_all_or_error(infcx)
}
pub fn fully_solve_bound<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
bound: DefId,
) -> Vec<FulfillmentError<'tcx>> {
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
engine.register_bound(infcx, param_env, ty, bound, cause);
engine.select_all_or_error(infcx)
}
/// Normalizes the predicates and checks whether they hold in an empty environment. If this /// Normalizes the predicates and checks whether they hold in an empty environment. If this
/// returns true, then either normalize encountered an error or one of the predicates did not /// returns true, then either normalize encountered an error or one of the predicates did not
/// hold. Used when creating vtables to check for unsatisfiable methods. /// hold. Used when creating vtables to check for unsatisfiable methods.

View file

@ -1,11 +1,9 @@
use crate::infer::canonical::query_response; use crate::infer::canonical::query_response;
use crate::infer::{InferCtxt, InferOk}; use crate::infer::{InferCtxt, InferOk};
use crate::traits::engine::TraitEngineExt as _; use crate::traits;
use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::type_op::TypeOpOutput;
use crate::traits::query::Fallible; use crate::traits::query::Fallible;
use crate::traits::TraitEngine;
use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::traits::TraitEngineExt as _;
use rustc_span::source_map::DUMMY_SP; use rustc_span::source_map::DUMMY_SP;
use std::fmt; use std::fmt;
@ -62,8 +60,6 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>, op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
// During NLL, we expect that nobody will register region // During NLL, we expect that nobody will register region
// obligations **except** as part of a custom type op (and, at the // obligations **except** as part of a custom type op (and, at the
// end of each custom type op, we scrape out the region // end of each custom type op, we scrape out the region
@ -77,8 +73,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
); );
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
fulfill_cx.register_predicate_obligations(infcx, obligations); let errors = traits::fully_solve_obligations(infcx, obligations);
let errors = fulfill_cx.select_all_or_error(infcx);
if !errors.is_empty() { if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug( infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP, DUMMY_SP,

View file

@ -14,9 +14,7 @@ use specialization_graph::GraphExt;
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::{ use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine, TraitEngineExt,
};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder}; use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
@ -26,8 +24,8 @@ use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use super::util;
use super::SelectionContext; use super::SelectionContext;
use super::{util, FulfillmentContext};
/// Information pertinent to an overlapping impl error. /// Information pertinent to an overlapping impl error.
#[derive(Debug)] #[derive(Debug)]
@ -210,11 +208,8 @@ fn fulfill_implication<'a, 'tcx>(
// (which are packed up in penv) // (which are packed up in penv)
infcx.save_and_restore_in_snapshot_flag(|infcx| { infcx.save_and_restore_in_snapshot_flag(|infcx| {
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
for oblig in obligations.chain(more_obligations) { match &errors[..] {
fulfill_cx.register_predicate_obligation(&infcx, oblig);
}
match fulfill_cx.select_all_or_error(infcx).as_slice() {
[] => { [] => {
debug!( debug!(
"fulfill_implication: an impl for {:?} specializes {:?}", "fulfill_implication: an impl for {:?} specializes {:?}",

View file

@ -15,7 +15,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeV
use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError}; use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
use rustc_trait_selection::traits::predicate_for_trait_def; use rustc_trait_selection::traits::predicate_for_trait_def;
use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt}; use rustc_trait_selection::traits::{self, ObligationCause};
use std::collections::BTreeMap; use std::collections::BTreeMap;
pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) { pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
@ -109,15 +109,13 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
// it is not immediately clear why Copy is not implemented for a field, since // it is not immediately clear why Copy is not implemented for a field, since
// all we point at is the field itself. // all we point at is the field itself.
tcx.infer_ctxt().ignoring_regions().enter(|infcx| { tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx); for error in traits::fully_solve_bound(
fulfill_cx.register_bound(
&infcx, &infcx,
traits::ObligationCause::dummy_with_span(field_ty_span),
param_env, param_env,
ty, ty,
tcx.lang_items().copy_trait().unwrap(), tcx.lang_items().copy_trait().unwrap(),
traits::ObligationCause::dummy_with_span(field_ty_span), ) {
);
for error in fulfill_cx.select_all_or_error(&infcx) {
let error_predicate = error.obligation.predicate; let error_predicate = error.obligation.predicate;
// Only note if it's not the root obligation, otherwise it's trivial and // Only note if it's not the root obligation, otherwise it's trivial and
// should be self-explanatory (i.e. a field literally doesn't implement Copy). // should be self-explanatory (i.e. a field literally doesn't implement Copy).
@ -315,10 +313,10 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
)) ))
.emit(); .emit();
} else { } else {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); let errors = traits::fully_solve_obligations(
&infcx,
for field in coerced_fields { coerced_fields.into_iter().map(|field| {
let predicate = predicate_for_trait_def( predicate_for_trait_def(
tcx, tcx,
param_env, param_env,
cause.clone(), cause.clone(),
@ -326,13 +324,9 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
0, 0,
field.ty(tcx, substs_a), field.ty(tcx, substs_a),
&[field.ty(tcx, substs_b).into()], &[field.ty(tcx, substs_b).into()],
)
}),
); );
fulfill_cx.register_predicate_obligation(&infcx, predicate);
}
// Check that all transitive obligations are satisfied.
let errors = fulfill_cx.select_all_or_error(&infcx);
if !errors.is_empty() { if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false); infcx.report_fulfillment_errors(&errors, None, false);
} }
@ -573,8 +567,6 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
} }
}; };
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
// Register an obligation for `A: Trait<B>`. // Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_hir_id); let cause = traits::ObligationCause::misc(span, impl_hir_id);
let predicate = predicate_for_trait_def( let predicate = predicate_for_trait_def(
@ -586,10 +578,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
source, source,
&[target.into()], &[target.into()],
); );
fulfill_cx.register_predicate_obligation(&infcx, predicate); let errors = traits::fully_solve_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
let errors = fulfill_cx.select_all_or_error(&infcx);
if !errors.is_empty() { if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false); infcx.report_fulfillment_errors(&errors, None, false);
} }

View file

@ -3,11 +3,10 @@ use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{ForeignItem, ForeignItemKind, HirId}; use rustc_hir::{ForeignItem, ForeignItemKind, HirId};
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::TraitEngine;
use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_infer::traits::{ObligationCause, WellFormedLoc};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder}; use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder};
use rustc_trait_selection::traits::{self, TraitEngineExt}; use rustc_trait_selection::traits;
pub fn provide(providers: &mut Providers) { pub fn provide(providers: &mut Providers) {
*providers = Providers { diagnostic_hir_wf_check, ..*providers }; *providers = Providers { diagnostic_hir_wf_check, ..*providers };
@ -66,7 +65,6 @@ fn diagnostic_hir_wf_check<'tcx>(
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
self.tcx.infer_ctxt().enter(|infcx| { self.tcx.infer_ctxt().enter(|infcx| {
let mut fulfill = <dyn TraitEngine<'tcx>>::new(self.tcx);
let tcx_ty = let tcx_ty =
self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
let cause = traits::ObligationCause::new( let cause = traits::ObligationCause::new(
@ -74,7 +72,7 @@ fn diagnostic_hir_wf_check<'tcx>(
self.hir_id, self.hir_id,
traits::ObligationCauseCode::WellFormed(None), traits::ObligationCauseCode::WellFormed(None),
); );
fulfill.register_predicate_obligation( let errors = traits::fully_solve_obligation(
&infcx, &infcx,
traits::Obligation::new( traits::Obligation::new(
cause, cause,
@ -83,8 +81,6 @@ fn diagnostic_hir_wf_check<'tcx>(
.to_predicate(self.tcx), .to_predicate(self.tcx),
), ),
); );
let errors = fulfill.select_all_or_error(&infcx);
if !errors.is_empty() { if !errors.is_empty() {
debug!("Wf-check got errors for {:?}: {:?}", ty, errors); debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors { for error in errors {

View file

@ -104,7 +104,6 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{Node, CRATE_HIR_ID}; use rustc_hir::{Node, CRATE_HIR_ID};
use rustc_infer::infer::{InferOk, TyCtxtInferExt}; use rustc_infer::infer::{InferOk, TyCtxtInferExt};
use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::middle; use rustc_middle::middle;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
@ -113,9 +112,7 @@ use rustc_session::config::EntryFnType;
use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
};
use std::iter; use std::iter;
@ -147,18 +144,15 @@ fn require_same_types<'tcx>(
) -> bool { ) -> bool {
tcx.infer_ctxt().enter(|ref infcx| { tcx.infer_ctxt().enter(|ref infcx| {
let param_env = ty::ParamEnv::empty(); let param_env = ty::ParamEnv::empty();
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); let errors = match infcx.at(cause, param_env).eq(expected, actual) {
match infcx.at(cause, param_env).eq(expected, actual) { Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
Ok(InferOk { obligations, .. }) => {
fulfill_cx.register_predicate_obligations(infcx, obligations);
}
Err(err) => { Err(err) => {
infcx.report_mismatched_types(cause, expected, actual, err).emit(); infcx.report_mismatched_types(cause, expected, actual, err).emit();
return false; return false;
} }
} };
match fulfill_cx.select_all_or_error(infcx).as_slice() { match &errors[..] {
[] => true, [] => true,
errors => { errors => {
infcx.report_fulfillment_errors(errors, None, false); infcx.report_fulfillment_errors(errors, None, false);

View file

@ -9,7 +9,7 @@ use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt;
use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine}; use rustc_trait_selection::traits::{self, FulfillmentError};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@ -80,9 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
let span = decl.output.span(); let span = decl.output.span();
let send_errors = cx.tcx.infer_ctxt().enter(|infcx| { let send_errors = cx.tcx.infer_ctxt().enter(|infcx| {
let cause = traits::ObligationCause::misc(span, hir_id); let cause = traits::ObligationCause::misc(span, hir_id);
let mut fulfillment_cx = traits::FulfillmentContext::new(); traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait)
fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause);
fulfillment_cx.select_all_or_error(&infcx)
}); });
if !send_errors.is_empty() { if !send_errors.is_empty() {
span_lint_and_then( span_lint_and_then(