@@ -364,6 +364,10 @@ private static object TryCompile(ref ClosureInfo closureInfo,
364
364
else
365
365
return null ;
366
366
367
+ if ( closureInfo . LabelCount > 0 )
368
+ closureInfo . Labels = new KeyValuePair < object , Label > [ closureInfo . LabelCount ] ;
369
+ closureInfo . LabelCount = 0 ;
370
+
367
371
var closureType = closureInfo . ClosureType ;
368
372
var methodParamTypes = closureType == null ? paramTypes : GetClosureAndParamTypes ( paramTypes , closureType ) ;
369
373
@@ -476,6 +480,10 @@ private struct ClosureInfo
476
480
// Helper to decide whether we are inside the block or not
477
481
public BlockInfo CurrentBlock ;
478
482
483
+ public int LabelCount ;
484
+ // Dictionary for the used Labels in IL
485
+ public KeyValuePair < object , Label > [ ] Labels ;
486
+
479
487
// Populates info directly with provided closure object and constants.
480
488
public ClosureInfo ( bool isConstructed , object closure = null , object [ ] closureConstantExpressions = null )
481
489
{
@@ -484,6 +492,8 @@ public ClosureInfo(bool isConstructed, object closure = null, object[] closureCo
484
492
NonPassedParameters = Tools . Empty < object > ( ) ;
485
493
NestedLambdas = Tools . Empty < NestedLambdaInfo > ( ) ;
486
494
CurrentBlock = BlockInfo . Empty ;
495
+ Labels = null ;
496
+ LabelCount = 0 ;
487
497
488
498
if ( closure == null )
489
499
{
@@ -986,6 +996,17 @@ private static bool TryCollectBoundConstants(ref ClosureInfo closure,
986
996
? TryCollectTryExprConstants ( ref closure , ( TryExpression ) exprObj , paramExprs )
987
997
: TryCollectTryExprInfoConstants ( ref closure , ( TryExpressionInfo ) exprObj , paramExprs ) ;
988
998
999
+ case ExpressionType . Label :
1000
+ closure . LabelCount ++ ;
1001
+ var defaultValueExpr = ( ( LabelExpression ) exprObj ) . DefaultValue ;
1002
+ return defaultValueExpr == null
1003
+ || TryCollectBoundConstants ( ref closure , defaultValueExpr , defaultValueExpr . NodeType , paramExprs ) ;
1004
+
1005
+ case ExpressionType . Goto :
1006
+ var gotoValueExpr = ( ( GotoExpression ) exprObj ) . Value ;
1007
+ return gotoValueExpr == null
1008
+ || TryCollectBoundConstants ( ref closure , gotoValueExpr , gotoValueExpr . NodeType , paramExprs ) ;
1009
+
989
1010
case ExpressionType . Default :
990
1011
return true ;
991
1012
@@ -1273,7 +1294,7 @@ private static class EmittingVisitor
1273
1294
. DeclaredMethods . First ( m => m . IsStatic && m . Name == "Equals" ) ;
1274
1295
1275
1296
public static bool TryEmit ( object exprObj , ExpressionType exprNodeType , Type exprType ,
1276
- object [ ] paramExprs , ILGenerator il , ref ClosureInfo closure , ExpressionType parent , int byRefIndex = - 1 )
1297
+ object [ ] paramExprs , ILGenerator il , ref ClosureInfo closure , ExpressionType parent , int byRefIndex = - 1 )
1277
1298
{
1278
1299
switch ( exprNodeType )
1279
1300
{
@@ -1346,11 +1367,58 @@ public static bool TryEmit(object exprObj, ExpressionType exprNodeType, Type exp
1346
1367
case ExpressionType . Index :
1347
1368
return TryEmitIndex ( ( IndexExpression ) exprObj , exprType , paramExprs , il , ref closure ) ;
1348
1369
1370
+ case ExpressionType . Goto :
1371
+ return TryEmitGoto ( ( GotoExpression ) exprObj , exprType , paramExprs , il , ref closure ) ;
1372
+
1373
+ case ExpressionType . Label :
1374
+ return TryEmitLabel ( ( LabelExpression ) exprObj , exprType , paramExprs , il , ref closure ) ;
1375
+
1349
1376
default :
1350
1377
return false ;
1351
1378
}
1352
1379
}
1353
1380
1381
+ private static bool TryEmitLabel ( LabelExpression exprObj , Type elemType ,
1382
+ object [ ] paramExprs , ILGenerator il , ref ClosureInfo closure )
1383
+ {
1384
+ var lbl = closure . Labels . FirstOrDefault ( x => x . Key == exprObj . Target ) ;
1385
+ if ( lbl . Key != exprObj . Target )
1386
+ {
1387
+ lbl = new KeyValuePair < object , Label > ( exprObj . Target , il . DefineLabel ( ) ) ;
1388
+ closure . Labels [ closure . LabelCount ++ ] = lbl ;
1389
+ }
1390
+ il . MarkLabel ( lbl . Value ) ;
1391
+
1392
+ if ( exprObj . DefaultValue != null && ! TryEmit ( exprObj . DefaultValue , exprObj . DefaultValue . NodeType , exprObj . DefaultValue . Type , paramExprs , il , ref closure , ExpressionType . Label ) )
1393
+ return false ;
1394
+ return true ;
1395
+ }
1396
+
1397
+ private static bool TryEmitGoto ( GotoExpression exprObj , Type elemType ,
1398
+ object [ ] paramExprs , ILGenerator il , ref ClosureInfo closure ) //todo : GotoExpression.Value
1399
+ {
1400
+ if ( closure . Labels == null )
1401
+ throw new InvalidOperationException ( "cannot jump, no labels found" ) ;
1402
+
1403
+ var lbl = closure . Labels . FirstOrDefault ( x => x . Key == exprObj . Target ) ;
1404
+ if ( lbl . Key != exprObj . Target )
1405
+ {
1406
+ if ( closure . Labels . Length == closure . LabelCount - 1 )
1407
+ throw new InvalidOperationException ( "Cannot jump, not all labels found" ) ;
1408
+
1409
+ lbl = new KeyValuePair < object , Label > ( exprObj . Target , il . DefineLabel ( ) ) ;
1410
+ closure . Labels [ closure . LabelCount ++ ] = lbl ;
1411
+ }
1412
+
1413
+ if ( exprObj . Kind == GotoExpressionKind . Goto )
1414
+ {
1415
+ il . Emit ( OpCodes . Br , lbl . Value ) ;
1416
+ return true ;
1417
+ }
1418
+
1419
+ return false ;
1420
+ }
1421
+
1354
1422
private static bool TryEmitIndex ( IndexExpression exprObj , Type elemType ,
1355
1423
object [ ] paramExprs , ILGenerator il , ref ClosureInfo closure )
1356
1424
{
@@ -1815,6 +1883,13 @@ private static bool TryEmitConvert(object exprObj, Type targetType,
1815
1883
1816
1884
if ( targetType == typeof ( object ) )
1817
1885
{
1886
+ var nullableType = Nullable . GetUnderlyingType ( sourceType ) ;
1887
+ if ( nullableType != null )
1888
+ {
1889
+ il . Emit ( OpCodes . Newobj , sourceType . GetTypeInfo ( ) . DeclaredConstructors . First ( ) ) ;
1890
+ il . Emit ( OpCodes . Box , sourceType ) ;
1891
+ return true ;
1892
+ }
1818
1893
// for value type to object, just box a value, otherwise do nothing - everything is object anyway
1819
1894
if ( sourceType . GetTypeInfo ( ) . IsValueType )
1820
1895
il . Emit ( OpCodes . Box , sourceType ) ;
0 commit comments