respect the tcx's recursion limit when peeling
This commit is contained in:
parent
923d95cc9f
commit
977c9ab7a2
4 changed files with 68 additions and 11 deletions
|
@ -2,8 +2,8 @@ use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_infer::traits::PredicateObligations;
|
use rustc_infer::traits::PredicateObligations;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_session::Limit;
|
use rustc_session::Limit;
|
||||||
use rustc_span::Span;
|
|
||||||
use rustc_span::def_id::{LOCAL_CRATE, LocalDefId};
|
use rustc_span::def_id::{LOCAL_CRATE, LocalDefId};
|
||||||
|
use rustc_span::{ErrorGuaranteed, Span};
|
||||||
use rustc_trait_selection::traits::ObligationCtxt;
|
use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
@ -259,7 +259,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
|
pub fn report_autoderef_recursion_limit_error<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> ErrorGuaranteed {
|
||||||
// We've reached the recursion limit, error gracefully.
|
// We've reached the recursion limit, error gracefully.
|
||||||
let suggested_limit = match tcx.recursion_limit() {
|
let suggested_limit = match tcx.recursion_limit() {
|
||||||
Limit(0) => Limit(2),
|
Limit(0) => Limit(2),
|
||||||
|
@ -270,5 +274,5 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa
|
||||||
ty,
|
ty,
|
||||||
suggested_limit,
|
suggested_limit,
|
||||||
crate_name: tcx.crate_name(LOCAL_CRATE),
|
crate_name: tcx.crate_name(LOCAL_CRATE),
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ use rustc_hir::{
|
||||||
self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
|
self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
|
||||||
PatExprKind, PatKind, expr_needs_parens,
|
PatExprKind, PatKind, expr_needs_parens,
|
||||||
};
|
};
|
||||||
|
use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error;
|
||||||
use rustc_infer::infer;
|
use rustc_infer::infer;
|
||||||
use rustc_middle::traits::PatternOriginExpr;
|
use rustc_middle::traits::PatternOriginExpr;
|
||||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||||
|
@ -552,17 +553,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref");
|
debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref");
|
||||||
// The scrutinee is a smart pointer; implicitly dereference it. This adds a
|
// The scrutinee is a smart pointer; implicitly dereference it. This adds a
|
||||||
// requirement that `expected: DerefPure`.
|
// requirement that `expected: DerefPure`.
|
||||||
let inner_ty = self.deref_pat_target(pat.span, expected);
|
let mut inner_ty = self.deref_pat_target(pat.span, expected);
|
||||||
// Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any
|
// Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any
|
||||||
// `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`.
|
// `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`.
|
||||||
|
|
||||||
// Preserve the smart pointer type for THIR lowering and upvar analysis.
|
let mut typeck_results = self.typeck_results.borrow_mut();
|
||||||
self.typeck_results
|
let mut pat_adjustments_table = typeck_results.pat_adjustments_mut();
|
||||||
.borrow_mut()
|
let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default();
|
||||||
.pat_adjustments_mut()
|
// We may reach the recursion limit if a user matches on a type `T` satisfying
|
||||||
.entry(pat.hir_id)
|
// `T: Deref<Target = T>`; error gracefully in this case.
|
||||||
.or_default()
|
// FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move
|
||||||
.push(PatAdjustment { kind: PatAdjust::OverloadedDeref, source: expected });
|
// this check out of this branch. Alternatively, this loop could be implemented with
|
||||||
|
// autoderef and this check removed. For now though, don't break code compiling on
|
||||||
|
// stable with lots of `&`s and a low recursion limit, if anyone's done that.
|
||||||
|
if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) {
|
||||||
|
// Preserve the smart pointer type for THIR lowering and closure upvar analysis.
|
||||||
|
pat_adjustments
|
||||||
|
.push(PatAdjustment { kind: PatAdjust::OverloadedDeref, source: expected });
|
||||||
|
} else {
|
||||||
|
let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected);
|
||||||
|
inner_ty = Ty::new_error(self.tcx, guar);
|
||||||
|
}
|
||||||
|
drop(typeck_results);
|
||||||
|
|
||||||
// Recurse, using the old pat info to keep `current_depth` to its old value.
|
// Recurse, using the old pat info to keep `current_depth` to its old value.
|
||||||
// Peeling smart pointers does not update the default binding mode.
|
// Peeling smart pointers does not update the default binding mode.
|
||||||
|
|
23
tests/ui/pattern/deref-patterns/recursion-limit.rs
Normal file
23
tests/ui/pattern/deref-patterns/recursion-limit.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//! Test that implicit deref patterns respect the recursion limit
|
||||||
|
#![feature(deref_patterns)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![recursion_limit = "8"]
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
struct Cyclic;
|
||||||
|
impl Deref for Cyclic {
|
||||||
|
type Target = Cyclic;
|
||||||
|
fn deref(&self) -> &Cyclic {
|
||||||
|
&Cyclic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match &Box::new(Cyclic) {
|
||||||
|
() => {}
|
||||||
|
//~^ ERROR: reached the recursion limit while auto-dereferencing `Cyclic`
|
||||||
|
//~| ERROR: the trait bound `Cyclic: DerefPure` is not satisfied
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
18
tests/ui/pattern/deref-patterns/recursion-limit.stderr
Normal file
18
tests/ui/pattern/deref-patterns/recursion-limit.stderr
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
error[E0055]: reached the recursion limit while auto-dereferencing `Cyclic`
|
||||||
|
--> $DIR/recursion-limit.rs:18:9
|
||||||
|
|
|
||||||
|
LL | () => {}
|
||||||
|
| ^^ deref recursion limit reached
|
||||||
|
|
|
||||||
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`recursion_limit`)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `Cyclic: DerefPure` is not satisfied
|
||||||
|
--> $DIR/recursion-limit.rs:18:9
|
||||||
|
|
|
||||||
|
LL | () => {}
|
||||||
|
| ^^ the trait `DerefPure` is not implemented for `Cyclic`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0055, E0277.
|
||||||
|
For more information about an error, try `rustc --explain E0055`.
|
Loading…
Add table
Add a link
Reference in a new issue