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::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::ObligationCtxt;
use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors;
@ -760,20 +761,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
else { return; };
// Try to find predicates on *generic params* that would allow copying `ty`
let infcx = tcx.infer_ctxt().build();
let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
let cause = ObligationCause::new(
span,
self.mir_def_id(),
rustc_infer::traits::ObligationCauseCode::MiscObligation,
);
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,
);
let ocx = ObligationCtxt::new(&infcx);
let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
let cause = ObligationCause::misc(span, self.mir_def_id());
ocx.register_bound(cause, self.param_env, infcx.tcx.erase_regions(ty), copy_did);
let errors = ocx.select_all_or_error();
// Only emit suggestion if all required predicates are on generic
let predicates: Result<Vec<_>, _> = errors

View File

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

View File

@ -9,7 +9,7 @@ use rustc_middle::mir;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
use rustc_trait_selection::traits::{
self, ImplSource, Obligation, ObligationCause, SelectionContext,
self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
};
use super::ConstCx;
@ -184,7 +184,10 @@ impl Qualif for NeedsNonConstDrop {
}
// 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>(

View File

@ -59,6 +59,7 @@ fn equate_intrinsic_type<'tcx>(
require_same_types(
tcx,
&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()),
fty,
);

View File

@ -11,13 +11,14 @@ use rustc_hir::ItemKind;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, RegionResolutionError};
use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
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::misc::{
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 std::collections::BTreeMap;
@ -334,19 +335,19 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
))
.emit();
} else {
let errors = traits::fully_solve_obligations(
&infcx,
coerced_fields.into_iter().map(|field| {
predicate_for_trait_def(
tcx,
param_env,
cause.clone(),
let ocx = ObligationCtxt::new(&infcx);
for field in coerced_fields {
ocx.register_obligation(Obligation::new(
tcx,
cause.clone(),
param_env,
ty::Binder::dummy(tcx.mk_trait_ref(
dispatch_from_dyn_trait,
0,
[field.ty(tcx, substs_a), field.ty(tcx, substs_b)],
)
}),
);
)),
));
}
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
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>`.
let ocx = ObligationCtxt::new(&infcx);
let cause = traits::ObligationCause::misc(span, impl_did);
let predicate =
predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]);
let errors = traits::fully_solve_obligation(&infcx, predicate);
let obligation =
Obligation::new(tcx, cause, param_env, tcx.mk_trait_ref(trait_def_id, [source, target]));
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
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::{self, Region, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::def_id::LocalDefId;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::{self, ObligationCtxt};
pub fn provide(providers: &mut 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> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
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 cause = traits::ObligationCause::new(
ty.span,
self.def_id,
traits::ObligationCauseCode::WellFormed(None),
);
let errors = traits::fully_solve_obligation(
&infcx,
traits::Obligation::new(
self.tcx,
cause,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())),
),
);
if !errors.is_empty() {
debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors {
if error.obligation.predicate == self.predicate {
// Save the cause from the greatest depth - this corresponds
// to picking more-specific types (e.g. `MyStruct<u8>`)
// over less-specific types (e.g. `Option<MyStruct<u8>>`)
if self.depth >= self.cause_depth {
self.cause = Some(error.obligation.cause);
self.cause_depth = self.depth
}
ocx.register_obligation(traits::Obligation::new(
self.tcx,
cause,
self.param_env,
ty::PredicateKind::WellFormed(tcx_ty.into()),
));
for error in ocx.select_all_or_error() {
debug!("Wf-check got error for {:?}: {:?}", ty, error);
if error.obligation.predicate == self.predicate {
// Save the cause from the greatest depth - this corresponds
// to picking more-specific types (e.g. `MyStruct<u8>`)
// over less-specific types (e.g. `Option<MyStruct<u8>>`)
if self.depth >= self.cause_depth {
self.cause = Some(error.obligation.cause);
self.cause_depth = self.depth
}
}
}
self.depth += 1;
intravisit::walk_ty(self, ty);
self.depth -= 1;

View File

@ -102,7 +102,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_hir as hir;
use rustc_hir::Node;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_macros::fluent_messages;
use rustc_middle::middle;
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_target::spec::abi::Abi;
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;
@ -160,24 +160,21 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
fn require_same_types<'tcx>(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> bool {
) {
let infcx = &tcx.infer_ctxt().build();
let param_env = ty::ParamEnv::empty();
let errors = match infcx.at(cause, param_env).eq(DefineOpaqueTypes::No, expected, actual) {
Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
let ocx = ObligationCtxt::new(infcx);
match ocx.eq(cause, param_env, expected, actual) {
Ok(()) => {
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
}
}
Err(err) => {
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;
}
// Main should have no WC, so empty param env is OK here.
let param_env = ty::ParamEnv::empty();
let expected_return_type;
if let Some(term_did) = tcx.lang_items().termination() {
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 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(
return_ty_span,
main_diagnostics_def_id,
@ -343,6 +340,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
main_diagnostics_def_id,
ObligationCauseCode::MainFunctionType,
),
param_env,
se_ty,
tcx.mk_fn_ptr(main_fnsig),
);
@ -417,6 +415,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
start_def_id,
ObligationCauseCode::StartFunctionType,
),
ty::ParamEnv::empty(), // start should not have any where bounds.
se_ty,
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 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 {
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);
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));
}
@ -722,7 +722,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
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.report_cast_to_unsized_type(fcx);

View File

@ -46,7 +46,7 @@ use rustc_hir::Expr;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
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::ty::adjustment::{
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
// allocation, at the (very small) cost of (occasionally) having to
// 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.fcx.param_env,
cause,
coerce_unsized_did,
0,
[coerce_source, coerce_target]
self.fcx.param_env,
self.tcx.mk_trait_ref(coerce_unsized_did, [coerce_source, coerce_target])
)];
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 unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
match (&self_ty.kind(), &unsize_ty.kind()) {
(ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
if self.type_var_is_sized(*v) =>
match (self_ty.kind(), unsize_ty.kind()) {
(&ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
if self.type_var_is_sized(v) =>
{
debug!("coerce_unsized: have sized infer {:?}", v);
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`,
// 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
// `steps` layers of boxes, not just one, but this is easier and most likely.
|| (checked_ty.is_box() && steps == 1)

View File

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

View File

@ -1011,11 +1011,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut suggest_copied_or_cloned = || {
let expr_inner_ty = 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()
&& self.can_eq(self.param_env, *ty, expected_inner_ty)
if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
&& self.can_eq(self.param_env, ty, expected_inner_ty)
{
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(
expr.span.shrink_to_hi(),
format!(
@ -1029,9 +1029,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self,
self.param_env,
*ty,
ty,
clone_did,
expr.span
)
{
diag.span_suggestion_verbose(

View File

@ -120,8 +120,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.infcx.tcx
}
pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
}
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_trait_selection::infer::InferCtxtExt;
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::*;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -434,7 +434,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.type_is_copy_modulo_regions(
self.param_env,
*lhs_deref_ty,
lhs_expr.span,
) {
suggest_deref_binop(*lhs_deref_ty);
}
@ -776,7 +775,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(None, Some(trait_did)) => {
let (obligation, _) =
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
// the closure gets handled.
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;
(place, capture_info)
@ -1822,9 +1822,8 @@ fn restrict_precision_for_drop_types<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>,
mut place: Place<'tcx>,
mut curr_mode: ty::UpvarCapture,
span: Span,
) -> (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) {
for i in 0..place.projections.len() {

View File

@ -8,6 +8,8 @@ mod project;
mod structural_impls;
pub mod util;
use std::cmp;
use hir::def_id::LocalDefId;
use rustc_hir as hir;
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)
}
/// 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(
tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>,

View File

@ -11,6 +11,7 @@ use rustc_hir as hir;
use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
use rustc_middle::ty::{self, List};
use rustc_span::{sym, Span};
use rustc_trait_selection::traits::ObligationCtxt;
declare_lint! {
/// 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 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 cause = ObligationCause::new(
span,
body_def_id,
rustc_infer::traits::ObligationCauseCode::MiscObligation,
);
let errors = rustc_trait_selection::traits::fully_solve_bound(
&infcx,
ocx.register_bound(
cause,
ty::ParamEnv::empty(),
cx.param_env,
// Erase any region vids from the type, which may not be resolved
infcx.tcx.erase_regions(ty),
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>> {
#[inline(always)]
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>> {
#[inline(always)]
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::ty::{self, Ty};
use rustc_span::{Span, DUMMY_SP};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
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> {
let tcx = self.tcx;
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)
} else {
Operand::Copy(place)

View File

@ -1,14 +1,14 @@
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::mir::{self, Field};
use rustc_middle::thir::{FieldPat, Pat, PatKind};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint;
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::{self, ObligationCause, PredicateObligation};
use rustc_trait_selection::traits::{self, ObligationCause};
use std::cell::Cell;
@ -189,17 +189,15 @@ impl<'tcx> ConstToPat<'tcx> {
// using `PartialEq::eq` in this scenario in the past.)
let partial_eq_trait_id =
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(),
ObligationCause::dummy(),
self.param_env,
ObligationCause::misc(self.span, self.id.owner.def_id),
partial_eq_trait_id,
0,
[ty, ty],
self.tcx().mk_trait_ref(partial_eq_trait_id, [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
// 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::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, ToPredicate};
use rustc_span::{Span, DUMMY_SP};
use rustc_span::DUMMY_SP;
use std::fmt::Debug;
pub use rustc_infer::infer::*;
pub trait InferCtxtExt<'tcx> {
fn type_is_copy_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool;
fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
fn type_is_sized_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool;
fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
/// Check whether a `ty` implements given trait(trait_def_id).
/// The inputs are:
@ -46,13 +36,9 @@ pub trait InferCtxtExt<'tcx> {
param_env: ty::ParamEnv<'tcx>,
) -> traits::EvaluationResult;
}
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
fn type_is_copy_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool {
fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
let ty = self.resolve_vars_if_possible(ty);
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
// moves_by_default has a cache, which we want to use in other
// 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(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool {
fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
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)]

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
// to store all of the necessary region/lifetime bounds in the InferContext, as well as
// an additional sanity check.
let errors =
super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
let ocx = ObligationCtxt::new(&infcx);
ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
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;
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;
}

View File

@ -30,7 +30,7 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
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 std::fmt::Debug;
@ -63,9 +63,7 @@ pub use self::util::{
elaborate_trait_ref, elaborate_trait_refs,
};
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
pub use self::util::{
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
};
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
pub use self::util::{
supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
SupertraitDefIds, Supertraits,
@ -131,29 +129,23 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
span: Span,
) -> bool {
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>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>,
span: Span,
) -> bool {
let has_non_region_infer = pred.has_non_region_infer();
let obligation = Obligation {
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 obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
let result = infcx.evaluate_obligation_no_overflow(&obligation);
debug!(?result);
@ -166,14 +158,13 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
// this function's result remains infallible, we must confirm
// 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,
// see issue #29149. We should be able to improve on this with
// NLL.
let errors = fully_solve_obligation(infcx, obligation);
match &errors[..] {
let ocx = ObligationCtxt::new(infcx);
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
match errors.as_slice() {
[] => true,
errors => {
debug!(?errors);
@ -389,43 +380,6 @@ where
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
/// 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.

View File

@ -1,7 +1,7 @@
use crate::infer::InferCtxt;
use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
use crate::traits::query::NoSolution;
use crate::traits::ObligationCause;
use crate::traits::{ObligationCause, ObligationCtxt};
use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::ty::{self, ParamEnv, Ty};
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 {
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() {
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() {
self.tcx.sess.delay_span_bug(
span,

View File

@ -1,8 +1,8 @@
use crate::infer::canonical::query_response;
use crate::infer::{InferCtxt, InferOk};
use crate::traits;
use crate::traits::query::type_op::TypeOpOutput;
use crate::traits::query::Fallible;
use crate::traits::ObligationCtxt;
use rustc_infer::infer::region_constraints::RegionConstraintData;
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 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() {
infcx.tcx.sess.diagnostic().delay_span_bug(
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_constraint_data = infcx.take_and_reset_region_constraints();
let region_constraints = query_response::make_query_region_constraints(
infcx.tcx,
region_obligations

View File

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

View File

@ -17,7 +17,7 @@ use super::project;
use super::project::normalize_with_depth_to;
use super::project::ProjectionTyObligation;
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::{
ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation,
@ -595,7 +595,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.evaluate_predicates_recursively_in_new_solver(predicates)
} else {
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())?;
if let EvaluatedToErr = eval {
// 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);
// Does this code ever run?
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
Ok(Ok(InferOk { mut obligations, .. })) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
self.evaluate_predicates_recursively(
previous_stack,
obligations.into_iter(),
)
Ok(Ok(InferOk { obligations, .. })) => {
self.evaluate_predicates_recursively(previous_stack, obligations)
}
Ok(Err(_)) => Ok(EvaluatedToErr),
Err(..) => Ok(EvaluatedToAmbig),
@ -677,12 +674,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let p = bound_predicate.rebind(p);
// Does this code ever run?
match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
Ok(Ok(InferOk { mut obligations, .. })) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
self.evaluate_predicates_recursively(
previous_stack,
obligations.into_iter(),
)
Ok(Ok(InferOk { obligations, .. })) => {
self.evaluate_predicates_recursively(previous_stack, obligations)
}
Ok(Err(_)) => Ok(EvaluatedToErr),
Err(..) => Ok(EvaluatedToAmbig),
@ -755,9 +748,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
arg,
obligation.cause.span,
) {
Some(mut obligations) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
Some(obligations) => {
cache.wf_args.borrow_mut().push((arg, previous_stack.depth()));
let result =
self.evaluate_predicates_recursively(previous_stack, obligations);
@ -826,10 +817,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
self.add_depth(
subobligations.iter_mut(),
obligation.recursion_depth,
);
// Need to explicitly set the depth of nested goals here as
// projection obligations can cycle by themselves and in
// `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(
previous_stack,
subobligations,
@ -909,38 +904,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if a.def.did == b.def.did
&& tcx.def_kind(a.def.did) == DefKind::AssocConst =>
{
if let Ok(new_obligations) = self
if let Ok(InferOk { obligations, value: () }) = self
.infcx
.at(&obligation.cause, obligation.param_env)
.trace(c1, c2)
.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(
previous_stack,
obligations.into_iter(),
obligations,
);
}
}
(_, Unevaluated(_)) | (Unevaluated(_), _) => (),
(_, _) => {
if let Ok(new_obligations) = self
if let Ok(InferOk { obligations, value: () }) = self
.infcx
.at(&obligation.cause, obligation.param_env)
.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(
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);
}
/// 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>(
&self,
depth: usize,
@ -2440,15 +2407,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
placeholder_ty,
)
});
let placeholder_obligation = predicate_for_trait_def(
let obligation = Obligation::new(
self.tcx(),
param_env,
cause.clone(),
trait_def_id,
recursion_depth,
[normalized_ty],
param_env,
self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]),
);
obligations.push(placeholder_obligation);
obligations.push(obligation);
obligations
})
.collect()

View File

@ -1,11 +1,11 @@
use super::NormalizeExt;
use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext};
use super::{ObligationCause, PredicateObligation, SelectionContext};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::InferOk;
use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, SubstsRef};
use rustc_span::Span;
use smallvec::SmallVec;
@ -218,33 +218,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
(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
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.

View File

@ -3,7 +3,6 @@
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits;
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 trait_def_id = tcx.require_lang_item(item, None);
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) {

View File

@ -9,7 +9,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
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! {
/// ### 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 span = decl.output.span();
let infcx = cx.tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);
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() {
span_lint_and_then(
cx,

View File

@ -3,7 +3,7 @@
// Regression for #93775, needs build-pass to test it.
#![recursion_limit = "1000"]
#![recursion_limit = "1001"]
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
|
LL | is_send::<A>();
| ^^^^^^^^^^^^
|
= 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`
--> $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 {}
| ^^^ ^ --- 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: 127 redundant requirements hidden
= note: 126 redundant requirements hidden
= note: required for `Bar<T>` to implement `Foo`
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 {
| ^^^ ^ --- 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: 127 redundant requirements hidden
= note: 126 redundant requirements hidden
= 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
|
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`)
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`
--> $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: 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`
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
|
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`)
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`
--> $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: 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`
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
|
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`
--> $DIR/cycle-cache-err-60010.rs:44:9
|

View File

@ -1,6 +1,6 @@
// build-fail
// 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
// 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
= 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`)
= note: required for `std::iter::Empty<()>` to implement `Iterator`
= note: 171 redundant requirements hidden
note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator`
--> $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: 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'