1
Fork 0

remove some trait solver helpers

they add more complexity then they are worth. It's confusing
which of these helpers should be used in which context.
This commit is contained in:
lcnr 2023-03-14 14:19:06 +01:00
parent 84c47b8279
commit 791ce0b7b5
31 changed files with 199 additions and 289 deletions

View file

@ -24,6 +24,7 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::{kw, sym}; use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, Symbol}; use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::ObligationCtxt;
use crate::borrow_set::TwoPhaseActivation; use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors; use crate::borrowck_errors;
@ -760,20 +761,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
else { return; }; else { return; };
// Try to find predicates on *generic params* that would allow copying `ty` // Try to find predicates on *generic params* that would allow copying `ty`
let infcx = tcx.infer_ctxt().build(); let infcx = tcx.infer_ctxt().build();
let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); let ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::new( let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
span, let cause = ObligationCause::misc(span, self.mir_def_id());
self.mir_def_id(),
rustc_infer::traits::ObligationCauseCode::MiscObligation, ocx.register_bound(cause, self.param_env, infcx.tcx.erase_regions(ty), copy_did);
); let errors = ocx.select_all_or_error();
let errors = rustc_trait_selection::traits::fully_solve_bound(
&infcx,
cause,
self.param_env,
// Erase any region vids from the type, which may not be resolved
infcx.tcx.erase_regions(ty),
copy_did,
);
// Only emit suggestion if all required predicates are on generic // Only emit suggestion if all required predicates are on generic
let predicates: Result<Vec<_>, _> = errors let predicates: Result<Vec<_>, _> = errors

View file

@ -1078,7 +1078,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.param_env, self.param_env,
tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)), tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
def_id, def_id,
DUMMY_SP,
) )
} }
_ => false, _ => false,

View file

@ -9,7 +9,7 @@ use rustc_middle::mir;
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_trait_selection::traits::{ use rustc_trait_selection::traits::{
self, ImplSource, Obligation, ObligationCause, SelectionContext, self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
}; };
use super::ConstCx; use super::ConstCx;
@ -184,7 +184,10 @@ impl Qualif for NeedsNonConstDrop {
} }
// If we had any errors, then it's bad // If we had any errors, then it's bad
!traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty() let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligations(impl_src.nested_obligations());
let errors = ocx.select_all_or_error();
!errors.is_empty()
} }
fn in_adt_inherently<'tcx>( fn in_adt_inherently<'tcx>(

View file

@ -59,6 +59,7 @@ fn equate_intrinsic_type<'tcx>(
require_same_types( require_same_types(
tcx, tcx,
&cause, &cause,
ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env?
tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()), tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()),
fty, fty,
); );

View file

@ -11,13 +11,14 @@ use rustc_hir::ItemKind;
use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, RegionResolutionError}; use rustc_infer::infer::{self, RegionResolutionError};
use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt}; use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::misc::{ use rustc_trait_selection::traits::misc::{
type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason, type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
}; };
use rustc_trait_selection::traits::predicate_for_trait_def; use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCause}; use rustc_trait_selection::traits::{self, ObligationCause};
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -334,19 +335,19 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
)) ))
.emit(); .emit();
} else { } else {
let errors = traits::fully_solve_obligations( let ocx = ObligationCtxt::new(&infcx);
&infcx, for field in coerced_fields {
coerced_fields.into_iter().map(|field| { ocx.register_obligation(Obligation::new(
predicate_for_trait_def( tcx,
tcx, cause.clone(),
param_env, param_env,
cause.clone(), ty::Binder::dummy(tcx.mk_trait_ref(
dispatch_from_dyn_trait, dispatch_from_dyn_trait,
0,
[field.ty(tcx, substs_a), field.ty(tcx, substs_b)], [field.ty(tcx, substs_a), field.ty(tcx, substs_b)],
) )),
}), ));
); }
let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors); infcx.err_ctxt().report_fulfillment_errors(&errors);
} }
@ -583,10 +584,12 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
}; };
// Register an obligation for `A: Trait<B>`. // Register an obligation for `A: Trait<B>`.
let ocx = ObligationCtxt::new(&infcx);
let cause = traits::ObligationCause::misc(span, impl_did); let cause = traits::ObligationCause::misc(span, impl_did);
let predicate = let obligation =
predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]); Obligation::new(tcx, cause, param_env, tcx.mk_trait_ref(trait_def_id, [source, target]));
let errors = traits::fully_solve_obligation(&infcx, predicate); ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors); infcx.err_ctxt().report_fulfillment_errors(&errors);
} }

View file

@ -7,7 +7,7 @@ use rustc_infer::traits::{ObligationCause, WellFormedLoc};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder}; use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_trait_selection::traits; use rustc_trait_selection::traits::{self, ObligationCtxt};
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,35 +66,35 @@ 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>) {
let infcx = self.tcx.infer_ctxt().build(); let infcx = self.tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);
let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
let cause = traits::ObligationCause::new( let cause = traits::ObligationCause::new(
ty.span, ty.span,
self.def_id, self.def_id,
traits::ObligationCauseCode::WellFormed(None), traits::ObligationCauseCode::WellFormed(None),
); );
let errors = traits::fully_solve_obligation(
&infcx, ocx.register_obligation(traits::Obligation::new(
traits::Obligation::new( self.tcx,
self.tcx, cause,
cause, self.param_env,
self.param_env, ty::PredicateKind::WellFormed(tcx_ty.into()),
ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())), ));
),
); for error in ocx.select_all_or_error() {
if !errors.is_empty() { debug!("Wf-check got error for {:?}: {:?}", ty, error);
debug!("Wf-check got errors for {:?}: {:?}", ty, errors); if error.obligation.predicate == self.predicate {
for error in errors { // Save the cause from the greatest depth - this corresponds
if error.obligation.predicate == self.predicate { // to picking more-specific types (e.g. `MyStruct<u8>`)
// Save the cause from the greatest depth - this corresponds // over less-specific types (e.g. `Option<MyStruct<u8>>`)
// to picking more-specific types (e.g. `MyStruct<u8>`) if self.depth >= self.cause_depth {
// over less-specific types (e.g. `Option<MyStruct<u8>>`) self.cause = Some(error.obligation.cause);
if self.depth >= self.cause_depth { self.cause_depth = self.depth
self.cause = Some(error.obligation.cause);
self.cause_depth = self.depth
}
} }
} }
} }
self.depth += 1; self.depth += 1;
intravisit::walk_ty(self, ty); intravisit::walk_ty(self, ty);
self.depth -= 1; self.depth -= 1;

View file

@ -102,7 +102,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::Node; use rustc_hir::Node;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::infer::TyCtxtInferExt;
use rustc_macros::fluent_messages; use rustc_macros::fluent_messages;
use rustc_middle::middle; use rustc_middle::middle;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
@ -113,7 +113,7 @@ use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
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::TypeErrCtxtExt as _; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt};
use std::ops::Not; use std::ops::Not;
@ -160,24 +160,21 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
fn require_same_types<'tcx>( fn require_same_types<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
actual: Ty<'tcx>, actual: Ty<'tcx>,
) -> bool { ) {
let infcx = &tcx.infer_ctxt().build(); let infcx = &tcx.infer_ctxt().build();
let param_env = ty::ParamEnv::empty(); let ocx = ObligationCtxt::new(infcx);
let errors = match infcx.at(cause, param_env).eq(DefineOpaqueTypes::No, expected, actual) { match ocx.eq(cause, param_env, expected, actual) {
Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations), Ok(()) => {
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
}
}
Err(err) => { Err(err) => {
infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit(); infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
return false;
}
};
match &errors[..] {
[] => true,
errors => {
infcx.err_ctxt().report_fulfillment_errors(errors);
false
} }
} }
} }
@ -296,6 +293,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
return; return;
} }
// Main should have no WC, so empty param env is OK here.
let param_env = ty::ParamEnv::empty();
let expected_return_type; let expected_return_type;
if let Some(term_did) = tcx.lang_items().termination() { if let Some(term_did) = tcx.lang_items().termination() {
let return_ty = main_fnsig.output(); let return_ty = main_fnsig.output();
@ -306,8 +305,6 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
} }
let return_ty = return_ty.skip_binder(); let return_ty = return_ty.skip_binder();
let infcx = tcx.infer_ctxt().build(); let infcx = tcx.infer_ctxt().build();
// Main should have no WC, so empty param env is OK here.
let param_env = ty::ParamEnv::empty();
let cause = traits::ObligationCause::new( let cause = traits::ObligationCause::new(
return_ty_span, return_ty_span,
main_diagnostics_def_id, main_diagnostics_def_id,
@ -343,6 +340,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
main_diagnostics_def_id, main_diagnostics_def_id,
ObligationCauseCode::MainFunctionType, ObligationCauseCode::MainFunctionType,
), ),
param_env,
se_ty, se_ty,
tcx.mk_fn_ptr(main_fnsig), tcx.mk_fn_ptr(main_fnsig),
); );
@ -417,6 +415,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
start_def_id, start_def_id,
ObligationCauseCode::StartFunctionType, ObligationCauseCode::StartFunctionType,
), ),
ty::ParamEnv::empty(), // start should not have any where bounds.
se_ty, se_ty,
tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()), tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()),
); );

View file

@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty) if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span) && !self.type_is_sized_modulo_regions(self.param_env, output_ty)
{ {
let descr = match maybe_def { let descr = match maybe_def {
DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id), DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id),

View file

@ -96,7 +96,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let t = self.resolve_vars_if_possible(t); let t = self.resolve_vars_if_possible(t);
t.error_reported()?; t.error_reported()?;
if self.type_is_sized_modulo_regions(self.param_env, t, span) { if self.type_is_sized_modulo_regions(self.param_env, t) {
return Ok(Some(PointerKind::Thin)); return Ok(Some(PointerKind::Thin));
} }
@ -722,7 +722,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span) if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty)
&& !self.cast_ty.has_infer_types() && !self.cast_ty.has_infer_types()
{ {
self.report_cast_to_unsized_type(fcx); self.report_cast_to_unsized_type(fcx);

View file

@ -46,7 +46,7 @@ use rustc_hir::Expr;
use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::Obligation; use rustc_infer::traits::{Obligation, PredicateObligation};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{ use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@ -597,13 +597,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// and almost never more than 3. By using a SmallVec we avoid an // and almost never more than 3. By using a SmallVec we avoid an
// allocation, at the (very small) cost of (occasionally) having to // allocation, at the (very small) cost of (occasionally) having to
// shift subsequent elements down when removing the front element. // shift subsequent elements down when removing the front element.
let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def( let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new(
self.tcx, self.tcx,
self.fcx.param_env,
cause, cause,
coerce_unsized_did, self.fcx.param_env,
0, self.tcx.mk_trait_ref(coerce_unsized_did, [coerce_source, coerce_target])
[coerce_source, coerce_target]
)]; )];
let mut has_unsized_tuple_coercion = false; let mut has_unsized_tuple_coercion = false;
@ -651,9 +649,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let self_ty = trait_pred.skip_binder().self_ty(); let self_ty = trait_pred.skip_binder().self_ty();
let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
match (&self_ty.kind(), &unsize_ty.kind()) { match (self_ty.kind(), unsize_ty.kind()) {
(ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
if self.type_var_is_sized(*v) => if self.type_var_is_sized(v) =>
{ {
debug!("coerce_unsized: have sized infer {:?}", v); debug!("coerce_unsized: have sized infer {:?}", v);
coercion.obligations.push(obligation); coercion.obligations.push(obligation);

View file

@ -1480,7 +1480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// For this suggestion to make sense, the type would need to be `Copy`, // For this suggestion to make sense, the type would need to be `Copy`,
// or we have to be moving out of a `Box<T>` // or we have to be moving out of a `Box<T>`
if self.type_is_copy_modulo_regions(self.param_env, expected, sp) if self.type_is_copy_modulo_regions(self.param_env, expected)
// FIXME(compiler-errors): We can actually do this if the checked_ty is // FIXME(compiler-errors): We can actually do this if the checked_ty is
// `steps` layers of boxes, not just one, but this is easier and most likely. // `steps` layers of boxes, not just one, but this is easier and most likely.
|| (checked_ty.is_box() && steps == 1) || (checked_ty.is_box() && steps == 1)

View file

@ -867,10 +867,7 @@ fn copy_or_move<'a, 'tcx>(
mc: &mc::MemCategorizationContext<'a, 'tcx>, mc: &mc::MemCategorizationContext<'a, 'tcx>,
place_with_id: &PlaceWithHirId<'tcx>, place_with_id: &PlaceWithHirId<'tcx>,
) -> ConsumeMode { ) -> ConsumeMode {
if !mc.type_is_copy_modulo_regions( if !mc.type_is_copy_modulo_regions(place_with_id.place.ty()) {
place_with_id.place.ty(),
mc.tcx().hir().span(place_with_id.hir_id),
) {
ConsumeMode::Move ConsumeMode::Move
} else { } else {
ConsumeMode::Copy ConsumeMode::Copy

View file

@ -1011,11 +1011,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut suggest_copied_or_cloned = || { let mut suggest_copied_or_cloned = || {
let expr_inner_ty = substs.type_at(0); let expr_inner_ty = substs.type_at(0);
let expected_inner_ty = expected_substs.type_at(0); let expected_inner_ty = expected_substs.type_at(0);
if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
&& self.can_eq(self.param_env, *ty, expected_inner_ty) && self.can_eq(self.param_env, ty, expected_inner_ty)
{ {
let def_path = self.tcx.def_path_str(adt_def.did()); let def_path = self.tcx.def_path_str(adt_def.did());
if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) { if self.type_is_copy_modulo_regions(self.param_env, ty) {
diag.span_suggestion_verbose( diag.span_suggestion_verbose(
expr.span.shrink_to_hi(), expr.span.shrink_to_hi(),
format!( format!(
@ -1029,9 +1029,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self, self,
self.param_env, self.param_env,
*ty, ty,
clone_did, clone_did,
expr.span
) )
{ {
diag.span_suggestion_verbose( diag.span_suggestion_verbose(

View file

@ -120,8 +120,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.infcx.tcx self.infcx.tcx
} }
pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
} }
fn resolve_vars_if_possible<T>(&self, value: T) -> T fn resolve_vars_if_possible<T>(&self, value: T) -> T

View file

@ -21,7 +21,7 @@ use rustc_span::symbol::{sym, Ident};
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, FulfillmentError}; use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
use rustc_type_ir::sty::TyKind::*; use rustc_type_ir::sty::TyKind::*;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -434,7 +434,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.type_is_copy_modulo_regions( if self.type_is_copy_modulo_regions(
self.param_env, self.param_env,
*lhs_deref_ty, *lhs_deref_ty,
lhs_expr.span,
) { ) {
suggest_deref_binop(*lhs_deref_ty); suggest_deref_binop(*lhs_deref_ty);
} }
@ -776,7 +775,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(None, Some(trait_did)) => { (None, Some(trait_did)) => {
let (obligation, _) = let (obligation, _) =
self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types)); self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation)) // FIXME: This should potentially just add the obligation to the `FnCtxt`
let ocx = ObligationCtxt::new(&self.infcx);
ocx.register_obligation(obligation);
Err(ocx.select_all_or_error())
} }
} }
} }

View file

@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// closures. We want to make sure any adjustment that might make us move the place into // closures. We want to make sure any adjustment that might make us move the place into
// the closure gets handled. // the closure gets handled.
let (place, capture_kind) = let (place, capture_kind) =
restrict_precision_for_drop_types(self, place, capture_kind, usage_span); restrict_precision_for_drop_types(self, place, capture_kind);
capture_info.capture_kind = capture_kind; capture_info.capture_kind = capture_kind;
(place, capture_info) (place, capture_info)
@ -1822,9 +1822,8 @@ fn restrict_precision_for_drop_types<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>, fcx: &'a FnCtxt<'a, 'tcx>,
mut place: Place<'tcx>, mut place: Place<'tcx>,
mut curr_mode: ty::UpvarCapture, mut curr_mode: ty::UpvarCapture,
span: Span,
) -> (Place<'tcx>, ty::UpvarCapture) { ) -> (Place<'tcx>, ty::UpvarCapture) {
let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span); let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty());
if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) { if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) {
for i in 0..place.projections.len() { for i in 0..place.projections.len() {

View file

@ -11,6 +11,7 @@ use rustc_hir as hir;
use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause}; use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
use rustc_middle::ty::{self, List}; use rustc_middle::ty::{self, List};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use rustc_trait_selection::traits::ObligationCtxt;
declare_lint! { declare_lint! {
/// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values. /// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values.
@ -136,20 +137,23 @@ fn suggest_question_mark<'tcx>(
let ty = substs.type_at(0); let ty = substs.type_at(0);
let infcx = cx.tcx.infer_ctxt().build(); let infcx = cx.tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);
let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); let body_def_id = cx.tcx.hir().body_owner_def_id(body_id);
let cause = ObligationCause::new( let cause = ObligationCause::new(
span, span,
body_def_id, body_def_id,
rustc_infer::traits::ObligationCauseCode::MiscObligation, rustc_infer::traits::ObligationCauseCode::MiscObligation,
); );
let errors = rustc_trait_selection::traits::fully_solve_bound(
&infcx, ocx.register_bound(
cause, cause,
// FIXME: using the empty param env is wrong, should use the one from `body_id`.
ty::ParamEnv::empty(), ty::ParamEnv::empty(),
// Erase any region vids from the type, which may not be resolved // Erase any region vids from the type, which may not be resolved
infcx.tcx.erase_regions(ty), infcx.tcx.erase_regions(ty),
into_iterator_did, into_iterator_did,
); );
errors.is_empty() ocx.select_all_or_error().is_empty()
} }

View file

@ -1128,6 +1128,13 @@ impl<'tcx, T> ToPredicate<'tcx, T> for T {
} }
} }
impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> {
#[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
ty::Binder::dummy(self).to_predicate(tcx)
}
}
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
#[inline(always)] #[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
@ -1142,6 +1149,13 @@ impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> {
} }
} }
impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
#[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
ty::Binder::dummy(self).to_predicate(tcx)
}
}
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
#[inline(always)] #[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {

View file

@ -5,7 +5,7 @@ use crate::build::Builder;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::infer::InferCtxtExt;
impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> {
@ -66,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let ty = place.ty(&self.local_decls, tcx).ty; let ty = place.ty(&self.local_decls, tcx).ty;
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) { if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) {
Operand::Move(place) Operand::Move(place)
} else { } else {
Operand::Copy(place) Operand::Copy(place)

View file

@ -1,14 +1,14 @@
use rustc_hir as hir; use rustc_hir as hir;
use rustc_index::vec::Idx; use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::mir::{self, Field}; use rustc_middle::mir::{self, Field};
use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::thir::{FieldPat, Pat, PatKind};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint; use rustc_session::lint;
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::traits::predicate_for_trait_def;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; use rustc_trait_selection::traits::{self, ObligationCause};
use std::cell::Cell; use std::cell::Cell;
@ -189,17 +189,15 @@ impl<'tcx> ConstToPat<'tcx> {
// using `PartialEq::eq` in this scenario in the past.) // using `PartialEq::eq` in this scenario in the past.)
let partial_eq_trait_id = let partial_eq_trait_id =
self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span));
let obligation: PredicateObligation<'_> = predicate_for_trait_def( let partial_eq_obligation = Obligation::new(
self.tcx(), self.tcx(),
ObligationCause::dummy(),
self.param_env, self.param_env,
ObligationCause::misc(self.span, self.id.owner.def_id), self.tcx().mk_trait_ref(partial_eq_trait_id, [ty, ty]),
partial_eq_trait_id,
0,
[ty, ty],
); );
// FIXME: should this call a `predicate_must_hold` variant instead?
let has_impl = self.infcx.predicate_may_hold(&obligation); // FIXME: should this call a `predicate_must_hold` variant instead?
let has_impl = self.infcx.predicate_may_hold(&partial_eq_obligation);
// Note: To fix rust-lang/rust#65466, we could just remove this type // Note: To fix rust-lang/rust#65466, we could just remove this type
// walk hack for function pointers, and unconditionally error // walk hack for function pointers, and unconditionally error

View file

@ -8,26 +8,16 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryRes
use rustc_middle::traits::query::Fallible; use rustc_middle::traits::query::Fallible;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, ToPredicate}; use rustc_middle::ty::{GenericArg, ToPredicate};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::DUMMY_SP;
use std::fmt::Debug; use std::fmt::Debug;
pub use rustc_infer::infer::*; pub use rustc_infer::infer::*;
pub trait InferCtxtExt<'tcx> { pub trait InferCtxtExt<'tcx> {
fn type_is_copy_modulo_regions( fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool;
fn type_is_sized_modulo_regions( fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool;
/// Check whether a `ty` implements given trait(trait_def_id). /// Check whether a `ty` implements given trait(trait_def_id).
/// The inputs are: /// The inputs are:
@ -46,13 +36,9 @@ pub trait InferCtxtExt<'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> traits::EvaluationResult; ) -> traits::EvaluationResult;
} }
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
fn type_is_copy_modulo_regions( fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool {
let ty = self.resolve_vars_if_possible(ty); let ty = self.resolve_vars_if_possible(ty);
if !(param_env, ty).needs_infer() { if !(param_env, ty).needs_infer() {
@ -65,17 +51,12 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
// rightly refuses to work with inference variables, but // rightly refuses to work with inference variables, but
// moves_by_default has a cache, which we want to use in other // moves_by_default has a cache, which we want to use in other
// cases. // cases.
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id)
} }
fn type_is_sized_modulo_regions( fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool {
let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span) traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)
} }
#[instrument(level = "debug", skip(self, params), ret)] #[instrument(level = "debug", skip(self, params), ret)]

View file

@ -180,8 +180,9 @@ 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 errors = let ocx = ObligationCtxt::new(&infcx);
super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did); ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did);
let errors = ocx.select_all_or_error();
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

@ -383,7 +383,10 @@ fn resolve_negative_obligation<'tcx>(
}; };
let param_env = o.param_env; let param_env = o.param_env;
if !super::fully_solve_obligation(&infcx, o).is_empty() { let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligation(o);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
return false; return false;
} }

View file

@ -30,7 +30,7 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_span::def_id::{DefId, CRATE_DEF_ID}; use rustc_span::def_id::DefId;
use rustc_span::Span; use rustc_span::Span;
use std::fmt::Debug; use std::fmt::Debug;
@ -63,9 +63,7 @@ pub use self::util::{
elaborate_trait_ref, elaborate_trait_refs, elaborate_trait_ref, elaborate_trait_refs,
}; };
pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{expand_trait_aliases, TraitAliasExpander};
pub use self::util::{ pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
};
pub use self::util::{ pub use self::util::{
supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
SupertraitDefIds, Supertraits, SupertraitDefIds, Supertraits,
@ -131,29 +129,23 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
def_id: DefId, def_id: DefId,
span: Span,
) -> bool { ) -> bool {
let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty])); let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty]));
pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const(), span) pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const())
} }
#[instrument(level = "debug", skip(infcx, param_env, span, pred), ret)] /// FIXME(@lcnr): this function doesn't seem right and shouldn't exist?
///
/// Ping me on zulip if you want to use this method and need help with finding
/// an appropriate replacement.
#[instrument(level = "debug", skip(infcx, param_env, pred), ret)]
fn pred_known_to_hold_modulo_regions<'tcx>( fn pred_known_to_hold_modulo_regions<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>, pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>,
span: Span,
) -> bool { ) -> bool {
let has_non_region_infer = pred.has_non_region_infer(); let has_non_region_infer = pred.has_non_region_infer();
let obligation = Obligation { let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
param_env,
// 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
// anyhow).
cause: ObligationCause::misc(span, CRATE_DEF_ID),
recursion_depth: 0,
predicate: pred.to_predicate(infcx.tcx),
};
let result = infcx.evaluate_obligation_no_overflow(&obligation); let result = infcx.evaluate_obligation_no_overflow(&obligation);
debug!(?result); debug!(?result);
@ -166,14 +158,13 @@ fn pred_known_to_hold_modulo_regions<'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.
// FIXME(@lcnr): this function doesn't seem right.
//
// The handling of regions in this area of the code is terrible, // The handling of regions in this area of the code is terrible,
// see issue #29149. We should be able to improve on this with // see issue #29149. We should be able to improve on this with
// NLL. // NLL.
let errors = fully_solve_obligation(infcx, obligation); let ocx = ObligationCtxt::new(infcx);
ocx.register_obligation(obligation);
match &errors[..] { let errors = ocx.select_all_or_error();
match errors.as_slice() {
[] => true, [] => true,
errors => { errors => {
debug!(?errors); debug!(?errors);
@ -389,43 +380,6 @@ where
Ok(resolved_value) Ok(resolved_value)
} }
/// Process an obligation (and any nested obligations that come from it) to
/// completion, returning any errors
pub fn fully_solve_obligation<'tcx>(
infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) -> Vec<FulfillmentError<'tcx>> {
fully_solve_obligations(infcx, [obligation])
}
/// Process a set of obligations (and any nested obligations that come from them)
/// to completion
pub fn fully_solve_obligations<'tcx>(
infcx: &InferCtxt<'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
) -> Vec<FulfillmentError<'tcx>> {
let ocx = ObligationCtxt::new(infcx);
ocx.register_obligations(obligations);
ocx.select_all_or_error()
}
/// Process a bound (and any nested obligations that come from it) to completion.
/// This is a convenience function for traits that have no generic arguments, such
/// as auto traits, and builtin traits like Copy or Sized.
pub fn fully_solve_bound<'tcx>(
infcx: &InferCtxt<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
bound: DefId,
) -> Vec<FulfillmentError<'tcx>> {
let tcx = infcx.tcx;
let trait_ref = tcx.mk_trait_ref(bound, [ty]);
let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref));
fully_solve_obligation(infcx, obligation)
}
/// 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,7 +1,7 @@
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
use crate::traits::query::NoSolution; use crate::traits::query::NoSolution;
use crate::traits::ObligationCause; use crate::traits::{ObligationCause, ObligationCtxt};
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::ty::{self, ParamEnv, Ty}; use rustc_middle::ty::{self, ParamEnv, Ty};
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
@ -71,22 +71,23 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
if let Some(constraints) = constraints { if let Some(constraints) = constraints {
debug!(?constraints); debug!(?constraints);
// Instantiation may have produced new inference variables and constraints on those
// variables. Process these constraints.
let cause = ObligationCause::misc(span, body_id);
let errors = super::fully_solve_obligations(
self,
constraints.outlives.iter().map(|constraint| {
self.query_outlives_constraint_to_obligation(
*constraint,
cause.clone(),
param_env,
)
}),
);
if !constraints.member_constraints.is_empty() { if !constraints.member_constraints.is_empty() {
span_bug!(span, "{:#?}", constraints.member_constraints); span_bug!(span, "{:#?}", constraints.member_constraints);
} }
// Instantiation may have produced new inference variables and constraints on those
// variables. Process these constraints.
let ocx = ObligationCtxt::new(self);
let cause = ObligationCause::misc(span, body_id);
for &constraint in &constraints.outlives {
ocx.register_obligation(self.query_outlives_constraint_to_obligation(
constraint,
cause.clone(),
param_env,
));
}
let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
self.tcx.sess.delay_span_bug( self.tcx.sess.delay_span_bug(
span, span,

View file

@ -1,8 +1,8 @@
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;
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::ObligationCtxt;
use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_span::source_map::DUMMY_SP; use rustc_span::source_map::DUMMY_SP;
@ -73,7 +73,9 @@ 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())?;
let errors = traits::fully_solve_obligations(infcx, obligations); let ocx = ObligationCtxt::new(infcx);
ocx.register_obligations(obligations);
let errors = ocx.select_all_or_error();
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,
@ -82,9 +84,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
} }
let region_obligations = infcx.take_registered_region_obligations(); let region_obligations = infcx.take_registered_region_obligations();
let region_constraint_data = infcx.take_and_reset_region_constraints(); let region_constraint_data = infcx.take_and_reset_region_constraints();
let region_constraints = query_response::make_query_region_constraints( let region_constraints = query_response::make_query_region_constraints(
infcx.tcx, infcx.tcx,
region_obligations region_obligations

View file

@ -18,7 +18,7 @@ use rustc_session::config::TraitSolver;
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def}; use crate::traits::util::{self, closure_trait_ref_and_return_type};
use crate::traits::vtable::{ use crate::traits::vtable::{
count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset, count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset,
VtblSegment, VtblSegment,
@ -253,15 +253,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}; };
let cause = obligation.derived_cause(BuiltinDerivedObligation); let cause = obligation.derived_cause(BuiltinDerivedObligation);
ensure_sufficient_stack(|| { self.collect_predicates_for_types(
self.collect_predicates_for_types( obligation.param_env,
obligation.param_env, cause,
cause, obligation.recursion_depth + 1,
obligation.recursion_depth + 1, trait_def,
trait_def, nested,
nested, )
)
})
} else { } else {
vec![] vec![]
}; };
@ -1118,14 +1116,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(obligations); nested.extend(obligations);
// Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate. // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate.
nested.push(predicate_for_trait_def( let tail_unsize_obligation = obligation.with(
tcx, tcx,
obligation.param_env, tcx.mk_trait_ref(obligation.predicate.def_id(), [source_tail, target_tail]),
obligation.cause.clone(), );
obligation.predicate.def_id(), nested.push(tail_unsize_obligation);
obligation.recursion_depth + 1,
[source_tail, target_tail],
));
} }
// `(.., T)` -> `(.., U)` // `(.., T)` -> `(.., U)`
@ -1147,17 +1142,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
nested.extend(obligations); nested.extend(obligations);
// Construct the nested `T: Unsize<U>` predicate. // Add a nested `T: Unsize<U>` predicate.
nested.push(ensure_sufficient_stack(|| { let last_unsize_obligation = obligation
predicate_for_trait_def( .with(tcx, tcx.mk_trait_ref(obligation.predicate.def_id(), [a_last, b_last]));
tcx, nested.push(last_unsize_obligation);
obligation.param_env,
obligation.cause.clone(),
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
[a_last, b_last],
)
}));
} }
_ => bug!("source: {source}, target: {target}"), _ => bug!("source: {source}, target: {target}"),

View file

@ -17,7 +17,7 @@ use super::project;
use super::project::normalize_with_depth_to; use super::project::normalize_with_depth_to;
use super::project::ProjectionTyObligation; use super::project::ProjectionTyObligation;
use super::util; use super::util;
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; use super::util::closure_trait_ref_and_return_type;
use super::wf; use super::wf;
use super::{ use super::{
ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation,
@ -2440,15 +2440,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
placeholder_ty, placeholder_ty,
) )
}); });
let placeholder_obligation = predicate_for_trait_def(
let obligation = Obligation::new(
self.tcx(), self.tcx(),
param_env,
cause.clone(), cause.clone(),
trait_def_id, param_env,
recursion_depth, self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]),
[normalized_ty],
); );
obligations.push(placeholder_obligation); obligations.push(obligation);
obligations obligations
}) })
.collect() .collect()

View file

@ -1,11 +1,11 @@
use super::NormalizeExt; use super::NormalizeExt;
use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext}; use super::{ObligationCause, PredicateObligation, SelectionContext};
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Diagnostic; use rustc_errors::Diagnostic;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::InferOk; use rustc_infer::infer::InferOk;
use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, SubstsRef};
use rustc_span::Span; use rustc_span::Span;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -218,33 +218,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
(subject, impl_obligations) (subject, impl_obligations)
} }
pub fn predicate_for_trait_ref<'tcx>(
tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
recursion_depth: usize,
) -> PredicateObligation<'tcx> {
Obligation {
cause,
param_env,
recursion_depth,
predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
}
}
pub fn predicate_for_trait_def<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
recursion_depth: usize,
params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
) -> PredicateObligation<'tcx> {
let trait_ref = tcx.mk_trait_ref(trait_def_id, params);
predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth)
}
/// Casts a trait reference into a reference to one of its super /// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a /// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait. /// supertrait.

View file

@ -3,7 +3,6 @@
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
@ -30,7 +29,7 @@ fn is_item_raw<'tcx>(
let (param_env, ty) = query.into_parts(); let (param_env, ty) = query.into_parts();
let trait_def_id = tcx.require_lang_item(item, None); let trait_def_id = tcx.require_lang_item(item, None);
let infcx = tcx.infer_ctxt().build(); let infcx = tcx.infer_ctxt().build();
traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id, DUMMY_SP) traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id)
} }
pub(crate) fn provide(providers: &mut ty::query::Providers) { pub(crate) fn provide(providers: &mut ty::query::Providers) {

View file

@ -9,7 +9,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
use rustc_trait_selection::traits::{self, FulfillmentError}; use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@ -79,8 +79,10 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span(); let span = decl.output.span();
let infcx = cx.tcx.infer_ctxt().build(); let infcx = cx.tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);
let cause = traits::ObligationCause::misc(span, fn_def_id); let cause = traits::ObligationCause::misc(span, fn_def_id);
let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait); ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
let send_errors = ocx.select_all_or_error();
if !send_errors.is_empty() { if !send_errors.is_empty() {
span_lint_and_then( span_lint_and_then(
cx, cx,