1
Fork 0

Auto merge of #109119 - lcnr:trait-system-cleanup, r=compiler-errors

a general type system cleanup

removes the helper functions `traits::fully_solve_X` as they add more complexity then they are worth. It's confusing which of these helpers should be used in which context.

changes the way we deal with overflow to always add depth in `evaluate_predicates_recursively`. It may make sense to actually fully transition to not have `recursion_depth` on obligations but that's probably a bit too much for this PR.

also removes some other small - and imo unnecessary - helpers.

r? types
This commit is contained in:
bors 2023-03-22 05:33:18 +00:00
commit 9bdb4881c7
39 changed files with 259 additions and 385 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);
} }
@ -580,10 +581,12 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
}; };
// 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

@ -8,6 +8,8 @@ mod project;
mod structural_impls; mod structural_impls;
pub mod util; pub mod util;
use std::cmp;
use hir::def_id::LocalDefId; use hir::def_id::LocalDefId;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
@ -139,6 +141,14 @@ impl<'tcx, O> Obligation<'tcx, O> {
Self::with_depth(tcx, cause, 0, param_env, predicate) Self::with_depth(tcx, cause, 0, param_env, predicate)
} }
/// We often create nested obligations without setting the correct depth.
///
/// To deal with this evaluate and fulfill explicitly update the depth
/// of nested obligations using this function.
pub fn set_depth_from_parent(&mut self, parent_depth: usize) {
self.recursion_depth = cmp::max(parent_depth + 1, self.recursion_depth);
}
pub fn with_depth( pub fn with_depth(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,

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,22 @@ 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,
ty::ParamEnv::empty(), cx.param_env,
// 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,
@ -595,7 +595,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.evaluate_predicates_recursively_in_new_solver(predicates) self.evaluate_predicates_recursively_in_new_solver(predicates)
} else { } else {
let mut result = EvaluatedToOk; let mut result = EvaluatedToOk;
for obligation in predicates { for mut obligation in predicates {
obligation.set_depth_from_parent(stack.depth());
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
if let EvaluatedToErr = eval { if let EvaluatedToErr = eval {
// fast-path - EvaluatedToErr is the top of the lattice, // fast-path - EvaluatedToErr is the top of the lattice,
@ -661,12 +662,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let p = bound_predicate.rebind(p); let p = bound_predicate.rebind(p);
// Does this code ever run? // Does this code ever run?
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
Ok(Ok(InferOk { mut obligations, .. })) => { Ok(Ok(InferOk { obligations, .. })) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth); self.evaluate_predicates_recursively(previous_stack, obligations)
self.evaluate_predicates_recursively(
previous_stack,
obligations.into_iter(),
)
} }
Ok(Err(_)) => Ok(EvaluatedToErr), Ok(Err(_)) => Ok(EvaluatedToErr),
Err(..) => Ok(EvaluatedToAmbig), Err(..) => Ok(EvaluatedToAmbig),
@ -677,12 +674,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let p = bound_predicate.rebind(p); let p = bound_predicate.rebind(p);
// Does this code ever run? // Does this code ever run?
match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
Ok(Ok(InferOk { mut obligations, .. })) => { Ok(Ok(InferOk { obligations, .. })) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth); self.evaluate_predicates_recursively(previous_stack, obligations)
self.evaluate_predicates_recursively(
previous_stack,
obligations.into_iter(),
)
} }
Ok(Err(_)) => Ok(EvaluatedToErr), Ok(Err(_)) => Ok(EvaluatedToErr),
Err(..) => Ok(EvaluatedToAmbig), Err(..) => Ok(EvaluatedToAmbig),
@ -755,9 +748,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
arg, arg,
obligation.cause.span, obligation.cause.span,
) { ) {
Some(mut obligations) => { Some(obligations) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
cache.wf_args.borrow_mut().push((arg, previous_stack.depth())); cache.wf_args.borrow_mut().push((arg, previous_stack.depth()));
let result = let result =
self.evaluate_predicates_recursively(previous_stack, obligations); self.evaluate_predicates_recursively(previous_stack, obligations);
@ -826,10 +817,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
} }
self.add_depth( // Need to explicitly set the depth of nested goals here as
subobligations.iter_mut(), // projection obligations can cycle by themselves and in
obligation.recursion_depth, // `evaluate_predicates_recursively` we only add the depth
); // for parent trait goals because only these get added to the
// `TraitObligationStackList`.
for subobligation in subobligations.iter_mut() {
subobligation.set_depth_from_parent(obligation.recursion_depth);
}
let res = self.evaluate_predicates_recursively( let res = self.evaluate_predicates_recursively(
previous_stack, previous_stack,
subobligations, subobligations,
@ -909,38 +904,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if a.def.did == b.def.did if a.def.did == b.def.did
&& tcx.def_kind(a.def.did) == DefKind::AssocConst => && tcx.def_kind(a.def.did) == DefKind::AssocConst =>
{ {
if let Ok(new_obligations) = self if let Ok(InferOk { obligations, value: () }) = self
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.trace(c1, c2) .trace(c1, c2)
.eq(DefineOpaqueTypes::No, a.substs, b.substs) .eq(DefineOpaqueTypes::No, a.substs, b.substs)
{ {
let mut obligations = new_obligations.obligations;
self.add_depth(
obligations.iter_mut(),
obligation.recursion_depth,
);
return self.evaluate_predicates_recursively( return self.evaluate_predicates_recursively(
previous_stack, previous_stack,
obligations.into_iter(), obligations,
); );
} }
} }
(_, Unevaluated(_)) | (Unevaluated(_), _) => (), (_, Unevaluated(_)) | (Unevaluated(_), _) => (),
(_, _) => { (_, _) => {
if let Ok(new_obligations) = self if let Ok(InferOk { obligations, value: () }) = self
.infcx .infcx
.at(&obligation.cause, obligation.param_env) .at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::No, c1, c2) .eq(DefineOpaqueTypes::No, c1, c2)
{ {
let mut obligations = new_obligations.obligations;
self.add_depth(
obligations.iter_mut(),
obligation.recursion_depth,
);
return self.evaluate_predicates_recursively( return self.evaluate_predicates_recursively(
previous_stack, previous_stack,
obligations.into_iter(), obligations,
); );
} }
} }
@ -1366,24 +1351,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result); self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
} }
/// For various reasons, it's possible for a subobligation
/// to have a *lower* recursion_depth than the obligation used to create it.
/// Projection sub-obligations may be returned from the projection cache,
/// which results in obligations with an 'old' `recursion_depth`.
/// Additionally, methods like `InferCtxt.subtype_predicate` produce
/// subobligations without taking in a 'parent' depth, causing the
/// generated subobligations to have a `recursion_depth` of `0`.
///
/// To ensure that obligation_depth never decreases, we force all subobligations
/// to have at least the depth of the original obligation.
fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(
&self,
it: I,
min_depth: usize,
) {
it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
}
fn check_recursion_depth<T>( fn check_recursion_depth<T>(
&self, &self,
depth: usize, depth: usize,
@ -2440,15 +2407,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,

View file

@ -3,7 +3,7 @@
// Regression for #93775, needs build-pass to test it. // Regression for #93775, needs build-pass to test it.
#![recursion_limit = "1000"] #![recursion_limit = "1001"]
use std::marker::PhantomData; use std::marker::PhantomData;

View file

@ -1,15 +1,10 @@
error[E0275]: overflow evaluating the requirement `K: Send` error[E0275]: overflow evaluating the requirement `J: Send`
--> $DIR/recursion_limit.rs:34:5 --> $DIR/recursion_limit.rs:34:5
| |
LL | is_send::<A>(); LL | is_send::<A>();
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
| |
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit`) = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit`)
note: required because it appears within the type `J`
--> $DIR/recursion_limit.rs:24:9
|
LL | link! { J, K }
| ^
note: required because it appears within the type `I` note: required because it appears within the type `I`
--> $DIR/recursion_limit.rs:23:9 --> $DIR/recursion_limit.rs:23:9
| |

View file

@ -11,7 +11,7 @@ note: required for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<
LL | impl<T> Foo for T where Bar<T>: Foo {} LL | impl<T> Foo for T where Bar<T>: Foo {}
| ^^^ ^ --- unsatisfied trait bound introduced here | ^^^ ^ --- unsatisfied trait bound introduced here
= note: the full type name has been written to '$TEST_BUILD_DIR/error-codes/E0275/E0275.long-type-hash.txt' = note: the full type name has been written to '$TEST_BUILD_DIR/error-codes/E0275/E0275.long-type-hash.txt'
= note: 127 redundant requirements hidden = note: 126 redundant requirements hidden
= note: required for `Bar<T>` to implement `Foo` = note: required for `Bar<T>` to implement `Foo`
error: aborting due to previous error error: aborting due to previous error

View file

@ -20,51 +20,51 @@ note: required for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoDa
LL | impl<T> Foo for T where NoData<T>: Foo { LL | impl<T> Foo for T where NoData<T>: Foo {
| ^^^ ^ --- unsatisfied trait bound introduced here | ^^^ ^ --- unsatisfied trait bound introduced here
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
= note: 127 redundant requirements hidden = note: 126 redundant requirements hidden
= note: required for `NoData<T>` to implement `Foo` = note: required for `NoData<T>` to implement `Foo`
error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>: Baz` error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>: Bar`
--> $DIR/issue-20413.rs:28:42 --> $DIR/issue-20413.rs:28:42
| |
LL | impl<T> Bar for T where EvenLessData<T>: Baz { LL | impl<T> Bar for T where EvenLessData<T>: Baz {
| ^^^ | ^^^
| |
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`)
note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
--> $DIR/issue-20413.rs:28:9
|
LL | impl<T> Bar for T where EvenLessData<T>: Baz {
| ^^^ ^ --- unsatisfied trait bound introduced here
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz` note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
--> $DIR/issue-20413.rs:35:9 --> $DIR/issue-20413.rs:35:9
| |
LL | impl<T> Baz for T where AlmostNoData<T>: Bar { LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
| ^^^ ^ --- unsatisfied trait bound introduced here | ^^^ ^ --- unsatisfied trait bound introduced here
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
= note: 126 redundant requirements hidden note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
--> $DIR/issue-20413.rs:28:9
|
LL | impl<T> Bar for T where EvenLessData<T>: Baz {
| ^^^ ^ --- unsatisfied trait bound introduced here
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
= note: 125 redundant requirements hidden
= note: required for `EvenLessData<T>` to implement `Baz` = note: required for `EvenLessData<T>` to implement `Baz`
error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>: Bar` error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>: Baz`
--> $DIR/issue-20413.rs:35:42 --> $DIR/issue-20413.rs:35:42
| |
LL | impl<T> Baz for T where AlmostNoData<T>: Bar { LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
| ^^^ | ^^^
| |
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`)
note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
--> $DIR/issue-20413.rs:35:9
|
LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
| ^^^ ^ --- unsatisfied trait bound introduced here
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar` note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
--> $DIR/issue-20413.rs:28:9 --> $DIR/issue-20413.rs:28:9
| |
LL | impl<T> Bar for T where EvenLessData<T>: Baz { LL | impl<T> Bar for T where EvenLessData<T>: Baz {
| ^^^ ^ --- unsatisfied trait bound introduced here | ^^^ ^ --- unsatisfied trait bound introduced here
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt' = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
= note: 126 redundant requirements hidden note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
--> $DIR/issue-20413.rs:35:9
|
LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
| ^^^ ^ --- unsatisfied trait bound introduced here
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
= note: 125 redundant requirements hidden
= note: required for `AlmostNoData<T>` to implement `Bar` = note: required for `AlmostNoData<T>` to implement `Bar`
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View file

@ -1,22 +1,9 @@
error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe` error[E0275]: overflow evaluating the requirement `RootDatabase: RefUnwindSafe`
--> $DIR/cycle-cache-err-60010.rs:27:13 --> $DIR/cycle-cache-err-60010.rs:27:13
| |
LL | _parse: <ParseQuery as Query<RootDatabase>>::Data, LL | _parse: <ParseQuery as Query<RootDatabase>>::Data,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: required because it appears within the type `PhantomData<SalsaStorage>`
= note: required because it appears within the type `Unique<SalsaStorage>`
= note: required because it appears within the type `Box<SalsaStorage>`
note: required because it appears within the type `Runtime<RootDatabase>`
--> $DIR/cycle-cache-err-60010.rs:23:8
|
LL | struct Runtime<DB: Database> {
| ^^^^^^^
note: required because it appears within the type `RootDatabase`
--> $DIR/cycle-cache-err-60010.rs:20:8
|
LL | struct RootDatabase {
| ^^^^^^^^^^^^
note: required for `RootDatabase` to implement `SourceDatabase` note: required for `RootDatabase` to implement `SourceDatabase`
--> $DIR/cycle-cache-err-60010.rs:44:9 --> $DIR/cycle-cache-err-60010.rs:44:9
| |

View file

@ -1,6 +1,6 @@
// build-fail // build-fail
// compile-flags: -Zinline-mir=no // compile-flags: -Zinline-mir=no
// error-pattern: overflow evaluating the requirement `(): Sized` // error-pattern: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
// error-pattern: function cannot return without recursing // error-pattern: function cannot return without recursing
// normalize-stderr-test: "long-type-\d+" -> "long-type-hash" // normalize-stderr-test: "long-type-\d+" -> "long-type-hash"

View file

@ -12,11 +12,17 @@ LL | recurse(IteratorOfWrapped(elements).map(|t| t.0))
= help: a `loop` may express intention better if this is on purpose = help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default = note: `#[warn(unconditional_recursion)]` on by default
error[E0275]: overflow evaluating the requirement `(): Sized` error[E0275]: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
| |
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`) = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`)
= note: required for `std::iter::Empty<()>` to implement `Iterator` note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator`
= note: 171 redundant requirements hidden --> $DIR/issue-91949-hangs-on-recursion.rs:16:32
|
LL | impl<T, I: Iterator<Item = T>> Iterator for IteratorOfWrapped<T, I> {
| -------- ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
| |
| unsatisfied trait bound introduced here
= note: 256 redundant requirements hidden
= note: required for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<..., ...>>, ...>>, ...>>` to implement `Iterator` = note: required for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<..., ...>>, ...>>, ...>>` to implement `Iterator`
= note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type-hash.txt' = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type-hash.txt'