@@ -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 } ;
@@ -655,8 +656,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
655
656
// `tests/ui/pattern/deref-patterns/`.
656
657
let mut pat_adjustments = vec ! [ ] ;
657
658
loop {
658
- // TODO: check # of iterations against tcx's recursion limit, so we don't loop until OOM
659
- // if someone tries matching on a type with a cyclic `Deref` impl.
660
659
let inner_ty = if let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
661
660
def_br = ByRef :: Yes ( match def_br {
662
661
// If default binding mode is by value, make it `ref` or `ref mut`
@@ -680,6 +679,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
680
679
// matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
681
680
&& until_adt != Some ( scrutinee_adt)
682
681
{
682
+ // We may reach the recursion limit if a user matches on a type `T` satisfying
683
+ // `T: Deref<Target = T>`; error gracefully in this case.
684
+ // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move
685
+ // this check out of this branch. Alternatively, this loop could be implemented with
686
+ // autoderef and this check removed. For now though, don't break code compiling on
687
+ // stable with lots of `&`s and a low recursion limit, if anyone's done that.
688
+ if !self . tcx . recursion_limit ( ) . value_within_limit ( pat_adjustments. len ( ) ) {
689
+ let guar = report_autoderef_recursion_limit_error ( self . tcx , pat. span , expected) ;
690
+ expected = Ty :: new_error ( self . tcx , guar) ;
691
+ break ;
692
+ }
693
+
683
694
// At this point, the pattern isn't able to match `expected` without peeling. Check
684
695
// that it implements `Deref` before assuming it's a smart pointer, to get a normal
685
696
// type error instead of a missing impl error if not. This only checks for `Deref`,
0 commit comments