@@ -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 } ;
@@ -621,8 +622,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
621622 // `tests/ui/pattern/deref-patterns/`.
622623 let mut pat_adjustments = vec ! [ ] ;
623624 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.
626625 let inner_ty = if let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
627626 def_br = ByRef :: Yes ( match def_br {
628627 // If default binding mode is by value, make it `ref` or `ref mut`
@@ -646,6 +645,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
646645 // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
647646 && until_adt != Some ( scrutinee_adt)
648647 {
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+
649660 // At this point, the pattern isn't able to match `expected` without peeling. Check
650661 // that it implements `Deref` before assuming it's a smart pointer, to get a normal
651662 // type error instead of a missing impl error if not. This only checks for `Deref`,
0 commit comments