@@ -14,6 +14,7 @@ use rustc_hir::{
14
14
self as hir, BindingMode , ByRef , ExprKind , HirId , LangItem , Mutability , Pat , PatExpr ,
15
15
PatExprKind , PatKind , expr_needs_parens,
16
16
} ;
17
+ use rustc_hir_analysis:: autoderef:: report_autoderef_recursion_limit_error;
17
18
use rustc_infer:: infer;
18
19
use rustc_middle:: traits:: PatternOriginExpr ;
19
20
use rustc_middle:: ty:: { self , AdtDef , Ty , TypeVisitableExt } ;
@@ -621,8 +622,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
621
622
// `tests/ui/pattern/deref-patterns/`.
622
623
let mut pat_adjustments = vec ! [ ] ;
623
624
loop {
624
- // TODO: check # of iterations against tcx's recursion limit, so we don't loop until OOM
625
- // if someone tries matching on a type with a cyclic `Deref` impl.
626
625
let inner_ty = if let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
627
626
def_br = ByRef :: Yes ( match def_br {
628
627
// If default binding mode is by value, make it `ref` or `ref mut`
@@ -646,6 +645,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
646
645
// matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
647
646
&& until_adt != Some ( scrutinee_adt)
648
647
{
648
+ // We may reach the recursion limit if a user matches on a type `T` satisfying
649
+ // `T: Deref<Target = T>`; error gracefully in this case.
650
+ // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move
651
+ // this check out of this branch. Alternatively, this loop could be implemented with
652
+ // autoderef and this check removed. For now though, don't break code compiling on
653
+ // stable with lots of `&`s and a low recursion limit, if anyone's done that.
654
+ if !self . tcx . recursion_limit ( ) . value_within_limit ( pat_adjustments. len ( ) ) {
655
+ let guar = report_autoderef_recursion_limit_error ( self . tcx , pat. span , expected) ;
656
+ expected = Ty :: new_error ( self . tcx , guar) ;
657
+ break ;
658
+ }
659
+
649
660
// At this point, the pattern isn't able to match `expected` without peeling. Check
650
661
// that it implements `Deref` before assuming it's a smart pointer, to get a normal
651
662
// type error instead of a missing impl error if not. This only checks for `Deref`,
0 commit comments