Stop the value-position `match` recursing into its own error probe
`result_ty` reports why a body failed by re-lowering it through `expr` -- and `expr` on a `match` now asks `result_ty` for the type, which asked `expr` again. A stack overflow, caught by winnow rather than by the suite, since no test case has a `match` in value position with no expectation to type it. The inner form recurses into itself and the probing wrapper stays at the top, where it belongs. winnow's unresolved opaque types: 45 to 33. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
b33ed0d parent: badeef1 modified
src/lower.rs +7 -7 | @@ -2072,7 +2072,7 @@ impl Lowerer { | ||
| 2072 | 2072 | for arm in &m.arms { |
| 2073 | 2073 | self.push_scope(); |
| 2074 | 2074 | let bound = self.pat_bind(&arm.pat, &scrut.code, &st).is_ok(); |
| 2075 | - let t = if bound { self.result_ty(&arm.body) } else { None }; | |
| 2075 | + let t = if bound { self.result_ty_inner(&arm.body) } else { None }; | |
| 2076 | 2076 | self.pop_scope(); |
| 2077 | 2077 | if t.is_some() { |
| 2078 | 2078 | return t; |
| @@ -2085,21 +2085,21 @@ impl Lowerer { | ||
| 2085 | 2085 | Stmt::Expr(e, None) => Some(e.clone()), |
| 2086 | 2086 | _ => None, |
| 2087 | 2087 | }); |
| 2088 | - if let Some(t) = then.and_then(|e| self.result_ty(&e)) { | |
| 2088 | + if let Some(t) = then.and_then(|e| self.result_ty_inner(&e)) { | |
| 2089 | 2089 | return Some(t); |
| 2090 | 2090 | } |
| 2091 | 2091 | let (_, els) = i.else_branch.as_ref()?; |
| 2092 | - self.result_ty(els) | |
| 2092 | + self.result_ty_inner(els) | |
| 2093 | 2093 | } |
| 2094 | 2094 | Expr::Block(b) => { |
| 2095 | 2095 | let tail = b.block.stmts.last().and_then(|st| match st { |
| 2096 | 2096 | Stmt::Expr(e, None) => Some(e.clone()), |
| 2097 | 2097 | _ => None, |
| 2098 | 2098 | })?; |
| 2099 | - self.result_ty(&tail) | |
| 2099 | + self.result_ty_inner(&tail) | |
| 2100 | 2100 | } |
| 2101 | - Expr::Paren(p) => self.result_ty(&p.expr), | |
| 2102 | - Expr::Group(g) => self.result_ty(&g.expr), | |
| 2101 | + Expr::Paren(p) => self.result_ty_inner(&p.expr), | |
| 2102 | + Expr::Group(g) => self.result_ty_inner(&g.expr), | |
| 2103 | 2103 | other => self.expr(other).ok().and_then(|v| v.ty), |
| 2104 | 2104 | } |
| 2105 | 2105 | } |
| @@ -5416,7 +5416,7 @@ impl Lowerer { | ||
| 5416 | 5416 | Some(t) => t.clone(), |
| 5417 | 5417 | None => { |
| 5418 | 5418 | let save = self.out.len(); |
| 5419 | - let probe = self.result_ty(e); | |
| 5419 | + let probe = self.result_ty_inner(e); | |
| 5420 | 5420 | self.out.truncate(save); |
| 5421 | 5421 | probe.ok_or_else(|| { |
| 5422 | 5422 | "cannot infer the type of a `match` used as a value; \ |
| @@ -2072,7 +2072,7 @@ impl Lowerer { | |||
| 2072 | for arm in &m.arms { | 2072 | for arm in &m.arms { |
| 2073 | self.push_scope(); | 2073 | self.push_scope(); |
| 2074 | let bound = self.pat_bind(&arm.pat, &scrut.code, &st).is_ok(); | 2074 | let bound = self.pat_bind(&arm.pat, &scrut.code, &st).is_ok(); |
| 2075 | - let t = if bound { self.result_ty(&arm.body) } else { None }; | 2075 | + let t = if bound { self.result_ty_inner(&arm.body) } else { None }; |
| 2076 | self.pop_scope(); | 2076 | self.pop_scope(); |
| 2077 | if t.is_some() { | 2077 | if t.is_some() { |
| 2078 | return t; | 2078 | return t; |
| @@ -2085,21 +2085,21 @@ impl Lowerer { | |||
| 2085 | Stmt::Expr(e, None) => Some(e.clone()), | 2085 | Stmt::Expr(e, None) => Some(e.clone()), |
| 2086 | _ => None, | 2086 | _ => None, |
| 2087 | }); | 2087 | }); |
| 2088 | - if let Some(t) = then.and_then(|e| self.result_ty(&e)) { | 2088 | + if let Some(t) = then.and_then(|e| self.result_ty_inner(&e)) { |
| 2089 | return Some(t); | 2089 | return Some(t); |
| 2090 | } | 2090 | } |
| 2091 | let (_, els) = i.else_branch.as_ref()?; | 2091 | let (_, els) = i.else_branch.as_ref()?; |
| 2092 | - self.result_ty(els) | 2092 | + self.result_ty_inner(els) |
| 2093 | } | 2093 | } |
| 2094 | Expr::Block(b) => { | 2094 | Expr::Block(b) => { |
| 2095 | let tail = b.block.stmts.last().and_then(|st| match st { | 2095 | let tail = b.block.stmts.last().and_then(|st| match st { |
| 2096 | Stmt::Expr(e, None) => Some(e.clone()), | 2096 | Stmt::Expr(e, None) => Some(e.clone()), |
| 2097 | _ => None, | 2097 | _ => None, |
| 2098 | })?; | 2098 | })?; |
| 2099 | - self.result_ty(&tail) | 2099 | + self.result_ty_inner(&tail) |
| 2100 | } | 2100 | } |
| 2101 | - Expr::Paren(p) => self.result_ty(&p.expr), | 2101 | + Expr::Paren(p) => self.result_ty_inner(&p.expr), |
| 2102 | - Expr::Group(g) => self.result_ty(&g.expr), | 2102 | + Expr::Group(g) => self.result_ty_inner(&g.expr), |
| 2103 | other => self.expr(other).ok().and_then(|v| v.ty), | 2103 | other => self.expr(other).ok().and_then(|v| v.ty), |
| 2104 | } | 2104 | } |
| 2105 | } | 2105 | } |
| @@ -5416,7 +5416,7 @@ impl Lowerer { | |||
| 5416 | Some(t) => t.clone(), | 5416 | Some(t) => t.clone(), |
| 5417 | None => { | 5417 | None => { |
| 5418 | let save = self.out.len(); | 5418 | let save = self.out.len(); |
| 5419 | - let probe = self.result_ty(e); | 5419 | + let probe = self.result_ty_inner(e); |
| 5420 | self.out.truncate(save); | 5420 | self.out.truncate(save); |
| 5421 | probe.ok_or_else(|| { | 5421 | probe.ok_or_else(|| { |
| 5422 | "cannot infer the type of a `match` used as a value; \ | 5422 | "cannot infer the type of a `match` used as a value; \ |