@@ -66,13 +66,118 @@ public int Run()
6666 Can_compile_nullable_boolean_and_also ( ) ;
6767 Can_compile_nullable_boolean_or_else ( ) ;
6868 Can_compile_nullable_boolean_not ( ) ;
69+ Can_make_goto_of_all_kinds_with_value_and_type ( ) ;
70+ Can_compile_goto_with_value_of_all_kinds ( ) ;
71+ Can_compile_loop_with_break_and_continue_with_value ( ) ;
6972
70- return 49 ;
73+ return 52 ;
7174 }
7275
7376 private static int _sideEffectCalls ;
7477 private static bool ? SideEffect ( bool ? value ) { ++ _sideEffectCalls ; return value ; }
7578
79+ public void Can_make_goto_of_all_kinds_with_value_and_type ( )
80+ {
81+ var label = Label ( typeof ( int ) , "label" ) ;
82+ var voidLabel = Label ( "voidLabel" ) ;
83+ var value = Constant ( 42 ) ;
84+ var kinds = new [ ] { GotoExpressionKind . Goto , GotoExpressionKind . Return , GotoExpressionKind . Break , GotoExpressionKind . Continue } ;
85+
86+ foreach ( var kind in kinds )
87+ {
88+ var plain = MakeGoto ( kind , voidLabel , null , null ) ;
89+ Asserts . AreEqual ( kind , plain . Kind ) ;
90+ Asserts . AreEqual ( null , plain . Value ) ;
91+ Asserts . AreEqual ( typeof ( void ) , plain . Type ) ;
92+
93+ var typed = MakeGoto ( kind , voidLabel , null , typeof ( string ) ) ;
94+ Asserts . AreEqual ( kind , typed . Kind ) ;
95+ Asserts . AreEqual ( null , typed . Value ) ;
96+ Asserts . AreEqual ( typeof ( string ) , typed . Type ) ;
97+
98+ var valued = MakeGoto ( kind , label , value , null ) ;
99+ Asserts . AreEqual ( kind , valued . Kind ) ;
100+ Asserts . IsNotNull ( valued . Value ) ;
101+
102+ var typedValued = MakeGoto ( kind , label , value , typeof ( string ) ) ;
103+ Asserts . AreEqual ( kind , typedValued . Kind ) ;
104+ Asserts . IsNotNull ( typedValued . Value ) ;
105+ Asserts . AreEqual ( typeof ( string ) , typedValued . Type ) ;
106+
107+ // converting to System expressions validates and preserves the kind, value and type
108+ foreach ( var g in new [ ] { plain , typed , valued , typedValued } )
109+ {
110+ var sys = ( System . Linq . Expressions . GotoExpression ) g . ToExpression ( ) ;
111+ Asserts . AreEqual ( kind , sys . Kind ) ;
112+ Asserts . AreEqual ( g . Value != null , sys . Value != null ) ;
113+ Asserts . AreEqual ( g . Type , sys . Type ) ;
114+ }
115+ }
116+
117+ // the public factories agree with MakeGoto
118+ Asserts . AreEqual ( GotoExpressionKind . Continue , Continue ( label ) . Kind ) ;
119+ Asserts . AreEqual ( typeof ( string ) , Continue ( label , typeof ( string ) ) . Type ) ;
120+ Asserts . AreEqual ( GotoExpressionKind . Continue , Continue ( label , value ) . Kind ) ;
121+ Asserts . IsNotNull ( Continue ( label , value ) . Value ) ;
122+ Asserts . AreEqual ( null , Continue ( label , ( Expression ) null ) . Value ) ;
123+ Asserts . AreEqual ( GotoExpressionKind . Continue , Continue ( label , value , typeof ( string ) ) . Kind ) ;
124+ Asserts . AreEqual ( typeof ( string ) , Continue ( label , value , typeof ( string ) ) . Type ) ;
125+ Asserts . AreEqual ( GotoExpressionKind . Break , Break ( label , value ) . Kind ) ;
126+ Asserts . AreEqual ( GotoExpressionKind . Break , Break ( label , value , typeof ( string ) ) . Kind ) ;
127+ Asserts . AreEqual ( GotoExpressionKind . Return , Return ( label , value ) . Kind ) ;
128+ Asserts . AreEqual ( GotoExpressionKind . Return , Return ( label , value , typeof ( string ) ) . Kind ) ;
129+ Asserts . AreEqual ( GotoExpressionKind . Goto , Goto ( label , value ) . Kind ) ;
130+ Asserts . AreEqual ( GotoExpressionKind . Goto , Goto ( label , value , typeof ( string ) ) . Kind ) ;
131+ }
132+
133+ public void Can_compile_goto_with_value_of_all_kinds ( )
134+ {
135+ foreach ( var kind in new [ ] { GotoExpressionKind . Goto , GotoExpressionKind . Return , GotoExpressionKind . Break , GotoExpressionKind . Continue } )
136+ foreach ( var withType in new [ ] { false , true } )
137+ {
138+ var label = Label ( typeof ( int ) , "label" ) ;
139+ var @goto = MakeGoto ( kind , label , Constant ( 42 ) , withType ? typeof ( void ) : null ) ;
140+ var lambda = Lambda < Func < int > > ( Block ( @goto , Label ( label , Constant ( 0 ) ) ) ) ;
141+
142+ var sys = lambda . CompileSys ( ) ;
143+ Asserts . AreEqual ( 42 , sys ( ) ) ;
144+
145+ var fast = lambda . CompileFast ( true ) ;
146+ Asserts . IsNotNull ( fast ) ;
147+ Asserts . AreEqual ( 42 , fast ( ) ) ;
148+ }
149+ }
150+
151+ public void Can_compile_loop_with_break_and_continue_with_value ( )
152+ {
153+ // sum of odd numbers below the limit, the loop result is provided by the `Break` with value
154+ foreach ( var continueKind in new [ ] { GotoExpressionKind . Continue , GotoExpressionKind . Goto } )
155+ {
156+ var limit = Parameter ( typeof ( int ) , "limit" ) ;
157+ var i = Parameter ( typeof ( int ) , "i" ) ;
158+ var sum = Parameter ( typeof ( int ) , "sum" ) ;
159+ var breakLabel = Label ( typeof ( int ) , "break" ) ;
160+ var continueLabel = Label ( "continue" ) ;
161+
162+ var body = Block (
163+ IfThen ( GreaterThanOrEqual ( PreIncrementAssign ( i ) , limit ) , Break ( breakLabel , sum ) ) ,
164+ IfThen ( Equal ( Modulo ( i , Constant ( 2 ) ) , Constant ( 0 ) ) , MakeGoto ( continueKind , continueLabel , null , null ) ) ,
165+ AddAssign ( sum , i ) ) ;
166+
167+ var lambda = Lambda < Func < int , int > > (
168+ Block ( new [ ] { i , sum } , Loop ( body , breakLabel , continueLabel ) ) ,
169+ limit ) ;
170+
171+ var sys = lambda . CompileSys ( ) ;
172+ Asserts . AreEqual ( 1 + 3 + 5 + 7 , sys ( 9 ) ) ;
173+
174+ var fast = lambda . CompileFast ( true ) ;
175+ Asserts . IsNotNull ( fast ) ;
176+ Asserts . AreEqual ( sys ( 9 ) , fast ( 9 ) ) ;
177+ Asserts . AreEqual ( sys ( 1 ) , fast ( 1 ) ) ;
178+ }
179+ }
180+
76181 private static int AndInts ( int left , int right ) => left & right ;
77182
78183 public void Can_compile_nullable_boolean_not ( )
0 commit comments