/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/expression.cs

http://github.com/icsharpcode/ILSpy · C# · 11921 lines · 8883 code · 2037 blank · 1001 comment · 2460 complexity · 24d900a0fd8e2b864aaeb0244c899382 MD5 · raw file

Large files are truncated click here to view the full file

  1. //
  2. // expression.cs: Expression representation for the IL tree.
  3. //
  4. // Author:
  5. // Miguel de Icaza (miguel@ximian.com)
  6. // Marek Safar (marek.safar@gmail.com)
  7. //
  8. // Copyright 2001, 2002, 2003 Ximian, Inc.
  9. // Copyright 2003-2008 Novell, Inc.
  10. // Copyright 2011 Xamarin Inc.
  11. //
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Linq;
  15. using SLE = System.Linq.Expressions;
  16. #if STATIC
  17. using MetaType = IKVM.Reflection.Type;
  18. using IKVM.Reflection;
  19. using IKVM.Reflection.Emit;
  20. #else
  21. using MetaType = System.Type;
  22. using System.Reflection;
  23. using System.Reflection.Emit;
  24. #endif
  25. namespace Mono.CSharp
  26. {
  27. //
  28. // This is an user operator expression, automatically created during
  29. // resolve phase
  30. //
  31. public class UserOperatorCall : Expression {
  32. protected readonly Arguments arguments;
  33. protected readonly MethodSpec oper;
  34. readonly Func<ResolveContext, Expression, Expression> expr_tree;
  35. public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
  36. {
  37. this.oper = oper;
  38. this.arguments = args;
  39. this.expr_tree = expr_tree;
  40. type = oper.ReturnType;
  41. eclass = ExprClass.Value;
  42. this.loc = loc;
  43. }
  44. public override bool ContainsEmitWithAwait ()
  45. {
  46. return arguments.ContainsEmitWithAwait ();
  47. }
  48. public override Expression CreateExpressionTree (ResolveContext ec)
  49. {
  50. if (expr_tree != null)
  51. return expr_tree (ec, new TypeOfMethod (oper, loc));
  52. Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
  53. new NullLiteral (loc),
  54. new TypeOfMethod (oper, loc));
  55. return CreateExpressionFactoryCall (ec, "Call", args);
  56. }
  57. protected override void CloneTo (CloneContext context, Expression target)
  58. {
  59. // Nothing to clone
  60. }
  61. protected override Expression DoResolve (ResolveContext ec)
  62. {
  63. //
  64. // We are born fully resolved
  65. //
  66. return this;
  67. }
  68. public override void Emit (EmitContext ec)
  69. {
  70. var call = new CallEmitter ();
  71. call.Emit (ec, oper, arguments, loc);
  72. }
  73. public override void FlowAnalysis (FlowAnalysisContext fc)
  74. {
  75. arguments.FlowAnalysis (fc);
  76. }
  77. public override SLE.Expression MakeExpression (BuilderContext ctx)
  78. {
  79. #if STATIC
  80. return base.MakeExpression (ctx);
  81. #else
  82. return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
  83. #endif
  84. }
  85. }
  86. public class ParenthesizedExpression : ShimExpression
  87. {
  88. public ParenthesizedExpression (Expression expr, Location loc)
  89. : base (expr)
  90. {
  91. this.loc = loc;
  92. }
  93. protected override Expression DoResolve (ResolveContext ec)
  94. {
  95. var res = expr.Resolve (ec);
  96. var constant = res as Constant;
  97. if (constant != null && constant.IsLiteral)
  98. return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
  99. return res;
  100. }
  101. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  102. {
  103. return expr.DoResolveLValue (ec, right_side);
  104. }
  105. public override object Accept (StructuralVisitor visitor)
  106. {
  107. return visitor.Visit (this);
  108. }
  109. }
  110. //
  111. // Unary implements unary expressions.
  112. //
  113. public class Unary : Expression
  114. {
  115. public enum Operator : byte {
  116. UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
  117. AddressOf, TOP
  118. }
  119. public readonly Operator Oper;
  120. public Expression Expr;
  121. ConvCast.Mode enum_conversion;
  122. public Unary (Operator op, Expression expr, Location loc)
  123. {
  124. Oper = op;
  125. Expr = expr;
  126. this.loc = loc;
  127. }
  128. // <summary>
  129. // This routine will attempt to simplify the unary expression when the
  130. // argument is a constant.
  131. // </summary>
  132. Constant TryReduceConstant (ResolveContext ec, Constant constant)
  133. {
  134. var e = constant;
  135. while (e is EmptyConstantCast)
  136. e = ((EmptyConstantCast) e).child;
  137. if (e is SideEffectConstant) {
  138. Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
  139. return r == null ? null : new SideEffectConstant (r, e, r.Location);
  140. }
  141. TypeSpec expr_type = e.Type;
  142. switch (Oper){
  143. case Operator.UnaryPlus:
  144. // Unary numeric promotions
  145. switch (expr_type.BuiltinType) {
  146. case BuiltinTypeSpec.Type.Byte:
  147. return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
  148. case BuiltinTypeSpec.Type.SByte:
  149. return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
  150. case BuiltinTypeSpec.Type.Short:
  151. return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
  152. case BuiltinTypeSpec.Type.UShort:
  153. return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
  154. case BuiltinTypeSpec.Type.Char:
  155. return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
  156. // Predefined operators
  157. case BuiltinTypeSpec.Type.Int:
  158. case BuiltinTypeSpec.Type.UInt:
  159. case BuiltinTypeSpec.Type.Long:
  160. case BuiltinTypeSpec.Type.ULong:
  161. case BuiltinTypeSpec.Type.Float:
  162. case BuiltinTypeSpec.Type.Double:
  163. case BuiltinTypeSpec.Type.Decimal:
  164. return e;
  165. }
  166. return null;
  167. case Operator.UnaryNegation:
  168. // Unary numeric promotions
  169. switch (expr_type.BuiltinType) {
  170. case BuiltinTypeSpec.Type.Byte:
  171. return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
  172. case BuiltinTypeSpec.Type.SByte:
  173. return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
  174. case BuiltinTypeSpec.Type.Short:
  175. return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
  176. case BuiltinTypeSpec.Type.UShort:
  177. return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
  178. case BuiltinTypeSpec.Type.Char:
  179. return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
  180. // Predefined operators
  181. case BuiltinTypeSpec.Type.Int:
  182. int ivalue = ((IntConstant) e).Value;
  183. if (ivalue == int.MinValue) {
  184. if (ec.ConstantCheckState) {
  185. ConstantFold.Error_CompileTimeOverflow (ec, loc);
  186. return null;
  187. }
  188. return e;
  189. }
  190. return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
  191. case BuiltinTypeSpec.Type.Long:
  192. long lvalue = ((LongConstant) e).Value;
  193. if (lvalue == long.MinValue) {
  194. if (ec.ConstantCheckState) {
  195. ConstantFold.Error_CompileTimeOverflow (ec, loc);
  196. return null;
  197. }
  198. return e;
  199. }
  200. return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
  201. case BuiltinTypeSpec.Type.UInt:
  202. UIntLiteral uil = constant as UIntLiteral;
  203. if (uil != null) {
  204. if (uil.Value == int.MaxValue + (uint) 1)
  205. return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
  206. return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
  207. }
  208. return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
  209. case BuiltinTypeSpec.Type.ULong:
  210. ULongLiteral ull = constant as ULongLiteral;
  211. if (ull != null && ull.Value == 9223372036854775808)
  212. return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
  213. return null;
  214. case BuiltinTypeSpec.Type.Float:
  215. FloatLiteral fl = constant as FloatLiteral;
  216. // For better error reporting
  217. if (fl != null)
  218. return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
  219. return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
  220. case BuiltinTypeSpec.Type.Double:
  221. DoubleLiteral dl = constant as DoubleLiteral;
  222. // For better error reporting
  223. if (dl != null)
  224. return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
  225. return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
  226. case BuiltinTypeSpec.Type.Decimal:
  227. return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
  228. }
  229. return null;
  230. case Operator.LogicalNot:
  231. if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
  232. return null;
  233. bool b = (bool)e.GetValue ();
  234. return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
  235. case Operator.OnesComplement:
  236. // Unary numeric promotions
  237. switch (expr_type.BuiltinType) {
  238. case BuiltinTypeSpec.Type.Byte:
  239. return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
  240. case BuiltinTypeSpec.Type.SByte:
  241. return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
  242. case BuiltinTypeSpec.Type.Short:
  243. return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
  244. case BuiltinTypeSpec.Type.UShort:
  245. return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
  246. case BuiltinTypeSpec.Type.Char:
  247. return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
  248. // Predefined operators
  249. case BuiltinTypeSpec.Type.Int:
  250. return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
  251. case BuiltinTypeSpec.Type.UInt:
  252. return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
  253. case BuiltinTypeSpec.Type.Long:
  254. return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
  255. case BuiltinTypeSpec.Type.ULong:
  256. return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
  257. }
  258. if (e is EnumConstant) {
  259. var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
  260. if (res != null) {
  261. //
  262. // Numeric promotion upgraded types to int but for enum constant
  263. // original underlying constant type is needed
  264. //
  265. if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
  266. int v = ((IntConstant) res).Value;
  267. switch (((EnumConstant) e).Child.Type.BuiltinType) {
  268. case BuiltinTypeSpec.Type.UShort:
  269. res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
  270. break;
  271. case BuiltinTypeSpec.Type.Short:
  272. res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
  273. break;
  274. case BuiltinTypeSpec.Type.Byte:
  275. res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
  276. break;
  277. case BuiltinTypeSpec.Type.SByte:
  278. res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
  279. break;
  280. }
  281. }
  282. res = new EnumConstant (res, expr_type);
  283. }
  284. return res;
  285. }
  286. return null;
  287. }
  288. throw new Exception ("Can not constant fold: " + Oper.ToString());
  289. }
  290. protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
  291. {
  292. eclass = ExprClass.Value;
  293. TypeSpec expr_type = expr.Type;
  294. Expression best_expr;
  295. TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
  296. //
  297. // Primitive types first
  298. //
  299. if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
  300. best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
  301. if (best_expr == null)
  302. return null;
  303. type = best_expr.Type;
  304. Expr = best_expr;
  305. return this;
  306. }
  307. //
  308. // E operator ~(E x);
  309. //
  310. if (Oper == Operator.OnesComplement && expr_type.IsEnum)
  311. return ResolveEnumOperator (ec, expr, predefined);
  312. return ResolveUserType (ec, expr, predefined);
  313. }
  314. protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
  315. {
  316. TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
  317. Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
  318. if (best_expr == null)
  319. return null;
  320. Expr = best_expr;
  321. enum_conversion = Binary.GetEnumResultCast (underlying_type);
  322. type = expr.Type;
  323. return EmptyCast.Create (this, type);
  324. }
  325. public override bool ContainsEmitWithAwait ()
  326. {
  327. return Expr.ContainsEmitWithAwait ();
  328. }
  329. public override Expression CreateExpressionTree (ResolveContext ec)
  330. {
  331. return CreateExpressionTree (ec, null);
  332. }
  333. Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
  334. {
  335. string method_name;
  336. switch (Oper) {
  337. case Operator.AddressOf:
  338. Error_PointerInsideExpressionTree (ec);
  339. return null;
  340. case Operator.UnaryNegation:
  341. if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
  342. method_name = "NegateChecked";
  343. else
  344. method_name = "Negate";
  345. break;
  346. case Operator.OnesComplement:
  347. case Operator.LogicalNot:
  348. method_name = "Not";
  349. break;
  350. case Operator.UnaryPlus:
  351. method_name = "UnaryPlus";
  352. break;
  353. default:
  354. throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
  355. }
  356. Arguments args = new Arguments (2);
  357. args.Add (new Argument (Expr.CreateExpressionTree (ec)));
  358. if (user_op != null)
  359. args.Add (new Argument (user_op));
  360. return CreateExpressionFactoryCall (ec, method_name, args);
  361. }
  362. public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
  363. {
  364. var predefined_operators = new TypeSpec[(int) Operator.TOP][];
  365. //
  366. // 7.6.1 Unary plus operator
  367. //
  368. predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
  369. types.Int, types.UInt,
  370. types.Long, types.ULong,
  371. types.Float, types.Double,
  372. types.Decimal
  373. };
  374. //
  375. // 7.6.2 Unary minus operator
  376. //
  377. predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
  378. types.Int, types.Long,
  379. types.Float, types.Double,
  380. types.Decimal
  381. };
  382. //
  383. // 7.6.3 Logical negation operator
  384. //
  385. predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
  386. types.Bool
  387. };
  388. //
  389. // 7.6.4 Bitwise complement operator
  390. //
  391. predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
  392. types.Int, types.UInt,
  393. types.Long, types.ULong
  394. };
  395. return predefined_operators;
  396. }
  397. //
  398. // Unary numeric promotions
  399. //
  400. static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
  401. {
  402. TypeSpec expr_type = expr.Type;
  403. if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
  404. switch (expr_type.BuiltinType) {
  405. case BuiltinTypeSpec.Type.Byte:
  406. case BuiltinTypeSpec.Type.SByte:
  407. case BuiltinTypeSpec.Type.Short:
  408. case BuiltinTypeSpec.Type.UShort:
  409. case BuiltinTypeSpec.Type.Char:
  410. return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
  411. }
  412. }
  413. if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
  414. return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
  415. return expr;
  416. }
  417. protected override Expression DoResolve (ResolveContext ec)
  418. {
  419. if (Oper == Operator.AddressOf) {
  420. return ResolveAddressOf (ec);
  421. }
  422. Expr = Expr.Resolve (ec);
  423. if (Expr == null)
  424. return null;
  425. if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  426. Arguments args = new Arguments (1);
  427. args.Add (new Argument (Expr));
  428. return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
  429. }
  430. if (Expr.Type.IsNullableType)
  431. return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
  432. //
  433. // Attempt to use a constant folding operation.
  434. //
  435. Constant cexpr = Expr as Constant;
  436. if (cexpr != null) {
  437. cexpr = TryReduceConstant (ec, cexpr);
  438. if (cexpr != null)
  439. return cexpr;
  440. }
  441. Expression expr = ResolveOperator (ec, Expr);
  442. if (expr == null)
  443. Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
  444. //
  445. // Reduce unary operator on predefined types
  446. //
  447. if (expr == this && Oper == Operator.UnaryPlus)
  448. return Expr;
  449. return expr;
  450. }
  451. public override Expression DoResolveLValue (ResolveContext ec, Expression right)
  452. {
  453. return null;
  454. }
  455. public override void Emit (EmitContext ec)
  456. {
  457. EmitOperator (ec, type);
  458. }
  459. protected void EmitOperator (EmitContext ec, TypeSpec type)
  460. {
  461. switch (Oper) {
  462. case Operator.UnaryPlus:
  463. Expr.Emit (ec);
  464. break;
  465. case Operator.UnaryNegation:
  466. if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
  467. if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
  468. Expr = Expr.EmitToField (ec);
  469. ec.EmitInt (0);
  470. if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
  471. ec.Emit (OpCodes.Conv_U8);
  472. Expr.Emit (ec);
  473. ec.Emit (OpCodes.Sub_Ovf);
  474. } else {
  475. Expr.Emit (ec);
  476. ec.Emit (OpCodes.Neg);
  477. }
  478. break;
  479. case Operator.LogicalNot:
  480. Expr.Emit (ec);
  481. ec.EmitInt (0);
  482. ec.Emit (OpCodes.Ceq);
  483. break;
  484. case Operator.OnesComplement:
  485. Expr.Emit (ec);
  486. ec.Emit (OpCodes.Not);
  487. break;
  488. case Operator.AddressOf:
  489. ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
  490. break;
  491. default:
  492. throw new Exception ("This should not happen: Operator = "
  493. + Oper.ToString ());
  494. }
  495. //
  496. // Same trick as in Binary expression
  497. //
  498. if (enum_conversion != 0) {
  499. using (ec.With (BuilderContext.Options.CheckedScope, false)) {
  500. ConvCast.Emit (ec, enum_conversion);
  501. }
  502. }
  503. }
  504. public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
  505. {
  506. if (Oper == Operator.LogicalNot)
  507. Expr.EmitBranchable (ec, target, !on_true);
  508. else
  509. base.EmitBranchable (ec, target, on_true);
  510. }
  511. public override void EmitSideEffect (EmitContext ec)
  512. {
  513. Expr.EmitSideEffect (ec);
  514. }
  515. public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
  516. {
  517. rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
  518. oper, type.GetSignatureForError ());
  519. }
  520. public override void FlowAnalysis (FlowAnalysisContext fc)
  521. {
  522. FlowAnalysis (fc, false);
  523. }
  524. public override void FlowAnalysisConditional (FlowAnalysisContext fc)
  525. {
  526. FlowAnalysis (fc, true);
  527. }
  528. void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
  529. {
  530. if (Oper == Operator.AddressOf) {
  531. var vr = Expr as VariableReference;
  532. if (vr != null && vr.VariableInfo != null)
  533. fc.SetVariableAssigned (vr.VariableInfo);
  534. return;
  535. }
  536. if (Oper == Operator.LogicalNot && conditional) {
  537. Expr.FlowAnalysisConditional (fc);
  538. var temp = fc.DefiniteAssignmentOnTrue;
  539. fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
  540. fc.DefiniteAssignmentOnFalse = temp;
  541. } else {
  542. Expr.FlowAnalysis (fc);
  543. }
  544. }
  545. //
  546. // Converts operator to System.Linq.Expressions.ExpressionType enum name
  547. //
  548. string GetOperatorExpressionTypeName ()
  549. {
  550. switch (Oper) {
  551. case Operator.OnesComplement:
  552. return "OnesComplement";
  553. case Operator.LogicalNot:
  554. return "Not";
  555. case Operator.UnaryNegation:
  556. return "Negate";
  557. case Operator.UnaryPlus:
  558. return "UnaryPlus";
  559. default:
  560. throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
  561. }
  562. }
  563. static bool IsFloat (TypeSpec t)
  564. {
  565. return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
  566. }
  567. //
  568. // Returns a stringified representation of the Operator
  569. //
  570. public static string OperName (Operator oper)
  571. {
  572. switch (oper) {
  573. case Operator.UnaryPlus:
  574. return "+";
  575. case Operator.UnaryNegation:
  576. return "-";
  577. case Operator.LogicalNot:
  578. return "!";
  579. case Operator.OnesComplement:
  580. return "~";
  581. case Operator.AddressOf:
  582. return "&";
  583. }
  584. throw new NotImplementedException (oper.ToString ());
  585. }
  586. public override SLE.Expression MakeExpression (BuilderContext ctx)
  587. {
  588. var expr = Expr.MakeExpression (ctx);
  589. bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
  590. switch (Oper) {
  591. case Operator.UnaryNegation:
  592. return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
  593. case Operator.LogicalNot:
  594. return SLE.Expression.Not (expr);
  595. #if NET_4_0 || MOBILE_DYNAMIC
  596. case Operator.OnesComplement:
  597. return SLE.Expression.OnesComplement (expr);
  598. #endif
  599. default:
  600. throw new NotImplementedException (Oper.ToString ());
  601. }
  602. }
  603. Expression ResolveAddressOf (ResolveContext ec)
  604. {
  605. if (!ec.IsUnsafe)
  606. UnsafeError (ec, loc);
  607. Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
  608. if (Expr == null || Expr.eclass != ExprClass.Variable) {
  609. ec.Report.Error (211, loc, "Cannot take the address of the given expression");
  610. return null;
  611. }
  612. if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
  613. return null;
  614. }
  615. IVariableReference vr = Expr as IVariableReference;
  616. bool is_fixed;
  617. if (vr != null) {
  618. is_fixed = vr.IsFixed;
  619. vr.SetHasAddressTaken ();
  620. if (vr.IsHoisted) {
  621. AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
  622. }
  623. } else {
  624. IFixedExpression fe = Expr as IFixedExpression;
  625. is_fixed = fe != null && fe.IsFixed;
  626. }
  627. if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
  628. ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
  629. }
  630. type = PointerContainer.MakeType (ec.Module, Expr.Type);
  631. eclass = ExprClass.Value;
  632. return this;
  633. }
  634. Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
  635. {
  636. expr = DoNumericPromotion (rc, Oper, expr);
  637. TypeSpec expr_type = expr.Type;
  638. foreach (TypeSpec t in predefined) {
  639. if (t == expr_type)
  640. return expr;
  641. }
  642. return null;
  643. }
  644. //
  645. // Perform user-operator overload resolution
  646. //
  647. protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
  648. {
  649. CSharp.Operator.OpType op_type;
  650. switch (Oper) {
  651. case Operator.LogicalNot:
  652. op_type = CSharp.Operator.OpType.LogicalNot; break;
  653. case Operator.OnesComplement:
  654. op_type = CSharp.Operator.OpType.OnesComplement; break;
  655. case Operator.UnaryNegation:
  656. op_type = CSharp.Operator.OpType.UnaryNegation; break;
  657. case Operator.UnaryPlus:
  658. op_type = CSharp.Operator.OpType.UnaryPlus; break;
  659. default:
  660. throw new InternalErrorException (Oper.ToString ());
  661. }
  662. var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
  663. if (methods == null)
  664. return null;
  665. Arguments args = new Arguments (1);
  666. args.Add (new Argument (expr));
  667. var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
  668. var oper = res.ResolveOperator (ec, ref args);
  669. if (oper == null)
  670. return null;
  671. Expr = args [0].Expr;
  672. return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
  673. }
  674. //
  675. // Unary user type overload resolution
  676. //
  677. Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
  678. {
  679. Expression best_expr = ResolveUserOperator (ec, expr);
  680. if (best_expr != null)
  681. return best_expr;
  682. foreach (TypeSpec t in predefined) {
  683. Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
  684. if (oper_expr == null)
  685. continue;
  686. if (oper_expr == ErrorExpression.Instance)
  687. return oper_expr;
  688. //
  689. // decimal type is predefined but has user-operators
  690. //
  691. if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
  692. oper_expr = ResolveUserType (ec, oper_expr, predefined);
  693. else
  694. oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
  695. if (oper_expr == null)
  696. continue;
  697. if (best_expr == null) {
  698. best_expr = oper_expr;
  699. continue;
  700. }
  701. int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
  702. if (result == 0) {
  703. if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
  704. Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
  705. } else {
  706. Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
  707. }
  708. break;
  709. }
  710. if (result == 2)
  711. best_expr = oper_expr;
  712. }
  713. if (best_expr == null)
  714. return null;
  715. //
  716. // HACK: Decimal user-operator is included in standard operators
  717. //
  718. if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
  719. return best_expr;
  720. Expr = best_expr;
  721. type = best_expr.Type;
  722. return this;
  723. }
  724. protected override void CloneTo (CloneContext clonectx, Expression t)
  725. {
  726. Unary target = (Unary) t;
  727. target.Expr = Expr.Clone (clonectx);
  728. }
  729. public override object Accept (StructuralVisitor visitor)
  730. {
  731. return visitor.Visit (this);
  732. }
  733. }
  734. //
  735. // Unary operators are turned into Indirection expressions
  736. // after semantic analysis (this is so we can take the address
  737. // of an indirection).
  738. //
  739. public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
  740. Expression expr;
  741. LocalTemporary temporary;
  742. bool prepared;
  743. public Indirection (Expression expr, Location l)
  744. {
  745. this.expr = expr;
  746. loc = l;
  747. }
  748. public Expression Expr {
  749. get {
  750. return expr;
  751. }
  752. }
  753. public bool IsFixed {
  754. get { return true; }
  755. }
  756. public override Location StartLocation {
  757. get {
  758. return expr.StartLocation;
  759. }
  760. }
  761. protected override void CloneTo (CloneContext clonectx, Expression t)
  762. {
  763. Indirection target = (Indirection) t;
  764. target.expr = expr.Clone (clonectx);
  765. }
  766. public override bool ContainsEmitWithAwait ()
  767. {
  768. throw new NotImplementedException ();
  769. }
  770. public override Expression CreateExpressionTree (ResolveContext ec)
  771. {
  772. Error_PointerInsideExpressionTree (ec);
  773. return null;
  774. }
  775. public override void Emit (EmitContext ec)
  776. {
  777. if (!prepared)
  778. expr.Emit (ec);
  779. ec.EmitLoadFromPtr (Type);
  780. }
  781. public void Emit (EmitContext ec, bool leave_copy)
  782. {
  783. Emit (ec);
  784. if (leave_copy) {
  785. ec.Emit (OpCodes.Dup);
  786. temporary = new LocalTemporary (expr.Type);
  787. temporary.Store (ec);
  788. }
  789. }
  790. public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
  791. {
  792. prepared = isCompound;
  793. expr.Emit (ec);
  794. if (isCompound)
  795. ec.Emit (OpCodes.Dup);
  796. source.Emit (ec);
  797. if (leave_copy) {
  798. ec.Emit (OpCodes.Dup);
  799. temporary = new LocalTemporary (source.Type);
  800. temporary.Store (ec);
  801. }
  802. ec.EmitStoreFromPtr (type);
  803. if (temporary != null) {
  804. temporary.Emit (ec);
  805. temporary.Release (ec);
  806. }
  807. }
  808. public void AddressOf (EmitContext ec, AddressOp Mode)
  809. {
  810. expr.Emit (ec);
  811. }
  812. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  813. {
  814. return DoResolve (ec);
  815. }
  816. protected override Expression DoResolve (ResolveContext ec)
  817. {
  818. expr = expr.Resolve (ec);
  819. if (expr == null)
  820. return null;
  821. if (!ec.IsUnsafe)
  822. UnsafeError (ec, loc);
  823. var pc = expr.Type as PointerContainer;
  824. if (pc == null) {
  825. ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
  826. return null;
  827. }
  828. type = pc.Element;
  829. if (type.Kind == MemberKind.Void) {
  830. Error_VoidPointerOperation (ec);
  831. return null;
  832. }
  833. eclass = ExprClass.Variable;
  834. return this;
  835. }
  836. public override object Accept (StructuralVisitor visitor)
  837. {
  838. return visitor.Visit (this);
  839. }
  840. }
  841. /// <summary>
  842. /// Unary Mutator expressions (pre and post ++ and --)
  843. /// </summary>
  844. ///
  845. /// <remarks>
  846. /// UnaryMutator implements ++ and -- expressions. It derives from
  847. /// ExpressionStatement becuase the pre/post increment/decrement
  848. /// operators can be used in a statement context.
  849. ///
  850. /// FIXME: Idea, we could split this up in two classes, one simpler
  851. /// for the common case, and one with the extra fields for more complex
  852. /// classes (indexers require temporary access; overloaded require method)
  853. ///
  854. /// </remarks>
  855. public class UnaryMutator : ExpressionStatement
  856. {
  857. class DynamicPostMutator : Expression, IAssignMethod
  858. {
  859. LocalTemporary temp;
  860. Expression expr;
  861. public DynamicPostMutator (Expression expr)
  862. {
  863. this.expr = expr;
  864. this.type = expr.Type;
  865. this.loc = expr.Location;
  866. }
  867. public override Expression CreateExpressionTree (ResolveContext ec)
  868. {
  869. throw new NotImplementedException ("ET");
  870. }
  871. protected override Expression DoResolve (ResolveContext rc)
  872. {
  873. eclass = expr.eclass;
  874. return this;
  875. }
  876. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  877. {
  878. expr.DoResolveLValue (ec, right_side);
  879. return DoResolve (ec);
  880. }
  881. public override void Emit (EmitContext ec)
  882. {
  883. temp.Emit (ec);
  884. }
  885. public void Emit (EmitContext ec, bool leave_copy)
  886. {
  887. throw new NotImplementedException ();
  888. }
  889. //
  890. // Emits target assignment using unmodified source value
  891. //
  892. public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
  893. {
  894. //
  895. // Allocate temporary variable to keep original value before it's modified
  896. //
  897. temp = new LocalTemporary (type);
  898. expr.Emit (ec);
  899. temp.Store (ec);
  900. ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
  901. if (leave_copy)
  902. Emit (ec);
  903. temp.Release (ec);
  904. temp = null;
  905. }
  906. }
  907. [Flags]
  908. public enum Mode : byte {
  909. IsIncrement = 0,
  910. IsDecrement = 1,
  911. IsPre = 0,
  912. IsPost = 2,
  913. PreIncrement = 0,
  914. PreDecrement = IsDecrement,
  915. PostIncrement = IsPost,
  916. PostDecrement = IsPost | IsDecrement
  917. }
  918. Mode mode;
  919. bool is_expr, recurse;
  920. protected Expression expr;
  921. // Holds the real operation
  922. Expression operation;
  923. public UnaryMutator (Mode m, Expression e, Location loc)
  924. {
  925. mode = m;
  926. this.loc = loc;
  927. expr = e;
  928. }
  929. public Mode UnaryMutatorMode {
  930. get {
  931. return mode;
  932. }
  933. }
  934. public Expression Expr {
  935. get {
  936. return expr;
  937. }
  938. }
  939. public override Location StartLocation {
  940. get {
  941. return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
  942. }
  943. }
  944. public override bool ContainsEmitWithAwait ()
  945. {
  946. return expr.ContainsEmitWithAwait ();
  947. }
  948. public override Expression CreateExpressionTree (ResolveContext ec)
  949. {
  950. return new SimpleAssign (this, this).CreateExpressionTree (ec);
  951. }
  952. public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
  953. {
  954. //
  955. // Predefined ++ and -- operators exist for the following types:
  956. // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
  957. //
  958. return new TypeSpec[] {
  959. types.Int,
  960. types.Long,
  961. types.SByte,
  962. types.Byte,
  963. types.Short,
  964. types.UInt,
  965. types.ULong,
  966. types.Char,
  967. types.Float,
  968. types.Double,
  969. types.Decimal
  970. };
  971. }
  972. protected override Expression DoResolve (ResolveContext ec)
  973. {
  974. expr = expr.Resolve (ec);
  975. if (expr == null || expr.Type == InternalType.ErrorType)
  976. return null;
  977. if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  978. //
  979. // Handle postfix unary operators using local
  980. // temporary variable
  981. //
  982. if ((mode & Mode.IsPost) != 0)
  983. expr = new DynamicPostMutator (expr);
  984. Arguments args = new Arguments (1);
  985. args.Add (new Argument (expr));
  986. return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
  987. }
  988. if (expr.Type.IsNullableType)
  989. return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
  990. return DoResolveOperation (ec);
  991. }
  992. protected Expression DoResolveOperation (ResolveContext ec)
  993. {
  994. eclass = ExprClass.Value;
  995. type = expr.Type;
  996. if (expr is RuntimeValueExpression) {
  997. operation = expr;
  998. } else {
  999. // Use itself at the top of the stack
  1000. operation = new EmptyExpression (type);
  1001. }
  1002. //
  1003. // The operand of the prefix/postfix increment decrement operators
  1004. // should be an expression that is classified as a variable,
  1005. // a property access or an indexer access
  1006. //
  1007. // TODO: Move to parser, expr is ATypeNameExpression
  1008. if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
  1009. expr = expr.ResolveLValue (ec, expr);
  1010. } else {
  1011. ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
  1012. }
  1013. //
  1014. // Step 1: Try to find a user operator, it has priority over predefined ones
  1015. //
  1016. var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
  1017. var methods = MemberCache.GetUserOperator (type, user_op, false);
  1018. if (methods != null) {
  1019. Arguments args = new Arguments (1);
  1020. args.Add (new Argument (expr));
  1021. var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
  1022. var method = res.ResolveOperator (ec, ref args);
  1023. if (method == null)
  1024. return null;
  1025. args[0].Expr = operation;
  1026. operation = new UserOperatorCall (method, args, null, loc);
  1027. operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
  1028. return this;
  1029. }
  1030. //
  1031. // Step 2: Try predefined types
  1032. //
  1033. Expression source = null;
  1034. bool primitive_type;
  1035. //
  1036. // Predefined without user conversion first for speed-up
  1037. //
  1038. // Predefined ++ and -- operators exist for the following types:
  1039. // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
  1040. //
  1041. switch (type.BuiltinType) {
  1042. case BuiltinTypeSpec.Type.Byte:
  1043. case BuiltinTypeSpec.Type.SByte:
  1044. case BuiltinTypeSpec.Type.Short:
  1045. case BuiltinTypeSpec.Type.UShort:
  1046. case BuiltinTypeSpec.Type.Int:
  1047. case BuiltinTypeSpec.Type.UInt:
  1048. case BuiltinTypeSpec.Type.Long:
  1049. case BuiltinTypeSpec.Type.ULong:
  1050. case BuiltinTypeSpec.Type.Char:
  1051. case BuiltinTypeSpec.Type.Float:
  1052. case BuiltinTypeSpec.Type.Double:
  1053. case BuiltinTypeSpec.Type.Decimal:
  1054. source = operation;
  1055. primitive_type = true;
  1056. break;
  1057. default:
  1058. primitive_type = false;
  1059. // ++/-- on pointer variables of all types except void*
  1060. if (type.IsPointer) {
  1061. if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
  1062. Error_VoidPointerOperation (ec);
  1063. return null;
  1064. }
  1065. source = operation;
  1066. } else {
  1067. Expression best_source = null;
  1068. foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
  1069. source = Convert.ImplicitUserConversion (ec, operation, t, loc);
  1070. // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
  1071. if (source == null)
  1072. continue;
  1073. if (best_source == null) {
  1074. best_source = source;
  1075. continue;
  1076. }
  1077. var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
  1078. if (better == 1)
  1079. continue;
  1080. if (better == 2) {
  1081. best_source = source;
  1082. continue;
  1083. }
  1084. Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
  1085. break;
  1086. }
  1087. source = best_source;
  1088. }
  1089. // ++/-- on enum types
  1090. if (source == null && type.IsEnum)
  1091. source = operation;
  1092. if (source == null) {
  1093. expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
  1094. return null;
  1095. }
  1096. break;
  1097. }
  1098. var one = new IntConstant (ec.BuiltinTypes, 1, loc);
  1099. var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
  1100. operation = new Binary (op, source, one);
  1101. operation = operation.Resolve (ec);
  1102. if (operation == null)
  1103. throw new NotImplementedException ("should not be reached");
  1104. if (operation.Type != type) {
  1105. if (primitive_type)
  1106. operation = Convert.ExplicitNumericConversion (ec, operation, type);
  1107. else
  1108. operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
  1109. }
  1110. return this;
  1111. }
  1112. void EmitCode (EmitContext ec, bool is_expr)
  1113. {
  1114. recurse = true;
  1115. this.is_expr = is_expr;
  1116. ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
  1117. }
  1118. public override void Emit (EmitContext ec)
  1119. {
  1120. //
  1121. // We use recurse to allow ourselfs to be the source
  1122. // of an assignment. This little hack prevents us from
  1123. // having to allocate another expression
  1124. //
  1125. if (recurse) {
  1126. ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
  1127. EmitOperation (ec);
  1128. recurse = false;
  1129. return;
  1130. }
  1131. EmitCode (ec, true);
  1132. }
  1133. protected virtual void EmitOperation (EmitContext ec)
  1134. {
  1135. operation.Emit (ec);
  1136. }
  1137. public override void EmitStatement (EmitContext ec)
  1138. {
  1139. EmitCode (ec, false);
  1140. }
  1141. public override void FlowAnalysis (FlowAnalysisContext fc)
  1142. {
  1143. expr.FlowAnalysis (fc);
  1144. }
  1145. //
  1146. // Converts operator to System.Linq.Expressions.ExpressionType enum name
  1147. //
  1148. string GetOperatorExpressionTypeName ()
  1149. {
  1150. return IsDecrement ? "Decrement" : "Increment";
  1151. }
  1152. bool IsDecrement {
  1153. get { return (mode & Mode.IsDecrement) != 0; }
  1154. }
  1155. #if NET_4_0 || MOBILE_DYNAMIC
  1156. public override SLE.Expression MakeExpression (BuilderContext ctx)
  1157. {
  1158. var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
  1159. var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
  1160. return SLE.Expression.Assign (target, source);
  1161. }
  1162. #endif
  1163. public static string OperName (Mode oper)
  1164. {
  1165. return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
  1166. }
  1167. protected override void CloneTo (CloneContext clonectx, Expression t)
  1168. {
  1169. UnaryMutator target = (UnaryMutator) t;
  1170. target.expr = expr.Clone (clonectx);
  1171. }
  1172. public override object Accept (StructuralVisitor visitor)
  1173. {
  1174. return visitor.Visit (this);
  1175. }
  1176. }
  1177. //
  1178. // Base class for the `is' and `as' operators
  1179. //
  1180. public abstract class Probe : Expression
  1181. {
  1182. public Expression ProbeType;
  1183. protected Expression expr;
  1184. protected TypeSpec probe_type_expr;
  1185. protected Probe (Expression expr, Expression probe_type, Location l)
  1186. {
  1187. ProbeType = probe_type;
  1188. loc = l;
  1189. this.expr = expr;
  1190. }
  1191. public Expression Expr {
  1192. get {
  1193. return expr;
  1194. }
  1195. }
  1196. public override bool ContainsEmitWithAwait ()
  1197. {
  1198. return expr.ContainsEmitWithAwait ();
  1199. }
  1200. protected Expression ResolveCommon (ResolveContext rc)
  1201. {
  1202. expr = expr.Resolve (rc);
  1203. if (expr == null)
  1204. return null;
  1205. ResolveProbeType (rc);
  1206. if (probe_type_expr == null)
  1207. return this;
  1208. if (probe_type_expr.IsStatic) {
  1209. rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
  1210. probe_type_expr.GetSignatureForError ());
  1211. return null;
  1212. }
  1213. if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
  1214. rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
  1215. OperatorName);
  1216. return null;
  1217. }
  1218. if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
  1219. rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
  1220. OperatorName);
  1221. return null;
  1222. }
  1223. return this;
  1224. }
  1225. protected virtual void ResolveProbeType (ResolveContext rc)
  1226. {
  1227. probe_type_expr = ProbeType.ResolveAsType (rc);
  1228. }
  1229. public override void EmitSideEffect (EmitContext ec)
  1230. {
  1231. expr.EmitSideEffect (ec);
  1232. }
  1233. public override void FlowAnalysis (FlowAnalysisContext fc)
  1234. {
  1235. expr.FlowAnalysis (fc);
  1236. }
  1237. protected abstract string OperatorName { get; }
  1238. protected override void CloneTo (CloneContext clonectx, Expression t)
  1239. {
  1240. Probe target = (Probe) t;
  1241. target.expr = expr.Clone (clonectx);
  1242. target.ProbeType = ProbeType.Clone (clonectx);
  1243. }
  1244. }
  1245. /// <summary>
  1246. /// Implementation of the `is' operator.
  1247. /// </summary>
  1248. public class Is : Probe
  1249. {
  1250. Nullable.Unwrap expr_unwrap;
  1251. MethodSpec number_mg;
  1252. Arguments number_args;
  1253. public Is (Expression expr, Expression probe_type, Location l)
  1254. : base (expr, probe_type, l)
  1255. {
  1256. }
  1257. protected override string OperatorName {
  1258. get { return "is"; }
  1259. }
  1260. public LocalVariable Variable { get; set; }
  1261. public override Expression CreateExpressionTree (ResolveContext ec)
  1262. {
  1263. if (Variable != null)
  1264. throw new NotSupportedException ();
  1265. Arguments args = Arguments.CreateForExpressionTree (ec, null,
  1266. expr.CreateExpressionTree (ec),
  1267. new TypeOf (probe_type_expr, loc));
  1268. return CreateExpressionFactoryCall (ec, "TypeIs", args);
  1269. }
  1270. Expression CreateConstantResult (ResolveContext rc, bool result)
  1271. {
  1272. if (result)
  1273. rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
  1274. probe_type_expr.GetSignatureForError ());
  1275. else
  1276. rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
  1277. probe_type_expr.GetSignatureForError ());
  1278. var c = new BoolConstant (rc.BuiltinTypes, result, loc);
  1279. return expr.IsSideEffectFree ?
  1280. ReducedExpression.Create (c, this) :
  1281. new SideEffectConstant (c, this, loc);
  1282. }
  1283. public override void Emit (EmitContext ec)
  1284. {
  1285. if (probe_type_expr == null) {
  1286. EmitConstantMatch (ec);
  1287. return;
  1288. }
  1289. EmitLoad (ec);
  1290. if (expr_unwrap == null) {
  1291. ec.EmitNull ();
  1292. ec.Emit (OpCodes.Cgt_Un);
  1293. }
  1294. }
  1295. public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
  1296. {
  1297. if (probe_type_expr == null) {
  1298. EmitConstantMatch (ec);
  1299. } else {
  1300. EmitLoad (ec);
  1301. }
  1302. ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
  1303. }
  1304. void EmitConstantMatch (EmitContext ec)
  1305. {
  1306. var no_match = ec.DefineLabel ();
  1307. var end = ec.DefineLabel ();
  1308. if (expr_unwrap != null) {
  1309. expr_unwrap.EmitCheck (ec);
  1310. if (ProbeType.IsNull) {
  1311. ec.EmitInt (0);
  1312. ec.Emit (OpCodes.Ceq);
  1313. return;
  1314. }
  1315. ec.Emit (OpCodes.Brfalse_S, no_match);
  1316. expr_unwrap.Emit (ec);
  1317. ProbeType.Emit (ec);
  1318. ec.Emit (OpCodes.Ceq);
  1319. ec.Emit (OpCodes.Br_S, end);
  1320. ec.MarkLabel (no_match);
  1321. ec.EmitInt (0);
  1322. ec.MarkLabel (end);
  1323. return;
  1324. }
  1325. if (number_args != null && number_args.Count == 3) {
  1326. var ce = new CallEmitter ();
  1327. ce.Emit (ec, number_mg, number_args, loc);
  1328. return;
  1329. }
  1330. Expr.Emit (ec);
  1331. ec.Emit (OpCodes.Isinst, ProbeType.Type);
  1332. ec.Emit (OpCodes.Dup);
  1333. ec.Emit (OpCodes.Brfalse, no_match);
  1334. if (number_mg != null) {
  1335. var ce = new CallEmitter ();
  1336. ce.Emit (ec, number_mg, number_args, loc);
  1337. } else {
  1338. ProbeType.Emit (ec);
  1339. ec.Emit (OpCodes.Ceq);
  1340. }
  1341. ec.Emit (OpCodes.Br_S, end);
  1342. ec.MarkLabel (no_match);
  1343. ec.Emit (OpCodes.Pop);
  1344. ec.EmitInt (0);
  1345. ec.MarkLabel (end);
  1346. }
  1347. void EmitLoad (EmitContext ec)
  1348. {
  1349. Label no_value_label = new Label ();
  1350. if (expr_unwrap != null) {
  1351. expr_unwrap.EmitCheck (ec);
  1352. if (Variable == null)
  1353. return;
  1354. ec.Emit (OpCodes.Dup);
  1355. no_value_label = ec.DefineLabel ();
  1356. ec.Emit (OpCodes.Brfalse_S, no_value_label);
  1357. expr_unwrap.Emit (ec);
  1358. } else {
  1359. expr.Emit (ec);
  1360. // Only to make verifier happy
  1361. if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
  1362. ec.Emit (OpCodes.Box, expr.Type);
  1363. ec.Emit (OpCodes.Isinst, probe_type_expr);
  1364. }
  1365. if (Variable != null) {
  1366. bool value_on_stack;
  1367. if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
  1368. ec.Emit (OpCodes.Dup);
  1369. ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
  1370. value_on_stack = true;
  1371. } else {
  1372. value_on_stack = false;
  1373. }
  1374. Variable.CreateBuilder (ec);
  1375. Variable.EmitAssign (ec);
  1376. if (expr_unwrap != null) {
  1377. ec.MarkLabel (no_value_label);
  1378. } else if (!value_on_stack) {
  1379. Variable.Emit (ec);
  1380. }
  1381. }
  1382. }
  1383. protected override Expression DoResolve (ResolveContext rc)
  1384. {
  1385. if (ResolveCommon (rc) == null)
  1386. return null;
  1387. type = rc.BuiltinTypes.Bool;
  1388. eclass = ExprClass.Value;
  1389. if (probe_type_expr == null)
  1390. return ResolveMatchingExpression (rc);
  1391. var res = ResolveResultExpression (rc);
  1392. if (Variable != null) {
  1393. if (res is Constant)
  1394. throw new NotImplementedException ("constant in type pattern matching");
  1395. Variable.Type = probe_type_expr;
  1396. var bc = rc as BlockContext;
  1397. if (bc != null)
  1398. Variable.PrepareAssignmentAnalysis (bc);
  1399. }
  1400. return res;
  1401. }
  1402. public override void FlowAnalysis (FlowAnalysisContext fc)
  1403. {
  1404. base.FlowAnalysis (fc);
  1405. if (Variable != null)
  1406. fc.SetVariableAssigned (Variable.VariableInfo, true);
  1407. }
  1408. protected override void ResolveProbeType (ResolveContext rc)
  1409. {
  1410. if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
  1411. ProbeType = ProbeType.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
  1412. if (ProbeType == null)
  1413. return;
  1414. if (ProbeType.eclass == ExprClass.Type) {
  1415. probe_type_expr = ProbeType.Type;
  1416. }
  1417. return;
  1418. }
  1419. base.ResolveProbeType (rc);
  1420. }
  1421. Expression ResolveMatchingExpression (ResolveContext rc)
  1422. {
  1423. var mc = ProbeType as Constant;
  1424. if (mc != null) {
  1425. if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
  1426. ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
  1427. return null;
  1428. }
  1429. if (mc.IsNull)
  1430. return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
  1431. var c = Expr as Constant;
  1432. if (c != null) {
  1433. c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
  1434. if (c != null)
  1435. return c;
  1436. }
  1437. if (Expr.Type.IsNullableType) {
  1438. expr_unwrap = new Nullable.Unwrap (Expr);
  1439. expr_unwrap.Resolve (rc);
  1440. } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
  1441. var helper = rc.Module.CreatePatterMatchingHelper ();
  1442. number_mg = helper.NumberMatcher.Spec;
  1443. //
  1444. // There are actually 3 arguments but the first one is already on the stack
  1445. //
  1446. number_args = new Arguments (3);
  1447. if (!ProbeType.Type.IsEnum)
  1448. number_args.Add (new Argument (Expr));
  1449. number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
  1450. number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
  1451. }
  1452. return this;
  1453. }
  1454. throw new NotImplementedException ();
  1455. }
  1456. Expression ResolveResultExpression (ResolveContext ec)
  1457. {
  1458. TypeSpec d = expr.Type;
  1459. bool d_is_nullable = false;
  1460. //
  1461. // If E is a method group or the null literal, or if the type of E is a reference
  1462. // type or a nullable type and the value of E is null, the result is false
  1463. //
  1464. if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
  1465. return CreateConstantResult (ec, false);
  1466. if (d.IsNullableType) {
  1467. var ut = Nullable.NullableInfo.GetUnderlyingType (d);
  1468. if (!ut.IsGenericParameter) {
  1469. d = ut;
  1470. d_is_nullable = true;
  1471. }
  1472. }
  1473. TypeSpec t = probe_type_expr;
  1474. bool t_is_nullable = false;
  1475. if (t.IsNullableType) {
  1476. var ut = Nullable.NullableInfo.GetUnderlyingType (t);
  1477. if (!ut.IsGenericParameter) {
  1478. t = ut;
  1479. t_is_nullable = true;
  1480. }
  1481. }
  1482. if (t.IsStruct) {
  1483. if (d == t) {
  1484. //
  1485. // D and T are the same value types but D can be null
  1486. //
  1487. if (d_is_nullable && !t_is_nullable) {
  1488. expr_unwrap = Nullable.Unwrap.Create (expr, true);
  1489. return this;
  1490. }
  1491. //
  1492. // The result is true if D and T are the same value types
  1493. //
  1494. return CreateConstantResult (ec, true);
  1495. }
  1496. var tp = d as TypeParameterSpec;
  1497. if (tp != null)
  1498. return ResolveGenericParameter (ec, t, tp);
  1499. //
  1500. // An unboxing conversion exists
  1501. //
  1502. if (Convert.ExplicitReferenceConversionExists (d, t))
  1503. return this;
  1504. //
  1505. // open generic type
  1506. //
  1507. if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
  1508. return this;
  1509. } else {
  1510. var tps = t as TypeParameterSpec;
  1511. if (tps != null)
  1512. return ResolveGenericParameter (ec, d, tps);
  1513. if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  1514. ec.Report.Warning (1981, 3, loc,
  1515. "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
  1516. OperatorName, t.GetSignatureForError ());
  1517. }
  1518. if (TypeManager.IsGenericParameter (d))
  1519. return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
  1520. if (TypeSpec.IsValueType (d)) {
  1521. if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
  1522. if (d_is_nullable && !t_is_nullable) {
  1523. expr_unwrap = Nullable.Unwrap.Create (expr, false);
  1524. return this;
  1525. }
  1526. return CreateConstantResult (ec, true);
  1527. }
  1528. } else {
  1529. if (Convert.ImplicitReferenceConversionExists (d, t)) {
  1530. var c = expr as Constant;
  1531. if (c != null)
  1532. return CreateConstantResult (ec, !c.IsNull);
  1533. //
  1534. // Do not optimize for imported type or dynamic type
  1535. //
  1536. if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
  1537. d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
  1538. return this;
  1539. }
  1540. if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
  1541. return this;
  1542. //
  1543. // Turn is check into simple null check for implicitly convertible reference types
  1544. //
  1545. return ReducedExpression.Create (
  1546. new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
  1547. this).Resolve (ec);
  1548. }
  1549. if (Convert.ExplicitReferenceConversionExists (d, t))
  1550. return this;
  1551. //
  1552. // open generic type
  1553. //
  1554. if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
  1555. return this;
  1556. }
  1557. }
  1558. return CreateConstantResult (ec, false);
  1559. }
  1560. Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
  1561. {
  1562. if (t.IsReferenceType) {
  1563. if (d.IsStruct)
  1564. return CreateConstantR