@@ -2,9 +2,9 @@ use std::collections::{BTreeMap, BTreeSet};
22
33use crate :: diagnostic:: Span ;
44use crate :: syntax:: ast:: {
5- BinaryOp , Block , CallArg , Callee , ConstDecl , DataEffect , EffectDecl , Expr , FieldDecl ,
6- ForStmt , FunctionDecl , GenericBound , Item , LetStmt , MatchPattern , MatchStmt , Param , Program ,
7- Stmt , SumTypeDecl , TypeAliasDecl , TypeDecl , TypeKind , TypeRef ,
5+ BinaryOp , Block , CallArg , Callee , ConstDecl , DataEffect , EffectDecl , Expr , FieldDecl , ForStmt ,
6+ FunctionDecl , GenericBound , Item , LetStmt , MatchPattern , MatchStmt , Param , Program , Stmt ,
7+ SumTypeDecl , TypeAliasDecl , TypeDecl , TypeKind , TypeRef ,
88} ;
99
1010use super :: helpers:: * ;
@@ -140,7 +140,7 @@ impl<'a> RustLowerer<'a> {
140140 // Module-isolated symbols carry a lowercase module prefix (`device__Device`,
141141 // `helpers__count`), so the camel/snake/upper-case lints don't apply.
142142 out. push_str (
143- "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]\n " ,
143+ "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals, unused_parens )]\n " ,
144144 ) ;
145145 let feature_names = lowered_feature_names ( & self . program . features ) ;
146146 if feature_names. is_empty ( ) {
@@ -1886,8 +1886,7 @@ impl<'a> RustLowerer<'a> {
18861886
18871887 fn lower_match_stmt ( & mut self , stmt : & MatchStmt , out : & mut String , pad : & str , indent : usize ) {
18881888 let scrutinee_type = self . infer_expr_type ( & stmt. value ) ;
1889- let mut scrutinee =
1890- self . lower_match_scrutinee_expr ( & stmt. value , scrutinee_type. as_ref ( ) ) ;
1889+ let mut scrutinee = self . lower_match_scrutinee_expr ( & stmt. value , scrutinee_type. as_ref ( ) ) ;
18911890 let by_ref = self . match_scrutinee_by_ref ( & stmt. value ) ;
18921891 // Native Rust slice patterns match a `[T]`, not a `Vec<T>`; view the
18931892 // list scrutinee as a slice so `[a, b]` / `[first, rest @ ..]` apply.
@@ -1896,11 +1895,8 @@ impl<'a> RustLowerer<'a> {
18961895 }
18971896 out. push_str ( & format ! ( "{pad}match {scrutinee} {{\n " ) ) ;
18981897 for arm in & stmt. arms {
1899- let pattern = self . lower_match_pattern_typed (
1900- & arm. pattern ,
1901- scrutinee_type. as_ref ( ) ,
1902- by_ref,
1903- ) ;
1898+ let pattern =
1899+ self . lower_match_pattern_typed ( & arm. pattern , scrutinee_type. as_ref ( ) , by_ref) ;
19041900 let guard = arm
19051901 . guard
19061902 . as_ref ( )
@@ -1912,8 +1908,7 @@ impl<'a> RustLowerer<'a> {
19121908 pattern,
19131909 guard
19141910 ) ) ;
1915- let scoped_binding =
1916- match_binding_type_ref ( & arm. pattern , scrutinee_type. as_ref ( ) ) ;
1911+ let scoped_binding = match_binding_type_ref ( & arm. pattern , scrutinee_type. as_ref ( ) ) ;
19171912 let previous_value_type = scoped_binding
19181913 . as_ref ( )
19191914 . and_then ( |( binding, _) | self . value_types . get ( binding) . cloned ( ) ) ;
@@ -2308,6 +2303,48 @@ impl<'a> RustLowerer<'a> {
23082303 op, left, right, ..
23092304 } => {
23102305 let binary_op = * op;
2306+ // Flatten a deep `&&`/`||` chain into a *balanced* tree so the
2307+ // generated Rust nests O(log n) deep instead of O(n): a left-linear
2308+ // chain of hundreds of `&&` overflows rustc's recursive parser/
2309+ // type-checker (the `RUST_MIN_STACK=2g` workaround). `&&`/`||` are
2310+ // associative for both value AND short-circuit/evaluation order, so
2311+ // balanced regrouping is behavior-identical. The chain is collected
2312+ // iteratively (its left spine is the deep part) so this lowerer pass
2313+ // does not itself recurse n-deep.
2314+ if matches ! ( binary_op, BinaryOp :: LogicalAnd | BinaryOp :: LogicalOr ) {
2315+ let mut rev: Vec < & Expr > = vec ! [ right. as_ref( ) ] ;
2316+ let mut node: & Expr = left. as_ref ( ) ;
2317+ loop {
2318+ match node {
2319+ Expr :: Binary {
2320+ op : inner,
2321+ left : inner_left,
2322+ right : inner_right,
2323+ ..
2324+ } if * inner == binary_op => {
2325+ rev. push ( inner_right. as_ref ( ) ) ;
2326+ node = inner_left. as_ref ( ) ;
2327+ }
2328+ other => {
2329+ rev. push ( other) ;
2330+ break ;
2331+ }
2332+ }
2333+ }
2334+ if rev. len ( ) >= 8 {
2335+ rev. reverse ( ) ;
2336+ let op_str = if binary_op == BinaryOp :: LogicalAnd {
2337+ "&&"
2338+ } else {
2339+ "||"
2340+ } ;
2341+ let leaves: Vec < String > = rev
2342+ . iter ( )
2343+ . map ( |operand| self . lower_binary_operand ( operand, binary_op, false ) )
2344+ . collect ( ) ;
2345+ return balanced_logical_join ( & leaves, op_str) ;
2346+ }
2347+ }
23112348 if matches ! ( op, BinaryOp :: ShiftLeft | BinaryOp :: ShiftRight ) {
23122349 let method = if * op == BinaryOp :: ShiftLeft {
23132350 "wrapping_shl"
@@ -3816,9 +3853,7 @@ impl<'a> RustLowerer<'a> {
38163853 Expr :: Ident ( name, span) if name == "true" || name == "false" => {
38173854 Some ( simple_type_ref ( "Bool" , span) )
38183855 }
3819- Expr :: Ident ( name, span) if name == "null" => {
3820- Some ( simple_type_ref ( "JsonLiteral" , span) )
3821- }
3856+ Expr :: Ident ( name, span) if name == "null" => Some ( simple_type_ref ( "JsonLiteral" , span) ) ,
38223857 Expr :: Ident ( name, span) => self . value_types . get ( name) . cloned ( ) . or_else ( || {
38233858 self . find_sum_type_for_variant ( name)
38243859 . map ( |sum_name| simple_type_ref ( & sum_name, span) )
@@ -5571,6 +5606,26 @@ fn expr_contains_try(expr: &Expr) -> bool {
55715606 }
55725607}
55735608
5609+ /// Join already-lowered operands with a short-circuit operator (`&&`/`||`) as a
5610+ /// *balanced* tree, so the resulting Rust expression nests O(log n) deep rather
5611+ /// than O(n). `&&`/`||` are associative for both value and evaluation order, so
5612+ /// any grouping evaluates the operands left-to-right with identical short-circuit
5613+ /// behavior. Recursion depth here is O(log n), so this helper is itself safe.
5614+ fn balanced_logical_join ( leaves : & [ String ] , op : & str ) -> String {
5615+ match leaves. len ( ) {
5616+ 0 => String :: new ( ) ,
5617+ 1 => leaves[ 0 ] . clone ( ) ,
5618+ n => {
5619+ let mid = n / 2 ;
5620+ format ! (
5621+ "({} {op} {})" ,
5622+ balanced_logical_join( & leaves[ ..mid] , op) ,
5623+ balanced_logical_join( & leaves[ mid..] , op)
5624+ )
5625+ }
5626+ }
5627+ }
5628+
55745629fn rust_binary_precedence ( op : BinaryOp ) -> u8 {
55755630 match op {
55765631 BinaryOp :: LogicalOr => 1 ,
0 commit comments