@@ -40,7 +40,11 @@ public int Run()
4040 Flat_nested_lambda_captures_outer_parameter_identity ( ) ;
4141 Flat_out_of_order_decl_block_in_lambda_compiles_correctly ( ) ;
4242 Flat_enum_constant_stored_inline_roundtrip ( ) ;
43- return 23 ;
43+ Flat_lambda_nodes_tracks_all_lambdas_during_direct_construction ( ) ;
44+ Flat_lambda_nodes_tracks_deeply_nested_lambdas_during_direct_construction ( ) ;
45+ Flat_lambda_nodes_tracks_lambdas_from_expression_conversion ( ) ;
46+ Flat_lambda_nodes_has_single_entry_for_root_only_lambda ( ) ;
47+ return 27 ;
4448 }
4549
4650
@@ -686,5 +690,111 @@ void Check<TEnum>(TEnum enumValue) where TEnum : Enum
686690 Check ( UIntEnum . A ) ;
687691 Check ( UIntEnum . B ) ;
688692 }
693+
694+ /// <summary>
695+ /// When building a flat expression directly, calling Lambda() for a nested lambda
696+ /// and then for the root lambda should result in both indices recorded in LambdaNodes.
697+ /// The root is identified by RootIndex; all others are nested.
698+ /// </summary>
699+ public void Flat_lambda_nodes_tracks_all_lambdas_during_direct_construction ( )
700+ {
701+ var fe = default ( ExprTree ) ;
702+ var x = fe . ParameterOf < int > ( "x" ) ;
703+
704+ // Build: outer: x => () => x
705+ var inner = fe . Lambda < Func < int > > ( x ) ;
706+ fe . RootIndex = fe . Lambda < Func < int , Func < int > > > ( inner , x ) ;
707+
708+ // Both the root and nested lambda indices should be recorded
709+ Asserts . AreEqual ( 2 , fe . LambdaNodes . Count ) ;
710+
711+ // Check that inner and root are both in LambdaNodes
712+ var foundInner = false ;
713+ var foundRoot = false ;
714+ for ( var i = 0 ; i < fe . LambdaNodes . Count ; i ++ )
715+ {
716+ if ( fe . LambdaNodes [ i ] == inner ) foundInner = true ;
717+ if ( fe . LambdaNodes [ i ] == fe . RootIndex ) foundRoot = true ;
718+ }
719+ Asserts . IsTrue ( foundInner ) ;
720+ Asserts . IsTrue ( foundRoot ) ;
721+
722+ // Nested lambdas are all LambdaNodes entries that are not the root
723+ var nestedCount = 0 ;
724+ for ( var i = 0 ; i < fe . LambdaNodes . Count ; i ++ )
725+ if ( fe . LambdaNodes [ i ] != fe . RootIndex )
726+ ++ nestedCount ;
727+ Asserts . AreEqual ( 1 , nestedCount ) ;
728+ }
729+
730+ /// <summary>
731+ /// When building a flat expression with multiple levels of nesting,
732+ /// all lambda node indices are captured in LambdaNodes.
733+ /// </summary>
734+ public void Flat_lambda_nodes_tracks_deeply_nested_lambdas_during_direct_construction ( )
735+ {
736+ var fe = default ( ExprTree ) ;
737+ var x = fe . ParameterOf < int > ( "x" ) ;
738+
739+ // Build: outer: x => (() => (() => x))
740+ var innermost = fe . Lambda < Func < int > > ( x ) ;
741+ var middle = fe . Lambda < Func < Func < int > > > ( innermost ) ;
742+ fe . RootIndex = fe . Lambda < Func < int , Func < Func < int > > > > ( middle , x ) ;
743+
744+ // All three lambda nodes should be recorded
745+ Asserts . AreEqual ( 3 , fe . LambdaNodes . Count ) ;
746+
747+ // Count nested (non-root) lambdas
748+ var nestedCount = 0 ;
749+ for ( var i = 0 ; i < fe . LambdaNodes . Count ; i ++ )
750+ if ( fe . LambdaNodes [ i ] != fe . RootIndex )
751+ ++ nestedCount ;
752+ Asserts . AreEqual ( 2 , nestedCount ) ;
753+ }
754+
755+ /// <summary>
756+ /// When converting a System.Linq expression tree with nested lambdas via FromExpression,
757+ /// the resulting ExprTree should have all lambda indices populated in LambdaNodes.
758+ /// </summary>
759+ public void Flat_lambda_nodes_tracks_lambdas_from_expression_conversion ( )
760+ {
761+ var p = SysExpr . Parameter ( typeof ( int ) , "p" ) ;
762+ // Build: p => () => p using System.Linq.Expressions
763+ var sysLambda = SysExpr . Lambda < Func < int , Func < int > > > (
764+ SysExpr . Lambda < Func < int > > ( p ) ,
765+ p ) ;
766+
767+ var fe = sysLambda . ToFlatExpression ( ) ;
768+
769+ // Both root and nested lambda indices should be recorded
770+ Asserts . AreEqual ( 2 , fe . LambdaNodes . Count ) ;
771+
772+ // The root lambda must be in the list
773+ var foundRoot = false ;
774+ for ( var i = 0 ; i < fe . LambdaNodes . Count ; i ++ )
775+ if ( fe . LambdaNodes [ i ] == fe . RootIndex ) { foundRoot = true ; break ; }
776+ Asserts . IsTrue ( foundRoot ) ;
777+
778+ // Exactly one nested lambda
779+ var nestedCount = 0 ;
780+ for ( var i = 0 ; i < fe . LambdaNodes . Count ; i ++ )
781+ if ( fe . LambdaNodes [ i ] != fe . RootIndex )
782+ ++ nestedCount ;
783+ Asserts . AreEqual ( 1 , nestedCount ) ;
784+ }
785+
786+ /// <summary>
787+ /// A flat expression with no nested lambdas (root-only) should have exactly one
788+ /// entry in LambdaNodes (the root itself).
789+ /// </summary>
790+ public void Flat_lambda_nodes_has_single_entry_for_root_only_lambda ( )
791+ {
792+ var fe = default ( ExprTree ) ;
793+ var p = fe . ParameterOf < int > ( "p" ) ;
794+ fe . RootIndex = fe . Lambda < Func < int , int > > ( fe . Add ( p , fe . ConstantInt ( 1 ) ) , p ) ;
795+
796+ Asserts . AreEqual ( 1 , fe . LambdaNodes . Count ) ;
797+ Asserts . AreEqual ( fe . RootIndex , fe . LambdaNodes [ 0 ] ) ;
798+ }
689799 }
690800}
0 commit comments