@@ -14,6 +14,7 @@ use rustc_hir::{
1414 self as hir, BindingMode , ByRef , ExprKind , HirId , LangItem , Mutability , Pat , PatExpr ,
1515 PatExprKind , PatKind , expr_needs_parens,
1616} ;
17+ use rustc_hir_analysis:: autoderef:: report_autoderef_recursion_limit_error;
1718use rustc_infer:: infer;
1819use rustc_middle:: traits:: PatternOriginExpr ;
1920use rustc_middle:: ty:: { self , AdtDef , Ty , TypeVisitableExt } ;
@@ -655,8 +656,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
655656 // `tests/ui/pattern/deref-patterns/`.
656657 let mut pat_adjustments = vec ! [ ] ;
657658 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.
660659 let inner_ty = if let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
661660 def_br = ByRef :: Yes ( match def_br {
662661 // If default binding mode is by value, make it `ref` or `ref mut`
@@ -680,6 +679,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
680679 // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
681680 && until_adt != Some ( scrutinee_adt)
682681 {
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+
683694 // At this point, the pattern isn't able to match `expected` without peeling. Check
684695 // that it implements `Deref` before assuming it's a smart pointer, to get a normal
685696 // type error instead of a missing impl error if not. This only checks for `Deref`,
0 commit comments