BinaryExpression.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. //
  2. // BinaryExpression.cs
  3. //
  4. // Author:
  5. // Jb Evain ([email protected])
  6. // Miguel de Icaza ([email protected])
  7. //
  8. // Contains code from the Mono C# compiler:
  9. // Marek Safar ([email protected])
  10. // Martin Baulig ([email protected])
  11. // Raja Harinath ([email protected])
  12. //
  13. // (C) 2001-2003 Ximian, Inc.
  14. // (C) 2004-2008 Novell, Inc. (http://www.novell.com)
  15. //
  16. // Permission is hereby granted, free of charge, to any person obtaining
  17. // a copy of this software and associated documentation files (the
  18. // "Software"), to deal in the Software without restriction, including
  19. // without limitation the rights to use, copy, modify, merge, publish,
  20. // distribute, sublicense, and/or sell copies of the Software, and to
  21. // permit persons to whom the Software is furnished to do so, subject to
  22. // the following conditions:
  23. //
  24. // The above copyright notice and this permission notice shall be
  25. // included in all copies or substantial portions of the Software.
  26. //
  27. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  28. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  29. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  30. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  31. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  32. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  33. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  34. //
  35. using System;
  36. using System.Reflection;
  37. using System.Reflection.Emit;
  38. namespace System.Linq.Expressions {
  39. public sealed class BinaryExpression : Expression {
  40. Expression left;
  41. Expression right;
  42. LambdaExpression conversion;
  43. MethodInfo method;
  44. bool lift_to_null, is_lifted;
  45. public Expression Left {
  46. get { return left; }
  47. }
  48. public Expression Right {
  49. get { return right; }
  50. }
  51. public MethodInfo Method {
  52. get { return method; }
  53. }
  54. public bool IsLifted {
  55. get { return is_lifted; }
  56. }
  57. public bool IsLiftedToNull {
  58. get { return lift_to_null; }
  59. }
  60. public LambdaExpression Conversion {
  61. get { return conversion; }
  62. }
  63. internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right)
  64. : base (node_type, type)
  65. {
  66. this.left = left;
  67. this.right = right;
  68. }
  69. internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, MethodInfo method)
  70. : base (node_type, type)
  71. {
  72. this.left = left;
  73. this.right = right;
  74. this.method = method;
  75. }
  76. internal BinaryExpression (ExpressionType node_type, Type type, Expression left, Expression right, bool lift_to_null,
  77. bool is_lifted, MethodInfo method, LambdaExpression conversion) : base (node_type, type)
  78. {
  79. this.left = left;
  80. this.right = right;
  81. this.method = method;
  82. this.conversion = conversion;
  83. this.lift_to_null = lift_to_null;
  84. this.is_lifted = is_lifted;
  85. }
  86. #if !FULL_AOT_RUNTIME
  87. void EmitArrayAccess (EmitContext ec)
  88. {
  89. left.Emit (ec);
  90. right.Emit (ec);
  91. ec.ig.Emit (OpCodes.Ldelem, this.Type);
  92. }
  93. void EmitLogicalBinary (EmitContext ec)
  94. {
  95. switch (NodeType) {
  96. case ExpressionType.And:
  97. case ExpressionType.Or:
  98. if (!IsLifted)
  99. EmitLogical (ec);
  100. else if (Type == typeof (bool?))
  101. EmitLiftedLogical (ec);
  102. else
  103. EmitLiftedArithmeticBinary (ec);
  104. break;
  105. case ExpressionType.AndAlso:
  106. case ExpressionType.OrElse:
  107. if (!IsLifted)
  108. EmitLogicalShortCircuit (ec);
  109. else
  110. EmitLiftedLogicalShortCircuit (ec);
  111. break;
  112. }
  113. }
  114. void EmitLogical (EmitContext ec)
  115. {
  116. EmitNonLiftedBinary (ec);
  117. }
  118. void EmitLiftedLogical (EmitContext ec)
  119. {
  120. var ig = ec.ig;
  121. var and = NodeType == ExpressionType.And;
  122. var left = ec.EmitStored (this.left);
  123. var right = ec.EmitStored (this.right);
  124. var ret_from_left = ig.DefineLabel ();
  125. var ret_from_right = ig.DefineLabel ();
  126. var done = ig.DefineLabel ();
  127. ec.EmitNullableGetValueOrDefault (left);
  128. ig.Emit (OpCodes.Brtrue, ret_from_left);
  129. ec.EmitNullableGetValueOrDefault (right);
  130. ig.Emit (OpCodes.Brtrue, ret_from_right);
  131. ec.EmitNullableHasValue (left);
  132. ig.Emit (OpCodes.Brfalse, ret_from_left);
  133. ig.MarkLabel (ret_from_right);
  134. ec.EmitLoad (and ? left : right);
  135. ig.Emit (OpCodes.Br, done);
  136. ig.MarkLabel (ret_from_left);
  137. ec.EmitLoad (and ? right : left);
  138. ig.MarkLabel (done);
  139. }
  140. void EmitLogicalShortCircuit (EmitContext ec)
  141. {
  142. var ig = ec.ig;
  143. var and = NodeType == ExpressionType.AndAlso;
  144. var ret = ig.DefineLabel ();
  145. var done = ig.DefineLabel ();
  146. ec.Emit (left);
  147. ig.Emit (and ? OpCodes.Brfalse : OpCodes.Brtrue, ret);
  148. ec.Emit (right);
  149. ig.Emit (OpCodes.Br, done);
  150. ig.MarkLabel (ret);
  151. ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
  152. ig.MarkLabel (done);
  153. }
  154. MethodInfo GetFalseOperator ()
  155. {
  156. return GetFalseOperator (left.Type.GetNotNullableType ());
  157. }
  158. MethodInfo GetTrueOperator ()
  159. {
  160. return GetTrueOperator (left.Type.GetNotNullableType ());
  161. }
  162. void EmitUserDefinedLogicalShortCircuit (EmitContext ec)
  163. {
  164. var ig = ec.ig;
  165. var and = NodeType == ExpressionType.AndAlso;
  166. var done = ig.DefineLabel ();
  167. var left = ec.EmitStored (this.left);
  168. ec.EmitLoad (left);
  169. ig.Emit (OpCodes.Dup);
  170. ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ());
  171. ig.Emit (OpCodes.Brtrue, done);
  172. ec.Emit (this.right);
  173. ec.EmitCall (method);
  174. ig.MarkLabel (done);
  175. }
  176. void EmitLiftedLogicalShortCircuit (EmitContext ec)
  177. {
  178. var ig = ec.ig;
  179. var and = NodeType == ExpressionType.AndAlso;
  180. var left_is_null = ig.DefineLabel ();
  181. var ret_from_left = ig.DefineLabel ();
  182. var ret_null = ig.DefineLabel ();
  183. var ret_new = ig.DefineLabel();
  184. var done = ig.DefineLabel();
  185. var left = ec.EmitStored (this.left);
  186. ec.EmitNullableHasValue (left);
  187. ig.Emit (OpCodes.Brfalse, left_is_null);
  188. ec.EmitNullableGetValueOrDefault (left);
  189. ig.Emit (OpCodes.Ldc_I4_0);
  190. ig.Emit (OpCodes.Ceq);
  191. ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
  192. ig.MarkLabel (left_is_null);
  193. var right = ec.EmitStored (this.right);
  194. ec.EmitNullableHasValue (right);
  195. ig.Emit (OpCodes.Brfalse_S, ret_null);
  196. ec.EmitNullableGetValueOrDefault (right);
  197. ig.Emit (OpCodes.Ldc_I4_0);
  198. ig.Emit (OpCodes.Ceq);
  199. ig.Emit (and ? OpCodes.Brtrue : OpCodes.Brfalse, ret_from_left);
  200. ec.EmitNullableHasValue (left);
  201. ig.Emit (OpCodes.Brfalse, ret_null);
  202. ig.Emit (and ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
  203. ig.Emit (OpCodes.Br_S, ret_new);
  204. ig.MarkLabel (ret_from_left);
  205. ig.Emit (and ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
  206. ig.MarkLabel (ret_new);
  207. ec.EmitNullableNew (Type);
  208. ig.Emit (OpCodes.Br, done);
  209. ig.MarkLabel (ret_null);
  210. var ret = ig.DeclareLocal (Type);
  211. ec.EmitNullableInitialize (ret);
  212. ig.MarkLabel (done);
  213. }
  214. void EmitCoalesce (EmitContext ec)
  215. {
  216. var ig = ec.ig;
  217. var done = ig.DefineLabel ();
  218. var load_right = ig.DefineLabel ();
  219. var left = ec.EmitStored (this.left);
  220. var left_is_nullable = left.LocalType.IsNullable ();
  221. if (left_is_nullable)
  222. ec.EmitNullableHasValue (left);
  223. else
  224. ec.EmitLoad (left);
  225. ig.Emit (OpCodes.Brfalse, load_right);
  226. if (left_is_nullable && !Type.IsNullable ())
  227. ec.EmitNullableGetValue (left);
  228. else
  229. ec.EmitLoad (left);
  230. ig.Emit (OpCodes.Br, done);
  231. ig.MarkLabel (load_right);
  232. ec.Emit (this.right);
  233. ig.MarkLabel (done);
  234. }
  235. void EmitConvertedCoalesce (EmitContext ec)
  236. {
  237. var ig = ec.ig;
  238. var done = ig.DefineLabel ();
  239. var load_right = ig.DefineLabel ();
  240. var left = ec.EmitStored (this.left);
  241. if (left.LocalType.IsNullable ())
  242. ec.EmitNullableHasValue (left);
  243. else
  244. ec.EmitLoad (left);
  245. ig.Emit (OpCodes.Brfalse, load_right);
  246. ec.Emit (conversion);
  247. ec.EmitLoad (left);
  248. ig.Emit (OpCodes.Callvirt, conversion.Type.GetInvokeMethod ());
  249. ig.Emit (OpCodes.Br, done);
  250. ig.MarkLabel (load_right);
  251. ec.Emit (this.right);
  252. ig.MarkLabel (done);
  253. }
  254. static bool IsInt32OrInt64 (Type type)
  255. {
  256. return type == typeof (int) || type == typeof (long);
  257. }
  258. static bool IsSingleOrDouble (Type type)
  259. {
  260. return type == typeof (float) || type == typeof (double);
  261. }
  262. void EmitBinaryOperator (EmitContext ec)
  263. {
  264. var ig = ec.ig;
  265. bool is_unsigned = IsUnsigned (left.Type);
  266. switch (NodeType) {
  267. case ExpressionType.Add:
  268. ig.Emit (OpCodes.Add);
  269. break;
  270. case ExpressionType.AddChecked:
  271. if (IsInt32OrInt64 (left.Type))
  272. ig.Emit (OpCodes.Add_Ovf);
  273. else
  274. ig.Emit (is_unsigned ? OpCodes.Add_Ovf_Un : OpCodes.Add);
  275. break;
  276. case ExpressionType.Subtract:
  277. ig.Emit (OpCodes.Sub);
  278. break;
  279. case ExpressionType.SubtractChecked:
  280. if (IsInt32OrInt64 (left.Type))
  281. ig.Emit (OpCodes.Sub_Ovf);
  282. else
  283. ig.Emit (is_unsigned ? OpCodes.Sub_Ovf_Un : OpCodes.Sub);
  284. break;
  285. case ExpressionType.Multiply:
  286. ig.Emit (OpCodes.Mul);
  287. break;
  288. case ExpressionType.MultiplyChecked:
  289. if (IsInt32OrInt64 (left.Type))
  290. ig.Emit (OpCodes.Mul_Ovf);
  291. else
  292. ig.Emit (is_unsigned ? OpCodes.Mul_Ovf_Un : OpCodes.Mul);
  293. break;
  294. case ExpressionType.Divide:
  295. ig.Emit (is_unsigned ? OpCodes.Div_Un : OpCodes.Div);
  296. break;
  297. case ExpressionType.Modulo:
  298. ig.Emit (is_unsigned ? OpCodes.Rem_Un : OpCodes.Rem);
  299. break;
  300. case ExpressionType.RightShift:
  301. case ExpressionType.LeftShift:
  302. ig.Emit (OpCodes.Ldc_I4, left.Type == typeof (int) ? 0x1f : 0x3f);
  303. ig.Emit (OpCodes.And);
  304. if (NodeType == ExpressionType.RightShift)
  305. ig.Emit (is_unsigned ? OpCodes.Shr_Un : OpCodes.Shr);
  306. else
  307. ig.Emit (OpCodes.Shl);
  308. break;
  309. case ExpressionType.And:
  310. ig.Emit (OpCodes.And);
  311. break;
  312. case ExpressionType.Or:
  313. ig.Emit (OpCodes.Or);
  314. break;
  315. case ExpressionType.ExclusiveOr:
  316. ig.Emit (OpCodes.Xor);
  317. break;
  318. case ExpressionType.GreaterThan:
  319. ig.Emit (is_unsigned ? OpCodes.Cgt_Un : OpCodes.Cgt);
  320. break;
  321. case ExpressionType.GreaterThanOrEqual:
  322. if (is_unsigned || IsSingleOrDouble (left.Type))
  323. ig.Emit (OpCodes.Clt_Un);
  324. else
  325. ig.Emit (OpCodes.Clt);
  326. ig.Emit (OpCodes.Ldc_I4_0);
  327. ig.Emit (OpCodes.Ceq);
  328. break;
  329. case ExpressionType.LessThan:
  330. ig.Emit (is_unsigned ? OpCodes.Clt_Un : OpCodes.Clt);
  331. break;
  332. case ExpressionType.LessThanOrEqual:
  333. if (is_unsigned || IsSingleOrDouble (left.Type))
  334. ig.Emit (OpCodes.Cgt_Un);
  335. else
  336. ig.Emit (OpCodes.Cgt);
  337. ig.Emit (OpCodes.Ldc_I4_0);
  338. ig.Emit (OpCodes.Ceq);
  339. break;
  340. case ExpressionType.Equal:
  341. ig.Emit (OpCodes.Ceq);
  342. break;
  343. case ExpressionType.NotEqual:
  344. ig.Emit (OpCodes.Ceq);
  345. ig.Emit (OpCodes.Ldc_I4_0);
  346. ig.Emit (OpCodes.Ceq);
  347. break;
  348. case ExpressionType.Power:
  349. ig.Emit (OpCodes.Call, typeof (Math).GetMethod ("Pow"));
  350. break;
  351. default:
  352. throw new InvalidOperationException (
  353. string.Format ("Internal error: BinaryExpression contains non-Binary nodetype {0}", NodeType));
  354. }
  355. }
  356. bool IsLeftLiftedBinary ()
  357. {
  358. return left.Type.IsNullable () && !right.Type.IsNullable ();
  359. }
  360. void EmitLeftLiftedToNullBinary (EmitContext ec)
  361. {
  362. var ig = ec.ig;
  363. var ret = ig.DefineLabel ();
  364. var done = ig.DefineLabel ();
  365. var left = ec.EmitStored (this.left);
  366. ec.EmitNullableHasValue (left);
  367. ig.Emit (OpCodes.Brfalse, ret);
  368. ec.EmitNullableGetValueOrDefault (left);
  369. ec.Emit (right);
  370. EmitBinaryOperator (ec);
  371. ec.EmitNullableNew (Type);
  372. ig.Emit (OpCodes.Br, done);
  373. ig.MarkLabel (ret);
  374. var temp = ig.DeclareLocal (Type);
  375. ec.EmitNullableInitialize (temp);
  376. ig.MarkLabel (done);
  377. }
  378. void EmitLiftedArithmeticBinary (EmitContext ec)
  379. {
  380. if (IsLeftLiftedBinary ())
  381. EmitLeftLiftedToNullBinary (ec);
  382. else
  383. EmitLiftedToNullBinary (ec);
  384. }
  385. void EmitLiftedToNullBinary (EmitContext ec)
  386. {
  387. var ig = ec.ig;
  388. var left = ec.EmitStored (this.left);
  389. var right = ec.EmitStored (this.right);
  390. var result = ig.DeclareLocal (Type);
  391. var has_value = ig.DefineLabel ();
  392. var done = ig.DefineLabel ();
  393. ec.EmitNullableHasValue (left);
  394. ec.EmitNullableHasValue (right);
  395. ig.Emit (OpCodes.And);
  396. ig.Emit (OpCodes.Brtrue, has_value);
  397. ec.EmitNullableInitialize (result);
  398. ig.Emit (OpCodes.Br, done);
  399. ig.MarkLabel (has_value);
  400. ec.EmitNullableGetValueOrDefault (left);
  401. ec.EmitNullableGetValueOrDefault (right);
  402. EmitBinaryOperator (ec);
  403. ec.EmitNullableNew (result.LocalType);
  404. ig.MarkLabel (done);
  405. }
  406. void EmitLiftedRelationalBinary (EmitContext ec)
  407. {
  408. var ig = ec.ig;
  409. var left = ec.EmitStored (this.left);
  410. var right = ec.EmitStored (this.right);
  411. var ret = ig.DefineLabel ();
  412. var done = ig.DefineLabel ();
  413. ec.EmitNullableGetValueOrDefault (left);
  414. ec.EmitNullableGetValueOrDefault (right);
  415. switch (NodeType) {
  416. case ExpressionType.Equal:
  417. case ExpressionType.NotEqual:
  418. ig.Emit (OpCodes.Bne_Un, ret);
  419. break;
  420. default:
  421. EmitBinaryOperator (ec);
  422. ig.Emit (OpCodes.Brfalse, ret);
  423. break;
  424. }
  425. ec.EmitNullableHasValue (left);
  426. ec.EmitNullableHasValue (right);
  427. switch (NodeType) {
  428. case ExpressionType.Equal:
  429. ig.Emit (OpCodes.Ceq);
  430. break;
  431. case ExpressionType.NotEqual:
  432. ig.Emit (OpCodes.Ceq);
  433. ig.Emit (OpCodes.Ldc_I4_0);
  434. ig.Emit (OpCodes.Ceq);
  435. break;
  436. default:
  437. ig.Emit (OpCodes.And);
  438. break;
  439. }
  440. ig.Emit (OpCodes.Br, done);
  441. ig.MarkLabel (ret);
  442. ig.Emit (NodeType == ExpressionType.NotEqual ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
  443. ig.MarkLabel (done);
  444. }
  445. void EmitArithmeticBinary (EmitContext ec)
  446. {
  447. if (!IsLifted)
  448. EmitNonLiftedBinary (ec);
  449. else
  450. EmitLiftedArithmeticBinary (ec);
  451. }
  452. void EmitNonLiftedBinary (EmitContext ec)
  453. {
  454. ec.Emit (left);
  455. ec.Emit (right);
  456. EmitBinaryOperator (ec);
  457. }
  458. void EmitRelationalBinary (EmitContext ec)
  459. {
  460. if (!IsLifted)
  461. EmitNonLiftedBinary (ec);
  462. else if (IsLiftedToNull)
  463. EmitLiftedToNullBinary (ec);
  464. else
  465. EmitLiftedRelationalBinary (ec);
  466. }
  467. void EmitLiftedUserDefinedOperator (EmitContext ec)
  468. {
  469. var ig = ec.ig;
  470. var ret_true = ig.DefineLabel ();
  471. var ret_false = ig.DefineLabel ();
  472. var done = ig.DefineLabel ();
  473. var left = ec.EmitStored (this.left);
  474. var right = ec.EmitStored (this.right);
  475. ec.EmitNullableHasValue (left);
  476. ec.EmitNullableHasValue (right);
  477. switch (NodeType) {
  478. case ExpressionType.Equal:
  479. ig.Emit (OpCodes.Bne_Un, ret_false);
  480. ec.EmitNullableHasValue (left);
  481. ig.Emit (OpCodes.Brfalse, ret_true);
  482. break;
  483. case ExpressionType.NotEqual:
  484. ig.Emit (OpCodes.Bne_Un, ret_true);
  485. ec.EmitNullableHasValue (left);
  486. ig.Emit (OpCodes.Brfalse, ret_false);
  487. break;
  488. default:
  489. ig.Emit (OpCodes.And);
  490. ig.Emit (OpCodes.Brfalse, ret_false);
  491. break;
  492. }
  493. ec.EmitNullableGetValueOrDefault (left);
  494. ec.EmitNullableGetValueOrDefault (right);
  495. ec.EmitCall (method);
  496. ig.Emit (OpCodes.Br, done);
  497. ig.MarkLabel (ret_true);
  498. ig.Emit (OpCodes.Ldc_I4_1);
  499. ig.Emit (OpCodes.Br, done);
  500. ig.MarkLabel (ret_false);
  501. ig.Emit (OpCodes.Ldc_I4_0);
  502. ig.Emit (OpCodes.Br, done);
  503. ig.MarkLabel (done);
  504. }
  505. void EmitLiftedToNullUserDefinedOperator (EmitContext ec)
  506. {
  507. var ig = ec.ig;
  508. var ret = ig.DefineLabel ();
  509. var done = ig.DefineLabel ();
  510. var left = ec.EmitStored (this.left);
  511. var right = ec.EmitStored (this.right);
  512. ec.EmitNullableHasValue (left);
  513. ec.EmitNullableHasValue (right);
  514. ig.Emit (OpCodes.And);
  515. ig.Emit (OpCodes.Brfalse, ret);
  516. ec.EmitNullableGetValueOrDefault (left);
  517. ec.EmitNullableGetValueOrDefault (right);
  518. ec.EmitCall (method);
  519. ec.EmitNullableNew (Type);
  520. ig.Emit (OpCodes.Br, done);
  521. ig.MarkLabel (ret);
  522. var temp = ig.DeclareLocal (Type);
  523. ec.EmitNullableInitialize (temp);
  524. ig.MarkLabel (done);
  525. }
  526. void EmitUserDefinedLiftedLogicalShortCircuit (EmitContext ec)
  527. {
  528. var ig = ec.ig;
  529. var and = NodeType == ExpressionType.AndAlso;
  530. var left_is_null = ig.DefineLabel ();
  531. var ret_left = ig.DefineLabel ();
  532. var ret_null = ig.DefineLabel ();
  533. var done = ig.DefineLabel ();
  534. var left = ec.EmitStored (this.left);
  535. ec.EmitNullableHasValue (left);
  536. ig.Emit (OpCodes.Brfalse, and ? ret_null : left_is_null);
  537. ec.EmitNullableGetValueOrDefault (left);
  538. ec.EmitCall (and ? GetFalseOperator () : GetTrueOperator ());
  539. ig.Emit (OpCodes.Brtrue, ret_left);
  540. ig.MarkLabel (left_is_null);
  541. var right = ec.EmitStored (this.right);
  542. ec.EmitNullableHasValue (right);
  543. ig.Emit (OpCodes.Brfalse, ret_null);
  544. ec.EmitNullableGetValueOrDefault (left);
  545. ec.EmitNullableGetValueOrDefault (right);
  546. ec.EmitCall (method);
  547. ec.EmitNullableNew (Type);
  548. ig.Emit (OpCodes.Br, done);
  549. ig.MarkLabel (ret_left);
  550. ec.EmitLoad (left);
  551. ig.Emit (OpCodes.Br, done);
  552. ig.MarkLabel (ret_null);
  553. var ret = ig.DeclareLocal (Type);
  554. ec.EmitNullableInitialize (ret);
  555. ig.MarkLabel (done);
  556. }
  557. void EmitUserDefinedOperator (EmitContext ec)
  558. {
  559. if (!IsLifted) {
  560. switch (NodeType) {
  561. case ExpressionType.AndAlso:
  562. case ExpressionType.OrElse:
  563. EmitUserDefinedLogicalShortCircuit (ec);
  564. break;
  565. default:
  566. left.Emit (ec);
  567. right.Emit (ec);
  568. ec.EmitCall (method);
  569. break;
  570. }
  571. } else if (IsLiftedToNull) {
  572. switch (NodeType) {
  573. case ExpressionType.AndAlso:
  574. case ExpressionType.OrElse:
  575. EmitUserDefinedLiftedLogicalShortCircuit (ec);
  576. break;
  577. default:
  578. EmitLiftedToNullUserDefinedOperator (ec);
  579. break;
  580. }
  581. } else
  582. EmitLiftedUserDefinedOperator (ec);
  583. }
  584. internal override void Emit (EmitContext ec)
  585. {
  586. if (method != null) {
  587. EmitUserDefinedOperator (ec);
  588. return;
  589. }
  590. switch (NodeType){
  591. case ExpressionType.ArrayIndex:
  592. EmitArrayAccess (ec);
  593. return;
  594. case ExpressionType.Coalesce:
  595. if (conversion != null)
  596. EmitConvertedCoalesce (ec);
  597. else
  598. EmitCoalesce (ec);
  599. return;
  600. case ExpressionType.Power:
  601. case ExpressionType.Add:
  602. case ExpressionType.AddChecked:
  603. case ExpressionType.Divide:
  604. case ExpressionType.ExclusiveOr:
  605. case ExpressionType.LeftShift:
  606. case ExpressionType.Modulo:
  607. case ExpressionType.Multiply:
  608. case ExpressionType.MultiplyChecked:
  609. case ExpressionType.RightShift:
  610. case ExpressionType.Subtract:
  611. case ExpressionType.SubtractChecked:
  612. EmitArithmeticBinary (ec);
  613. return;
  614. case ExpressionType.Equal:
  615. case ExpressionType.GreaterThan:
  616. case ExpressionType.GreaterThanOrEqual:
  617. case ExpressionType.LessThan:
  618. case ExpressionType.LessThanOrEqual:
  619. case ExpressionType.NotEqual:
  620. EmitRelationalBinary (ec);
  621. return;
  622. case ExpressionType.And:
  623. case ExpressionType.Or:
  624. case ExpressionType.AndAlso:
  625. case ExpressionType.OrElse:
  626. EmitLogicalBinary (ec);
  627. return;
  628. default:
  629. throw new NotSupportedException (this.NodeType.ToString ());
  630. }
  631. }
  632. #endif
  633. }
  634. }