PageRenderTime 107ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 2ms

/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
Possible License(s): LGPL-2.1, MIT, CC-BY-SA-3.0
  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 CreateConstantResult (ec, false);
  1565. }
  1566. if (expr.Type.IsGenericParameter) {
  1567. if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
  1568. return CreateConstantResult (ec, true);
  1569. expr = new BoxedCast (expr, d);
  1570. }
  1571. return this;
  1572. }
  1573. public override object Accept (StructuralVisitor visitor)
  1574. {
  1575. return visitor.Visit (this);
  1576. }
  1577. }
  1578. /// <summary>
  1579. /// Implementation of the `as' operator.
  1580. /// </summary>
  1581. public class As : Probe {
  1582. public As (Expression expr, Expression probe_type, Location l)
  1583. : base (expr, probe_type, l)
  1584. {
  1585. }
  1586. protected override string OperatorName {
  1587. get { return "as"; }
  1588. }
  1589. public override Expression CreateExpressionTree (ResolveContext ec)
  1590. {
  1591. Arguments args = Arguments.CreateForExpressionTree (ec, null,
  1592. expr.CreateExpressionTree (ec),
  1593. new TypeOf (probe_type_expr, loc));
  1594. return CreateExpressionFactoryCall (ec, "TypeAs", args);
  1595. }
  1596. public override void Emit (EmitContext ec)
  1597. {
  1598. expr.Emit (ec);
  1599. ec.Emit (OpCodes.Isinst, type);
  1600. if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
  1601. ec.Emit (OpCodes.Unbox_Any, type);
  1602. }
  1603. protected override Expression DoResolve (ResolveContext ec)
  1604. {
  1605. if (ResolveCommon (ec) == null)
  1606. return null;
  1607. type = probe_type_expr;
  1608. eclass = ExprClass.Value;
  1609. TypeSpec etype = expr.Type;
  1610. if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
  1611. if (TypeManager.IsGenericParameter (type)) {
  1612. ec.Report.Error (413, loc,
  1613. "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
  1614. probe_type_expr.GetSignatureForError ());
  1615. } else {
  1616. ec.Report.Error (77, loc,
  1617. "The `as' operator cannot be used with a non-nullable value type `{0}'",
  1618. type.GetSignatureForError ());
  1619. }
  1620. return null;
  1621. }
  1622. if (expr.IsNull && type.IsNullableType) {
  1623. return Nullable.LiftedNull.CreateFromExpression (ec, this);
  1624. }
  1625. // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
  1626. if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  1627. return this;
  1628. }
  1629. Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
  1630. if (e != null) {
  1631. e = EmptyCast.Create (e, type);
  1632. return ReducedExpression.Create (e, this).Resolve (ec);
  1633. }
  1634. if (Convert.ExplicitReferenceConversionExists (etype, type)){
  1635. if (TypeManager.IsGenericParameter (etype))
  1636. expr = new BoxedCast (expr, etype);
  1637. return this;
  1638. }
  1639. if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
  1640. expr = new BoxedCast (expr, etype);
  1641. return this;
  1642. }
  1643. if (etype != InternalType.ErrorType) {
  1644. ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
  1645. etype.GetSignatureForError (), type.GetSignatureForError ());
  1646. }
  1647. return null;
  1648. }
  1649. public override object Accept (StructuralVisitor visitor)
  1650. {
  1651. return visitor.Visit (this);
  1652. }
  1653. }
  1654. //
  1655. // This represents a typecast in the source language.
  1656. //
  1657. public class Cast : ShimExpression {
  1658. Expression target_type;
  1659. public Cast (Expression cast_type, Expression expr, Location loc)
  1660. : base (expr)
  1661. {
  1662. this.target_type = cast_type;
  1663. this.loc = loc;
  1664. }
  1665. public Expression TargetType {
  1666. get { return target_type; }
  1667. }
  1668. protected override Expression DoResolve (ResolveContext ec)
  1669. {
  1670. expr = expr.Resolve (ec);
  1671. if (expr == null)
  1672. return null;
  1673. type = target_type.ResolveAsType (ec);
  1674. if (type == null)
  1675. return null;
  1676. if (type.IsStatic) {
  1677. ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
  1678. return null;
  1679. }
  1680. if (type.IsPointer && !ec.IsUnsafe) {
  1681. UnsafeError (ec, loc);
  1682. }
  1683. eclass = ExprClass.Value;
  1684. Constant c = expr as Constant;
  1685. if (c != null) {
  1686. c = c.Reduce (ec, type);
  1687. if (c != null)
  1688. return c;
  1689. }
  1690. var res = Convert.ExplicitConversion (ec, expr, type, loc);
  1691. if (res == expr)
  1692. return EmptyCast.Create (res, type);
  1693. return res;
  1694. }
  1695. protected override void CloneTo (CloneContext clonectx, Expression t)
  1696. {
  1697. Cast target = (Cast) t;
  1698. target.target_type = target_type.Clone (clonectx);
  1699. target.expr = expr.Clone (clonectx);
  1700. }
  1701. public override object Accept (StructuralVisitor visitor)
  1702. {
  1703. return visitor.Visit (this);
  1704. }
  1705. }
  1706. public class ImplicitCast : ShimExpression
  1707. {
  1708. bool arrayAccess;
  1709. public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
  1710. : base (expr)
  1711. {
  1712. this.loc = expr.Location;
  1713. this.type = target;
  1714. this.arrayAccess = arrayAccess;
  1715. }
  1716. protected override Expression DoResolve (ResolveContext ec)
  1717. {
  1718. expr = expr.Resolve (ec);
  1719. if (expr == null)
  1720. return null;
  1721. if (arrayAccess)
  1722. expr = ConvertExpressionToArrayIndex (ec, expr);
  1723. else
  1724. expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
  1725. return expr;
  1726. }
  1727. }
  1728. //
  1729. // C# 2.0 Default value expression
  1730. //
  1731. public class DefaultValueExpression : Expression
  1732. {
  1733. Expression expr;
  1734. public DefaultValueExpression (Expression expr, Location loc)
  1735. {
  1736. this.expr = expr;
  1737. this.loc = loc;
  1738. }
  1739. public Expression Expr {
  1740. get {
  1741. return this.expr;
  1742. }
  1743. }
  1744. public override bool IsSideEffectFree {
  1745. get {
  1746. return true;
  1747. }
  1748. }
  1749. public override bool ContainsEmitWithAwait ()
  1750. {
  1751. return false;
  1752. }
  1753. public override Expression CreateExpressionTree (ResolveContext ec)
  1754. {
  1755. Arguments args = new Arguments (2);
  1756. args.Add (new Argument (this));
  1757. args.Add (new Argument (new TypeOf (type, loc)));
  1758. return CreateExpressionFactoryCall (ec, "Constant", args);
  1759. }
  1760. protected override Expression DoResolve (ResolveContext ec)
  1761. {
  1762. type = expr.ResolveAsType (ec);
  1763. if (type == null)
  1764. return null;
  1765. if (type.IsStatic) {
  1766. ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
  1767. }
  1768. if (type.IsPointer)
  1769. return new NullLiteral (Location).ConvertImplicitly (type);
  1770. if (TypeSpec.IsReferenceType (type))
  1771. return new NullConstant (type, loc);
  1772. Constant c = New.Constantify (type, expr.Location);
  1773. if (c != null)
  1774. return c;
  1775. eclass = ExprClass.Variable;
  1776. return this;
  1777. }
  1778. public override void Emit (EmitContext ec)
  1779. {
  1780. LocalTemporary temp_storage = new LocalTemporary(type);
  1781. temp_storage.AddressOf(ec, AddressOp.LoadStore);
  1782. ec.Emit(OpCodes.Initobj, type);
  1783. temp_storage.Emit(ec);
  1784. temp_storage.Release (ec);
  1785. }
  1786. #if (NET_4_0 || MOBILE_DYNAMIC) && !STATIC
  1787. public override SLE.Expression MakeExpression (BuilderContext ctx)
  1788. {
  1789. return SLE.Expression.Default (type.GetMetaInfo ());
  1790. }
  1791. #endif
  1792. protected override void CloneTo (CloneContext clonectx, Expression t)
  1793. {
  1794. DefaultValueExpression target = (DefaultValueExpression) t;
  1795. target.expr = expr.Clone (clonectx);
  1796. }
  1797. public override object Accept (StructuralVisitor visitor)
  1798. {
  1799. return visitor.Visit (this);
  1800. }
  1801. }
  1802. /// <summary>
  1803. /// Binary operators
  1804. /// </summary>
  1805. public class Binary : Expression, IDynamicBinder
  1806. {
  1807. public class PredefinedOperator
  1808. {
  1809. protected readonly TypeSpec left;
  1810. protected readonly TypeSpec right;
  1811. protected readonly TypeSpec left_unwrap;
  1812. protected readonly TypeSpec right_unwrap;
  1813. public readonly Operator OperatorsMask;
  1814. public TypeSpec ReturnType;
  1815. public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
  1816. : this (ltype, rtype, op_mask, ltype)
  1817. {
  1818. }
  1819. public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
  1820. : this (type, type, op_mask, return_type)
  1821. {
  1822. }
  1823. public PredefinedOperator (TypeSpec type, Operator op_mask)
  1824. : this (type, type, op_mask, type)
  1825. {
  1826. }
  1827. public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
  1828. {
  1829. if ((op_mask & Operator.ValuesOnlyMask) != 0)
  1830. throw new InternalErrorException ("Only masked values can be used");
  1831. if ((op_mask & Operator.NullableMask) != 0) {
  1832. left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
  1833. right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
  1834. } else {
  1835. left_unwrap = ltype;
  1836. right_unwrap = rtype;
  1837. }
  1838. this.left = ltype;
  1839. this.right = rtype;
  1840. this.OperatorsMask = op_mask;
  1841. this.ReturnType = return_type;
  1842. }
  1843. public bool IsLifted {
  1844. get {
  1845. return (OperatorsMask & Operator.NullableMask) != 0;
  1846. }
  1847. }
  1848. public virtual Expression ConvertResult (ResolveContext rc, Binary b)
  1849. {
  1850. Constant c;
  1851. var left_expr = b.left;
  1852. var right_expr = b.right;
  1853. b.type = ReturnType;
  1854. if (IsLifted) {
  1855. if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
  1856. b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
  1857. b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
  1858. }
  1859. if (right_expr.IsNull) {
  1860. if ((b.oper & Operator.EqualityMask) != 0) {
  1861. if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
  1862. return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
  1863. } else if ((b.oper & Operator.BitwiseMask) != 0) {
  1864. if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
  1865. return Nullable.LiftedNull.CreateFromExpression (rc, b);
  1866. } else {
  1867. b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
  1868. b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
  1869. if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
  1870. return Nullable.LiftedNull.CreateFromExpression (rc, b);
  1871. return b.CreateLiftedValueTypeResult (rc, left);
  1872. }
  1873. } else if (left_expr.IsNull) {
  1874. if ((b.oper & Operator.EqualityMask) != 0) {
  1875. if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
  1876. return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
  1877. } else if ((b.oper & Operator.BitwiseMask) != 0) {
  1878. if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
  1879. return Nullable.LiftedNull.CreateFromExpression (rc, b);
  1880. } else {
  1881. b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
  1882. b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
  1883. if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
  1884. return Nullable.LiftedNull.CreateFromExpression (rc, b);
  1885. return b.CreateLiftedValueTypeResult (rc, right);
  1886. }
  1887. }
  1888. }
  1889. //
  1890. // A user operators does not support multiple user conversions, but decimal type
  1891. // is considered to be predefined type therefore we apply predefined operators rules
  1892. // and then look for decimal user-operator implementation
  1893. //
  1894. if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
  1895. b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
  1896. b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
  1897. return b.ResolveUserOperator (rc, b.left, b.right);
  1898. }
  1899. c = right_expr as Constant;
  1900. if (c != null) {
  1901. if (c.IsDefaultValue) {
  1902. //
  1903. // Optimizes
  1904. //
  1905. // (expr + 0) to expr
  1906. // (expr - 0) to expr
  1907. // (bool? | false) to bool?
  1908. //
  1909. if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
  1910. (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
  1911. b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
  1912. return ReducedExpression.Create (b.left, b).Resolve (rc);
  1913. }
  1914. //
  1915. // Optimizes (value &/&& 0) to 0
  1916. //
  1917. if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
  1918. Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
  1919. return ReducedExpression.Create (side_effect, b);
  1920. }
  1921. } else {
  1922. //
  1923. // Optimizes (bool? & true) to bool?
  1924. //
  1925. if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
  1926. return ReducedExpression.Create (b.left, b).Resolve (rc);
  1927. }
  1928. }
  1929. if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
  1930. return ReducedExpression.Create (b.left, b).Resolve (rc);
  1931. if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
  1932. b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
  1933. }
  1934. }
  1935. c = b.left as Constant;
  1936. if (c != null) {
  1937. if (c.IsDefaultValue) {
  1938. //
  1939. // Optimizes
  1940. //
  1941. // (0 + expr) to expr
  1942. // (false | bool?) to bool?
  1943. //
  1944. if (b.oper == Operator.Addition ||
  1945. (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
  1946. b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
  1947. return ReducedExpression.Create (b.right, b).Resolve (rc);
  1948. }
  1949. //
  1950. // Optimizes (false && expr) to false
  1951. //
  1952. if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
  1953. // No rhs side-effects
  1954. Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
  1955. return ReducedExpression.Create (c, b);
  1956. }
  1957. //
  1958. // Optimizes (0 & value) to 0
  1959. //
  1960. if (b.oper == Operator.BitwiseAnd && !IsLifted) {
  1961. Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
  1962. return ReducedExpression.Create (side_effect, b);
  1963. }
  1964. } else {
  1965. //
  1966. // Optimizes (true & bool?) to bool?
  1967. //
  1968. if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
  1969. return ReducedExpression.Create (b.right, b).Resolve (rc);
  1970. }
  1971. //
  1972. // Optimizes (true || expr) to true
  1973. //
  1974. if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
  1975. // No rhs side-effects
  1976. Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
  1977. return ReducedExpression.Create (c, b);
  1978. }
  1979. }
  1980. if (b.oper == Operator.Multiply && c.IsOneInteger)
  1981. return ReducedExpression.Create (b.right, b).Resolve (rc);
  1982. }
  1983. if (IsLifted) {
  1984. var lifted = new Nullable.LiftedBinaryOperator (b);
  1985. TypeSpec ltype, rtype;
  1986. if (b.left.Type.IsNullableType) {
  1987. lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
  1988. ltype = left_unwrap;
  1989. } else {
  1990. ltype = left;
  1991. }
  1992. if (b.right.Type.IsNullableType) {
  1993. lifted.UnwrapRight = new Nullable.Unwrap (b.right);
  1994. rtype = right_unwrap;
  1995. } else {
  1996. rtype = right;
  1997. }
  1998. lifted.Left = b.left.IsNull ?
  1999. b.left :
  2000. Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
  2001. lifted.Right = b.right.IsNull ?
  2002. b.right :
  2003. Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
  2004. return lifted.Resolve (rc);
  2005. }
  2006. b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
  2007. b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
  2008. return b;
  2009. }
  2010. public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
  2011. {
  2012. //
  2013. // We are dealing with primitive types only
  2014. //
  2015. return left == ltype && ltype == rtype;
  2016. }
  2017. public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
  2018. {
  2019. // Quick path
  2020. if (left == lexpr.Type && right == rexpr.Type)
  2021. return true;
  2022. return Convert.ImplicitConversionExists (ec, lexpr, left) &&
  2023. Convert.ImplicitConversionExists (ec, rexpr, right);
  2024. }
  2025. public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
  2026. {
  2027. if ((OperatorsMask & Operator.DecomposedMask) != 0)
  2028. return best_operator;
  2029. if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
  2030. return this;
  2031. int result = 0;
  2032. if (left != null && best_operator.left != null) {
  2033. result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
  2034. }
  2035. //
  2036. // When second argument is same as the first one, the result is same
  2037. //
  2038. if (right != null && (left != right || best_operator.left != best_operator.right)) {
  2039. result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
  2040. }
  2041. if (result == 0 || result > 2)
  2042. return null;
  2043. return result == 1 ? best_operator : this;
  2044. }
  2045. }
  2046. sealed class PredefinedStringOperator : PredefinedOperator
  2047. {
  2048. public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
  2049. : base (type, type, op_mask, retType)
  2050. {
  2051. }
  2052. public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
  2053. : base (ltype, rtype, op_mask, retType)
  2054. {
  2055. }
  2056. public override Expression ConvertResult (ResolveContext ec, Binary b)
  2057. {
  2058. //
  2059. // Use original expression for nullable arguments
  2060. //
  2061. Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
  2062. if (unwrap != null)
  2063. b.left = unwrap.Original;
  2064. unwrap = b.right as Nullable.Unwrap;
  2065. if (unwrap != null)
  2066. b.right = unwrap.Original;
  2067. b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
  2068. b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
  2069. //
  2070. // Start a new concat expression using converted expression
  2071. //
  2072. return StringConcat.Create (ec, b.left, b.right, b.loc);
  2073. }
  2074. }
  2075. sealed class PredefinedEqualityOperator : PredefinedOperator
  2076. {
  2077. MethodSpec equal_method, inequal_method;
  2078. public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
  2079. : base (arg, arg, Operator.EqualityMask, retType)
  2080. {
  2081. }
  2082. public override Expression ConvertResult (ResolveContext ec, Binary b)
  2083. {
  2084. b.type = ReturnType;
  2085. b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
  2086. b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
  2087. Arguments args = new Arguments (2);
  2088. args.Add (new Argument (b.left));
  2089. args.Add (new Argument (b.right));
  2090. MethodSpec method;
  2091. if (b.oper == Operator.Equality) {
  2092. if (equal_method == null) {
  2093. if (left.BuiltinType == BuiltinTypeSpec.Type.String)
  2094. equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
  2095. else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
  2096. equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
  2097. else
  2098. throw new NotImplementedException (left.GetSignatureForError ());
  2099. }
  2100. method = equal_method;
  2101. } else {
  2102. if (inequal_method == null) {
  2103. if (left.BuiltinType == BuiltinTypeSpec.Type.String)
  2104. inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
  2105. else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
  2106. inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
  2107. else
  2108. throw new NotImplementedException (left.GetSignatureForError ());
  2109. }
  2110. method = inequal_method;
  2111. }
  2112. return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
  2113. }
  2114. }
  2115. class PredefinedPointerOperator : PredefinedOperator
  2116. {
  2117. public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
  2118. : base (ltype, rtype, op_mask)
  2119. {
  2120. }
  2121. public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
  2122. : base (ltype, rtype, op_mask, retType)
  2123. {
  2124. }
  2125. public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
  2126. : base (type, op_mask, return_type)
  2127. {
  2128. }
  2129. public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
  2130. {
  2131. if (left == null) {
  2132. if (!lexpr.Type.IsPointer)
  2133. return false;
  2134. } else {
  2135. if (!Convert.ImplicitConversionExists (ec, lexpr, left))
  2136. return false;
  2137. }
  2138. if (right == null) {
  2139. if (!rexpr.Type.IsPointer)
  2140. return false;
  2141. } else {
  2142. if (!Convert.ImplicitConversionExists (ec, rexpr, right))
  2143. return false;
  2144. }
  2145. return true;
  2146. }
  2147. public override Expression ConvertResult (ResolveContext ec, Binary b)
  2148. {
  2149. if (left != null) {
  2150. b.left = EmptyCast.Create (b.left, left);
  2151. } else if (right != null) {
  2152. b.right = EmptyCast.Create (b.right, right);
  2153. }
  2154. TypeSpec r_type = ReturnType;
  2155. Expression left_arg, right_arg;
  2156. if (r_type == null) {
  2157. if (left == null) {
  2158. left_arg = b.left;
  2159. right_arg = b.right;
  2160. r_type = b.left.Type;
  2161. } else {
  2162. left_arg = b.right;
  2163. right_arg = b.left;
  2164. r_type = b.right.Type;
  2165. }
  2166. } else {
  2167. left_arg = b.left;
  2168. right_arg = b.right;
  2169. }
  2170. return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
  2171. }
  2172. }
  2173. [Flags]
  2174. public enum Operator {
  2175. Multiply = 0 | ArithmeticMask,
  2176. Division = 1 | ArithmeticMask,
  2177. Modulus = 2 | ArithmeticMask,
  2178. Addition = 3 | ArithmeticMask | AdditionMask,
  2179. Subtraction = 4 | ArithmeticMask | SubtractionMask,
  2180. LeftShift = 5 | ShiftMask,
  2181. RightShift = 6 | ShiftMask,
  2182. LessThan = 7 | ComparisonMask | RelationalMask,
  2183. GreaterThan = 8 | ComparisonMask | RelationalMask,
  2184. LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
  2185. GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
  2186. Equality = 11 | ComparisonMask | EqualityMask,
  2187. Inequality = 12 | ComparisonMask | EqualityMask,
  2188. BitwiseAnd = 13 | BitwiseMask,
  2189. ExclusiveOr = 14 | BitwiseMask,
  2190. BitwiseOr = 15 | BitwiseMask,
  2191. LogicalAnd = 16 | LogicalMask,
  2192. LogicalOr = 17 | LogicalMask,
  2193. //
  2194. // Operator masks
  2195. //
  2196. ValuesOnlyMask = ArithmeticMask - 1,
  2197. ArithmeticMask = 1 << 5,
  2198. ShiftMask = 1 << 6,
  2199. ComparisonMask = 1 << 7,
  2200. EqualityMask = 1 << 8,
  2201. BitwiseMask = 1 << 9,
  2202. LogicalMask = 1 << 10,
  2203. AdditionMask = 1 << 11,
  2204. SubtractionMask = 1 << 12,
  2205. RelationalMask = 1 << 13,
  2206. DecomposedMask = 1 << 19,
  2207. NullableMask = 1 << 20,
  2208. }
  2209. [Flags]
  2210. enum State : byte
  2211. {
  2212. None = 0,
  2213. Compound = 1 << 1,
  2214. }
  2215. readonly Operator oper;
  2216. Expression left, right;
  2217. State state;
  2218. ConvCast.Mode enum_conversion;
  2219. public Binary (Operator oper, Expression left, Expression right, bool isCompound)
  2220. : this (oper, left, right)
  2221. {
  2222. if (isCompound)
  2223. state |= State.Compound;
  2224. }
  2225. public Binary (Operator oper, Expression left, Expression right)
  2226. {
  2227. this.oper = oper;
  2228. this.left = left;
  2229. this.right = right;
  2230. this.loc = left.Location;
  2231. }
  2232. #region Properties
  2233. public bool IsCompound {
  2234. get {
  2235. return (state & State.Compound) != 0;
  2236. }
  2237. }
  2238. public Operator Oper {
  2239. get {
  2240. return oper;
  2241. }
  2242. }
  2243. public Expression Left {
  2244. get {
  2245. return this.left;
  2246. }
  2247. }
  2248. public Expression Right {
  2249. get {
  2250. return this.right;
  2251. }
  2252. }
  2253. public override Location StartLocation {
  2254. get {
  2255. return left.StartLocation;
  2256. }
  2257. }
  2258. #endregion
  2259. /// <summary>
  2260. /// Returns a stringified representation of the Operator
  2261. /// </summary>
  2262. string OperName (Operator oper)
  2263. {
  2264. string s;
  2265. switch (oper){
  2266. case Operator.Multiply:
  2267. s = "*";
  2268. break;
  2269. case Operator.Division:
  2270. s = "/";
  2271. break;
  2272. case Operator.Modulus:
  2273. s = "%";
  2274. break;
  2275. case Operator.Addition:
  2276. s = "+";
  2277. break;
  2278. case Operator.Subtraction:
  2279. s = "-";
  2280. break;
  2281. case Operator.LeftShift:
  2282. s = "<<";
  2283. break;
  2284. case Operator.RightShift:
  2285. s = ">>";
  2286. break;
  2287. case Operator.LessThan:
  2288. s = "<";
  2289. break;
  2290. case Operator.GreaterThan:
  2291. s = ">";
  2292. break;
  2293. case Operator.LessThanOrEqual:
  2294. s = "<=";
  2295. break;
  2296. case Operator.GreaterThanOrEqual:
  2297. s = ">=";
  2298. break;
  2299. case Operator.Equality:
  2300. s = "==";
  2301. break;
  2302. case Operator.Inequality:
  2303. s = "!=";
  2304. break;
  2305. case Operator.BitwiseAnd:
  2306. s = "&";
  2307. break;
  2308. case Operator.BitwiseOr:
  2309. s = "|";
  2310. break;
  2311. case Operator.ExclusiveOr:
  2312. s = "^";
  2313. break;
  2314. case Operator.LogicalOr:
  2315. s = "||";
  2316. break;
  2317. case Operator.LogicalAnd:
  2318. s = "&&";
  2319. break;
  2320. default:
  2321. s = oper.ToString ();
  2322. break;
  2323. }
  2324. if (IsCompound)
  2325. return s + "=";
  2326. return s;
  2327. }
  2328. public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
  2329. {
  2330. new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
  2331. }
  2332. public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
  2333. {
  2334. if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
  2335. return;
  2336. string l, r;
  2337. l = left.Type.GetSignatureForError ();
  2338. r = right.Type.GetSignatureForError ();
  2339. ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
  2340. oper, l, r);
  2341. }
  2342. void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
  2343. {
  2344. Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
  2345. }
  2346. public override void FlowAnalysis (FlowAnalysisContext fc)
  2347. {
  2348. //
  2349. // Optimized version when on-true/on-false data are not needed
  2350. //
  2351. if ((oper & Operator.LogicalMask) == 0) {
  2352. left.FlowAnalysis (fc);
  2353. right.FlowAnalysis (fc);
  2354. return;
  2355. }
  2356. left.FlowAnalysisConditional (fc);
  2357. var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
  2358. var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
  2359. fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
  2360. oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
  2361. right.FlowAnalysisConditional (fc);
  2362. if (oper == Operator.LogicalOr)
  2363. fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
  2364. else
  2365. fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
  2366. }
  2367. public override void FlowAnalysisConditional (FlowAnalysisContext fc)
  2368. {
  2369. if ((oper & Operator.LogicalMask) == 0) {
  2370. base.FlowAnalysisConditional (fc);
  2371. return;
  2372. }
  2373. left.FlowAnalysisConditional (fc);
  2374. var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
  2375. var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
  2376. fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
  2377. oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
  2378. right.FlowAnalysisConditional (fc);
  2379. var lc = left as Constant;
  2380. if (oper == Operator.LogicalOr) {
  2381. fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
  2382. if (lc != null && lc.IsDefaultValue)
  2383. fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
  2384. else
  2385. fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
  2386. } else {
  2387. fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
  2388. if (lc != null && !lc.IsDefaultValue)
  2389. fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
  2390. else
  2391. fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
  2392. }
  2393. }
  2394. //
  2395. // Converts operator to System.Linq.Expressions.ExpressionType enum name
  2396. //
  2397. string GetOperatorExpressionTypeName ()
  2398. {
  2399. switch (oper) {
  2400. case Operator.Addition:
  2401. return IsCompound ? "AddAssign" : "Add";
  2402. case Operator.BitwiseAnd:
  2403. return IsCompound ? "AndAssign" : "And";
  2404. case Operator.BitwiseOr:
  2405. return IsCompound ? "OrAssign" : "Or";
  2406. case Operator.Division:
  2407. return IsCompound ? "DivideAssign" : "Divide";
  2408. case Operator.ExclusiveOr:
  2409. return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
  2410. case Operator.Equality:
  2411. return "Equal";
  2412. case Operator.GreaterThan:
  2413. return "GreaterThan";
  2414. case Operator.GreaterThanOrEqual:
  2415. return "GreaterThanOrEqual";
  2416. case Operator.Inequality:
  2417. return "NotEqual";
  2418. case Operator.LeftShift:
  2419. return IsCompound ? "LeftShiftAssign" : "LeftShift";
  2420. case Operator.LessThan:
  2421. return "LessThan";
  2422. case Operator.LessThanOrEqual:
  2423. return "LessThanOrEqual";
  2424. case Operator.LogicalAnd:
  2425. return "And";
  2426. case Operator.LogicalOr:
  2427. return "Or";
  2428. case Operator.Modulus:
  2429. return IsCompound ? "ModuloAssign" : "Modulo";
  2430. case Operator.Multiply:
  2431. return IsCompound ? "MultiplyAssign" : "Multiply";
  2432. case Operator.RightShift:
  2433. return IsCompound ? "RightShiftAssign" : "RightShift";
  2434. case Operator.Subtraction:
  2435. return IsCompound ? "SubtractAssign" : "Subtract";
  2436. default:
  2437. throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
  2438. }
  2439. }
  2440. static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
  2441. {
  2442. switch (op) {
  2443. case Operator.Addition:
  2444. return CSharp.Operator.OpType.Addition;
  2445. case Operator.BitwiseAnd:
  2446. case Operator.LogicalAnd:
  2447. return CSharp.Operator.OpType.BitwiseAnd;
  2448. case Operator.BitwiseOr:
  2449. case Operator.LogicalOr:
  2450. return CSharp.Operator.OpType.BitwiseOr;
  2451. case Operator.Division:
  2452. return CSharp.Operator.OpType.Division;
  2453. case Operator.Equality:
  2454. return CSharp.Operator.OpType.Equality;
  2455. case Operator.ExclusiveOr:
  2456. return CSharp.Operator.OpType.ExclusiveOr;
  2457. case Operator.GreaterThan:
  2458. return CSharp.Operator.OpType.GreaterThan;
  2459. case Operator.GreaterThanOrEqual:
  2460. return CSharp.Operator.OpType.GreaterThanOrEqual;
  2461. case Operator.Inequality:
  2462. return CSharp.Operator.OpType.Inequality;
  2463. case Operator.LeftShift:
  2464. return CSharp.Operator.OpType.LeftShift;
  2465. case Operator.LessThan:
  2466. return CSharp.Operator.OpType.LessThan;
  2467. case Operator.LessThanOrEqual:
  2468. return CSharp.Operator.OpType.LessThanOrEqual;
  2469. case Operator.Modulus:
  2470. return CSharp.Operator.OpType.Modulus;
  2471. case Operator.Multiply:
  2472. return CSharp.Operator.OpType.Multiply;
  2473. case Operator.RightShift:
  2474. return CSharp.Operator.OpType.RightShift;
  2475. case Operator.Subtraction:
  2476. return CSharp.Operator.OpType.Subtraction;
  2477. default:
  2478. throw new InternalErrorException (op.ToString ());
  2479. }
  2480. }
  2481. public override bool ContainsEmitWithAwait ()
  2482. {
  2483. return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
  2484. }
  2485. public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
  2486. {
  2487. OpCode opcode;
  2488. switch (oper){
  2489. case Operator.Multiply:
  2490. if (ec.HasSet (EmitContext.Options.CheckedScope)) {
  2491. if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
  2492. opcode = OpCodes.Mul_Ovf;
  2493. else if (!IsFloat (l))
  2494. opcode = OpCodes.Mul_Ovf_Un;
  2495. else
  2496. opcode = OpCodes.Mul;
  2497. } else
  2498. opcode = OpCodes.Mul;
  2499. break;
  2500. case Operator.Division:
  2501. if (IsUnsigned (l))
  2502. opcode = OpCodes.Div_Un;
  2503. else
  2504. opcode = OpCodes.Div;
  2505. break;
  2506. case Operator.Modulus:
  2507. if (IsUnsigned (l))
  2508. opcode = OpCodes.Rem_Un;
  2509. else
  2510. opcode = OpCodes.Rem;
  2511. break;
  2512. case Operator.Addition:
  2513. if (ec.HasSet (EmitContext.Options.CheckedScope)) {
  2514. if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
  2515. opcode = OpCodes.Add_Ovf;
  2516. else if (!IsFloat (l))
  2517. opcode = OpCodes.Add_Ovf_Un;
  2518. else
  2519. opcode = OpCodes.Add;
  2520. } else
  2521. opcode = OpCodes.Add;
  2522. break;
  2523. case Operator.Subtraction:
  2524. if (ec.HasSet (EmitContext.Options.CheckedScope)) {
  2525. if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
  2526. opcode = OpCodes.Sub_Ovf;
  2527. else if (!IsFloat (l))
  2528. opcode = OpCodes.Sub_Ovf_Un;
  2529. else
  2530. opcode = OpCodes.Sub;
  2531. } else
  2532. opcode = OpCodes.Sub;
  2533. break;
  2534. case Operator.RightShift:
  2535. if (!(right is IntConstant)) {
  2536. ec.EmitInt (GetShiftMask (l));
  2537. ec.Emit (OpCodes.And);
  2538. }
  2539. if (IsUnsigned (l))
  2540. opcode = OpCodes.Shr_Un;
  2541. else
  2542. opcode = OpCodes.Shr;
  2543. break;
  2544. case Operator.LeftShift:
  2545. if (!(right is IntConstant)) {
  2546. ec.EmitInt (GetShiftMask (l));
  2547. ec.Emit (OpCodes.And);
  2548. }
  2549. opcode = OpCodes.Shl;
  2550. break;
  2551. case Operator.Equality:
  2552. opcode = OpCodes.Ceq;
  2553. break;
  2554. case Operator.Inequality:
  2555. ec.Emit (OpCodes.Ceq);
  2556. ec.EmitInt (0);
  2557. opcode = OpCodes.Ceq;
  2558. break;
  2559. case Operator.LessThan:
  2560. if (IsUnsigned (l))
  2561. opcode = OpCodes.Clt_Un;
  2562. else
  2563. opcode = OpCodes.Clt;
  2564. break;
  2565. case Operator.GreaterThan:
  2566. if (IsUnsigned (l))
  2567. opcode = OpCodes.Cgt_Un;
  2568. else
  2569. opcode = OpCodes.Cgt;
  2570. break;
  2571. case Operator.LessThanOrEqual:
  2572. if (IsUnsigned (l) || IsFloat (l))
  2573. ec.Emit (OpCodes.Cgt_Un);
  2574. else
  2575. ec.Emit (OpCodes.Cgt);
  2576. ec.EmitInt (0);
  2577. opcode = OpCodes.Ceq;
  2578. break;
  2579. case Operator.GreaterThanOrEqual:
  2580. if (IsUnsigned (l) || IsFloat (l))
  2581. ec.Emit (OpCodes.Clt_Un);
  2582. else
  2583. ec.Emit (OpCodes.Clt);
  2584. ec.EmitInt (0);
  2585. opcode = OpCodes.Ceq;
  2586. break;
  2587. case Operator.BitwiseOr:
  2588. opcode = OpCodes.Or;
  2589. break;
  2590. case Operator.BitwiseAnd:
  2591. opcode = OpCodes.And;
  2592. break;
  2593. case Operator.ExclusiveOr:
  2594. opcode = OpCodes.Xor;
  2595. break;
  2596. default:
  2597. throw new InternalErrorException (oper.ToString ());
  2598. }
  2599. ec.Emit (opcode);
  2600. }
  2601. static int GetShiftMask (TypeSpec type)
  2602. {
  2603. return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
  2604. }
  2605. static bool IsUnsigned (TypeSpec t)
  2606. {
  2607. switch (t.BuiltinType) {
  2608. case BuiltinTypeSpec.Type.Char:
  2609. case BuiltinTypeSpec.Type.UInt:
  2610. case BuiltinTypeSpec.Type.ULong:
  2611. case BuiltinTypeSpec.Type.UShort:
  2612. case BuiltinTypeSpec.Type.Byte:
  2613. return true;
  2614. }
  2615. return t.IsPointer;
  2616. }
  2617. static bool IsFloat (TypeSpec t)
  2618. {
  2619. return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
  2620. }
  2621. public Expression ResolveOperator (ResolveContext rc)
  2622. {
  2623. eclass = ExprClass.Value;
  2624. TypeSpec l = left.Type;
  2625. TypeSpec r = right.Type;
  2626. Expression expr;
  2627. bool primitives_only = false;
  2628. //
  2629. // Handles predefined primitive types
  2630. //
  2631. if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
  2632. (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
  2633. if ((oper & Operator.ShiftMask) == 0) {
  2634. if (!DoBinaryOperatorPromotion (rc))
  2635. return null;
  2636. primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
  2637. }
  2638. } else {
  2639. // Pointers
  2640. if (l.IsPointer || r.IsPointer)
  2641. return ResolveOperatorPointer (rc, l, r);
  2642. // User operators
  2643. expr = ResolveUserOperator (rc, left, right);
  2644. if (expr != null)
  2645. return expr;
  2646. bool lenum = l.IsEnum;
  2647. bool renum = r.IsEnum;
  2648. if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
  2649. //
  2650. // Enumerations
  2651. //
  2652. if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
  2653. expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
  2654. if (expr == null)
  2655. return null;
  2656. if ((oper & Operator.BitwiseMask) != 0) {
  2657. expr = EmptyCast.Create (expr, type);
  2658. enum_conversion = GetEnumResultCast (type);
  2659. if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
  2660. expr = OptimizeAndOperation (expr);
  2661. }
  2662. }
  2663. left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
  2664. right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
  2665. return expr;
  2666. }
  2667. } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
  2668. if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
  2669. //
  2670. // Enumerations
  2671. //
  2672. expr = ResolveEnumOperators (rc, lenum, renum, l, r);
  2673. //
  2674. // We cannot break here there is also Enum + String possible match
  2675. // which is not ambiguous with predefined enum operators
  2676. //
  2677. if (expr != null) {
  2678. left = ConvertEnumOperandToUnderlyingType (rc, left, false);
  2679. right = ConvertEnumOperandToUnderlyingType (rc, right, false);
  2680. return expr;
  2681. }
  2682. } else if (l.IsDelegate || r.IsDelegate) {
  2683. //
  2684. // Delegates
  2685. //
  2686. expr = ResolveOperatorDelegate (rc, l, r);
  2687. // TODO: Can this be ambiguous
  2688. if (expr != null)
  2689. return expr;
  2690. }
  2691. }
  2692. }
  2693. //
  2694. // Equality operators are more complicated
  2695. //
  2696. if ((oper & Operator.EqualityMask) != 0) {
  2697. return ResolveEquality (rc, l, r, primitives_only);
  2698. }
  2699. expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
  2700. if (expr != null)
  2701. return expr;
  2702. if (primitives_only)
  2703. return null;
  2704. //
  2705. // Lifted operators have lower priority
  2706. //
  2707. return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
  2708. }
  2709. static bool IsEnumOrNullableEnum (TypeSpec type)
  2710. {
  2711. return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
  2712. }
  2713. // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
  2714. // if 'left' is not an enumeration constant, create one from the type of 'right'
  2715. Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
  2716. {
  2717. switch (oper) {
  2718. case Operator.BitwiseOr:
  2719. case Operator.BitwiseAnd:
  2720. case Operator.ExclusiveOr:
  2721. case Operator.Equality:
  2722. case Operator.Inequality:
  2723. case Operator.LessThan:
  2724. case Operator.LessThanOrEqual:
  2725. case Operator.GreaterThan:
  2726. case Operator.GreaterThanOrEqual:
  2727. if (left.Type.IsEnum)
  2728. return left;
  2729. if (left.IsZeroInteger)
  2730. return left.Reduce (ec, right.Type);
  2731. break;
  2732. case Operator.Addition:
  2733. case Operator.Subtraction:
  2734. return left;
  2735. case Operator.Multiply:
  2736. case Operator.Division:
  2737. case Operator.Modulus:
  2738. case Operator.LeftShift:
  2739. case Operator.RightShift:
  2740. if (right.Type.IsEnum || left.Type.IsEnum)
  2741. break;
  2742. return left;
  2743. }
  2744. return null;
  2745. }
  2746. //
  2747. // The `|' operator used on types which were extended is dangerous
  2748. //
  2749. void CheckBitwiseOrOnSignExtended (ResolveContext ec)
  2750. {
  2751. OpcodeCast lcast = left as OpcodeCast;
  2752. if (lcast != null) {
  2753. if (IsUnsigned (lcast.UnderlyingType))
  2754. lcast = null;
  2755. }
  2756. OpcodeCast rcast = right as OpcodeCast;
  2757. if (rcast != null) {
  2758. if (IsUnsigned (rcast.UnderlyingType))
  2759. rcast = null;
  2760. }
  2761. if (lcast == null && rcast == null)
  2762. return;
  2763. // FIXME: consider constants
  2764. var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
  2765. ec.Report.Warning (675, 3, loc,
  2766. "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
  2767. ltype.GetSignatureForError ());
  2768. }
  2769. public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
  2770. {
  2771. return new PredefinedOperator[] {
  2772. //
  2773. // Pointer arithmetic:
  2774. //
  2775. // T* operator + (T* x, int y); T* operator - (T* x, int y);
  2776. // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
  2777. // T* operator + (T* x, long y); T* operator - (T* x, long y);
  2778. // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
  2779. //
  2780. new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
  2781. new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
  2782. new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
  2783. new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
  2784. //
  2785. // T* operator + (int y, T* x);
  2786. // T* operator + (uint y, T *x);
  2787. // T* operator + (long y, T *x);
  2788. // T* operator + (ulong y, T *x);
  2789. //
  2790. new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
  2791. new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
  2792. new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
  2793. new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
  2794. //
  2795. // long operator - (T* x, T *y)
  2796. //
  2797. new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
  2798. };
  2799. }
  2800. public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
  2801. {
  2802. TypeSpec bool_type = types.Bool;
  2803. return new [] {
  2804. new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
  2805. new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
  2806. new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
  2807. new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
  2808. new PredefinedOperator (types.Float, Operator.ArithmeticMask),
  2809. new PredefinedOperator (types.Double, Operator.ArithmeticMask),
  2810. new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
  2811. new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
  2812. new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
  2813. new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
  2814. new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
  2815. new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
  2816. new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
  2817. new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
  2818. new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
  2819. // Remaining string operators are in lifted tables
  2820. new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
  2821. new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
  2822. new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
  2823. new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
  2824. };
  2825. }
  2826. public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
  2827. {
  2828. var types = module.Compiler.BuiltinTypes;
  2829. //
  2830. // Not strictly lifted but need to be in second group otherwise expressions like
  2831. // int + null would resolve to +(object, string) instead of +(int?, int?)
  2832. //
  2833. var string_operators = new [] {
  2834. new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
  2835. new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
  2836. };
  2837. var nullable = module.PredefinedTypes.Nullable.TypeSpec;
  2838. if (nullable == null)
  2839. return string_operators;
  2840. var bool_type = types.Bool;
  2841. var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
  2842. var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
  2843. var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
  2844. var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
  2845. var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
  2846. var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
  2847. var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
  2848. var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
  2849. return new[] {
  2850. new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
  2851. new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
  2852. new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
  2853. new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
  2854. new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
  2855. new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
  2856. new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
  2857. new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
  2858. new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
  2859. new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
  2860. new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
  2861. new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
  2862. new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
  2863. new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
  2864. new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
  2865. new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
  2866. new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
  2867. new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
  2868. string_operators [0],
  2869. string_operators [1]
  2870. };
  2871. }
  2872. public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
  2873. {
  2874. TypeSpec bool_type = types.Bool;
  2875. return new[] {
  2876. new PredefinedEqualityOperator (types.String, bool_type),
  2877. new PredefinedEqualityOperator (types.Delegate, bool_type),
  2878. new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
  2879. new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
  2880. new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
  2881. new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
  2882. new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
  2883. new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
  2884. new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
  2885. new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
  2886. };
  2887. }
  2888. public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
  2889. {
  2890. var nullable = module.PredefinedTypes.Nullable.TypeSpec;
  2891. if (nullable == null)
  2892. return new PredefinedOperator [0];
  2893. var types = module.Compiler.BuiltinTypes;
  2894. var bool_type = types.Bool;
  2895. var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
  2896. var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
  2897. var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
  2898. var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
  2899. var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
  2900. var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
  2901. var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
  2902. var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
  2903. return new [] {
  2904. new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
  2905. new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
  2906. new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
  2907. new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
  2908. new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
  2909. new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
  2910. new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
  2911. new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
  2912. };
  2913. }
  2914. //
  2915. // 7.2.6.2 Binary numeric promotions
  2916. //
  2917. bool DoBinaryOperatorPromotion (ResolveContext rc)
  2918. {
  2919. TypeSpec ltype = left.Type;
  2920. if (ltype.IsNullableType) {
  2921. ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
  2922. }
  2923. //
  2924. // This is numeric promotion code only
  2925. //
  2926. if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
  2927. return true;
  2928. TypeSpec rtype = right.Type;
  2929. if (rtype.IsNullableType) {
  2930. rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
  2931. }
  2932. var lb = ltype.BuiltinType;
  2933. var rb = rtype.BuiltinType;
  2934. TypeSpec type;
  2935. Expression expr;
  2936. if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
  2937. type = rc.BuiltinTypes.Decimal;
  2938. } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
  2939. type = rc.BuiltinTypes.Double;
  2940. } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
  2941. type = rc.BuiltinTypes.Float;
  2942. } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
  2943. type = rc.BuiltinTypes.ULong;
  2944. if (IsSignedType (lb)) {
  2945. expr = ConvertSignedConstant (left, type);
  2946. if (expr == null)
  2947. return false;
  2948. left = expr;
  2949. } else if (IsSignedType (rb)) {
  2950. expr = ConvertSignedConstant (right, type);
  2951. if (expr == null)
  2952. return false;
  2953. right = expr;
  2954. }
  2955. } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
  2956. type = rc.BuiltinTypes.Long;
  2957. } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
  2958. type = rc.BuiltinTypes.UInt;
  2959. if (IsSignedType (lb)) {
  2960. expr = ConvertSignedConstant (left, type);
  2961. if (expr == null)
  2962. type = rc.BuiltinTypes.Long;
  2963. } else if (IsSignedType (rb)) {
  2964. expr = ConvertSignedConstant (right, type);
  2965. if (expr == null)
  2966. type = rc.BuiltinTypes.Long;
  2967. }
  2968. } else {
  2969. type = rc.BuiltinTypes.Int;
  2970. }
  2971. if (ltype != type) {
  2972. expr = PromoteExpression (rc, left, type);
  2973. if (expr == null)
  2974. return false;
  2975. left = expr;
  2976. }
  2977. if (rtype != type) {
  2978. expr = PromoteExpression (rc, right, type);
  2979. if (expr == null)
  2980. return false;
  2981. right = expr;
  2982. }
  2983. return true;
  2984. }
  2985. static bool IsSignedType (BuiltinTypeSpec.Type type)
  2986. {
  2987. switch (type) {
  2988. case BuiltinTypeSpec.Type.Int:
  2989. case BuiltinTypeSpec.Type.Short:
  2990. case BuiltinTypeSpec.Type.SByte:
  2991. case BuiltinTypeSpec.Type.Long:
  2992. return true;
  2993. default:
  2994. return false;
  2995. }
  2996. }
  2997. static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
  2998. {
  2999. var c = expr as Constant;
  3000. if (c == null)
  3001. return null;
  3002. return c.ConvertImplicitly (type);
  3003. }
  3004. static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
  3005. {
  3006. if (expr.Type.IsNullableType) {
  3007. return Convert.ImplicitConversionStandard (rc, expr,
  3008. rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
  3009. }
  3010. var c = expr as Constant;
  3011. if (c != null)
  3012. return c.ConvertImplicitly (type);
  3013. return Convert.ImplicitNumericConversion (expr, type);
  3014. }
  3015. protected override Expression DoResolve (ResolveContext ec)
  3016. {
  3017. if (left == null)
  3018. return null;
  3019. if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
  3020. left = ((ParenthesizedExpression) left).Expr;
  3021. left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
  3022. if (left == null)
  3023. return null;
  3024. if (left.eclass == ExprClass.Type) {
  3025. ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
  3026. return null;
  3027. }
  3028. } else
  3029. left = left.Resolve (ec);
  3030. if (left == null)
  3031. return null;
  3032. right = right.Resolve (ec);
  3033. if (right == null)
  3034. return null;
  3035. Constant lc = left as Constant;
  3036. Constant rc = right as Constant;
  3037. // The conversion rules are ignored in enum context but why
  3038. if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
  3039. lc = EnumLiftUp (ec, lc, rc);
  3040. if (lc != null)
  3041. rc = EnumLiftUp (ec, rc, lc);
  3042. }
  3043. if (rc != null && lc != null) {
  3044. int prev_e = ec.Report.Errors;
  3045. Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
  3046. if (e != null || ec.Report.Errors != prev_e)
  3047. return e;
  3048. }
  3049. // Comparison warnings
  3050. if ((oper & Operator.ComparisonMask) != 0) {
  3051. if (left.Equals (right)) {
  3052. ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
  3053. }
  3054. CheckOutOfRangeComparison (ec, lc, right.Type);
  3055. CheckOutOfRangeComparison (ec, rc, left.Type);
  3056. }
  3057. if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
  3058. return DoResolveDynamic (ec);
  3059. return DoResolveCore (ec, left, right);
  3060. }
  3061. Expression DoResolveDynamic (ResolveContext rc)
  3062. {
  3063. var lt = left.Type;
  3064. var rt = right.Type;
  3065. if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
  3066. rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
  3067. Error_OperatorCannotBeApplied (rc, left, right);
  3068. return null;
  3069. }
  3070. Arguments args;
  3071. //
  3072. // Special handling for logical boolean operators which require rhs not to be
  3073. // evaluated based on lhs value
  3074. //
  3075. if ((oper & Operator.LogicalMask) != 0) {
  3076. Expression cond_left, cond_right, expr;
  3077. args = new Arguments (2);
  3078. if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  3079. LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
  3080. var cond_args = new Arguments (1);
  3081. cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
  3082. //
  3083. // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
  3084. // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
  3085. //
  3086. left = temp.CreateReferenceExpression (rc, loc);
  3087. if (oper == Operator.LogicalAnd) {
  3088. expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
  3089. cond_left = left;
  3090. } else {
  3091. expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
  3092. cond_left = left;
  3093. }
  3094. args.Add (new Argument (left));
  3095. args.Add (new Argument (right));
  3096. cond_right = new DynamicExpressionStatement (this, args, loc);
  3097. } else {
  3098. LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
  3099. if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
  3100. rc.Report.Error (7083, left.Location,
  3101. "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
  3102. lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
  3103. return null;
  3104. }
  3105. args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
  3106. args.Add (new Argument (right));
  3107. right = new DynamicExpressionStatement (this, args, loc);
  3108. //
  3109. // bool && dynamic => (temp = left) ? temp && right : temp;
  3110. // bool || dynamic => (temp = left) ? temp : temp || right;
  3111. //
  3112. if (oper == Operator.LogicalAnd) {
  3113. cond_left = right;
  3114. cond_right = temp.CreateReferenceExpression (rc, loc);
  3115. } else {
  3116. cond_left = temp.CreateReferenceExpression (rc, loc);
  3117. cond_right = right;
  3118. }
  3119. expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
  3120. }
  3121. return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
  3122. }
  3123. args = new Arguments (2);
  3124. args.Add (new Argument (left));
  3125. args.Add (new Argument (right));
  3126. return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
  3127. }
  3128. Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
  3129. {
  3130. Expression expr = ResolveOperator (ec);
  3131. if (expr == null)
  3132. Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
  3133. if (left == null || right == null)
  3134. throw new InternalErrorException ("Invalid conversion");
  3135. if (oper == Operator.BitwiseOr)
  3136. CheckBitwiseOrOnSignExtended (ec);
  3137. return expr;
  3138. }
  3139. public override SLE.Expression MakeExpression (BuilderContext ctx)
  3140. {
  3141. return MakeExpression (ctx, left, right);
  3142. }
  3143. public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
  3144. {
  3145. var le = left.MakeExpression (ctx);
  3146. var re = right.MakeExpression (ctx);
  3147. bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
  3148. switch (oper) {
  3149. case Operator.Addition:
  3150. return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
  3151. case Operator.BitwiseAnd:
  3152. return SLE.Expression.And (le, re);
  3153. case Operator.BitwiseOr:
  3154. return SLE.Expression.Or (le, re);
  3155. case Operator.Division:
  3156. return SLE.Expression.Divide (le, re);
  3157. case Operator.Equality:
  3158. return SLE.Expression.Equal (le, re);
  3159. case Operator.ExclusiveOr:
  3160. return SLE.Expression.ExclusiveOr (le, re);
  3161. case Operator.GreaterThan:
  3162. return SLE.Expression.GreaterThan (le, re);
  3163. case Operator.GreaterThanOrEqual:
  3164. return SLE.Expression.GreaterThanOrEqual (le, re);
  3165. case Operator.Inequality:
  3166. return SLE.Expression.NotEqual (le, re);
  3167. case Operator.LeftShift:
  3168. return SLE.Expression.LeftShift (le, re);
  3169. case Operator.LessThan:
  3170. return SLE.Expression.LessThan (le, re);
  3171. case Operator.LessThanOrEqual:
  3172. return SLE.Expression.LessThanOrEqual (le, re);
  3173. case Operator.LogicalAnd:
  3174. return SLE.Expression.AndAlso (le, re);
  3175. case Operator.LogicalOr:
  3176. return SLE.Expression.OrElse (le, re);
  3177. case Operator.Modulus:
  3178. return SLE.Expression.Modulo (le, re);
  3179. case Operator.Multiply:
  3180. return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
  3181. case Operator.RightShift:
  3182. return SLE.Expression.RightShift (le, re);
  3183. case Operator.Subtraction:
  3184. return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
  3185. default:
  3186. throw new NotImplementedException (oper.ToString ());
  3187. }
  3188. }
  3189. //
  3190. // D operator + (D x, D y)
  3191. // D operator - (D x, D y)
  3192. //
  3193. Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
  3194. {
  3195. if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
  3196. Expression tmp;
  3197. if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
  3198. tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
  3199. if (tmp == null)
  3200. return null;
  3201. right = tmp;
  3202. r = right.Type;
  3203. } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
  3204. tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
  3205. if (tmp == null)
  3206. return null;
  3207. left = tmp;
  3208. l = left.Type;
  3209. } else {
  3210. return null;
  3211. }
  3212. }
  3213. MethodSpec method = null;
  3214. Arguments args = new Arguments (2);
  3215. args.Add (new Argument (left));
  3216. args.Add (new Argument (right));
  3217. if (oper == Operator.Addition) {
  3218. method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
  3219. } else if (oper == Operator.Subtraction) {
  3220. method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
  3221. }
  3222. if (method == null)
  3223. return new EmptyExpression (ec.BuiltinTypes.Decimal);
  3224. Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
  3225. return new ClassCast (expr, l);
  3226. }
  3227. //
  3228. // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
  3229. //
  3230. Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
  3231. {
  3232. //
  3233. // bool operator == (E x, E y);
  3234. // bool operator != (E x, E y);
  3235. // bool operator < (E x, E y);
  3236. // bool operator > (E x, E y);
  3237. // bool operator <= (E x, E y);
  3238. // bool operator >= (E x, E y);
  3239. //
  3240. // E operator & (E x, E y);
  3241. // E operator | (E x, E y);
  3242. // E operator ^ (E x, E y);
  3243. //
  3244. Expression expr;
  3245. if ((oper & Operator.ComparisonMask) != 0) {
  3246. type = rc.BuiltinTypes.Bool;
  3247. } else {
  3248. if (lenum)
  3249. type = ltype;
  3250. else if (renum)
  3251. type = rtype;
  3252. else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
  3253. type = ltype;
  3254. else
  3255. type = rtype;
  3256. }
  3257. if (ltype == rtype) {
  3258. if (lenum || renum)
  3259. return this;
  3260. var lifted = new Nullable.LiftedBinaryOperator (this);
  3261. lifted.Left = left;
  3262. lifted.Right = right;
  3263. return lifted.Resolve (rc);
  3264. }
  3265. if (renum && !ltype.IsNullableType) {
  3266. expr = Convert.ImplicitConversion (rc, left, rtype, loc);
  3267. if (expr != null) {
  3268. left = expr;
  3269. return this;
  3270. }
  3271. } else if (lenum && !rtype.IsNullableType) {
  3272. expr = Convert.ImplicitConversion (rc, right, ltype, loc);
  3273. if (expr != null) {
  3274. right = expr;
  3275. return this;
  3276. }
  3277. }
  3278. //
  3279. // Now try lifted version of predefined operator
  3280. //
  3281. var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
  3282. if (nullable_type != null) {
  3283. if (renum && !ltype.IsNullableType) {
  3284. var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
  3285. expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
  3286. if (expr != null) {
  3287. left = expr;
  3288. right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
  3289. }
  3290. if ((oper & Operator.BitwiseMask) != 0)
  3291. type = lifted_type;
  3292. if (left.IsNull) {
  3293. if ((oper & Operator.BitwiseMask) != 0)
  3294. return Nullable.LiftedNull.CreateFromExpression (rc, this);
  3295. return CreateLiftedValueTypeResult (rc, rtype);
  3296. }
  3297. if (expr != null) {
  3298. var lifted = new Nullable.LiftedBinaryOperator (this);
  3299. lifted.Left = expr;
  3300. lifted.Right = right;
  3301. return lifted.Resolve (rc);
  3302. }
  3303. } else if (lenum && !rtype.IsNullableType) {
  3304. var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
  3305. expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
  3306. if (expr != null) {
  3307. right = expr;
  3308. left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
  3309. }
  3310. if ((oper & Operator.BitwiseMask) != 0)
  3311. type = lifted_type;
  3312. if (right.IsNull) {
  3313. if ((oper & Operator.BitwiseMask) != 0)
  3314. return Nullable.LiftedNull.CreateFromExpression (rc, this);
  3315. return CreateLiftedValueTypeResult (rc, ltype);
  3316. }
  3317. if (expr != null) {
  3318. var lifted = new Nullable.LiftedBinaryOperator (this);
  3319. lifted.Left = left;
  3320. lifted.Right = expr;
  3321. return lifted.Resolve (rc);
  3322. }
  3323. } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
  3324. Nullable.Unwrap unwrap = null;
  3325. if (left.IsNull || right.IsNull) {
  3326. if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
  3327. left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
  3328. if ((oper & Operator.RelationalMask) != 0)
  3329. return CreateLiftedValueTypeResult (rc, rtype);
  3330. if ((oper & Operator.BitwiseMask) != 0)
  3331. return Nullable.LiftedNull.CreateFromExpression (rc, this);
  3332. if (right.IsNull)
  3333. return CreateLiftedValueTypeResult (rc, left.Type);
  3334. // Equality operators are valid between E? and null
  3335. expr = left;
  3336. unwrap = new Nullable.Unwrap (right);
  3337. } else {
  3338. expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
  3339. if (expr == null)
  3340. return null;
  3341. }
  3342. if (expr != null) {
  3343. var lifted = new Nullable.LiftedBinaryOperator (this);
  3344. lifted.Left = expr;
  3345. lifted.Right = right;
  3346. lifted.UnwrapRight = unwrap;
  3347. return lifted.Resolve (rc);
  3348. }
  3349. } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
  3350. Nullable.Unwrap unwrap = null;
  3351. if (right.IsNull || left.IsNull) {
  3352. if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
  3353. right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
  3354. if ((oper & Operator.RelationalMask) != 0)
  3355. return CreateLiftedValueTypeResult (rc, ltype);
  3356. if ((oper & Operator.BitwiseMask) != 0)
  3357. return Nullable.LiftedNull.CreateFromExpression (rc, this);
  3358. if (left.IsNull)
  3359. return CreateLiftedValueTypeResult (rc, right.Type);
  3360. // Equality operators are valid between E? and null
  3361. expr = right;
  3362. unwrap = new Nullable.Unwrap (left);
  3363. } else {
  3364. expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
  3365. if (expr == null)
  3366. return null;
  3367. }
  3368. if (expr != null) {
  3369. var lifted = new Nullable.LiftedBinaryOperator (this);
  3370. lifted.Left = left;
  3371. lifted.UnwrapLeft = unwrap;
  3372. lifted.Right = expr;
  3373. return lifted.Resolve (rc);
  3374. }
  3375. }
  3376. }
  3377. return null;
  3378. }
  3379. static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
  3380. {
  3381. TypeSpec underlying_type;
  3382. if (expr.Type.IsNullableType) {
  3383. var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
  3384. if (nt.IsEnum)
  3385. underlying_type = EnumSpec.GetUnderlyingType (nt);
  3386. else
  3387. underlying_type = nt;
  3388. } else if (expr.Type.IsEnum) {
  3389. underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
  3390. } else {
  3391. underlying_type = expr.Type;
  3392. }
  3393. switch (underlying_type.BuiltinType) {
  3394. case BuiltinTypeSpec.Type.SByte:
  3395. case BuiltinTypeSpec.Type.Byte:
  3396. case BuiltinTypeSpec.Type.Short:
  3397. case BuiltinTypeSpec.Type.UShort:
  3398. underlying_type = rc.BuiltinTypes.Int;
  3399. break;
  3400. }
  3401. if (expr.Type.IsNullableType || liftType)
  3402. underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
  3403. if (expr.Type == underlying_type)
  3404. return expr;
  3405. return EmptyCast.Create (expr, underlying_type);
  3406. }
  3407. Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
  3408. {
  3409. //
  3410. // U operator - (E e, E f)
  3411. // E operator - (E e, U x) // Internal decomposition operator
  3412. // E operator - (U x, E e) // Internal decomposition operator
  3413. //
  3414. // E operator + (E e, U x)
  3415. // E operator + (U x, E e)
  3416. //
  3417. TypeSpec enum_type;
  3418. if (lenum)
  3419. enum_type = ltype;
  3420. else if (renum)
  3421. enum_type = rtype;
  3422. else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
  3423. enum_type = ltype;
  3424. else
  3425. enum_type = rtype;
  3426. Expression expr;
  3427. if (!enum_type.IsNullableType) {
  3428. expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
  3429. if (expr != null) {
  3430. if (oper == Operator.Subtraction)
  3431. expr = ConvertEnumSubtractionResult (rc, expr);
  3432. else
  3433. expr = ConvertEnumAdditionalResult (expr, enum_type);
  3434. enum_conversion = GetEnumResultCast (expr.Type);
  3435. return expr;
  3436. }
  3437. enum_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
  3438. }
  3439. expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
  3440. if (expr != null) {
  3441. if (oper == Operator.Subtraction)
  3442. expr = ConvertEnumSubtractionResult (rc, expr);
  3443. else
  3444. expr = ConvertEnumAdditionalResult (expr, enum_type);
  3445. enum_conversion = GetEnumResultCast (expr.Type);
  3446. }
  3447. return expr;
  3448. }
  3449. static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
  3450. {
  3451. return EmptyCast.Create (expr, enumType);
  3452. }
  3453. Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
  3454. {
  3455. //
  3456. // Enumeration subtraction has different result type based on
  3457. // best overload
  3458. //
  3459. TypeSpec result_type;
  3460. if (left.Type == right.Type) {
  3461. var c = right as EnumConstant;
  3462. if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
  3463. //
  3464. // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
  3465. // E which is not what expressions E - 1 or 0 - E return
  3466. //
  3467. result_type = left.Type;
  3468. } else {
  3469. result_type = left.Type.IsNullableType ?
  3470. Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
  3471. EnumSpec.GetUnderlyingType (left.Type);
  3472. }
  3473. } else {
  3474. if (IsEnumOrNullableEnum (left.Type)) {
  3475. result_type = left.Type;
  3476. } else {
  3477. result_type = right.Type;
  3478. }
  3479. if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
  3480. result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
  3481. }
  3482. return EmptyCast.Create (expr, result_type);
  3483. }
  3484. public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
  3485. {
  3486. if (type.IsNullableType)
  3487. type = Nullable.NullableInfo.GetUnderlyingType (type);
  3488. if (type.IsEnum)
  3489. type = EnumSpec.GetUnderlyingType (type);
  3490. switch (type.BuiltinType) {
  3491. case BuiltinTypeSpec.Type.SByte:
  3492. return ConvCast.Mode.I4_I1;
  3493. case BuiltinTypeSpec.Type.Byte:
  3494. return ConvCast.Mode.I4_U1;
  3495. case BuiltinTypeSpec.Type.Short:
  3496. return ConvCast.Mode.I4_I2;
  3497. case BuiltinTypeSpec.Type.UShort:
  3498. return ConvCast.Mode.I4_U2;
  3499. }
  3500. return 0;
  3501. }
  3502. //
  3503. // Equality operators rules
  3504. //
  3505. Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
  3506. {
  3507. Expression result;
  3508. type = ec.BuiltinTypes.Bool;
  3509. bool no_arg_conv = false;
  3510. if (!primitives_only) {
  3511. //
  3512. // a, Both operands are reference-type values or the value null
  3513. // b, One operand is a value of type T where T is a type-parameter and
  3514. // the other operand is the value null. Furthermore T does not have the
  3515. // value type constraint
  3516. //
  3517. // LAMESPEC: Very confusing details in the specification, basically any
  3518. // reference like type-parameter is allowed
  3519. //
  3520. var tparam_l = l as TypeParameterSpec;
  3521. var tparam_r = r as TypeParameterSpec;
  3522. if (tparam_l != null) {
  3523. if (right is NullLiteral) {
  3524. if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
  3525. return null;
  3526. left = new BoxedCast (left, ec.BuiltinTypes.Object);
  3527. return this;
  3528. }
  3529. if (!tparam_l.IsReferenceType)
  3530. return null;
  3531. l = tparam_l.GetEffectiveBase ();
  3532. left = new BoxedCast (left, l);
  3533. } else if (left is NullLiteral && tparam_r == null) {
  3534. if (TypeSpec.IsReferenceType (r))
  3535. return this;
  3536. if (r.Kind == MemberKind.InternalCompilerType)
  3537. return null;
  3538. }
  3539. if (tparam_r != null) {
  3540. if (left is NullLiteral) {
  3541. if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
  3542. return null;
  3543. right = new BoxedCast (right, ec.BuiltinTypes.Object);
  3544. return this;
  3545. }
  3546. if (!tparam_r.IsReferenceType)
  3547. return null;
  3548. r = tparam_r.GetEffectiveBase ();
  3549. right = new BoxedCast (right, r);
  3550. } else if (right is NullLiteral) {
  3551. if (TypeSpec.IsReferenceType (l))
  3552. return this;
  3553. if (l.Kind == MemberKind.InternalCompilerType)
  3554. return null;
  3555. }
  3556. //
  3557. // LAMESPEC: method groups can be compared when they convert to other side delegate
  3558. //
  3559. if (l.IsDelegate) {
  3560. if (right.eclass == ExprClass.MethodGroup) {
  3561. result = Convert.ImplicitConversion (ec, right, l, loc);
  3562. if (result == null)
  3563. return null;
  3564. right = result;
  3565. r = l;
  3566. } else if (r.IsDelegate && l != r) {
  3567. return null;
  3568. }
  3569. } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
  3570. result = Convert.ImplicitConversionRequired (ec, left, r, loc);
  3571. if (result == null)
  3572. return null;
  3573. left = result;
  3574. l = r;
  3575. } else {
  3576. no_arg_conv = l == r && !l.IsStruct;
  3577. }
  3578. }
  3579. //
  3580. // bool operator != (string a, string b)
  3581. // bool operator == (string a, string b)
  3582. //
  3583. // bool operator != (Delegate a, Delegate b)
  3584. // bool operator == (Delegate a, Delegate b)
  3585. //
  3586. // bool operator != (bool a, bool b)
  3587. // bool operator == (bool a, bool b)
  3588. //
  3589. // LAMESPEC: Reference equality comparison can apply to value/reference types when
  3590. // they implement an implicit conversion to any of types above. This does
  3591. // not apply when both operands are of same reference type
  3592. //
  3593. if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
  3594. result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
  3595. if (result != null)
  3596. return result;
  3597. //
  3598. // Now try lifted version of predefined operators
  3599. //
  3600. if (no_arg_conv && !l.IsNullableType) {
  3601. //
  3602. // Optimizes cases which won't match
  3603. //
  3604. } else {
  3605. result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
  3606. if (result != null)
  3607. return result;
  3608. }
  3609. //
  3610. // The == and != operators permit one operand to be a value of a nullable
  3611. // type and the other to be the null literal, even if no predefined or user-defined
  3612. // operator (in unlifted or lifted form) exists for the operation.
  3613. //
  3614. if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
  3615. var lifted = new Nullable.LiftedBinaryOperator (this);
  3616. lifted.Left = left;
  3617. lifted.Right = right;
  3618. return lifted.Resolve (ec);
  3619. }
  3620. }
  3621. //
  3622. // bool operator != (object a, object b)
  3623. // bool operator == (object a, object b)
  3624. //
  3625. // An explicit reference conversion exists from the
  3626. // type of either operand to the type of the other operand.
  3627. //
  3628. // Optimize common path
  3629. if (l == r) {
  3630. return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
  3631. }
  3632. if (!Convert.ExplicitReferenceConversionExists (l, r) &&
  3633. !Convert.ExplicitReferenceConversionExists (r, l))
  3634. return null;
  3635. // Reject allowed explicit conversions like int->object
  3636. if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
  3637. return null;
  3638. if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
  3639. ec.Report.Warning (253, 2, loc,
  3640. "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
  3641. l.GetSignatureForError ());
  3642. if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
  3643. ec.Report.Warning (252, 2, loc,
  3644. "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
  3645. r.GetSignatureForError ());
  3646. return this;
  3647. }
  3648. Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
  3649. {
  3650. //
  3651. // bool operator == (void* x, void* y);
  3652. // bool operator != (void* x, void* y);
  3653. // bool operator < (void* x, void* y);
  3654. // bool operator > (void* x, void* y);
  3655. // bool operator <= (void* x, void* y);
  3656. // bool operator >= (void* x, void* y);
  3657. //
  3658. if ((oper & Operator.ComparisonMask) != 0) {
  3659. Expression temp;
  3660. if (!l.IsPointer) {
  3661. temp = Convert.ImplicitConversion (ec, left, r, left.Location);
  3662. if (temp == null)
  3663. return null;
  3664. left = temp;
  3665. }
  3666. if (!r.IsPointer) {
  3667. temp = Convert.ImplicitConversion (ec, right, l, right.Location);
  3668. if (temp == null)
  3669. return null;
  3670. right = temp;
  3671. }
  3672. type = ec.BuiltinTypes.Bool;
  3673. return this;
  3674. }
  3675. return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
  3676. }
  3677. //
  3678. // Build-in operators method overloading
  3679. //
  3680. Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
  3681. {
  3682. PredefinedOperator best_operator = null;
  3683. TypeSpec l = left.Type;
  3684. TypeSpec r = right.Type;
  3685. Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
  3686. foreach (PredefinedOperator po in operators) {
  3687. if ((po.OperatorsMask & oper_mask) == 0)
  3688. continue;
  3689. if (primitives_only) {
  3690. if (!po.IsPrimitiveApplicable (l, r))
  3691. continue;
  3692. } else {
  3693. if (!po.IsApplicable (ec, left, right))
  3694. continue;
  3695. }
  3696. if (best_operator == null) {
  3697. best_operator = po;
  3698. if (primitives_only)
  3699. break;
  3700. continue;
  3701. }
  3702. best_operator = po.ResolveBetterOperator (ec, best_operator);
  3703. if (best_operator == null) {
  3704. ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
  3705. OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
  3706. best_operator = po;
  3707. break;
  3708. }
  3709. }
  3710. if (best_operator == null)
  3711. return null;
  3712. return best_operator.ConvertResult (ec, this);
  3713. }
  3714. //
  3715. // Optimize & constant expressions with 0 value
  3716. //
  3717. Expression OptimizeAndOperation (Expression expr)
  3718. {
  3719. Constant rc = right as Constant;
  3720. Constant lc = left as Constant;
  3721. if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
  3722. //
  3723. // The result is a constant with side-effect
  3724. //
  3725. Constant side_effect = rc == null ?
  3726. new SideEffectConstant (lc, right, loc) :
  3727. new SideEffectConstant (rc, left, loc);
  3728. return ReducedExpression.Create (side_effect, expr);
  3729. }
  3730. return expr;
  3731. }
  3732. //
  3733. // Value types can be compared with the null literal because of the lifting
  3734. // language rules. However the result is always true or false.
  3735. //
  3736. public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
  3737. {
  3738. if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
  3739. type = rc.BuiltinTypes.Bool;
  3740. return this;
  3741. }
  3742. // FIXME: Handle side effect constants
  3743. Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
  3744. if ((Oper & Operator.EqualityMask) != 0) {
  3745. rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
  3746. valueType.GetSignatureForError (), c.GetValueAsLiteral ());
  3747. } else {
  3748. rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
  3749. valueType.GetSignatureForError (), c.GetValueAsLiteral ());
  3750. }
  3751. return c;
  3752. }
  3753. //
  3754. // Performs user-operator overloading
  3755. //
  3756. Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
  3757. {
  3758. Expression oper_expr;
  3759. var op = ConvertBinaryToUserOperator (oper);
  3760. var l = left.Type;
  3761. if (l.IsNullableType)
  3762. l = Nullable.NullableInfo.GetUnderlyingType (l);
  3763. var r = right.Type;
  3764. if (r.IsNullableType)
  3765. r = Nullable.NullableInfo.GetUnderlyingType (r);
  3766. IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
  3767. IList<MemberSpec> right_operators = null;
  3768. if (l != r) {
  3769. right_operators = MemberCache.GetUserOperator (r, op, false);
  3770. if (right_operators == null && left_operators == null)
  3771. return null;
  3772. } else if (left_operators == null) {
  3773. return null;
  3774. }
  3775. Arguments args = new Arguments (2);
  3776. Argument larg = new Argument (left);
  3777. args.Add (larg);
  3778. Argument rarg = new Argument (right);
  3779. args.Add (rarg);
  3780. //
  3781. // User-defined operator implementations always take precedence
  3782. // over predefined operator implementations
  3783. //
  3784. if (left_operators != null && right_operators != null) {
  3785. left_operators = CombineUserOperators (left_operators, right_operators);
  3786. } else if (right_operators != null) {
  3787. left_operators = right_operators;
  3788. }
  3789. const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
  3790. OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
  3791. var res = new OverloadResolver (left_operators, restr, loc);
  3792. var oper_method = res.ResolveOperator (rc, ref args);
  3793. if (oper_method == null) {
  3794. //
  3795. // Logical && and || cannot be lifted
  3796. //
  3797. if ((oper & Operator.LogicalMask) != 0)
  3798. return null;
  3799. //
  3800. // Apply lifted user operators only for liftable types. Implicit conversion
  3801. // to nullable types is not allowed
  3802. //
  3803. if (!IsLiftedOperatorApplicable ())
  3804. return null;
  3805. // TODO: Cache the result in module container
  3806. var lifted_methods = CreateLiftedOperators (rc, left_operators);
  3807. if (lifted_methods == null)
  3808. return null;
  3809. res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
  3810. oper_method = res.ResolveOperator (rc, ref args);
  3811. if (oper_method == null)
  3812. return null;
  3813. MethodSpec best_original = null;
  3814. foreach (MethodSpec ms in left_operators) {
  3815. if (ms.MemberDefinition == oper_method.MemberDefinition) {
  3816. best_original = ms;
  3817. break;
  3818. }
  3819. }
  3820. if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
  3821. //
  3822. // Expression trees use lifted notation in this case
  3823. //
  3824. this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
  3825. this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
  3826. }
  3827. var ptypes = best_original.Parameters.Types;
  3828. if (left.IsNull || right.IsNull) {
  3829. //
  3830. // The lifted operator produces a null value if one or both operands are null
  3831. //
  3832. if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
  3833. type = oper_method.ReturnType;
  3834. return Nullable.LiftedNull.CreateFromExpression (rc, this);
  3835. }
  3836. //
  3837. // The lifted operator produces the value false if one or both operands are null for
  3838. // relational operators.
  3839. //
  3840. if ((oper & Operator.RelationalMask) != 0) {
  3841. //
  3842. // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
  3843. // because return type is actually bool
  3844. //
  3845. return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
  3846. }
  3847. if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
  3848. return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
  3849. }
  3850. }
  3851. type = oper_method.ReturnType;
  3852. var lifted = new Nullable.LiftedBinaryOperator (this);
  3853. lifted.UserOperator = best_original;
  3854. if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
  3855. lifted.UnwrapLeft = new Nullable.Unwrap (left);
  3856. }
  3857. if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
  3858. lifted.UnwrapRight = new Nullable.Unwrap (right);
  3859. }
  3860. lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
  3861. lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
  3862. return lifted.Resolve (rc);
  3863. }
  3864. if ((oper & Operator.LogicalMask) != 0) {
  3865. // TODO: CreateExpressionTree is allocated every time
  3866. oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
  3867. oper == Operator.LogicalAnd, loc).Resolve (rc);
  3868. } else {
  3869. oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
  3870. }
  3871. this.left = larg.Expr;
  3872. this.right = rarg.Expr;
  3873. return oper_expr;
  3874. }
  3875. bool IsLiftedOperatorApplicable ()
  3876. {
  3877. if (left.Type.IsNullableType) {
  3878. if ((oper & Operator.EqualityMask) != 0)
  3879. return !right.IsNull;
  3880. return true;
  3881. }
  3882. if (right.Type.IsNullableType) {
  3883. if ((oper & Operator.EqualityMask) != 0)
  3884. return !left.IsNull;
  3885. return true;
  3886. }
  3887. if (TypeSpec.IsValueType (left.Type))
  3888. return right.IsNull;
  3889. if (TypeSpec.IsValueType (right.Type))
  3890. return left.IsNull;
  3891. return false;
  3892. }
  3893. List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
  3894. {
  3895. var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
  3896. if (nullable_type == null)
  3897. return null;
  3898. //
  3899. // Lifted operators permit predefined and user-defined operators that operate
  3900. // on non-nullable value types to also be used with nullable forms of those types.
  3901. // Lifted operators are constructed from predefined and user-defined operators
  3902. // that meet certain requirements
  3903. //
  3904. List<MemberSpec> lifted = null;
  3905. foreach (MethodSpec oper in operators) {
  3906. TypeSpec rt;
  3907. if ((Oper & Operator.ComparisonMask) != 0) {
  3908. //
  3909. // Result type must be of type bool for lifted comparison operators
  3910. //
  3911. rt = oper.ReturnType;
  3912. if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
  3913. continue;
  3914. } else {
  3915. if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
  3916. continue;
  3917. rt = null;
  3918. }
  3919. var ptypes = oper.Parameters.Types;
  3920. if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
  3921. continue;
  3922. //
  3923. // LAMESPEC: I am not sure why but for equality operators to be lifted
  3924. // both types have to match
  3925. //
  3926. if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
  3927. continue;
  3928. if (lifted == null)
  3929. lifted = new List<MemberSpec> ();
  3930. //
  3931. // The lifted form is constructed by adding a single ? modifier to each operand and
  3932. // result type except for comparison operators where return type is bool
  3933. //
  3934. if (rt == null)
  3935. rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
  3936. var parameters = ParametersCompiled.CreateFullyResolved (
  3937. nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
  3938. nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
  3939. var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
  3940. rt, parameters, oper.Modifiers);
  3941. lifted.Add (lifted_op);
  3942. }
  3943. return lifted;
  3944. }
  3945. //
  3946. // Merge two sets of user operators into one, they are mostly distinguish
  3947. // except when they share base type and it contains an operator
  3948. //
  3949. static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
  3950. {
  3951. var combined = new List<MemberSpec> (left.Count + right.Count);
  3952. combined.AddRange (left);
  3953. foreach (var r in right) {
  3954. bool same = false;
  3955. foreach (var l in left) {
  3956. if (l.DeclaringType == r.DeclaringType) {
  3957. same = true;
  3958. break;
  3959. }
  3960. }
  3961. if (!same)
  3962. combined.Add (r);
  3963. }
  3964. return combined;
  3965. }
  3966. void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
  3967. {
  3968. if (c is IntegralConstant || c is CharConstant) {
  3969. try {
  3970. c.ConvertExplicitly (true, type);
  3971. } catch (OverflowException) {
  3972. ec.Report.Warning (652, 2, loc,
  3973. "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
  3974. type.GetSignatureForError ());
  3975. }
  3976. }
  3977. }
  3978. /// <remarks>
  3979. /// EmitBranchable is called from Statement.EmitBoolExpression in the
  3980. /// context of a conditional bool expression. This function will return
  3981. /// false if it is was possible to use EmitBranchable, or true if it was.
  3982. ///
  3983. /// The expression's code is generated, and we will generate a branch to `target'
  3984. /// if the resulting expression value is equal to isTrue
  3985. /// </remarks>
  3986. public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
  3987. {
  3988. if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
  3989. left = left.EmitToField (ec);
  3990. if ((oper & Operator.LogicalMask) == 0) {
  3991. right = right.EmitToField (ec);
  3992. }
  3993. }
  3994. //
  3995. // This is more complicated than it looks, but its just to avoid
  3996. // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
  3997. // but on top of that we want for == and != to use a special path
  3998. // if we are comparing against null
  3999. //
  4000. if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
  4001. bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
  4002. //
  4003. // put the constant on the rhs, for simplicity
  4004. //
  4005. if (left is Constant) {
  4006. Expression swap = right;
  4007. right = left;
  4008. left = swap;
  4009. }
  4010. //
  4011. // brtrue/brfalse works with native int only
  4012. //
  4013. if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
  4014. left.EmitBranchable (ec, target, my_on_true);
  4015. return;
  4016. }
  4017. if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
  4018. // right is a boolean, and it's not 'false' => it is 'true'
  4019. left.EmitBranchable (ec, target, !my_on_true);
  4020. return;
  4021. }
  4022. } else if (oper == Operator.LogicalAnd) {
  4023. if (on_true) {
  4024. Label tests_end = ec.DefineLabel ();
  4025. left.EmitBranchable (ec, tests_end, false);
  4026. right.EmitBranchable (ec, target, true);
  4027. ec.MarkLabel (tests_end);
  4028. } else {
  4029. //
  4030. // This optimizes code like this
  4031. // if (true && i > 4)
  4032. //
  4033. if (!(left is Constant))
  4034. left.EmitBranchable (ec, target, false);
  4035. if (!(right is Constant))
  4036. right.EmitBranchable (ec, target, false);
  4037. }
  4038. return;
  4039. } else if (oper == Operator.LogicalOr){
  4040. if (on_true) {
  4041. left.EmitBranchable (ec, target, true);
  4042. right.EmitBranchable (ec, target, true);
  4043. } else {
  4044. Label tests_end = ec.DefineLabel ();
  4045. left.EmitBranchable (ec, tests_end, true);
  4046. right.EmitBranchable (ec, target, false);
  4047. ec.MarkLabel (tests_end);
  4048. }
  4049. return;
  4050. } else if ((oper & Operator.ComparisonMask) == 0) {
  4051. base.EmitBranchable (ec, target, on_true);
  4052. return;
  4053. }
  4054. left.Emit (ec);
  4055. right.Emit (ec);
  4056. TypeSpec t = left.Type;
  4057. bool is_float = IsFloat (t);
  4058. bool is_unsigned = is_float || IsUnsigned (t);
  4059. switch (oper){
  4060. case Operator.Equality:
  4061. if (on_true)
  4062. ec.Emit (OpCodes.Beq, target);
  4063. else
  4064. ec.Emit (OpCodes.Bne_Un, target);
  4065. break;
  4066. case Operator.Inequality:
  4067. if (on_true)
  4068. ec.Emit (OpCodes.Bne_Un, target);
  4069. else
  4070. ec.Emit (OpCodes.Beq, target);
  4071. break;
  4072. case Operator.LessThan:
  4073. if (on_true)
  4074. if (is_unsigned && !is_float)
  4075. ec.Emit (OpCodes.Blt_Un, target);
  4076. else
  4077. ec.Emit (OpCodes.Blt, target);
  4078. else
  4079. if (is_unsigned)
  4080. ec.Emit (OpCodes.Bge_Un, target);
  4081. else
  4082. ec.Emit (OpCodes.Bge, target);
  4083. break;
  4084. case Operator.GreaterThan:
  4085. if (on_true)
  4086. if (is_unsigned && !is_float)
  4087. ec.Emit (OpCodes.Bgt_Un, target);
  4088. else
  4089. ec.Emit (OpCodes.Bgt, target);
  4090. else
  4091. if (is_unsigned)
  4092. ec.Emit (OpCodes.Ble_Un, target);
  4093. else
  4094. ec.Emit (OpCodes.Ble, target);
  4095. break;
  4096. case Operator.LessThanOrEqual:
  4097. if (on_true)
  4098. if (is_unsigned && !is_float)
  4099. ec.Emit (OpCodes.Ble_Un, target);
  4100. else
  4101. ec.Emit (OpCodes.Ble, target);
  4102. else
  4103. if (is_unsigned)
  4104. ec.Emit (OpCodes.Bgt_Un, target);
  4105. else
  4106. ec.Emit (OpCodes.Bgt, target);
  4107. break;
  4108. case Operator.GreaterThanOrEqual:
  4109. if (on_true)
  4110. if (is_unsigned && !is_float)
  4111. ec.Emit (OpCodes.Bge_Un, target);
  4112. else
  4113. ec.Emit (OpCodes.Bge, target);
  4114. else
  4115. if (is_unsigned)
  4116. ec.Emit (OpCodes.Blt_Un, target);
  4117. else
  4118. ec.Emit (OpCodes.Blt, target);
  4119. break;
  4120. default:
  4121. throw new InternalErrorException (oper.ToString ());
  4122. }
  4123. }
  4124. public override void Emit (EmitContext ec)
  4125. {
  4126. if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
  4127. left = left.EmitToField (ec);
  4128. if ((oper & Operator.LogicalMask) == 0) {
  4129. right = right.EmitToField (ec);
  4130. }
  4131. }
  4132. //
  4133. // Handle short-circuit operators differently
  4134. // than the rest
  4135. //
  4136. if ((oper & Operator.LogicalMask) != 0) {
  4137. Label load_result = ec.DefineLabel ();
  4138. Label end = ec.DefineLabel ();
  4139. bool is_or = oper == Operator.LogicalOr;
  4140. left.EmitBranchable (ec, load_result, is_or);
  4141. right.Emit (ec);
  4142. ec.Emit (OpCodes.Br_S, end);
  4143. ec.MarkLabel (load_result);
  4144. ec.EmitInt (is_or ? 1 : 0);
  4145. ec.MarkLabel (end);
  4146. return;
  4147. }
  4148. //
  4149. // Optimize zero-based operations which cannot be optimized at expression level
  4150. //
  4151. if (oper == Operator.Subtraction) {
  4152. var lc = left as IntegralConstant;
  4153. if (lc != null && lc.IsDefaultValue) {
  4154. right.Emit (ec);
  4155. ec.Emit (OpCodes.Neg);
  4156. return;
  4157. }
  4158. }
  4159. EmitOperator (ec, left, right);
  4160. }
  4161. public void EmitOperator (EmitContext ec, Expression left, Expression right)
  4162. {
  4163. left.Emit (ec);
  4164. right.Emit (ec);
  4165. EmitOperatorOpcode (ec, oper, left.Type, right);
  4166. //
  4167. // Emit result enumerable conversion this way because it's quite complicated get it
  4168. // to resolved tree because expression tree cannot see it.
  4169. //
  4170. if (enum_conversion != 0)
  4171. ConvCast.Emit (ec, enum_conversion);
  4172. }
  4173. public override void EmitSideEffect (EmitContext ec)
  4174. {
  4175. if ((oper & Operator.LogicalMask) != 0 ||
  4176. (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
  4177. base.EmitSideEffect (ec);
  4178. } else {
  4179. left.EmitSideEffect (ec);
  4180. right.EmitSideEffect (ec);
  4181. }
  4182. }
  4183. public override Expression EmitToField (EmitContext ec)
  4184. {
  4185. if ((oper & Operator.LogicalMask) == 0) {
  4186. var await_expr = left as Await;
  4187. if (await_expr != null && right.IsSideEffectFree) {
  4188. await_expr.Statement.EmitPrologue (ec);
  4189. left = await_expr.Statement.GetResultExpression (ec);
  4190. return this;
  4191. }
  4192. await_expr = right as Await;
  4193. if (await_expr != null && left.IsSideEffectFree) {
  4194. await_expr.Statement.EmitPrologue (ec);
  4195. right = await_expr.Statement.GetResultExpression (ec);
  4196. return this;
  4197. }
  4198. }
  4199. return base.EmitToField (ec);
  4200. }
  4201. protected override void CloneTo (CloneContext clonectx, Expression t)
  4202. {
  4203. Binary target = (Binary) t;
  4204. target.left = left.Clone (clonectx);
  4205. target.right = right.Clone (clonectx);
  4206. }
  4207. public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
  4208. {
  4209. Arguments binder_args = new Arguments (4);
  4210. MemberAccess sle = new MemberAccess (new MemberAccess (
  4211. new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
  4212. CSharpBinderFlags flags = 0;
  4213. if (ec.HasSet (ResolveContext.Options.CheckedScope))
  4214. flags = CSharpBinderFlags.CheckedContext;
  4215. if ((oper & Operator.LogicalMask) != 0)
  4216. flags |= CSharpBinderFlags.BinaryOperationLogical;
  4217. binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
  4218. binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
  4219. binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
  4220. binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
  4221. return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
  4222. }
  4223. public override Expression CreateExpressionTree (ResolveContext ec)
  4224. {
  4225. return CreateExpressionTree (ec, null);
  4226. }
  4227. public Expression CreateExpressionTree (ResolveContext ec, Expression method)
  4228. {
  4229. string method_name;
  4230. bool lift_arg = false;
  4231. switch (oper) {
  4232. case Operator.Addition:
  4233. if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
  4234. method_name = "AddChecked";
  4235. else
  4236. method_name = "Add";
  4237. break;
  4238. case Operator.BitwiseAnd:
  4239. method_name = "And";
  4240. break;
  4241. case Operator.BitwiseOr:
  4242. method_name = "Or";
  4243. break;
  4244. case Operator.Division:
  4245. method_name = "Divide";
  4246. break;
  4247. case Operator.Equality:
  4248. method_name = "Equal";
  4249. lift_arg = true;
  4250. break;
  4251. case Operator.ExclusiveOr:
  4252. method_name = "ExclusiveOr";
  4253. break;
  4254. case Operator.GreaterThan:
  4255. method_name = "GreaterThan";
  4256. lift_arg = true;
  4257. break;
  4258. case Operator.GreaterThanOrEqual:
  4259. method_name = "GreaterThanOrEqual";
  4260. lift_arg = true;
  4261. break;
  4262. case Operator.Inequality:
  4263. method_name = "NotEqual";
  4264. lift_arg = true;
  4265. break;
  4266. case Operator.LeftShift:
  4267. method_name = "LeftShift";
  4268. break;
  4269. case Operator.LessThan:
  4270. method_name = "LessThan";
  4271. lift_arg = true;
  4272. break;
  4273. case Operator.LessThanOrEqual:
  4274. method_name = "LessThanOrEqual";
  4275. lift_arg = true;
  4276. break;
  4277. case Operator.LogicalAnd:
  4278. method_name = "AndAlso";
  4279. break;
  4280. case Operator.LogicalOr:
  4281. method_name = "OrElse";
  4282. break;
  4283. case Operator.Modulus:
  4284. method_name = "Modulo";
  4285. break;
  4286. case Operator.Multiply:
  4287. if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
  4288. method_name = "MultiplyChecked";
  4289. else
  4290. method_name = "Multiply";
  4291. break;
  4292. case Operator.RightShift:
  4293. method_name = "RightShift";
  4294. break;
  4295. case Operator.Subtraction:
  4296. if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
  4297. method_name = "SubtractChecked";
  4298. else
  4299. method_name = "Subtract";
  4300. break;
  4301. default:
  4302. throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
  4303. }
  4304. Arguments args = new Arguments (2);
  4305. args.Add (new Argument (left.CreateExpressionTree (ec)));
  4306. args.Add (new Argument (right.CreateExpressionTree (ec)));
  4307. if (method != null) {
  4308. if (lift_arg)
  4309. args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
  4310. args.Add (new Argument (method));
  4311. }
  4312. return CreateExpressionFactoryCall (ec, method_name, args);
  4313. }
  4314. public override object Accept (StructuralVisitor visitor)
  4315. {
  4316. return visitor.Visit (this);
  4317. }
  4318. }
  4319. //
  4320. // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
  4321. // b, c, d... may be strings or objects.
  4322. //
  4323. public class StringConcat : Expression
  4324. {
  4325. Arguments arguments;
  4326. StringConcat (Location loc)
  4327. {
  4328. this.loc = loc;
  4329. arguments = new Arguments (2);
  4330. }
  4331. public override bool ContainsEmitWithAwait ()
  4332. {
  4333. return arguments.ContainsEmitWithAwait ();
  4334. }
  4335. public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
  4336. {
  4337. if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
  4338. throw new ArgumentException ();
  4339. var s = new StringConcat (loc);
  4340. s.type = rc.BuiltinTypes.String;
  4341. s.eclass = ExprClass.Value;
  4342. s.Append (rc, left);
  4343. s.Append (rc, right);
  4344. return s;
  4345. }
  4346. public override Expression CreateExpressionTree (ResolveContext ec)
  4347. {
  4348. Argument arg = arguments [0];
  4349. return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
  4350. }
  4351. //
  4352. // Creates nested calls tree from an array of arguments used for IL emit
  4353. //
  4354. Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
  4355. {
  4356. Arguments concat_args = new Arguments (2);
  4357. Arguments add_args = new Arguments (3);
  4358. concat_args.Add (left);
  4359. add_args.Add (new Argument (left_etree));
  4360. concat_args.Add (arguments [pos]);
  4361. add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
  4362. var methods = GetConcatMethodCandidates ();
  4363. if (methods == null)
  4364. return null;
  4365. var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
  4366. var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
  4367. if (method == null)
  4368. return null;
  4369. add_args.Add (new Argument (new TypeOfMethod (method, loc)));
  4370. Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
  4371. if (++pos == arguments.Count)
  4372. return expr;
  4373. left = new Argument (new EmptyExpression (method.ReturnType));
  4374. return CreateExpressionAddCall (ec, left, expr, pos);
  4375. }
  4376. protected override Expression DoResolve (ResolveContext ec)
  4377. {
  4378. return this;
  4379. }
  4380. void Append (ResolveContext rc, Expression operand)
  4381. {
  4382. //
  4383. // Constant folding
  4384. //
  4385. StringConstant sc = operand as StringConstant;
  4386. if (sc != null) {
  4387. if (arguments.Count != 0) {
  4388. Argument last_argument = arguments [arguments.Count - 1];
  4389. StringConstant last_expr_constant = last_argument.Expr as StringConstant;
  4390. if (last_expr_constant != null) {
  4391. last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
  4392. return;
  4393. }
  4394. }
  4395. } else {
  4396. //
  4397. // Multiple (3+) concatenation are resolved as multiple StringConcat instances
  4398. //
  4399. StringConcat concat_oper = operand as StringConcat;
  4400. if (concat_oper != null) {
  4401. arguments.AddRange (concat_oper.arguments);
  4402. return;
  4403. }
  4404. }
  4405. arguments.Add (new Argument (operand));
  4406. }
  4407. IList<MemberSpec> GetConcatMethodCandidates ()
  4408. {
  4409. return MemberCache.FindMembers (type, "Concat", true);
  4410. }
  4411. public override void Emit (EmitContext ec)
  4412. {
  4413. // Optimize by removing any extra null arguments, they are no-op
  4414. for (int i = 0; i < arguments.Count; ++i) {
  4415. if (arguments[i].Expr is NullConstant)
  4416. arguments.RemoveAt (i--);
  4417. }
  4418. var members = GetConcatMethodCandidates ();
  4419. var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
  4420. var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
  4421. if (method != null) {
  4422. var call = new CallEmitter ();
  4423. call.EmitPredefined (ec, method, arguments, false);
  4424. }
  4425. }
  4426. public override void FlowAnalysis (FlowAnalysisContext fc)
  4427. {
  4428. arguments.FlowAnalysis (fc);
  4429. }
  4430. public override SLE.Expression MakeExpression (BuilderContext ctx)
  4431. {
  4432. if (arguments.Count != 2)
  4433. throw new NotImplementedException ("arguments.Count != 2");
  4434. var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
  4435. return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
  4436. }
  4437. }
  4438. //
  4439. // User-defined conditional logical operator
  4440. //
  4441. public class ConditionalLogicalOperator : UserOperatorCall
  4442. {
  4443. readonly bool is_and;
  4444. Expression oper_expr;
  4445. public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
  4446. : base (oper, arguments, expr_tree, loc)
  4447. {
  4448. this.is_and = is_and;
  4449. eclass = ExprClass.Unresolved;
  4450. }
  4451. protected override Expression DoResolve (ResolveContext ec)
  4452. {
  4453. AParametersCollection pd = oper.Parameters;
  4454. if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
  4455. ec.Report.Error (217, loc,
  4456. "A user-defined operator `{0}' must have each parameter type and return type of the same type in order to be applicable as a short circuit operator",
  4457. oper.GetSignatureForError ());
  4458. return null;
  4459. }
  4460. Expression left_dup = new EmptyExpression (type);
  4461. Expression op_true = GetOperatorTrue (ec, left_dup, loc);
  4462. Expression op_false = GetOperatorFalse (ec, left_dup, loc);
  4463. if (op_true == null || op_false == null) {
  4464. ec.Report.Error (218, loc,
  4465. "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
  4466. type.GetSignatureForError (), oper.GetSignatureForError ());
  4467. return null;
  4468. }
  4469. oper_expr = is_and ? op_false : op_true;
  4470. eclass = ExprClass.Value;
  4471. return this;
  4472. }
  4473. public override void Emit (EmitContext ec)
  4474. {
  4475. Label end_target = ec.DefineLabel ();
  4476. //
  4477. // Emit and duplicate left argument
  4478. //
  4479. bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
  4480. if (right_contains_await) {
  4481. arguments[0] = arguments[0].EmitToField (ec, false);
  4482. arguments[0].Expr.Emit (ec);
  4483. } else {
  4484. arguments[0].Expr.Emit (ec);
  4485. ec.Emit (OpCodes.Dup);
  4486. arguments.RemoveAt (0);
  4487. }
  4488. oper_expr.EmitBranchable (ec, end_target, true);
  4489. base.Emit (ec);
  4490. if (right_contains_await) {
  4491. //
  4492. // Special handling when right expression contains await and left argument
  4493. // could not be left on stack before logical branch
  4494. //
  4495. Label skip_left_load = ec.DefineLabel ();
  4496. ec.Emit (OpCodes.Br_S, skip_left_load);
  4497. ec.MarkLabel (end_target);
  4498. arguments[0].Expr.Emit (ec);
  4499. ec.MarkLabel (skip_left_load);
  4500. } else {
  4501. ec.MarkLabel (end_target);
  4502. }
  4503. }
  4504. }
  4505. public class PointerArithmetic : Expression {
  4506. Expression left, right;
  4507. readonly Binary.Operator op;
  4508. //
  4509. // We assume that `l' is always a pointer
  4510. //
  4511. public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
  4512. {
  4513. type = t;
  4514. this.loc = loc;
  4515. left = l;
  4516. right = r;
  4517. this.op = op;
  4518. }
  4519. public override bool ContainsEmitWithAwait ()
  4520. {
  4521. throw new NotImplementedException ();
  4522. }
  4523. public override Expression CreateExpressionTree (ResolveContext ec)
  4524. {
  4525. Error_PointerInsideExpressionTree (ec);
  4526. return null;
  4527. }
  4528. protected override Expression DoResolve (ResolveContext ec)
  4529. {
  4530. eclass = ExprClass.Variable;
  4531. var pc = left.Type as PointerContainer;
  4532. if (pc != null && pc.Element.Kind == MemberKind.Void) {
  4533. Error_VoidPointerOperation (ec);
  4534. return null;
  4535. }
  4536. return this;
  4537. }
  4538. public override void Emit (EmitContext ec)
  4539. {
  4540. TypeSpec op_type = left.Type;
  4541. // It must be either array or fixed buffer
  4542. TypeSpec element;
  4543. if (TypeManager.HasElementType (op_type)) {
  4544. element = TypeManager.GetElementType (op_type);
  4545. } else {
  4546. FieldExpr fe = left as FieldExpr;
  4547. if (fe != null)
  4548. element = ((FixedFieldSpec) (fe.Spec)).ElementType;
  4549. else
  4550. element = op_type;
  4551. }
  4552. int size = BuiltinTypeSpec.GetSize(element);
  4553. TypeSpec rtype = right.Type;
  4554. if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
  4555. //
  4556. // handle (pointer - pointer)
  4557. //
  4558. left.Emit (ec);
  4559. right.Emit (ec);
  4560. ec.Emit (OpCodes.Sub);
  4561. if (size != 1){
  4562. if (size == 0)
  4563. ec.Emit (OpCodes.Sizeof, element);
  4564. else
  4565. ec.EmitInt (size);
  4566. ec.Emit (OpCodes.Div);
  4567. }
  4568. ec.Emit (OpCodes.Conv_I8);
  4569. } else {
  4570. //
  4571. // handle + and - on (pointer op int)
  4572. //
  4573. Constant left_const = left as Constant;
  4574. if (left_const != null) {
  4575. //
  4576. // Optimize ((T*)null) pointer operations
  4577. //
  4578. if (left_const.IsDefaultValue) {
  4579. left = EmptyExpression.Null;
  4580. } else {
  4581. left_const = null;
  4582. }
  4583. }
  4584. left.Emit (ec);
  4585. var right_const = right as Constant;
  4586. if (right_const != null) {
  4587. //
  4588. // Optimize 0-based arithmetic
  4589. //
  4590. if (right_const.IsDefaultValue)
  4591. return;
  4592. if (size != 0)
  4593. right = new IntConstant (ec.BuiltinTypes, size, right.Location);
  4594. else
  4595. right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
  4596. // TODO: Should be the checks resolve context sensitive?
  4597. ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
  4598. right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
  4599. if (right == null)
  4600. return;
  4601. }
  4602. right.Emit (ec);
  4603. switch (rtype.BuiltinType) {
  4604. case BuiltinTypeSpec.Type.SByte:
  4605. case BuiltinTypeSpec.Type.Byte:
  4606. case BuiltinTypeSpec.Type.Short:
  4607. case BuiltinTypeSpec.Type.UShort:
  4608. ec.Emit (OpCodes.Conv_I);
  4609. break;
  4610. case BuiltinTypeSpec.Type.UInt:
  4611. ec.Emit (OpCodes.Conv_U);
  4612. break;
  4613. }
  4614. if (right_const == null && size != 1){
  4615. if (size == 0)
  4616. ec.Emit (OpCodes.Sizeof, element);
  4617. else
  4618. ec.EmitInt (size);
  4619. if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
  4620. ec.Emit (OpCodes.Conv_I8);
  4621. Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
  4622. }
  4623. if (left_const == null) {
  4624. if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
  4625. ec.Emit (OpCodes.Conv_I);
  4626. else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
  4627. ec.Emit (OpCodes.Conv_U);
  4628. Binary.EmitOperatorOpcode (ec, op, op_type, right);
  4629. }
  4630. }
  4631. }
  4632. }
  4633. //
  4634. // A boolean-expression is an expression that yields a result
  4635. // of type bool
  4636. //
  4637. public class BooleanExpression : ShimExpression
  4638. {
  4639. public BooleanExpression (Expression expr)
  4640. : base (expr)
  4641. {
  4642. this.loc = expr.Location;
  4643. }
  4644. public override Expression CreateExpressionTree (ResolveContext ec)
  4645. {
  4646. // TODO: We should emit IsTrue (v4) instead of direct user operator
  4647. // call but that would break csc compatibility
  4648. return base.CreateExpressionTree (ec);
  4649. }
  4650. protected override Expression DoResolve (ResolveContext ec)
  4651. {
  4652. // A boolean-expression is required to be of a type
  4653. // that can be implicitly converted to bool or of
  4654. // a type that implements operator true
  4655. expr = expr.Resolve (ec);
  4656. if (expr == null)
  4657. return null;
  4658. Assign ass = expr as Assign;
  4659. if (ass != null && ass.Source is Constant) {
  4660. ec.Report.Warning (665, 3, loc,
  4661. "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
  4662. }
  4663. if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
  4664. return expr;
  4665. if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  4666. Arguments args = new Arguments (1);
  4667. args.Add (new Argument (expr));
  4668. return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
  4669. }
  4670. type = ec.BuiltinTypes.Bool;
  4671. Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
  4672. if (converted != null)
  4673. return converted;
  4674. //
  4675. // If no implicit conversion to bool exists, try using `operator true'
  4676. //
  4677. converted = GetOperatorTrue (ec, expr, loc);
  4678. if (converted == null) {
  4679. expr.Error_ValueCannotBeConverted (ec, type, false);
  4680. return null;
  4681. }
  4682. return converted;
  4683. }
  4684. public override object Accept (StructuralVisitor visitor)
  4685. {
  4686. return visitor.Visit (this);
  4687. }
  4688. }
  4689. public class BooleanExpressionFalse : Unary
  4690. {
  4691. public BooleanExpressionFalse (Expression expr)
  4692. : base (Operator.LogicalNot, expr, expr.Location)
  4693. {
  4694. }
  4695. protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
  4696. {
  4697. return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
  4698. }
  4699. }
  4700. /// <summary>
  4701. /// Implements the ternary conditional operator (?:)
  4702. /// </summary>
  4703. public class Conditional : Expression {
  4704. Expression expr, true_expr, false_expr;
  4705. public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
  4706. {
  4707. this.expr = expr;
  4708. this.true_expr = true_expr;
  4709. this.false_expr = false_expr;
  4710. this.loc = loc;
  4711. }
  4712. #region Properties
  4713. public Expression Expr {
  4714. get {
  4715. return expr;
  4716. }
  4717. }
  4718. public Expression TrueExpr {
  4719. get {
  4720. return true_expr;
  4721. }
  4722. }
  4723. public Expression FalseExpr {
  4724. get {
  4725. return false_expr;
  4726. }
  4727. }
  4728. #endregion
  4729. public override bool ContainsEmitWithAwait ()
  4730. {
  4731. return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
  4732. }
  4733. public override Expression CreateExpressionTree (ResolveContext ec)
  4734. {
  4735. Arguments args = new Arguments (3);
  4736. args.Add (new Argument (expr.CreateExpressionTree (ec)));
  4737. args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
  4738. args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
  4739. return CreateExpressionFactoryCall (ec, "Condition", args);
  4740. }
  4741. protected override Expression DoResolve (ResolveContext ec)
  4742. {
  4743. expr = expr.Resolve (ec);
  4744. true_expr = true_expr.Resolve (ec);
  4745. false_expr = false_expr.Resolve (ec);
  4746. if (true_expr == null || false_expr == null || expr == null)
  4747. return null;
  4748. eclass = ExprClass.Value;
  4749. TypeSpec true_type = true_expr.Type;
  4750. TypeSpec false_type = false_expr.Type;
  4751. type = true_type;
  4752. //
  4753. // First, if an implicit conversion exists from true_expr
  4754. // to false_expr, then the result type is of type false_expr.Type
  4755. //
  4756. if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
  4757. Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
  4758. if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
  4759. //
  4760. // Check if both can convert implicitly to each other's type
  4761. //
  4762. type = false_type;
  4763. if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
  4764. var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
  4765. //
  4766. // LAMESPEC: There seems to be hardcoded promotition to int type when
  4767. // both sides are numeric constants and one side is int constant and
  4768. // other side is numeric constant convertible to int.
  4769. //
  4770. // var res = condition ? (short)1 : 1;
  4771. //
  4772. // Type of res is int even if according to the spec the conversion is
  4773. // ambiguous because 1 literal can be converted to short.
  4774. //
  4775. if (conv_false_expr != null) {
  4776. if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
  4777. type = true_type;
  4778. conv_false_expr = null;
  4779. } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
  4780. conv_false_expr = null;
  4781. }
  4782. }
  4783. if (conv_false_expr != null) {
  4784. ec.Report.Error (172, true_expr.Location,
  4785. "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
  4786. true_type.GetSignatureForError (), false_type.GetSignatureForError ());
  4787. }
  4788. }
  4789. true_expr = conv;
  4790. if (true_expr.Type != type)
  4791. true_expr = EmptyCast.Create (true_expr, type);
  4792. } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
  4793. false_expr = conv;
  4794. } else {
  4795. ec.Report.Error (173, true_expr.Location,
  4796. "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
  4797. true_type.GetSignatureForError (), false_type.GetSignatureForError ());
  4798. return null;
  4799. }
  4800. }
  4801. Constant c = expr as Constant;
  4802. if (c != null) {
  4803. bool is_false = c.IsDefaultValue;
  4804. //
  4805. // Don't issue the warning for constant expressions
  4806. //
  4807. if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
  4808. // CSC: Missing warning
  4809. Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
  4810. }
  4811. return ReducedExpression.Create (
  4812. is_false ? false_expr : true_expr, this,
  4813. false_expr is Constant && true_expr is Constant).Resolve (ec);
  4814. }
  4815. return this;
  4816. }
  4817. public override void Emit (EmitContext ec)
  4818. {
  4819. Label false_target = ec.DefineLabel ();
  4820. Label end_target = ec.DefineLabel ();
  4821. expr.EmitBranchable (ec, false_target, false);
  4822. true_expr.Emit (ec);
  4823. //
  4824. // Verifier doesn't support interface merging. When there are two types on
  4825. // the stack without common type hint and the common type is an interface.
  4826. // Use temporary local to give verifier hint on what type to unify the stack
  4827. //
  4828. if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
  4829. var temp = ec.GetTemporaryLocal (type);
  4830. ec.Emit (OpCodes.Stloc, temp);
  4831. ec.Emit (OpCodes.Ldloc, temp);
  4832. ec.FreeTemporaryLocal (temp, type);
  4833. }
  4834. ec.Emit (OpCodes.Br, end_target);
  4835. ec.MarkLabel (false_target);
  4836. false_expr.Emit (ec);
  4837. ec.MarkLabel (end_target);
  4838. }
  4839. public override void FlowAnalysis (FlowAnalysisContext fc)
  4840. {
  4841. expr.FlowAnalysisConditional (fc);
  4842. var expr_true = fc.DefiniteAssignmentOnTrue;
  4843. var expr_false = fc.DefiniteAssignmentOnFalse;
  4844. fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
  4845. true_expr.FlowAnalysis (fc);
  4846. var true_fc = fc.DefiniteAssignment;
  4847. fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
  4848. false_expr.FlowAnalysis (fc);
  4849. fc.DefiniteAssignment &= true_fc;
  4850. }
  4851. public override void FlowAnalysisConditional (FlowAnalysisContext fc)
  4852. {
  4853. expr.FlowAnalysisConditional (fc);
  4854. var expr_true = fc.DefiniteAssignmentOnTrue;
  4855. var expr_false = fc.DefiniteAssignmentOnFalse;
  4856. fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
  4857. true_expr.FlowAnalysisConditional (fc);
  4858. var true_fc = fc.DefiniteAssignment;
  4859. var true_da_true = fc.DefiniteAssignmentOnTrue;
  4860. var true_da_false = fc.DefiniteAssignmentOnFalse;
  4861. fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
  4862. false_expr.FlowAnalysisConditional (fc);
  4863. fc.DefiniteAssignment &= true_fc;
  4864. fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
  4865. fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
  4866. }
  4867. protected override void CloneTo (CloneContext clonectx, Expression t)
  4868. {
  4869. Conditional target = (Conditional) t;
  4870. target.expr = expr.Clone (clonectx);
  4871. target.true_expr = true_expr.Clone (clonectx);
  4872. target.false_expr = false_expr.Clone (clonectx);
  4873. }
  4874. public override object Accept (StructuralVisitor visitor)
  4875. {
  4876. return visitor.Visit (this);
  4877. }
  4878. }
  4879. public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
  4880. {
  4881. LocalTemporary temp;
  4882. #region Abstract
  4883. public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
  4884. public abstract void SetHasAddressTaken ();
  4885. public abstract bool IsLockedByStatement { get; set; }
  4886. public abstract bool IsFixed { get; }
  4887. public abstract bool IsRef { get; }
  4888. public abstract string Name { get; }
  4889. //
  4890. // Variable IL data, it has to be protected to encapsulate hoisted variables
  4891. //
  4892. protected abstract ILocalVariable Variable { get; }
  4893. //
  4894. // Variable flow-analysis data
  4895. //
  4896. public abstract VariableInfo VariableInfo { get; }
  4897. #endregion
  4898. public virtual void AddressOf (EmitContext ec, AddressOp mode)
  4899. {
  4900. HoistedVariable hv = GetHoistedVariable (ec);
  4901. if (hv != null) {
  4902. hv.AddressOf (ec, mode);
  4903. return;
  4904. }
  4905. Variable.EmitAddressOf (ec);
  4906. }
  4907. public override bool ContainsEmitWithAwait ()
  4908. {
  4909. return false;
  4910. }
  4911. public override Expression CreateExpressionTree (ResolveContext ec)
  4912. {
  4913. HoistedVariable hv = GetHoistedVariable (ec);
  4914. if (hv != null)
  4915. return hv.CreateExpressionTree ();
  4916. Arguments arg = new Arguments (1);
  4917. arg.Add (new Argument (this));
  4918. return CreateExpressionFactoryCall (ec, "Constant", arg);
  4919. }
  4920. public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
  4921. {
  4922. if (IsLockedByStatement) {
  4923. rc.Report.Warning (728, 2, loc,
  4924. "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
  4925. Name);
  4926. }
  4927. return this;
  4928. }
  4929. public override void Emit (EmitContext ec)
  4930. {
  4931. Emit (ec, false);
  4932. }
  4933. public override void EmitSideEffect (EmitContext ec)
  4934. {
  4935. // do nothing
  4936. }
  4937. //
  4938. // This method is used by parameters that are references, that are
  4939. // being passed as references: we only want to pass the pointer (that
  4940. // is already stored in the parameter, not the address of the pointer,
  4941. // and not the value of the variable).
  4942. //
  4943. public void EmitLoad (EmitContext ec)
  4944. {
  4945. Variable.Emit (ec);
  4946. }
  4947. public void Emit (EmitContext ec, bool leave_copy)
  4948. {
  4949. HoistedVariable hv = GetHoistedVariable (ec);
  4950. if (hv != null) {
  4951. hv.Emit (ec, leave_copy);
  4952. return;
  4953. }
  4954. EmitLoad (ec);
  4955. if (IsRef) {
  4956. //
  4957. // If we are a reference, we loaded on the stack a pointer
  4958. // Now lets load the real value
  4959. //
  4960. ec.EmitLoadFromPtr (type);
  4961. }
  4962. if (leave_copy) {
  4963. ec.Emit (OpCodes.Dup);
  4964. if (IsRef) {
  4965. temp = new LocalTemporary (Type);
  4966. temp.Store (ec);
  4967. }
  4968. }
  4969. }
  4970. public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
  4971. bool prepare_for_load)
  4972. {
  4973. HoistedVariable hv = GetHoistedVariable (ec);
  4974. if (hv != null) {
  4975. hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
  4976. return;
  4977. }
  4978. New n_source = source as New;
  4979. if (n_source != null) {
  4980. if (!n_source.Emit (ec, this)) {
  4981. if (leave_copy) {
  4982. EmitLoad (ec);
  4983. if (IsRef)
  4984. ec.EmitLoadFromPtr (type);
  4985. }
  4986. return;
  4987. }
  4988. } else {
  4989. if (IsRef)
  4990. EmitLoad (ec);
  4991. source.Emit (ec);
  4992. }
  4993. if (leave_copy) {
  4994. ec.Emit (OpCodes.Dup);
  4995. if (IsRef) {
  4996. temp = new LocalTemporary (Type);
  4997. temp.Store (ec);
  4998. }
  4999. }
  5000. if (IsRef)
  5001. ec.EmitStoreFromPtr (type);
  5002. else
  5003. Variable.EmitAssign (ec);
  5004. if (temp != null) {
  5005. temp.Emit (ec);
  5006. temp.Release (ec);
  5007. }
  5008. }
  5009. public override Expression EmitToField (EmitContext ec)
  5010. {
  5011. HoistedVariable hv = GetHoistedVariable (ec);
  5012. if (hv != null) {
  5013. return hv.EmitToField (ec);
  5014. }
  5015. return base.EmitToField (ec);
  5016. }
  5017. public HoistedVariable GetHoistedVariable (ResolveContext rc)
  5018. {
  5019. return GetHoistedVariable (rc.CurrentAnonymousMethod);
  5020. }
  5021. public HoistedVariable GetHoistedVariable (EmitContext ec)
  5022. {
  5023. return GetHoistedVariable (ec.CurrentAnonymousMethod);
  5024. }
  5025. public override string GetSignatureForError ()
  5026. {
  5027. return Name;
  5028. }
  5029. public bool IsHoisted {
  5030. get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
  5031. }
  5032. }
  5033. //
  5034. // Resolved reference to a local variable
  5035. //
  5036. public class LocalVariableReference : VariableReference
  5037. {
  5038. public LocalVariable local_info;
  5039. public LocalVariableReference (LocalVariable li, Location l)
  5040. {
  5041. this.local_info = li;
  5042. loc = l;
  5043. }
  5044. public override VariableInfo VariableInfo {
  5045. get { return local_info.VariableInfo; }
  5046. }
  5047. public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
  5048. {
  5049. return local_info.HoistedVariant;
  5050. }
  5051. #region Properties
  5052. //
  5053. // A local variable is always fixed
  5054. //
  5055. public override bool IsFixed {
  5056. get {
  5057. return true;
  5058. }
  5059. }
  5060. public override bool IsLockedByStatement {
  5061. get {
  5062. return local_info.IsLocked;
  5063. }
  5064. set {
  5065. local_info.IsLocked = value;
  5066. }
  5067. }
  5068. public override bool IsRef {
  5069. get { return false; }
  5070. }
  5071. public override string Name {
  5072. get { return local_info.Name; }
  5073. }
  5074. #endregion
  5075. public override void FlowAnalysis (FlowAnalysisContext fc)
  5076. {
  5077. VariableInfo variable_info = VariableInfo;
  5078. if (variable_info == null)
  5079. return;
  5080. if (fc.IsDefinitelyAssigned (variable_info))
  5081. return;
  5082. fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
  5083. variable_info.SetAssigned (fc.DefiniteAssignment, true);
  5084. }
  5085. public override void SetHasAddressTaken ()
  5086. {
  5087. local_info.SetHasAddressTaken ();
  5088. }
  5089. void DoResolveBase (ResolveContext ec)
  5090. {
  5091. //
  5092. // If we are referencing a variable from the external block
  5093. // flag it for capturing
  5094. //
  5095. if (ec.MustCaptureVariable (local_info)) {
  5096. if (local_info.AddressTaken) {
  5097. AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
  5098. } else if (local_info.IsFixed) {
  5099. ec.Report.Error (1764, loc,
  5100. "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
  5101. GetSignatureForError ());
  5102. }
  5103. if (ec.IsVariableCapturingRequired) {
  5104. AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
  5105. storey.CaptureLocalVariable (ec, local_info);
  5106. }
  5107. }
  5108. eclass = ExprClass.Variable;
  5109. type = local_info.Type;
  5110. }
  5111. protected override Expression DoResolve (ResolveContext ec)
  5112. {
  5113. local_info.SetIsUsed ();
  5114. DoResolveBase (ec);
  5115. return this;
  5116. }
  5117. public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
  5118. {
  5119. //
  5120. // Don't be too pedantic when variable is used as out param or for some broken code
  5121. // which uses property/indexer access to run some initialization
  5122. //
  5123. if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
  5124. local_info.SetIsUsed ();
  5125. if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
  5126. if (rhs == EmptyExpression.LValueMemberAccess) {
  5127. // CS1654 already reported
  5128. } else {
  5129. int code;
  5130. string msg;
  5131. if (rhs == EmptyExpression.OutAccess) {
  5132. code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
  5133. } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
  5134. code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
  5135. } else if (rhs == EmptyExpression.UnaryAddress) {
  5136. code = 459; msg = "Cannot take the address of {1} `{0}'";
  5137. } else {
  5138. code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
  5139. }
  5140. ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
  5141. }
  5142. }
  5143. if (eclass == ExprClass.Unresolved)
  5144. DoResolveBase (ec);
  5145. return base.DoResolveLValue (ec, rhs);
  5146. }
  5147. public override int GetHashCode ()
  5148. {
  5149. return local_info.GetHashCode ();
  5150. }
  5151. public override bool Equals (object obj)
  5152. {
  5153. LocalVariableReference lvr = obj as LocalVariableReference;
  5154. if (lvr == null)
  5155. return false;
  5156. return local_info == lvr.local_info;
  5157. }
  5158. protected override ILocalVariable Variable {
  5159. get { return local_info; }
  5160. }
  5161. public override string ToString ()
  5162. {
  5163. return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
  5164. }
  5165. protected override void CloneTo (CloneContext clonectx, Expression t)
  5166. {
  5167. // Nothing
  5168. }
  5169. public override object Accept (StructuralVisitor visitor)
  5170. {
  5171. return visitor.Visit (this);
  5172. }
  5173. }
  5174. /// <summary>
  5175. /// This represents a reference to a parameter in the intermediate
  5176. /// representation.
  5177. /// </summary>
  5178. public class ParameterReference : VariableReference
  5179. {
  5180. protected ParametersBlock.ParameterInfo pi;
  5181. public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
  5182. {
  5183. this.pi = pi;
  5184. this.loc = loc;
  5185. }
  5186. #region Properties
  5187. public override bool IsLockedByStatement {
  5188. get {
  5189. return pi.IsLocked;
  5190. }
  5191. set {
  5192. pi.IsLocked = value;
  5193. }
  5194. }
  5195. public override bool IsRef {
  5196. get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
  5197. }
  5198. bool HasOutModifier {
  5199. get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
  5200. }
  5201. public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
  5202. {
  5203. return pi.Parameter.HoistedVariant;
  5204. }
  5205. //
  5206. // A ref or out parameter is classified as a moveable variable, even
  5207. // if the argument given for the parameter is a fixed variable
  5208. //
  5209. public override bool IsFixed {
  5210. get { return !IsRef; }
  5211. }
  5212. public override string Name {
  5213. get { return Parameter.Name; }
  5214. }
  5215. public Parameter Parameter {
  5216. get { return pi.Parameter; }
  5217. }
  5218. public override VariableInfo VariableInfo {
  5219. get { return pi.VariableInfo; }
  5220. }
  5221. protected override ILocalVariable Variable {
  5222. get { return Parameter; }
  5223. }
  5224. #endregion
  5225. public override void AddressOf (EmitContext ec, AddressOp mode)
  5226. {
  5227. //
  5228. // ParameterReferences might already be a reference
  5229. //
  5230. if (IsRef) {
  5231. EmitLoad (ec);
  5232. return;
  5233. }
  5234. base.AddressOf (ec, mode);
  5235. }
  5236. public override void SetHasAddressTaken ()
  5237. {
  5238. Parameter.HasAddressTaken = true;
  5239. }
  5240. bool DoResolveBase (ResolveContext ec)
  5241. {
  5242. if (eclass != ExprClass.Unresolved)
  5243. return true;
  5244. type = pi.ParameterType;
  5245. eclass = ExprClass.Variable;
  5246. //
  5247. // If we are referencing a parameter from the external block
  5248. // flag it for capturing
  5249. //
  5250. if (ec.MustCaptureVariable (pi)) {
  5251. if (Parameter.HasAddressTaken)
  5252. AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
  5253. if (IsRef) {
  5254. ec.Report.Error (1628, loc,
  5255. "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
  5256. Name, ec.CurrentAnonymousMethod.ContainerType);
  5257. }
  5258. if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
  5259. AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
  5260. storey.CaptureParameter (ec, pi, this);
  5261. }
  5262. }
  5263. return true;
  5264. }
  5265. public override int GetHashCode ()
  5266. {
  5267. return Name.GetHashCode ();
  5268. }
  5269. public override bool Equals (object obj)
  5270. {
  5271. ParameterReference pr = obj as ParameterReference;
  5272. if (pr == null)
  5273. return false;
  5274. return Name == pr.Name;
  5275. }
  5276. protected override void CloneTo (CloneContext clonectx, Expression target)
  5277. {
  5278. // Nothing to clone
  5279. return;
  5280. }
  5281. public override Expression CreateExpressionTree (ResolveContext ec)
  5282. {
  5283. HoistedVariable hv = GetHoistedVariable (ec);
  5284. if (hv != null)
  5285. return hv.CreateExpressionTree ();
  5286. return Parameter.ExpressionTreeVariableReference ();
  5287. }
  5288. protected override Expression DoResolve (ResolveContext ec)
  5289. {
  5290. if (!DoResolveBase (ec))
  5291. return null;
  5292. return this;
  5293. }
  5294. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  5295. {
  5296. if (!DoResolveBase (ec))
  5297. return null;
  5298. if (Parameter.HoistedVariant != null)
  5299. Parameter.HoistedVariant.IsAssigned = true;
  5300. return base.DoResolveLValue (ec, right_side);
  5301. }
  5302. public override void FlowAnalysis (FlowAnalysisContext fc)
  5303. {
  5304. VariableInfo variable_info = VariableInfo;
  5305. if (variable_info == null)
  5306. return;
  5307. if (fc.IsDefinitelyAssigned (variable_info))
  5308. return;
  5309. fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
  5310. fc.SetVariableAssigned (variable_info);
  5311. }
  5312. }
  5313. /// <summary>
  5314. /// Invocation of methods or delegates.
  5315. /// </summary>
  5316. public class Invocation : ExpressionStatement
  5317. {
  5318. public class Predefined : Invocation
  5319. {
  5320. public Predefined (MethodGroupExpr expr, Arguments arguments)
  5321. : base (expr, arguments)
  5322. {
  5323. this.mg = expr;
  5324. }
  5325. protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
  5326. {
  5327. if (!rc.IsObsolete) {
  5328. var member = mg.BestCandidate;
  5329. ObsoleteAttribute oa = member.GetAttributeObsolete ();
  5330. if (oa != null)
  5331. AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
  5332. }
  5333. return mg;
  5334. }
  5335. }
  5336. protected Arguments arguments;
  5337. protected Expression expr;
  5338. protected MethodGroupExpr mg;
  5339. bool conditional_access_receiver;
  5340. public Invocation (Expression expr, Arguments arguments)
  5341. {
  5342. this.expr = expr;
  5343. this.arguments = arguments;
  5344. if (expr != null) {
  5345. loc = expr.Location;
  5346. }
  5347. }
  5348. #region Properties
  5349. public Arguments Arguments {
  5350. get {
  5351. return arguments;
  5352. }
  5353. }
  5354. public Expression Exp {
  5355. get {
  5356. return expr;
  5357. }
  5358. }
  5359. public MethodGroupExpr MethodGroup {
  5360. get {
  5361. return mg;
  5362. }
  5363. }
  5364. public override Location StartLocation {
  5365. get {
  5366. return expr.StartLocation;
  5367. }
  5368. }
  5369. #endregion
  5370. public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
  5371. {
  5372. if (MethodGroup == null)
  5373. return null;
  5374. var candidate = MethodGroup.BestCandidate;
  5375. if (candidate == null || !(candidate.IsStatic || Exp is This))
  5376. return null;
  5377. var args_count = arguments == null ? 0 : arguments.Count;
  5378. if (args_count != body.Parameters.Count)
  5379. return null;
  5380. var lambda_parameters = body.Block.Parameters.FixedParameters;
  5381. for (int i = 0; i < args_count; ++i) {
  5382. var pr = arguments[i].Expr as ParameterReference;
  5383. if (pr == null)
  5384. return null;
  5385. if (lambda_parameters[i] != pr.Parameter)
  5386. return null;
  5387. if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
  5388. return null;
  5389. }
  5390. var emg = MethodGroup as ExtensionMethodGroupExpr;
  5391. if (emg != null) {
  5392. var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
  5393. if (candidate.IsGeneric) {
  5394. var targs = new TypeExpression [candidate.Arity];
  5395. for (int i = 0; i < targs.Length; ++i) {
  5396. targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
  5397. }
  5398. mg.SetTypeArguments (null, new TypeArguments (targs));
  5399. }
  5400. return mg;
  5401. }
  5402. return MethodGroup;
  5403. }
  5404. protected override void CloneTo (CloneContext clonectx, Expression t)
  5405. {
  5406. Invocation target = (Invocation) t;
  5407. if (arguments != null)
  5408. target.arguments = arguments.Clone (clonectx);
  5409. target.expr = expr.Clone (clonectx);
  5410. }
  5411. public override bool ContainsEmitWithAwait ()
  5412. {
  5413. if (arguments != null && arguments.ContainsEmitWithAwait ())
  5414. return true;
  5415. return mg.ContainsEmitWithAwait ();
  5416. }
  5417. public override Expression CreateExpressionTree (ResolveContext ec)
  5418. {
  5419. Expression instance = mg.IsInstance ?
  5420. mg.InstanceExpression.CreateExpressionTree (ec) :
  5421. new NullLiteral (loc);
  5422. var args = Arguments.CreateForExpressionTree (ec, arguments,
  5423. instance,
  5424. mg.CreateExpressionTree (ec));
  5425. return CreateExpressionFactoryCall (ec, "Call", args);
  5426. }
  5427. protected override Expression DoResolve (ResolveContext rc)
  5428. {
  5429. if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
  5430. if (expr.HasConditionalAccess ()) {
  5431. conditional_access_receiver = true;
  5432. using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
  5433. return DoResolveInvocation (rc);
  5434. }
  5435. }
  5436. }
  5437. return DoResolveInvocation (rc);
  5438. }
  5439. Expression DoResolveInvocation (ResolveContext ec)
  5440. {
  5441. Expression member_expr;
  5442. var atn = expr as ATypeNameExpression;
  5443. if (atn != null) {
  5444. member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
  5445. if (member_expr != null) {
  5446. var name_of = member_expr as NameOf;
  5447. if (name_of != null) {
  5448. return name_of.ResolveOverload (ec, arguments);
  5449. }
  5450. member_expr = member_expr.Resolve (ec);
  5451. }
  5452. } else {
  5453. member_expr = expr.Resolve (ec);
  5454. }
  5455. if (member_expr == null)
  5456. return null;
  5457. //
  5458. // Next, evaluate all the expressions in the argument list
  5459. //
  5460. bool dynamic_arg = false;
  5461. if (arguments != null)
  5462. arguments.Resolve (ec, out dynamic_arg);
  5463. TypeSpec expr_type = member_expr.Type;
  5464. if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
  5465. return DoResolveDynamic (ec, member_expr);
  5466. mg = member_expr as MethodGroupExpr;
  5467. Expression invoke = null;
  5468. if (mg == null) {
  5469. if (expr_type != null && expr_type.IsDelegate) {
  5470. invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
  5471. invoke = invoke.Resolve (ec);
  5472. if (invoke == null || !dynamic_arg)
  5473. return invoke;
  5474. } else {
  5475. if (member_expr is RuntimeValueExpression) {
  5476. ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
  5477. member_expr.Type.GetSignatureForError ());
  5478. return null;
  5479. }
  5480. MemberExpr me = member_expr as MemberExpr;
  5481. if (me == null) {
  5482. member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
  5483. return null;
  5484. }
  5485. ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
  5486. member_expr.GetSignatureForError ());
  5487. return null;
  5488. }
  5489. }
  5490. if (invoke == null) {
  5491. mg = DoResolveOverload (ec);
  5492. if (mg == null)
  5493. return null;
  5494. }
  5495. if (dynamic_arg)
  5496. return DoResolveDynamic (ec, member_expr);
  5497. var method = mg.BestCandidate;
  5498. type = mg.BestCandidateReturnType;
  5499. if (conditional_access_receiver)
  5500. type = LiftMemberType (ec, type);
  5501. if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
  5502. if (mg.IsBase)
  5503. ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
  5504. else
  5505. ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
  5506. return null;
  5507. }
  5508. IsSpecialMethodInvocation (ec, method, loc);
  5509. eclass = ExprClass.Value;
  5510. return this;
  5511. }
  5512. protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
  5513. {
  5514. Arguments args;
  5515. DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
  5516. if (dmb != null) {
  5517. args = dmb.Arguments;
  5518. if (arguments != null)
  5519. args.AddRange (arguments);
  5520. } else if (mg == null) {
  5521. if (arguments == null)
  5522. args = new Arguments (1);
  5523. else
  5524. args = arguments;
  5525. args.Insert (0, new Argument (memberExpr));
  5526. this.expr = null;
  5527. } else {
  5528. if (mg.IsBase) {
  5529. ec.Report.Error (1971, loc,
  5530. "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
  5531. mg.Name);
  5532. return null;
  5533. }
  5534. if (arguments == null)
  5535. args = new Arguments (1);
  5536. else
  5537. args = arguments;
  5538. MemberAccess ma = expr as MemberAccess;
  5539. if (ma != null) {
  5540. var inst = mg.InstanceExpression;
  5541. var left_type = inst as TypeExpr;
  5542. if (left_type != null) {
  5543. args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
  5544. } else if (inst != null) {
  5545. //
  5546. // Any value type has to be pass as by-ref to get back the same
  5547. // instance on which the member was called
  5548. //
  5549. var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
  5550. Argument.AType.Ref : Argument.AType.None;
  5551. args.Insert (0, new Argument (inst.Resolve (ec), mod));
  5552. }
  5553. } else { // is SimpleName
  5554. if (ec.IsStatic) {
  5555. args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
  5556. } else {
  5557. args.Insert (0, new Argument (new This (loc).Resolve (ec)));
  5558. }
  5559. }
  5560. }
  5561. return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
  5562. }
  5563. protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
  5564. {
  5565. return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
  5566. }
  5567. public override void FlowAnalysis (FlowAnalysisContext fc)
  5568. {
  5569. if (mg.IsConditionallyExcluded)
  5570. return;
  5571. mg.FlowAnalysis (fc);
  5572. if (arguments != null)
  5573. arguments.FlowAnalysis (fc);
  5574. if (conditional_access_receiver)
  5575. fc.ConditionalAccessEnd ();
  5576. }
  5577. public override string GetSignatureForError ()
  5578. {
  5579. return mg.GetSignatureForError ();
  5580. }
  5581. public override bool HasConditionalAccess ()
  5582. {
  5583. return expr.HasConditionalAccess ();
  5584. }
  5585. //
  5586. // If a member is a method or event, or if it is a constant, field or property of either a delegate type
  5587. // or the type dynamic, then the member is invocable
  5588. //
  5589. public static bool IsMemberInvocable (MemberSpec member)
  5590. {
  5591. switch (member.Kind) {
  5592. case MemberKind.Event:
  5593. return true;
  5594. case MemberKind.Field:
  5595. case MemberKind.Property:
  5596. var m = member as IInterfaceMemberSpec;
  5597. return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
  5598. default:
  5599. return false;
  5600. }
  5601. }
  5602. public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
  5603. {
  5604. if (!method.IsReservedMethod)
  5605. return false;
  5606. if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
  5607. return false;
  5608. ec.Report.SymbolRelatedToPreviousError (method);
  5609. ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
  5610. method.GetSignatureForError ());
  5611. return true;
  5612. }
  5613. public override void Emit (EmitContext ec)
  5614. {
  5615. if (mg.IsConditionallyExcluded)
  5616. return;
  5617. if (conditional_access_receiver)
  5618. mg.EmitCall (ec, arguments, type, false);
  5619. else
  5620. mg.EmitCall (ec, arguments, false);
  5621. }
  5622. public override void EmitStatement (EmitContext ec)
  5623. {
  5624. if (mg.IsConditionallyExcluded)
  5625. return;
  5626. if (conditional_access_receiver)
  5627. mg.EmitCall (ec, arguments, type, true);
  5628. else
  5629. mg.EmitCall (ec, arguments, true);
  5630. }
  5631. public override SLE.Expression MakeExpression (BuilderContext ctx)
  5632. {
  5633. return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
  5634. }
  5635. public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
  5636. {
  5637. #if STATIC
  5638. throw new NotSupportedException ();
  5639. #else
  5640. var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
  5641. return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
  5642. #endif
  5643. }
  5644. public override object Accept (StructuralVisitor visitor)
  5645. {
  5646. return visitor.Visit (this);
  5647. }
  5648. }
  5649. //
  5650. // Implements simple new expression
  5651. //
  5652. public class New : ExpressionStatement, IMemoryLocation
  5653. {
  5654. protected Arguments arguments;
  5655. //
  5656. // During bootstrap, it contains the RequestedType,
  5657. // but if `type' is not null, it *might* contain a NewDelegate
  5658. // (because of field multi-initialization)
  5659. //
  5660. protected Expression RequestedType;
  5661. protected MethodSpec method;
  5662. public New (Expression requested_type, Arguments arguments, Location l)
  5663. {
  5664. RequestedType = requested_type;
  5665. this.arguments = arguments;
  5666. loc = l;
  5667. }
  5668. #region Properties
  5669. public Arguments Arguments {
  5670. get {
  5671. return arguments;
  5672. }
  5673. }
  5674. public Expression TypeRequested {
  5675. get {
  5676. return RequestedType;
  5677. }
  5678. }
  5679. //
  5680. // Returns true for resolved `new S()'
  5681. //
  5682. public bool IsDefaultStruct {
  5683. get {
  5684. return arguments == null && type.IsStruct && GetType () == typeof (New);
  5685. }
  5686. }
  5687. public Expression TypeExpression {
  5688. get {
  5689. return RequestedType;
  5690. }
  5691. }
  5692. #endregion
  5693. /// <summary>
  5694. /// Converts complex core type syntax like 'new int ()' to simple constant
  5695. /// </summary>
  5696. public static Constant Constantify (TypeSpec t, Location loc)
  5697. {
  5698. switch (t.BuiltinType) {
  5699. case BuiltinTypeSpec.Type.Int:
  5700. return new IntConstant (t, 0, loc);
  5701. case BuiltinTypeSpec.Type.UInt:
  5702. return new UIntConstant (t, 0, loc);
  5703. case BuiltinTypeSpec.Type.Long:
  5704. return new LongConstant (t, 0, loc);
  5705. case BuiltinTypeSpec.Type.ULong:
  5706. return new ULongConstant (t, 0, loc);
  5707. case BuiltinTypeSpec.Type.Float:
  5708. return new FloatConstant (t, 0, loc);
  5709. case BuiltinTypeSpec.Type.Double:
  5710. return new DoubleConstant (t, 0, loc);
  5711. case BuiltinTypeSpec.Type.Short:
  5712. return new ShortConstant (t, 0, loc);
  5713. case BuiltinTypeSpec.Type.UShort:
  5714. return new UShortConstant (t, 0, loc);
  5715. case BuiltinTypeSpec.Type.SByte:
  5716. return new SByteConstant (t, 0, loc);
  5717. case BuiltinTypeSpec.Type.Byte:
  5718. return new ByteConstant (t, 0, loc);
  5719. case BuiltinTypeSpec.Type.Char:
  5720. return new CharConstant (t, '\0', loc);
  5721. case BuiltinTypeSpec.Type.Bool:
  5722. return new BoolConstant (t, false, loc);
  5723. case BuiltinTypeSpec.Type.Decimal:
  5724. return new DecimalConstant (t, 0, loc);
  5725. }
  5726. if (t.IsEnum)
  5727. return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
  5728. if (t.IsNullableType)
  5729. return Nullable.LiftedNull.Create (t, loc);
  5730. return null;
  5731. }
  5732. public override bool ContainsEmitWithAwait ()
  5733. {
  5734. return arguments != null && arguments.ContainsEmitWithAwait ();
  5735. }
  5736. //
  5737. // Checks whether the type is an interface that has the
  5738. // [ComImport, CoClass] attributes and must be treated
  5739. // specially
  5740. //
  5741. public Expression CheckComImport (ResolveContext ec)
  5742. {
  5743. if (!type.IsInterface)
  5744. return null;
  5745. //
  5746. // Turn the call into:
  5747. // (the-interface-stated) (new class-referenced-in-coclassattribute ())
  5748. //
  5749. var real_class = type.MemberDefinition.GetAttributeCoClass ();
  5750. if (real_class == null)
  5751. return null;
  5752. New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
  5753. Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
  5754. return cast.Resolve (ec);
  5755. }
  5756. public override Expression CreateExpressionTree (ResolveContext ec)
  5757. {
  5758. Arguments args;
  5759. if (method == null) {
  5760. args = new Arguments (1);
  5761. args.Add (new Argument (new TypeOf (type, loc)));
  5762. } else {
  5763. args = Arguments.CreateForExpressionTree (ec,
  5764. arguments, new TypeOfMethod (method, loc));
  5765. }
  5766. return CreateExpressionFactoryCall (ec, "New", args);
  5767. }
  5768. protected override Expression DoResolve (ResolveContext ec)
  5769. {
  5770. type = RequestedType.ResolveAsType (ec);
  5771. if (type == null)
  5772. return null;
  5773. eclass = ExprClass.Value;
  5774. if (type.IsPointer) {
  5775. ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
  5776. type.GetSignatureForError ());
  5777. return null;
  5778. }
  5779. if (arguments == null) {
  5780. Constant c = Constantify (type, RequestedType.Location);
  5781. if (c != null)
  5782. return ReducedExpression.Create (c, this);
  5783. }
  5784. if (type.IsDelegate) {
  5785. return (new NewDelegate (type, arguments, loc)).Resolve (ec);
  5786. }
  5787. var tparam = type as TypeParameterSpec;
  5788. if (tparam != null) {
  5789. //
  5790. // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
  5791. // where type parameter constraint is inflated to struct
  5792. //
  5793. if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
  5794. ec.Report.Error (304, loc,
  5795. "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
  5796. type.GetSignatureForError ());
  5797. }
  5798. if ((arguments != null) && (arguments.Count != 0)) {
  5799. ec.Report.Error (417, loc,
  5800. "`{0}': cannot provide arguments when creating an instance of a variable type",
  5801. type.GetSignatureForError ());
  5802. }
  5803. return this;
  5804. }
  5805. if (type.IsStatic) {
  5806. ec.Report.SymbolRelatedToPreviousError (type);
  5807. ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
  5808. return null;
  5809. }
  5810. if (type.IsInterface || type.IsAbstract){
  5811. if (!TypeManager.IsGenericType (type)) {
  5812. RequestedType = CheckComImport (ec);
  5813. if (RequestedType != null)
  5814. return RequestedType;
  5815. }
  5816. ec.Report.SymbolRelatedToPreviousError (type);
  5817. ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
  5818. return null;
  5819. }
  5820. //
  5821. // Any struct always defines parameterless constructor
  5822. //
  5823. if (type.IsStruct && arguments == null)
  5824. return this;
  5825. bool dynamic;
  5826. if (arguments != null) {
  5827. arguments.Resolve (ec, out dynamic);
  5828. } else {
  5829. dynamic = false;
  5830. }
  5831. method = ConstructorLookup (ec, type, ref arguments, loc);
  5832. if (dynamic) {
  5833. arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
  5834. return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
  5835. }
  5836. return this;
  5837. }
  5838. bool DoEmitTypeParameter (EmitContext ec)
  5839. {
  5840. var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
  5841. if (m == null)
  5842. return true;
  5843. var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
  5844. var tparam = (TypeParameterSpec) type;
  5845. if (tparam.IsReferenceType) {
  5846. ec.Emit (OpCodes.Call, ctor_factory);
  5847. return true;
  5848. }
  5849. // Allow DoEmit() to be called multiple times.
  5850. // We need to create a new LocalTemporary each time since
  5851. // you can't share LocalBuilders among ILGeneators.
  5852. LocalTemporary temp = new LocalTemporary (type);
  5853. Label label_activator = ec.DefineLabel ();
  5854. Label label_end = ec.DefineLabel ();
  5855. temp.AddressOf (ec, AddressOp.Store);
  5856. ec.Emit (OpCodes.Initobj, type);
  5857. temp.Emit (ec);
  5858. ec.Emit (OpCodes.Box, type);
  5859. ec.Emit (OpCodes.Brfalse, label_activator);
  5860. temp.AddressOf (ec, AddressOp.Store);
  5861. ec.Emit (OpCodes.Initobj, type);
  5862. temp.Emit (ec);
  5863. temp.Release (ec);
  5864. ec.Emit (OpCodes.Br_S, label_end);
  5865. ec.MarkLabel (label_activator);
  5866. ec.Emit (OpCodes.Call, ctor_factory);
  5867. ec.MarkLabel (label_end);
  5868. return true;
  5869. }
  5870. //
  5871. // This Emit can be invoked in two contexts:
  5872. // * As a mechanism that will leave a value on the stack (new object)
  5873. // * As one that wont (init struct)
  5874. //
  5875. // If we are dealing with a ValueType, we have a few
  5876. // situations to deal with:
  5877. //
  5878. // * The target is a ValueType, and we have been provided
  5879. // the instance (this is easy, we are being assigned).
  5880. //
  5881. // * The target of New is being passed as an argument,
  5882. // to a boxing operation or a function that takes a
  5883. // ValueType.
  5884. //
  5885. // In this case, we need to create a temporary variable
  5886. // that is the argument of New.
  5887. //
  5888. // Returns whether a value is left on the stack
  5889. //
  5890. // *** Implementation note ***
  5891. //
  5892. // To benefit from this optimization, each assignable expression
  5893. // has to manually cast to New and call this Emit.
  5894. //
  5895. // TODO: It's worth to implement it for arrays and fields
  5896. //
  5897. public virtual bool Emit (EmitContext ec, IMemoryLocation target)
  5898. {
  5899. bool is_value_type = TypeSpec.IsValueType (type);
  5900. VariableReference vr = target as VariableReference;
  5901. if (target != null && is_value_type && (vr != null || method == null)) {
  5902. target.AddressOf (ec, AddressOp.Store);
  5903. } else if (vr != null && vr.IsRef) {
  5904. vr.EmitLoad (ec);
  5905. }
  5906. if (arguments != null) {
  5907. if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
  5908. arguments = arguments.Emit (ec, false, true);
  5909. arguments.Emit (ec);
  5910. }
  5911. if (is_value_type) {
  5912. if (method == null) {
  5913. ec.Emit (OpCodes.Initobj, type);
  5914. return false;
  5915. }
  5916. if (vr != null) {
  5917. ec.MarkCallEntry (loc);
  5918. ec.Emit (OpCodes.Call, method);
  5919. return false;
  5920. }
  5921. }
  5922. if (type is TypeParameterSpec)
  5923. return DoEmitTypeParameter (ec);
  5924. ec.MarkCallEntry (loc);
  5925. ec.Emit (OpCodes.Newobj, method);
  5926. return true;
  5927. }
  5928. public override void Emit (EmitContext ec)
  5929. {
  5930. LocalTemporary v = null;
  5931. if (method == null && TypeSpec.IsValueType (type)) {
  5932. // TODO: Use temporary variable from pool
  5933. v = new LocalTemporary (type);
  5934. }
  5935. if (!Emit (ec, v))
  5936. v.Emit (ec);
  5937. }
  5938. public override void EmitStatement (EmitContext ec)
  5939. {
  5940. LocalTemporary v = null;
  5941. if (method == null && TypeSpec.IsValueType (type)) {
  5942. // TODO: Use temporary variable from pool
  5943. v = new LocalTemporary (type);
  5944. }
  5945. if (Emit (ec, v))
  5946. ec.Emit (OpCodes.Pop);
  5947. }
  5948. public override void FlowAnalysis (FlowAnalysisContext fc)
  5949. {
  5950. if (arguments != null)
  5951. arguments.FlowAnalysis (fc);
  5952. }
  5953. public void AddressOf (EmitContext ec, AddressOp mode)
  5954. {
  5955. EmitAddressOf (ec, mode);
  5956. }
  5957. protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
  5958. {
  5959. LocalTemporary value_target = new LocalTemporary (type);
  5960. if (type is TypeParameterSpec) {
  5961. DoEmitTypeParameter (ec);
  5962. value_target.Store (ec);
  5963. value_target.AddressOf (ec, mode);
  5964. return value_target;
  5965. }
  5966. value_target.AddressOf (ec, AddressOp.Store);
  5967. if (method == null) {
  5968. ec.Emit (OpCodes.Initobj, type);
  5969. } else {
  5970. if (arguments != null)
  5971. arguments.Emit (ec);
  5972. ec.Emit (OpCodes.Call, method);
  5973. }
  5974. value_target.AddressOf (ec, mode);
  5975. return value_target;
  5976. }
  5977. protected override void CloneTo (CloneContext clonectx, Expression t)
  5978. {
  5979. New target = (New) t;
  5980. target.RequestedType = RequestedType.Clone (clonectx);
  5981. if (arguments != null){
  5982. target.arguments = arguments.Clone (clonectx);
  5983. }
  5984. }
  5985. public override SLE.Expression MakeExpression (BuilderContext ctx)
  5986. {
  5987. #if STATIC
  5988. return base.MakeExpression (ctx);
  5989. #else
  5990. return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
  5991. #endif
  5992. }
  5993. public override object Accept (StructuralVisitor visitor)
  5994. {
  5995. return visitor.Visit (this);
  5996. }
  5997. }
  5998. //
  5999. // Array initializer expression, the expression is allowed in
  6000. // variable or field initialization only which makes it tricky as
  6001. // the type has to be infered based on the context either from field
  6002. // type or variable type (think of multiple declarators)
  6003. //
  6004. public class ArrayInitializer : Expression
  6005. {
  6006. List<Expression> elements;
  6007. BlockVariable variable;
  6008. public ArrayInitializer (List<Expression> init, Location loc)
  6009. {
  6010. elements = init;
  6011. this.loc = loc;
  6012. }
  6013. public ArrayInitializer (int count, Location loc)
  6014. : this (new List<Expression> (count), loc)
  6015. {
  6016. }
  6017. public ArrayInitializer (Location loc)
  6018. : this (4, loc)
  6019. {
  6020. }
  6021. #region Properties
  6022. public int Count {
  6023. get { return elements.Count; }
  6024. }
  6025. public List<Expression> Elements {
  6026. get {
  6027. return elements;
  6028. }
  6029. }
  6030. public Expression this [int index] {
  6031. get {
  6032. return elements [index];
  6033. }
  6034. }
  6035. public BlockVariable VariableDeclaration {
  6036. get {
  6037. return variable;
  6038. }
  6039. set {
  6040. variable = value;
  6041. }
  6042. }
  6043. #endregion
  6044. public void Add (Expression expr)
  6045. {
  6046. elements.Add (expr);
  6047. }
  6048. public override bool ContainsEmitWithAwait ()
  6049. {
  6050. throw new NotSupportedException ();
  6051. }
  6052. public override Expression CreateExpressionTree (ResolveContext ec)
  6053. {
  6054. throw new NotSupportedException ("ET");
  6055. }
  6056. protected override void CloneTo (CloneContext clonectx, Expression t)
  6057. {
  6058. var target = (ArrayInitializer) t;
  6059. target.elements = new List<Expression> (elements.Count);
  6060. foreach (var element in elements)
  6061. target.elements.Add (element.Clone (clonectx));
  6062. }
  6063. protected override Expression DoResolve (ResolveContext rc)
  6064. {
  6065. var current_field = rc.CurrentMemberDefinition as FieldBase;
  6066. TypeExpression type;
  6067. if (current_field != null && rc.CurrentAnonymousMethod == null) {
  6068. type = new TypeExpression (current_field.MemberType, current_field.Location);
  6069. } else if (variable != null) {
  6070. if (variable.TypeExpression is VarExpr) {
  6071. rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
  6072. return EmptyExpression.Null;
  6073. }
  6074. type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
  6075. } else {
  6076. throw new NotImplementedException ("Unexpected array initializer context");
  6077. }
  6078. return new ArrayCreation (type, this).Resolve (rc);
  6079. }
  6080. public override void Emit (EmitContext ec)
  6081. {
  6082. throw new InternalErrorException ("Missing Resolve call");
  6083. }
  6084. public override void FlowAnalysis (FlowAnalysisContext fc)
  6085. {
  6086. throw new InternalErrorException ("Missing Resolve call");
  6087. }
  6088. public override object Accept (StructuralVisitor visitor)
  6089. {
  6090. return visitor.Visit (this);
  6091. }
  6092. }
  6093. /// <summary>
  6094. /// 14.5.10.2: Represents an array creation expression.
  6095. /// </summary>
  6096. ///
  6097. /// <remarks>
  6098. /// There are two possible scenarios here: one is an array creation
  6099. /// expression that specifies the dimensions and optionally the
  6100. /// initialization data and the other which does not need dimensions
  6101. /// specified but where initialization data is mandatory.
  6102. /// </remarks>
  6103. public class ArrayCreation : Expression
  6104. {
  6105. FullNamedExpression requested_base_type;
  6106. ArrayInitializer initializers;
  6107. //
  6108. // The list of Argument types.
  6109. // This is used to construct the `newarray' or constructor signature
  6110. //
  6111. protected List<Expression> arguments;
  6112. protected TypeSpec array_element_type;
  6113. int num_arguments;
  6114. protected int dimensions;
  6115. protected readonly ComposedTypeSpecifier rank;
  6116. Expression first_emit;
  6117. LocalTemporary first_emit_temp;
  6118. protected List<Expression> array_data;
  6119. Dictionary<int, int> bounds;
  6120. #if STATIC
  6121. // The number of constants in array initializers
  6122. int const_initializers_count;
  6123. bool only_constant_initializers;
  6124. #endif
  6125. public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
  6126. : this (requested_base_type, rank, initializers, l)
  6127. {
  6128. arguments = exprs;
  6129. num_arguments = arguments.Count;
  6130. }
  6131. //
  6132. // For expressions like int[] foo = new int[] { 1, 2, 3 };
  6133. //
  6134. public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
  6135. {
  6136. this.requested_base_type = requested_base_type;
  6137. this.rank = rank;
  6138. this.initializers = initializers;
  6139. this.loc = loc;
  6140. if (rank != null)
  6141. num_arguments = rank.Dimension;
  6142. }
  6143. //
  6144. // For compiler generated single dimensional arrays only
  6145. //
  6146. public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
  6147. : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
  6148. {
  6149. }
  6150. //
  6151. // For expressions like int[] foo = { 1, 2, 3 };
  6152. //
  6153. public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
  6154. : this (requested_base_type, null, initializers, initializers.Location)
  6155. {
  6156. }
  6157. public ComposedTypeSpecifier Rank {
  6158. get {
  6159. return this.rank;
  6160. }
  6161. }
  6162. public FullNamedExpression TypeExpression {
  6163. get {
  6164. return this.requested_base_type;
  6165. }
  6166. }
  6167. public ArrayInitializer Initializers {
  6168. get {
  6169. return this.initializers;
  6170. }
  6171. }
  6172. public List<Expression> Arguments {
  6173. get { return this.arguments; }
  6174. }
  6175. bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
  6176. {
  6177. if (initializers != null && bounds == null) {
  6178. //
  6179. // We use this to store all the data values in the order in which we
  6180. // will need to store them in the byte blob later
  6181. //
  6182. array_data = new List<Expression> (probe.Count);
  6183. bounds = new Dictionary<int, int> ();
  6184. }
  6185. if (specified_dims) {
  6186. Expression a = arguments [idx];
  6187. a = a.Resolve (ec);
  6188. if (a == null)
  6189. return false;
  6190. a = ConvertExpressionToArrayIndex (ec, a);
  6191. if (a == null)
  6192. return false;
  6193. arguments[idx] = a;
  6194. if (initializers != null) {
  6195. Constant c = a as Constant;
  6196. if (c == null && a is ArrayIndexCast)
  6197. c = ((ArrayIndexCast) a).Child as Constant;
  6198. if (c == null) {
  6199. ec.Report.Error (150, a.Location, "A constant value is expected");
  6200. return false;
  6201. }
  6202. int value;
  6203. try {
  6204. value = System.Convert.ToInt32 (c.GetValue ());
  6205. } catch {
  6206. ec.Report.Error (150, a.Location, "A constant value is expected");
  6207. return false;
  6208. }
  6209. // TODO: probe.Count does not fit ulong in
  6210. if (value != probe.Count) {
  6211. ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
  6212. return false;
  6213. }
  6214. bounds[idx] = value;
  6215. }
  6216. }
  6217. if (initializers == null)
  6218. return true;
  6219. for (int i = 0; i < probe.Count; ++i) {
  6220. var o = probe [i];
  6221. if (o is ArrayInitializer) {
  6222. var sub_probe = o as ArrayInitializer;
  6223. if (idx + 1 >= dimensions){
  6224. ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
  6225. return false;
  6226. }
  6227. // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
  6228. if (!bounds.ContainsKey(idx + 1))
  6229. bounds[idx + 1] = sub_probe.Count;
  6230. if (bounds[idx + 1] != sub_probe.Count) {
  6231. ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
  6232. return false;
  6233. }
  6234. bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
  6235. if (!ret)
  6236. return false;
  6237. } else if (child_bounds > 1) {
  6238. ec.Report.Error (846, o.Location, "A nested array initializer was expected");
  6239. } else {
  6240. Expression element = ResolveArrayElement (ec, o);
  6241. if (element == null)
  6242. continue;
  6243. #if STATIC
  6244. // Initializers with the default values can be ignored
  6245. Constant c = element as Constant;
  6246. if (c != null) {
  6247. if (!c.IsDefaultInitializer (array_element_type)) {
  6248. ++const_initializers_count;
  6249. }
  6250. } else {
  6251. only_constant_initializers = false;
  6252. }
  6253. #endif
  6254. array_data.Add (element);
  6255. }
  6256. }
  6257. return true;
  6258. }
  6259. public override bool ContainsEmitWithAwait ()
  6260. {
  6261. foreach (var arg in arguments) {
  6262. if (arg.ContainsEmitWithAwait ())
  6263. return true;
  6264. }
  6265. return InitializersContainAwait ();
  6266. }
  6267. public override Expression CreateExpressionTree (ResolveContext ec)
  6268. {
  6269. Arguments args;
  6270. if (array_data == null) {
  6271. args = new Arguments (arguments.Count + 1);
  6272. args.Add (new Argument (new TypeOf (array_element_type, loc)));
  6273. foreach (Expression a in arguments)
  6274. args.Add (new Argument (a.CreateExpressionTree (ec)));
  6275. return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
  6276. }
  6277. if (dimensions > 1) {
  6278. ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
  6279. return null;
  6280. }
  6281. args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
  6282. args.Add (new Argument (new TypeOf (array_element_type, loc)));
  6283. if (array_data != null) {
  6284. for (int i = 0; i < array_data.Count; ++i) {
  6285. Expression e = array_data [i];
  6286. args.Add (new Argument (e.CreateExpressionTree (ec)));
  6287. }
  6288. }
  6289. return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
  6290. }
  6291. void UpdateIndices (ResolveContext rc)
  6292. {
  6293. int i = 0;
  6294. for (var probe = initializers; probe != null;) {
  6295. Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
  6296. arguments.Add (e);
  6297. bounds[i++] = probe.Count;
  6298. if (probe.Count > 0 && probe [0] is ArrayInitializer) {
  6299. probe = (ArrayInitializer) probe[0];
  6300. } else if (dimensions > i) {
  6301. continue;
  6302. } else {
  6303. return;
  6304. }
  6305. }
  6306. }
  6307. protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
  6308. {
  6309. ec.Report.Error (248, loc, "Cannot create an array with a negative size");
  6310. }
  6311. public override void FlowAnalysis (FlowAnalysisContext fc)
  6312. {
  6313. foreach (var arg in arguments)
  6314. arg.FlowAnalysis (fc);
  6315. if (array_data != null) {
  6316. foreach (var ad in array_data)
  6317. ad.FlowAnalysis (fc);
  6318. }
  6319. }
  6320. bool InitializersContainAwait ()
  6321. {
  6322. if (array_data == null)
  6323. return false;
  6324. foreach (var expr in array_data) {
  6325. if (expr.ContainsEmitWithAwait ())
  6326. return true;
  6327. }
  6328. return false;
  6329. }
  6330. protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
  6331. {
  6332. element = element.Resolve (ec);
  6333. if (element == null)
  6334. return null;
  6335. if (element is CompoundAssign.TargetExpression) {
  6336. if (first_emit != null)
  6337. throw new InternalErrorException ("Can only handle one mutator at a time");
  6338. first_emit = element;
  6339. element = first_emit_temp = new LocalTemporary (element.Type);
  6340. }
  6341. return Convert.ImplicitConversionRequired (
  6342. ec, element, array_element_type, loc);
  6343. }
  6344. protected bool ResolveInitializers (ResolveContext ec)
  6345. {
  6346. #if STATIC
  6347. only_constant_initializers = true;
  6348. #endif
  6349. if (arguments != null) {
  6350. bool res = true;
  6351. for (int i = 0; i < arguments.Count; ++i) {
  6352. res &= CheckIndices (ec, initializers, i, true, dimensions);
  6353. if (initializers != null)
  6354. break;
  6355. }
  6356. return res;
  6357. }
  6358. arguments = new List<Expression> ();
  6359. if (!CheckIndices (ec, initializers, 0, false, dimensions))
  6360. return false;
  6361. UpdateIndices (ec);
  6362. return true;
  6363. }
  6364. //
  6365. // Resolved the type of the array
  6366. //
  6367. bool ResolveArrayType (ResolveContext ec)
  6368. {
  6369. //
  6370. // Lookup the type
  6371. //
  6372. FullNamedExpression array_type_expr;
  6373. if (num_arguments > 0) {
  6374. array_type_expr = new ComposedCast (requested_base_type, rank);
  6375. } else {
  6376. array_type_expr = requested_base_type;
  6377. }
  6378. type = array_type_expr.ResolveAsType (ec);
  6379. if (array_type_expr == null)
  6380. return false;
  6381. var ac = type as ArrayContainer;
  6382. if (ac == null) {
  6383. ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
  6384. return false;
  6385. }
  6386. array_element_type = ac.Element;
  6387. dimensions = ac.Rank;
  6388. return true;
  6389. }
  6390. protected override Expression DoResolve (ResolveContext ec)
  6391. {
  6392. if (type != null)
  6393. return this;
  6394. if (!ResolveArrayType (ec))
  6395. return null;
  6396. //
  6397. // validate the initializers and fill in any missing bits
  6398. //
  6399. if (!ResolveInitializers (ec))
  6400. return null;
  6401. eclass = ExprClass.Value;
  6402. return this;
  6403. }
  6404. byte [] MakeByteBlob ()
  6405. {
  6406. int factor;
  6407. byte [] data;
  6408. byte [] element;
  6409. int count = array_data.Count;
  6410. TypeSpec element_type = array_element_type;
  6411. if (element_type.IsEnum)
  6412. element_type = EnumSpec.GetUnderlyingType (element_type);
  6413. factor = BuiltinTypeSpec.GetSize (element_type);
  6414. if (factor == 0)
  6415. throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
  6416. data = new byte [(count * factor + 3) & ~3];
  6417. int idx = 0;
  6418. for (int i = 0; i < count; ++i) {
  6419. var c = array_data[i] as Constant;
  6420. if (c == null) {
  6421. idx += factor;
  6422. continue;
  6423. }
  6424. object v = c.GetValue ();
  6425. switch (element_type.BuiltinType) {
  6426. case BuiltinTypeSpec.Type.Long:
  6427. long lval = (long) v;
  6428. for (int j = 0; j < factor; ++j) {
  6429. data[idx + j] = (byte) (lval & 0xFF);
  6430. lval = (lval >> 8);
  6431. }
  6432. break;
  6433. case BuiltinTypeSpec.Type.ULong:
  6434. ulong ulval = (ulong) v;
  6435. for (int j = 0; j < factor; ++j) {
  6436. data[idx + j] = (byte) (ulval & 0xFF);
  6437. ulval = (ulval >> 8);
  6438. }
  6439. break;
  6440. case BuiltinTypeSpec.Type.Float:
  6441. var fval = SingleConverter.SingleToInt32Bits((float) v);
  6442. data[idx] = (byte) (fval & 0xff);
  6443. data[idx + 1] = (byte) ((fval >> 8) & 0xff);
  6444. data[idx + 2] = (byte) ((fval >> 16) & 0xff);
  6445. data[idx + 3] = (byte) (fval >> 24);
  6446. break;
  6447. case BuiltinTypeSpec.Type.Double:
  6448. element = BitConverter.GetBytes ((double) v);
  6449. for (int j = 0; j < factor; ++j)
  6450. data[idx + j] = element[j];
  6451. // FIXME: Handle the ARM float format.
  6452. if (!BitConverter.IsLittleEndian)
  6453. System.Array.Reverse (data, idx, 8);
  6454. break;
  6455. case BuiltinTypeSpec.Type.Char:
  6456. int chval = (int) ((char) v);
  6457. data[idx] = (byte) (chval & 0xff);
  6458. data[idx + 1] = (byte) (chval >> 8);
  6459. break;
  6460. case BuiltinTypeSpec.Type.Short:
  6461. int sval = (int) ((short) v);
  6462. data[idx] = (byte) (sval & 0xff);
  6463. data[idx + 1] = (byte) (sval >> 8);
  6464. break;
  6465. case BuiltinTypeSpec.Type.UShort:
  6466. int usval = (int) ((ushort) v);
  6467. data[idx] = (byte) (usval & 0xff);
  6468. data[idx + 1] = (byte) (usval >> 8);
  6469. break;
  6470. case BuiltinTypeSpec.Type.Int:
  6471. int val = (int) v;
  6472. data[idx] = (byte) (val & 0xff);
  6473. data[idx + 1] = (byte) ((val >> 8) & 0xff);
  6474. data[idx + 2] = (byte) ((val >> 16) & 0xff);
  6475. data[idx + 3] = (byte) (val >> 24);
  6476. break;
  6477. case BuiltinTypeSpec.Type.UInt:
  6478. uint uval = (uint) v;
  6479. data[idx] = (byte) (uval & 0xff);
  6480. data[idx + 1] = (byte) ((uval >> 8) & 0xff);
  6481. data[idx + 2] = (byte) ((uval >> 16) & 0xff);
  6482. data[idx + 3] = (byte) (uval >> 24);
  6483. break;
  6484. case BuiltinTypeSpec.Type.SByte:
  6485. data[idx] = (byte) (sbyte) v;
  6486. break;
  6487. case BuiltinTypeSpec.Type.Byte:
  6488. data[idx] = (byte) v;
  6489. break;
  6490. case BuiltinTypeSpec.Type.Bool:
  6491. data[idx] = (byte) ((bool) v ? 1 : 0);
  6492. break;
  6493. case BuiltinTypeSpec.Type.Decimal:
  6494. int[] bits = Decimal.GetBits ((decimal) v);
  6495. int p = idx;
  6496. // FIXME: For some reason, this doesn't work on the MS runtime.
  6497. int[] nbits = new int[4];
  6498. nbits[0] = bits[3];
  6499. nbits[1] = bits[2];
  6500. nbits[2] = bits[0];
  6501. nbits[3] = bits[1];
  6502. for (int j = 0; j < 4; j++) {
  6503. data[p++] = (byte) (nbits[j] & 0xff);
  6504. data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
  6505. data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
  6506. data[p++] = (byte) (nbits[j] >> 24);
  6507. }
  6508. break;
  6509. default:
  6510. throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
  6511. }
  6512. idx += factor;
  6513. }
  6514. return data;
  6515. }
  6516. #if NET_4_0 || MOBILE_DYNAMIC
  6517. public override SLE.Expression MakeExpression (BuilderContext ctx)
  6518. {
  6519. #if STATIC
  6520. return base.MakeExpression (ctx);
  6521. #else
  6522. var initializers = new SLE.Expression [array_data.Count];
  6523. for (var i = 0; i < initializers.Length; i++) {
  6524. if (array_data [i] == null)
  6525. initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
  6526. else
  6527. initializers [i] = array_data [i].MakeExpression (ctx);
  6528. }
  6529. return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
  6530. #endif
  6531. }
  6532. #endif
  6533. #if STATIC
  6534. //
  6535. // Emits the initializers for the array
  6536. //
  6537. void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
  6538. {
  6539. var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
  6540. if (m == null)
  6541. return;
  6542. //
  6543. // First, the static data
  6544. //
  6545. byte [] data = MakeByteBlob ();
  6546. var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
  6547. if (stackArray == null) {
  6548. ec.Emit (OpCodes.Dup);
  6549. } else {
  6550. stackArray.Emit (ec);
  6551. }
  6552. ec.Emit (OpCodes.Ldtoken, fb);
  6553. ec.Emit (OpCodes.Call, m);
  6554. }
  6555. #endif
  6556. //
  6557. // Emits pieces of the array that can not be computed at compile
  6558. // time (variables and string locations).
  6559. //
  6560. // This always expect the top value on the stack to be the array
  6561. //
  6562. void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
  6563. {
  6564. int dims = bounds.Count;
  6565. var current_pos = new int [dims];
  6566. for (int i = 0; i < array_data.Count; i++){
  6567. Expression e = array_data [i];
  6568. var c = e as Constant;
  6569. // Constant can be initialized via StaticInitializer
  6570. if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
  6571. var etype = e.Type;
  6572. if (stackArray != null) {
  6573. if (e.ContainsEmitWithAwait ()) {
  6574. e = e.EmitToField (ec);
  6575. }
  6576. stackArray.EmitLoad (ec);
  6577. } else {
  6578. ec.Emit (OpCodes.Dup);
  6579. }
  6580. for (int idx = 0; idx < dims; idx++)
  6581. ec.EmitInt (current_pos [idx]);
  6582. //
  6583. // If we are dealing with a struct, get the
  6584. // address of it, so we can store it.
  6585. //
  6586. if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
  6587. ec.Emit (OpCodes.Ldelema, etype);
  6588. e.Emit (ec);
  6589. ec.EmitArrayStore ((ArrayContainer) type);
  6590. }
  6591. //
  6592. // Advance counter
  6593. //
  6594. for (int j = dims - 1; j >= 0; j--){
  6595. current_pos [j]++;
  6596. if (current_pos [j] < bounds [j])
  6597. break;
  6598. current_pos [j] = 0;
  6599. }
  6600. }
  6601. if (stackArray != null)
  6602. stackArray.PrepareCleanup (ec);
  6603. }
  6604. public override void Emit (EmitContext ec)
  6605. {
  6606. var await_field = EmitToFieldSource (ec);
  6607. if (await_field != null)
  6608. await_field.Emit (ec);
  6609. }
  6610. protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
  6611. {
  6612. if (first_emit != null) {
  6613. first_emit.Emit (ec);
  6614. first_emit_temp.Store (ec);
  6615. }
  6616. StackFieldExpr await_stack_field;
  6617. if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
  6618. await_stack_field = ec.GetTemporaryField (type);
  6619. ec.EmitThis ();
  6620. } else {
  6621. await_stack_field = null;
  6622. }
  6623. EmitExpressionsList (ec, arguments);
  6624. ec.EmitArrayNew ((ArrayContainer) type);
  6625. if (initializers == null)
  6626. return await_stack_field;
  6627. if (await_stack_field != null)
  6628. await_stack_field.EmitAssignFromStack (ec);
  6629. #if STATIC
  6630. //
  6631. // Emit static initializer for arrays which contain more than 2 items and
  6632. // the static initializer will initialize at least 25% of array values or there
  6633. // is more than 10 items to be initialized
  6634. //
  6635. // NOTE: const_initializers_count does not contain default constant values.
  6636. //
  6637. if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
  6638. (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
  6639. EmitStaticInitializers (ec, await_stack_field);
  6640. if (!only_constant_initializers)
  6641. EmitDynamicInitializers (ec, false, await_stack_field);
  6642. } else
  6643. #endif
  6644. {
  6645. EmitDynamicInitializers (ec, true, await_stack_field);
  6646. }
  6647. if (first_emit_temp != null)
  6648. first_emit_temp.Release (ec);
  6649. return await_stack_field;
  6650. }
  6651. public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
  6652. {
  6653. // no multi dimensional or jagged arrays
  6654. if (arguments.Count != 1 || array_element_type.IsArray) {
  6655. base.EncodeAttributeValue (rc, enc, targetType, parameterType);
  6656. return;
  6657. }
  6658. // No array covariance, except for array -> object
  6659. if (type != targetType) {
  6660. if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
  6661. base.EncodeAttributeValue (rc, enc, targetType, parameterType);
  6662. return;
  6663. }
  6664. if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
  6665. Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
  6666. return;
  6667. }
  6668. }
  6669. // Single dimensional array of 0 size
  6670. if (array_data == null) {
  6671. IntConstant ic = arguments[0] as IntConstant;
  6672. if (ic == null || !ic.IsDefaultValue) {
  6673. base.EncodeAttributeValue (rc, enc, targetType, parameterType);
  6674. } else {
  6675. enc.Encode (0);
  6676. }
  6677. return;
  6678. }
  6679. enc.Encode (array_data.Count);
  6680. foreach (var element in array_data) {
  6681. element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
  6682. }
  6683. }
  6684. protected override void CloneTo (CloneContext clonectx, Expression t)
  6685. {
  6686. ArrayCreation target = (ArrayCreation) t;
  6687. if (requested_base_type != null)
  6688. target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
  6689. if (arguments != null){
  6690. target.arguments = new List<Expression> (arguments.Count);
  6691. foreach (Expression e in arguments)
  6692. target.arguments.Add (e.Clone (clonectx));
  6693. }
  6694. if (initializers != null)
  6695. target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
  6696. }
  6697. public override object Accept (StructuralVisitor visitor)
  6698. {
  6699. return visitor.Visit (this);
  6700. }
  6701. }
  6702. //
  6703. // Represents an implicitly typed array epxression
  6704. //
  6705. class ImplicitlyTypedArrayCreation : ArrayCreation
  6706. {
  6707. TypeInferenceContext best_type_inference;
  6708. public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
  6709. : base (null, rank, initializers, loc)
  6710. {
  6711. }
  6712. public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
  6713. : base (null, initializers, loc)
  6714. {
  6715. }
  6716. protected override Expression DoResolve (ResolveContext ec)
  6717. {
  6718. if (type != null)
  6719. return this;
  6720. dimensions = rank.Dimension;
  6721. best_type_inference = new TypeInferenceContext ();
  6722. if (!ResolveInitializers (ec))
  6723. return null;
  6724. best_type_inference.FixAllTypes (ec);
  6725. array_element_type = best_type_inference.InferredTypeArguments[0];
  6726. best_type_inference = null;
  6727. if (array_element_type == null ||
  6728. array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
  6729. arguments.Count != rank.Dimension) {
  6730. ec.Report.Error (826, loc,
  6731. "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
  6732. return null;
  6733. }
  6734. //
  6735. // At this point we found common base type for all initializer elements
  6736. // but we have to be sure that all static initializer elements are of
  6737. // same type
  6738. //
  6739. UnifyInitializerElement (ec);
  6740. type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
  6741. eclass = ExprClass.Value;
  6742. return this;
  6743. }
  6744. //
  6745. // Converts static initializer only
  6746. //
  6747. void UnifyInitializerElement (ResolveContext ec)
  6748. {
  6749. for (int i = 0; i < array_data.Count; ++i) {
  6750. Expression e = array_data[i];
  6751. if (e != null)
  6752. array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
  6753. }
  6754. }
  6755. protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
  6756. {
  6757. element = element.Resolve (ec);
  6758. if (element != null)
  6759. best_type_inference.AddCommonTypeBound (element.Type);
  6760. return element;
  6761. }
  6762. }
  6763. sealed class CompilerGeneratedThis : This
  6764. {
  6765. public CompilerGeneratedThis (TypeSpec type, Location loc)
  6766. : base (loc)
  6767. {
  6768. this.type = type;
  6769. }
  6770. protected override Expression DoResolve (ResolveContext rc)
  6771. {
  6772. eclass = ExprClass.Variable;
  6773. var block = rc.CurrentBlock;
  6774. if (block != null) {
  6775. var top = block.ParametersBlock.TopBlock;
  6776. if (top.ThisVariable != null)
  6777. variable_info = top.ThisVariable.VariableInfo;
  6778. }
  6779. return this;
  6780. }
  6781. public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
  6782. {
  6783. return DoResolve (rc);
  6784. }
  6785. public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
  6786. {
  6787. return null;
  6788. }
  6789. }
  6790. /// <summary>
  6791. /// Represents the `this' construct
  6792. /// </summary>
  6793. public class This : VariableReference
  6794. {
  6795. sealed class ThisVariable : ILocalVariable
  6796. {
  6797. public static readonly ILocalVariable Instance = new ThisVariable ();
  6798. public void Emit (EmitContext ec)
  6799. {
  6800. ec.EmitThis ();
  6801. }
  6802. public void EmitAssign (EmitContext ec)
  6803. {
  6804. throw new InvalidOperationException ();
  6805. }
  6806. public void EmitAddressOf (EmitContext ec)
  6807. {
  6808. ec.EmitThis ();
  6809. }
  6810. }
  6811. protected VariableInfo variable_info;
  6812. public This (Location loc)
  6813. {
  6814. this.loc = loc;
  6815. }
  6816. #region Properties
  6817. public override string Name {
  6818. get { return "this"; }
  6819. }
  6820. public override bool IsLockedByStatement {
  6821. get {
  6822. return false;
  6823. }
  6824. set {
  6825. }
  6826. }
  6827. public override bool IsRef {
  6828. get { return type.IsStruct; }
  6829. }
  6830. public override bool IsSideEffectFree {
  6831. get {
  6832. return true;
  6833. }
  6834. }
  6835. protected override ILocalVariable Variable {
  6836. get { return ThisVariable.Instance; }
  6837. }
  6838. public override VariableInfo VariableInfo {
  6839. get { return variable_info; }
  6840. }
  6841. public override bool IsFixed {
  6842. get { return false; }
  6843. }
  6844. #endregion
  6845. void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
  6846. {
  6847. //
  6848. // It's null for all cases when we don't need to check `this'
  6849. // definitive assignment
  6850. //
  6851. if (variable_info == null)
  6852. return;
  6853. if (fc.IsDefinitelyAssigned (variable_info))
  6854. return;
  6855. fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
  6856. }
  6857. protected virtual void Error_ThisNotAvailable (ResolveContext ec)
  6858. {
  6859. if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
  6860. ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
  6861. } else if (ec.CurrentAnonymousMethod != null) {
  6862. ec.Report.Error (1673, loc,
  6863. "Anonymous methods inside structs cannot access instance members of `this'. " +
  6864. "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
  6865. } else {
  6866. ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
  6867. }
  6868. }
  6869. public override void FlowAnalysis (FlowAnalysisContext fc)
  6870. {
  6871. CheckStructThisDefiniteAssignment (fc);
  6872. }
  6873. public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
  6874. {
  6875. if (ae == null)
  6876. return null;
  6877. AnonymousMethodStorey storey = ae.Storey;
  6878. return storey != null ? storey.HoistedThis : null;
  6879. }
  6880. public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
  6881. {
  6882. if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
  6883. return false;
  6884. if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
  6885. return true;
  6886. if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
  6887. return false;
  6888. return true;
  6889. }
  6890. public virtual void ResolveBase (ResolveContext ec)
  6891. {
  6892. eclass = ExprClass.Variable;
  6893. type = ec.CurrentType;
  6894. if (!IsThisAvailable (ec, false)) {
  6895. Error_ThisNotAvailable (ec);
  6896. return;
  6897. }
  6898. var block = ec.CurrentBlock;
  6899. if (block != null) {
  6900. var top = block.ParametersBlock.TopBlock;
  6901. if (top.ThisVariable != null)
  6902. variable_info = top.ThisVariable.VariableInfo;
  6903. AnonymousExpression am = ec.CurrentAnonymousMethod;
  6904. if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
  6905. //
  6906. // Hoisted this is almost like hoisted variable but not exactly. When
  6907. // there is no variable hoisted we can simply emit an instance method
  6908. // without lifting this into a storey. Unfotunatelly this complicates
  6909. // things in other cases because we don't know where this will be hoisted
  6910. // until top-level block is fully resolved
  6911. //
  6912. top.AddThisReferenceFromChildrenBlock (block.Explicit);
  6913. am.SetHasThisAccess ();
  6914. }
  6915. }
  6916. }
  6917. protected override Expression DoResolve (ResolveContext ec)
  6918. {
  6919. ResolveBase (ec);
  6920. return this;
  6921. }
  6922. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  6923. {
  6924. if (eclass == ExprClass.Unresolved)
  6925. ResolveBase (ec);
  6926. if (type.IsClass){
  6927. if (right_side == EmptyExpression.UnaryAddress)
  6928. ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
  6929. else if (right_side == EmptyExpression.OutAccess)
  6930. ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
  6931. else
  6932. ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
  6933. }
  6934. return this;
  6935. }
  6936. public override int GetHashCode()
  6937. {
  6938. throw new NotImplementedException ();
  6939. }
  6940. public override bool Equals (object obj)
  6941. {
  6942. This t = obj as This;
  6943. if (t == null)
  6944. return false;
  6945. return true;
  6946. }
  6947. protected override void CloneTo (CloneContext clonectx, Expression t)
  6948. {
  6949. // Nothing
  6950. }
  6951. public override void SetHasAddressTaken ()
  6952. {
  6953. // Nothing
  6954. }
  6955. public override object Accept (StructuralVisitor visitor)
  6956. {
  6957. return visitor.Visit (this);
  6958. }
  6959. }
  6960. /// <summary>
  6961. /// Represents the `__arglist' construct
  6962. /// </summary>
  6963. public class ArglistAccess : Expression
  6964. {
  6965. public ArglistAccess (Location loc)
  6966. {
  6967. this.loc = loc;
  6968. }
  6969. protected override void CloneTo (CloneContext clonectx, Expression target)
  6970. {
  6971. // nothing.
  6972. }
  6973. public override bool ContainsEmitWithAwait ()
  6974. {
  6975. return false;
  6976. }
  6977. public override Expression CreateExpressionTree (ResolveContext ec)
  6978. {
  6979. throw new NotSupportedException ("ET");
  6980. }
  6981. protected override Expression DoResolve (ResolveContext ec)
  6982. {
  6983. eclass = ExprClass.Variable;
  6984. type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
  6985. if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
  6986. ec.Report.Error (190, loc,
  6987. "The __arglist construct is valid only within a variable argument method");
  6988. }
  6989. return this;
  6990. }
  6991. public override void Emit (EmitContext ec)
  6992. {
  6993. ec.Emit (OpCodes.Arglist);
  6994. }
  6995. public override object Accept (StructuralVisitor visitor)
  6996. {
  6997. return visitor.Visit (this);
  6998. }
  6999. }
  7000. /// <summary>
  7001. /// Represents the `__arglist (....)' construct
  7002. /// </summary>
  7003. public class Arglist : Expression
  7004. {
  7005. Arguments arguments;
  7006. public Arglist (Location loc)
  7007. : this (null, loc)
  7008. {
  7009. }
  7010. public Arglist (Arguments args, Location l)
  7011. {
  7012. arguments = args;
  7013. loc = l;
  7014. }
  7015. public Arguments Arguments {
  7016. get {
  7017. return arguments;
  7018. }
  7019. }
  7020. public MetaType[] ArgumentTypes {
  7021. get {
  7022. if (arguments == null)
  7023. return MetaType.EmptyTypes;
  7024. var retval = new MetaType[arguments.Count];
  7025. for (int i = 0; i < retval.Length; i++)
  7026. retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
  7027. return retval;
  7028. }
  7029. }
  7030. public override bool ContainsEmitWithAwait ()
  7031. {
  7032. throw new NotImplementedException ();
  7033. }
  7034. public override Expression CreateExpressionTree (ResolveContext ec)
  7035. {
  7036. ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
  7037. return null;
  7038. }
  7039. protected override Expression DoResolve (ResolveContext ec)
  7040. {
  7041. eclass = ExprClass.Variable;
  7042. type = InternalType.Arglist;
  7043. if (arguments != null) {
  7044. bool dynamic; // Can be ignored as there is always only 1 overload
  7045. arguments.Resolve (ec, out dynamic);
  7046. }
  7047. return this;
  7048. }
  7049. public override void Emit (EmitContext ec)
  7050. {
  7051. if (arguments != null)
  7052. arguments.Emit (ec);
  7053. }
  7054. protected override void CloneTo (CloneContext clonectx, Expression t)
  7055. {
  7056. Arglist target = (Arglist) t;
  7057. if (arguments != null)
  7058. target.arguments = arguments.Clone (clonectx);
  7059. }
  7060. public override object Accept (StructuralVisitor visitor)
  7061. {
  7062. return visitor.Visit (this);
  7063. }
  7064. }
  7065. public class RefValueExpr : ShimExpression, IAssignMethod
  7066. {
  7067. FullNamedExpression texpr;
  7068. public FullNamedExpression FullNamedExpression {
  7069. get { return texpr;}
  7070. }
  7071. public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
  7072. : base (expr)
  7073. {
  7074. this.texpr = texpr;
  7075. this.loc = loc;
  7076. }
  7077. public FullNamedExpression TypeExpression {
  7078. get {
  7079. return texpr;
  7080. }
  7081. }
  7082. public override bool ContainsEmitWithAwait ()
  7083. {
  7084. return false;
  7085. }
  7086. protected override Expression DoResolve (ResolveContext rc)
  7087. {
  7088. expr = expr.Resolve (rc);
  7089. type = texpr.ResolveAsType (rc);
  7090. if (expr == null || type == null)
  7091. return null;
  7092. expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
  7093. eclass = ExprClass.Value;
  7094. return this;
  7095. }
  7096. public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
  7097. {
  7098. return DoResolve (rc);
  7099. }
  7100. public override void Emit (EmitContext ec)
  7101. {
  7102. expr.Emit (ec);
  7103. ec.Emit (OpCodes.Refanyval, type);
  7104. ec.EmitLoadFromPtr (type);
  7105. }
  7106. public void Emit (EmitContext ec, bool leave_copy)
  7107. {
  7108. throw new NotImplementedException ();
  7109. }
  7110. public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
  7111. {
  7112. expr.Emit (ec);
  7113. ec.Emit (OpCodes.Refanyval, type);
  7114. source.Emit (ec);
  7115. LocalTemporary temporary = null;
  7116. if (leave_copy) {
  7117. ec.Emit (OpCodes.Dup);
  7118. temporary = new LocalTemporary (source.Type);
  7119. temporary.Store (ec);
  7120. }
  7121. ec.EmitStoreFromPtr (type);
  7122. if (temporary != null) {
  7123. temporary.Emit (ec);
  7124. temporary.Release (ec);
  7125. }
  7126. }
  7127. public override object Accept (StructuralVisitor visitor)
  7128. {
  7129. return visitor.Visit (this);
  7130. }
  7131. }
  7132. public class RefTypeExpr : ShimExpression
  7133. {
  7134. public RefTypeExpr (Expression expr, Location loc)
  7135. : base (expr)
  7136. {
  7137. this.loc = loc;
  7138. }
  7139. protected override Expression DoResolve (ResolveContext rc)
  7140. {
  7141. expr = expr.Resolve (rc);
  7142. if (expr == null)
  7143. return null;
  7144. expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
  7145. if (expr == null)
  7146. return null;
  7147. type = rc.BuiltinTypes.Type;
  7148. eclass = ExprClass.Value;
  7149. return this;
  7150. }
  7151. public override void Emit (EmitContext ec)
  7152. {
  7153. expr.Emit (ec);
  7154. ec.Emit (OpCodes.Refanytype);
  7155. var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
  7156. if (m != null)
  7157. ec.Emit (OpCodes.Call, m);
  7158. }
  7159. public override object Accept (StructuralVisitor visitor)
  7160. {
  7161. return visitor.Visit (this);
  7162. }
  7163. }
  7164. public class MakeRefExpr : ShimExpression
  7165. {
  7166. public MakeRefExpr (Expression expr, Location loc)
  7167. : base (expr)
  7168. {
  7169. this.loc = loc;
  7170. }
  7171. public override bool ContainsEmitWithAwait ()
  7172. {
  7173. throw new NotImplementedException ();
  7174. }
  7175. protected override Expression DoResolve (ResolveContext rc)
  7176. {
  7177. expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
  7178. type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
  7179. eclass = ExprClass.Value;
  7180. return this;
  7181. }
  7182. public override void Emit (EmitContext ec)
  7183. {
  7184. ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
  7185. ec.Emit (OpCodes.Mkrefany, expr.Type);
  7186. }
  7187. public override object Accept (StructuralVisitor visitor)
  7188. {
  7189. return visitor.Visit (this);
  7190. }
  7191. }
  7192. /// <summary>
  7193. /// Implements the typeof operator
  7194. /// </summary>
  7195. public class TypeOf : Expression {
  7196. FullNamedExpression QueriedType;
  7197. TypeSpec typearg;
  7198. public TypeOf (FullNamedExpression queried_type, Location l)
  7199. {
  7200. QueriedType = queried_type;
  7201. loc = l;
  7202. }
  7203. //
  7204. // Use this constructor for any compiler generated typeof expression
  7205. //
  7206. public TypeOf (TypeSpec type, Location loc)
  7207. {
  7208. this.typearg = type;
  7209. this.loc = loc;
  7210. }
  7211. #region Properties
  7212. public override bool IsSideEffectFree {
  7213. get {
  7214. return true;
  7215. }
  7216. }
  7217. public TypeSpec TypeArgument {
  7218. get {
  7219. return typearg;
  7220. }
  7221. }
  7222. public FullNamedExpression TypeExpression {
  7223. get {
  7224. return QueriedType;
  7225. }
  7226. }
  7227. #endregion
  7228. protected override void CloneTo (CloneContext clonectx, Expression t)
  7229. {
  7230. TypeOf target = (TypeOf) t;
  7231. if (QueriedType != null)
  7232. target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
  7233. }
  7234. public override bool ContainsEmitWithAwait ()
  7235. {
  7236. return false;
  7237. }
  7238. public override Expression CreateExpressionTree (ResolveContext ec)
  7239. {
  7240. Arguments args = new Arguments (2);
  7241. args.Add (new Argument (this));
  7242. args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
  7243. return CreateExpressionFactoryCall (ec, "Constant", args);
  7244. }
  7245. protected override Expression DoResolve (ResolveContext ec)
  7246. {
  7247. if (eclass != ExprClass.Unresolved)
  7248. return this;
  7249. if (typearg == null) {
  7250. //
  7251. // Pointer types are allowed without explicit unsafe, they are just tokens
  7252. //
  7253. using (ec.Set (ResolveContext.Options.UnsafeScope)) {
  7254. typearg = QueriedType.ResolveAsType (ec, true);
  7255. }
  7256. if (typearg == null)
  7257. return null;
  7258. if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  7259. ec.Report.Error (1962, QueriedType.Location,
  7260. "The typeof operator cannot be used on the dynamic type");
  7261. }
  7262. }
  7263. type = ec.BuiltinTypes.Type;
  7264. // Even though what is returned is a type object, it's treated as a value by the compiler.
  7265. // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
  7266. eclass = ExprClass.Value;
  7267. return this;
  7268. }
  7269. static bool ContainsDynamicType (TypeSpec type)
  7270. {
  7271. if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
  7272. return true;
  7273. var element_container = type as ElementTypeSpec;
  7274. if (element_container != null)
  7275. return ContainsDynamicType (element_container.Element);
  7276. foreach (var t in type.TypeArguments) {
  7277. if (ContainsDynamicType (t)) {
  7278. return true;
  7279. }
  7280. }
  7281. return false;
  7282. }
  7283. public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
  7284. {
  7285. // Target type is not System.Type therefore must be object
  7286. // and we need to use different encoding sequence
  7287. if (targetType != type)
  7288. enc.Encode (type);
  7289. if (typearg is InflatedTypeSpec) {
  7290. var gt = typearg;
  7291. do {
  7292. if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
  7293. rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
  7294. typearg.GetSignatureForError ());
  7295. return;
  7296. }
  7297. gt = gt.DeclaringType;
  7298. } while (gt != null);
  7299. }
  7300. if (ContainsDynamicType (typearg)) {
  7301. Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
  7302. return;
  7303. }
  7304. enc.EncodeTypeName (typearg);
  7305. }
  7306. public override void Emit (EmitContext ec)
  7307. {
  7308. ec.Emit (OpCodes.Ldtoken, typearg);
  7309. var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
  7310. if (m != null)
  7311. ec.Emit (OpCodes.Call, m);
  7312. }
  7313. public override object Accept (StructuralVisitor visitor)
  7314. {
  7315. return visitor.Visit (this);
  7316. }
  7317. }
  7318. sealed class TypeOfMethod : TypeOfMember<MethodSpec>
  7319. {
  7320. public TypeOfMethod (MethodSpec method, Location loc)
  7321. : base (method, loc)
  7322. {
  7323. }
  7324. protected override Expression DoResolve (ResolveContext ec)
  7325. {
  7326. if (member.IsConstructor) {
  7327. type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
  7328. } else {
  7329. type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
  7330. }
  7331. if (type == null)
  7332. return null;
  7333. return base.DoResolve (ec);
  7334. }
  7335. public override void Emit (EmitContext ec)
  7336. {
  7337. ec.Emit (OpCodes.Ldtoken, member);
  7338. base.Emit (ec);
  7339. ec.Emit (OpCodes.Castclass, type);
  7340. }
  7341. protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
  7342. {
  7343. return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
  7344. }
  7345. protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
  7346. {
  7347. return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
  7348. }
  7349. }
  7350. abstract class TypeOfMember<T> : Expression where T : MemberSpec
  7351. {
  7352. protected readonly T member;
  7353. protected TypeOfMember (T member, Location loc)
  7354. {
  7355. this.member = member;
  7356. this.loc = loc;
  7357. }
  7358. public override bool IsSideEffectFree {
  7359. get {
  7360. return true;
  7361. }
  7362. }
  7363. public override bool ContainsEmitWithAwait ()
  7364. {
  7365. return false;
  7366. }
  7367. public override Expression CreateExpressionTree (ResolveContext ec)
  7368. {
  7369. Arguments args = new Arguments (2);
  7370. args.Add (new Argument (this));
  7371. args.Add (new Argument (new TypeOf (type, loc)));
  7372. return CreateExpressionFactoryCall (ec, "Constant", args);
  7373. }
  7374. protected override Expression DoResolve (ResolveContext ec)
  7375. {
  7376. eclass = ExprClass.Value;
  7377. return this;
  7378. }
  7379. public override void Emit (EmitContext ec)
  7380. {
  7381. bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
  7382. PredefinedMember<MethodSpec> p;
  7383. if (is_generic) {
  7384. p = GetTypeFromHandleGeneric (ec);
  7385. ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
  7386. } else {
  7387. p = GetTypeFromHandle (ec);
  7388. }
  7389. var mi = p.Resolve (loc);
  7390. if (mi != null)
  7391. ec.Emit (OpCodes.Call, mi);
  7392. }
  7393. protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
  7394. protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
  7395. }
  7396. sealed class TypeOfField : TypeOfMember<FieldSpec>
  7397. {
  7398. public TypeOfField (FieldSpec field, Location loc)
  7399. : base (field, loc)
  7400. {
  7401. }
  7402. protected override Expression DoResolve (ResolveContext ec)
  7403. {
  7404. type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
  7405. if (type == null)
  7406. return null;
  7407. return base.DoResolve (ec);
  7408. }
  7409. public override void Emit (EmitContext ec)
  7410. {
  7411. ec.Emit (OpCodes.Ldtoken, member);
  7412. base.Emit (ec);
  7413. }
  7414. protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
  7415. {
  7416. return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
  7417. }
  7418. protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
  7419. {
  7420. return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
  7421. }
  7422. }
  7423. /// <summary>
  7424. /// Implements the sizeof expression
  7425. /// </summary>
  7426. public class SizeOf : Expression {
  7427. readonly Expression texpr;
  7428. TypeSpec type_queried;
  7429. public SizeOf (Expression queried_type, Location l)
  7430. {
  7431. this.texpr = queried_type;
  7432. loc = l;
  7433. }
  7434. public override bool IsSideEffectFree {
  7435. get {
  7436. return true;
  7437. }
  7438. }
  7439. public Expression TypeExpression {
  7440. get {
  7441. return texpr;
  7442. }
  7443. }
  7444. public override bool ContainsEmitWithAwait ()
  7445. {
  7446. return false;
  7447. }
  7448. public override Expression CreateExpressionTree (ResolveContext ec)
  7449. {
  7450. Error_PointerInsideExpressionTree (ec);
  7451. return null;
  7452. }
  7453. protected override Expression DoResolve (ResolveContext ec)
  7454. {
  7455. type_queried = texpr.ResolveAsType (ec);
  7456. if (type_queried == null)
  7457. return null;
  7458. if (type_queried.IsEnum)
  7459. type_queried = EnumSpec.GetUnderlyingType (type_queried);
  7460. int size_of = BuiltinTypeSpec.GetSize (type_queried);
  7461. if (size_of > 0) {
  7462. return new IntConstant (ec.BuiltinTypes, size_of, loc);
  7463. }
  7464. if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
  7465. return null;
  7466. }
  7467. if (!ec.IsUnsafe) {
  7468. ec.Report.Error (233, loc,
  7469. "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
  7470. type_queried.GetSignatureForError ());
  7471. }
  7472. type = ec.BuiltinTypes.Int;
  7473. eclass = ExprClass.Value;
  7474. return this;
  7475. }
  7476. public override void Emit (EmitContext ec)
  7477. {
  7478. ec.Emit (OpCodes.Sizeof, type_queried);
  7479. }
  7480. protected override void CloneTo (CloneContext clonectx, Expression t)
  7481. {
  7482. }
  7483. public override object Accept (StructuralVisitor visitor)
  7484. {
  7485. return visitor.Visit (this);
  7486. }
  7487. }
  7488. /// <summary>
  7489. /// Implements the qualified-alias-member (::) expression.
  7490. /// </summary>
  7491. public class QualifiedAliasMember : MemberAccess
  7492. {
  7493. public readonly string alias;
  7494. public static readonly string GlobalAlias = "global";
  7495. public QualifiedAliasMember (string alias, string identifier, Location l)
  7496. : base (null, identifier, l)
  7497. {
  7498. this.alias = alias;
  7499. }
  7500. public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
  7501. : base (null, identifier, targs, l)
  7502. {
  7503. this.alias = alias;
  7504. }
  7505. public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
  7506. : base (null, identifier, arity, l)
  7507. {
  7508. this.alias = alias;
  7509. }
  7510. public string Alias {
  7511. get {
  7512. return alias;
  7513. }
  7514. }
  7515. public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
  7516. {
  7517. if (alias == GlobalAlias)
  7518. return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
  7519. int errors = mc.Module.Compiler.Report.Errors;
  7520. var expr = mc.LookupNamespaceAlias (alias);
  7521. if (expr == null) {
  7522. if (errors == mc.Module.Compiler.Report.Errors)
  7523. mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
  7524. return null;
  7525. }
  7526. return expr;
  7527. }
  7528. public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
  7529. {
  7530. expr = CreateExpressionFromAlias (mc);
  7531. if (expr == null)
  7532. return null;
  7533. return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
  7534. }
  7535. protected override Expression DoResolve (ResolveContext rc)
  7536. {
  7537. return ResolveAsTypeOrNamespace (rc, false);
  7538. }
  7539. public override string GetSignatureForError ()
  7540. {
  7541. string name = Name;
  7542. if (targs != null) {
  7543. name = Name + "<" + targs.GetSignatureForError () + ">";
  7544. }
  7545. return alias + "::" + name;
  7546. }
  7547. public override bool HasConditionalAccess ()
  7548. {
  7549. return false;
  7550. }
  7551. public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
  7552. {
  7553. if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
  7554. rc.Module.Compiler.Report.Error (687, loc,
  7555. "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
  7556. GetSignatureForError ());
  7557. return null;
  7558. }
  7559. return DoResolve (rc);
  7560. }
  7561. protected override void CloneTo (CloneContext clonectx, Expression t)
  7562. {
  7563. // Nothing
  7564. }
  7565. public override object Accept (StructuralVisitor visitor)
  7566. {
  7567. return visitor.Visit (this);
  7568. }
  7569. }
  7570. /// <summary>
  7571. /// Implements the member access expression
  7572. /// </summary>
  7573. public class MemberAccess : ATypeNameExpression
  7574. {
  7575. protected Expression expr;
  7576. public MemberAccess (Expression expr, string id)
  7577. : base (id, expr.Location)
  7578. {
  7579. this.expr = expr;
  7580. }
  7581. public MemberAccess (Expression expr, string identifier, Location loc)
  7582. : base (identifier, loc)
  7583. {
  7584. this.expr = expr;
  7585. }
  7586. public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
  7587. : base (identifier, args, loc)
  7588. {
  7589. this.expr = expr;
  7590. }
  7591. public MemberAccess (Expression expr, string identifier, int arity, Location loc)
  7592. : base (identifier, arity, loc)
  7593. {
  7594. this.expr = expr;
  7595. }
  7596. public Expression LeftExpression {
  7597. get {
  7598. return expr;
  7599. }
  7600. }
  7601. public override Location StartLocation {
  7602. get {
  7603. return expr == null ? loc : expr.StartLocation;
  7604. }
  7605. }
  7606. protected override Expression DoResolve (ResolveContext rc)
  7607. {
  7608. var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
  7609. if (e != null)
  7610. e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
  7611. return e;
  7612. }
  7613. public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
  7614. {
  7615. var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
  7616. if (e is TypeExpr) {
  7617. e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
  7618. return null;
  7619. }
  7620. if (e != null)
  7621. e = e.ResolveLValue (rc, rhs);
  7622. return e;
  7623. }
  7624. protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
  7625. {
  7626. if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
  7627. rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
  7628. else
  7629. expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
  7630. }
  7631. public override bool HasConditionalAccess ()
  7632. {
  7633. return LeftExpression.HasConditionalAccess ();
  7634. }
  7635. public static bool IsValidDotExpression (TypeSpec type)
  7636. {
  7637. const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
  7638. MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
  7639. return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
  7640. }
  7641. public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
  7642. {
  7643. var sn = expr as SimpleName;
  7644. const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
  7645. if (sn != null) {
  7646. expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
  7647. //
  7648. // Resolve expression which does have type set as we need expression type
  7649. // with disable flow analysis as we don't know whether left side expression
  7650. // is used as variable or type
  7651. //
  7652. if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
  7653. expr = expr.Resolve (rc);
  7654. } else if (expr is TypeParameterExpr) {
  7655. expr.Error_UnexpectedKind (rc, flags, sn.Location);
  7656. expr = null;
  7657. }
  7658. } else {
  7659. using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
  7660. expr = expr.Resolve (rc, flags);
  7661. }
  7662. }
  7663. if (expr == null)
  7664. return null;
  7665. var ns = expr as NamespaceExpression;
  7666. if (ns != null) {
  7667. var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
  7668. if (retval == null) {
  7669. ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
  7670. return null;
  7671. }
  7672. if (HasTypeArguments)
  7673. return new GenericTypeExpr (retval.Type, targs, loc);
  7674. return retval;
  7675. }
  7676. MemberExpr me;
  7677. TypeSpec expr_type = expr.Type;
  7678. if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  7679. me = expr as MemberExpr;
  7680. if (me != null)
  7681. me.ResolveInstanceExpression (rc, null);
  7682. Arguments args = new Arguments (1);
  7683. args.Add (new Argument (expr));
  7684. return new DynamicMemberBinder (Name, args, loc);
  7685. }
  7686. var cma = this as ConditionalMemberAccess;
  7687. if (cma != null) {
  7688. if (!IsNullPropagatingValid (expr.Type)) {
  7689. expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
  7690. return null;
  7691. }
  7692. if (expr_type.IsNullableType) {
  7693. expr = Nullable.Unwrap.Create (expr, true).Resolve (rc);
  7694. expr_type = expr.Type;
  7695. }
  7696. }
  7697. if (!IsValidDotExpression (expr_type)) {
  7698. Error_OperatorCannotBeApplied (rc, expr_type);
  7699. return null;
  7700. }
  7701. var lookup_arity = Arity;
  7702. bool errorMode = false;
  7703. Expression member_lookup;
  7704. while (true) {
  7705. member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
  7706. if (member_lookup == null) {
  7707. //
  7708. // Try to look for extension method when member lookup failed
  7709. //
  7710. if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
  7711. var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity);
  7712. if (methods != null) {
  7713. var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
  7714. if (HasTypeArguments) {
  7715. if (!targs.Resolve (rc))
  7716. return null;
  7717. emg.SetTypeArguments (rc, targs);
  7718. }
  7719. if (cma != null)
  7720. emg.ConditionalAccess = true;
  7721. // TODO: it should really skip the checks bellow
  7722. return emg.Resolve (rc);
  7723. }
  7724. }
  7725. }
  7726. if (errorMode) {
  7727. if (member_lookup == null) {
  7728. var dep = expr_type.GetMissingDependencies ();
  7729. if (dep != null) {
  7730. ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
  7731. } else if (expr is TypeExpr) {
  7732. base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
  7733. } else {
  7734. Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
  7735. }
  7736. return null;
  7737. }
  7738. if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
  7739. // Leave it to overload resolution to report correct error
  7740. } else if (!(member_lookup is TypeExpr)) {
  7741. // TODO: rc.SymbolRelatedToPreviousError
  7742. ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
  7743. }
  7744. break;
  7745. }
  7746. if (member_lookup != null)
  7747. break;
  7748. lookup_arity = 0;
  7749. restrictions &= ~MemberLookupRestrictions.InvocableOnly;
  7750. errorMode = true;
  7751. }
  7752. TypeExpr texpr = member_lookup as TypeExpr;
  7753. if (texpr != null) {
  7754. if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
  7755. rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
  7756. Name, texpr.GetSignatureForError ());
  7757. }
  7758. if (!texpr.Type.IsAccessible (rc)) {
  7759. rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
  7760. ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
  7761. return null;
  7762. }
  7763. if (HasTypeArguments) {
  7764. return new GenericTypeExpr (member_lookup.Type, targs, loc);
  7765. }
  7766. return member_lookup;
  7767. }
  7768. me = member_lookup as MemberExpr;
  7769. if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
  7770. sn = null;
  7771. }
  7772. if (cma != null) {
  7773. me.ConditionalAccess = true;
  7774. }
  7775. me = me.ResolveMemberAccess (rc, expr, sn);
  7776. if (Arity > 0) {
  7777. if (!targs.Resolve (rc))
  7778. return null;
  7779. me.SetTypeArguments (rc, targs);
  7780. }
  7781. return me;
  7782. }
  7783. public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
  7784. {
  7785. FullNamedExpression fexpr = expr as FullNamedExpression;
  7786. if (fexpr == null) {
  7787. expr.ResolveAsType (rc);
  7788. return null;
  7789. }
  7790. FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
  7791. if (expr_resolved == null)
  7792. return null;
  7793. var ns = expr_resolved as NamespaceExpression;
  7794. if (ns != null) {
  7795. FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
  7796. if (retval == null) {
  7797. ns.Error_NamespaceDoesNotExist (rc, Name, Arity);
  7798. } else if (Arity > 0) {
  7799. if (HasTypeArguments) {
  7800. retval = new GenericTypeExpr (retval.Type, targs, loc);
  7801. if (retval.ResolveAsType (rc) == null)
  7802. return null;
  7803. } else {
  7804. if (!allowUnboundTypeArguments)
  7805. Error_OpenGenericTypeIsNotAllowed (rc);
  7806. retval = new GenericOpenTypeExpr (retval.Type, loc);
  7807. }
  7808. }
  7809. return retval;
  7810. }
  7811. var tnew_expr = expr_resolved.ResolveAsType (rc);
  7812. if (tnew_expr == null)
  7813. return null;
  7814. TypeSpec expr_type = tnew_expr;
  7815. if (TypeManager.IsGenericParameter (expr_type)) {
  7816. rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
  7817. tnew_expr.GetSignatureForError ());
  7818. return null;
  7819. }
  7820. var qam = this as QualifiedAliasMember;
  7821. if (qam != null) {
  7822. rc.Module.Compiler.Report.Error (431, loc,
  7823. "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
  7824. qam.Alias);
  7825. }
  7826. TypeSpec nested = null;
  7827. while (expr_type != null) {
  7828. nested = MemberCache.FindNestedType (expr_type, Name, Arity);
  7829. if (nested == null) {
  7830. if (expr_type == tnew_expr) {
  7831. Error_IdentifierNotFound (rc, expr_type);
  7832. return null;
  7833. }
  7834. expr_type = tnew_expr;
  7835. nested = MemberCache.FindNestedType (expr_type, Name, Arity);
  7836. ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
  7837. break;
  7838. }
  7839. if (nested.IsAccessible (rc))
  7840. break;
  7841. //
  7842. // Keep looking after inaccessible candidate but only if
  7843. // we are not in same context as the definition itself
  7844. //
  7845. if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
  7846. break;
  7847. expr_type = expr_type.BaseType;
  7848. }
  7849. TypeExpr texpr;
  7850. if (Arity > 0) {
  7851. if (HasTypeArguments) {
  7852. texpr = new GenericTypeExpr (nested, targs, loc);
  7853. } else {
  7854. if (!allowUnboundTypeArguments || expr_resolved is GenericTypeExpr) // && HasTypeArguments
  7855. Error_OpenGenericTypeIsNotAllowed (rc);
  7856. texpr = new GenericOpenTypeExpr (nested, loc);
  7857. }
  7858. } else if (expr_resolved is GenericOpenTypeExpr) {
  7859. texpr = new GenericOpenTypeExpr (nested, loc);
  7860. } else {
  7861. texpr = new TypeExpression (nested, loc);
  7862. }
  7863. if (texpr.ResolveAsType (rc) == null)
  7864. return null;
  7865. return texpr;
  7866. }
  7867. public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
  7868. {
  7869. var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
  7870. if (nested != null) {
  7871. Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
  7872. return;
  7873. }
  7874. var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
  7875. if (any_other_member != null) {
  7876. Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
  7877. return;
  7878. }
  7879. rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
  7880. Name, expr_type.GetSignatureForError ());
  7881. }
  7882. protected override void Error_InvalidExpressionStatement (Report report, Location loc)
  7883. {
  7884. base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
  7885. }
  7886. protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
  7887. {
  7888. if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
  7889. ec.Report.SymbolRelatedToPreviousError (type);
  7890. var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
  7891. string missing;
  7892. // a using directive or an assembly reference
  7893. if (cand != null) {
  7894. missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
  7895. } else {
  7896. missing = "an assembly reference";
  7897. }
  7898. ec.Report.Error (1061, loc,
  7899. "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
  7900. type.GetSignatureForError (), name, missing);
  7901. return;
  7902. }
  7903. base.Error_TypeDoesNotContainDefinition (ec, type, name);
  7904. }
  7905. public override string GetSignatureForError ()
  7906. {
  7907. return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
  7908. }
  7909. protected override void CloneTo (CloneContext clonectx, Expression t)
  7910. {
  7911. MemberAccess target = (MemberAccess) t;
  7912. target.expr = expr.Clone (clonectx);
  7913. }
  7914. public override object Accept (StructuralVisitor visitor)
  7915. {
  7916. return visitor.Visit (this);
  7917. }
  7918. }
  7919. public class ConditionalMemberAccess : MemberAccess
  7920. {
  7921. public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
  7922. : base (expr, identifier, args, loc)
  7923. {
  7924. }
  7925. public override bool HasConditionalAccess ()
  7926. {
  7927. return true;
  7928. }
  7929. }
  7930. /// <summary>
  7931. /// Implements checked expressions
  7932. /// </summary>
  7933. public class CheckedExpr : Expression {
  7934. public Expression Expr;
  7935. public CheckedExpr (Expression e, Location l)
  7936. {
  7937. Expr = e;
  7938. loc = l;
  7939. }
  7940. public override bool ContainsEmitWithAwait ()
  7941. {
  7942. return Expr.ContainsEmitWithAwait ();
  7943. }
  7944. public override Expression CreateExpressionTree (ResolveContext ec)
  7945. {
  7946. using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
  7947. return Expr.CreateExpressionTree (ec);
  7948. }
  7949. protected override Expression DoResolve (ResolveContext ec)
  7950. {
  7951. using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
  7952. Expr = Expr.Resolve (ec);
  7953. if (Expr == null)
  7954. return null;
  7955. if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
  7956. return Expr;
  7957. eclass = Expr.eclass;
  7958. type = Expr.Type;
  7959. return this;
  7960. }
  7961. public override void Emit (EmitContext ec)
  7962. {
  7963. using (ec.With (EmitContext.Options.CheckedScope, true))
  7964. Expr.Emit (ec);
  7965. }
  7966. public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
  7967. {
  7968. using (ec.With (EmitContext.Options.CheckedScope, true))
  7969. Expr.EmitBranchable (ec, target, on_true);
  7970. }
  7971. public override void FlowAnalysis (FlowAnalysisContext fc)
  7972. {
  7973. Expr.FlowAnalysis (fc);
  7974. }
  7975. public override SLE.Expression MakeExpression (BuilderContext ctx)
  7976. {
  7977. using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
  7978. return Expr.MakeExpression (ctx);
  7979. }
  7980. }
  7981. protected override void CloneTo (CloneContext clonectx, Expression t)
  7982. {
  7983. CheckedExpr target = (CheckedExpr) t;
  7984. target.Expr = Expr.Clone (clonectx);
  7985. }
  7986. public override object Accept (StructuralVisitor visitor)
  7987. {
  7988. return visitor.Visit (this);
  7989. }
  7990. }
  7991. /// <summary>
  7992. /// Implements the unchecked expression
  7993. /// </summary>
  7994. public class UnCheckedExpr : Expression {
  7995. public Expression Expr;
  7996. public UnCheckedExpr (Expression e, Location l)
  7997. {
  7998. Expr = e;
  7999. loc = l;
  8000. }
  8001. public override bool ContainsEmitWithAwait ()
  8002. {
  8003. return Expr.ContainsEmitWithAwait ();
  8004. }
  8005. public override Expression CreateExpressionTree (ResolveContext ec)
  8006. {
  8007. using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
  8008. return Expr.CreateExpressionTree (ec);
  8009. }
  8010. protected override Expression DoResolve (ResolveContext ec)
  8011. {
  8012. using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
  8013. Expr = Expr.Resolve (ec);
  8014. if (Expr == null)
  8015. return null;
  8016. if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
  8017. return Expr;
  8018. eclass = Expr.eclass;
  8019. type = Expr.Type;
  8020. return this;
  8021. }
  8022. public override void Emit (EmitContext ec)
  8023. {
  8024. using (ec.With (EmitContext.Options.CheckedScope, false))
  8025. Expr.Emit (ec);
  8026. }
  8027. public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
  8028. {
  8029. using (ec.With (EmitContext.Options.CheckedScope, false))
  8030. Expr.EmitBranchable (ec, target, on_true);
  8031. }
  8032. public override void FlowAnalysis (FlowAnalysisContext fc)
  8033. {
  8034. Expr.FlowAnalysis (fc);
  8035. }
  8036. protected override void CloneTo (CloneContext clonectx, Expression t)
  8037. {
  8038. UnCheckedExpr target = (UnCheckedExpr) t;
  8039. target.Expr = Expr.Clone (clonectx);
  8040. }
  8041. public override object Accept (StructuralVisitor visitor)
  8042. {
  8043. return visitor.Visit (this);
  8044. }
  8045. }
  8046. /// <summary>
  8047. /// An Element Access expression.
  8048. ///
  8049. /// During semantic analysis these are transformed into
  8050. /// IndexerAccess, ArrayAccess or a PointerArithmetic.
  8051. /// </summary>
  8052. public class ElementAccess : Expression
  8053. {
  8054. public Arguments Arguments;
  8055. public Expression Expr;
  8056. public ElementAccess (Expression e, Arguments args, Location loc)
  8057. {
  8058. Expr = e;
  8059. this.loc = loc;
  8060. this.Arguments = args;
  8061. }
  8062. public bool ConditionalAccess { get; set; }
  8063. public override Location StartLocation {
  8064. get {
  8065. return Expr.StartLocation;
  8066. }
  8067. }
  8068. public override bool ContainsEmitWithAwait ()
  8069. {
  8070. return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
  8071. }
  8072. //
  8073. // We perform some simple tests, and then to "split" the emit and store
  8074. // code we create an instance of a different class, and return that.
  8075. //
  8076. Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
  8077. {
  8078. Expr = Expr.Resolve (ec);
  8079. if (Expr == null)
  8080. return null;
  8081. type = Expr.Type;
  8082. if (ConditionalAccess && !IsNullPropagatingValid (type)) {
  8083. Error_OperatorCannotBeApplied (ec, loc, "?", type);
  8084. return null;
  8085. }
  8086. if (type.IsArray)
  8087. return new ArrayAccess (this, loc) {
  8088. ConditionalAccess = ConditionalAccess,
  8089. ConditionalAccessReceiver = conditionalAccessReceiver
  8090. };
  8091. if (type.IsPointer)
  8092. return MakePointerAccess (ec, type);
  8093. FieldExpr fe = Expr as FieldExpr;
  8094. if (fe != null) {
  8095. var ff = fe.Spec as FixedFieldSpec;
  8096. if (ff != null) {
  8097. return MakePointerAccess (ec, ff.ElementType);
  8098. }
  8099. }
  8100. var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
  8101. if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  8102. var indexer = new IndexerExpr (indexers, type, this) {
  8103. ConditionalAccess = ConditionalAccess
  8104. };
  8105. if (conditionalAccessReceiver)
  8106. indexer.SetConditionalAccessReceiver ();
  8107. return indexer;
  8108. }
  8109. Error_CannotApplyIndexing (ec, type, loc);
  8110. return null;
  8111. }
  8112. public override Expression CreateExpressionTree (ResolveContext ec)
  8113. {
  8114. Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
  8115. Expr.CreateExpressionTree (ec));
  8116. return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
  8117. }
  8118. public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
  8119. {
  8120. if (type != InternalType.ErrorType) {
  8121. rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
  8122. type.GetSignatureForError ());
  8123. }
  8124. }
  8125. public override bool HasConditionalAccess ()
  8126. {
  8127. return ConditionalAccess || Expr.HasConditionalAccess ();
  8128. }
  8129. Expression MakePointerAccess (ResolveContext rc, TypeSpec type)
  8130. {
  8131. if (Arguments.Count != 1){
  8132. rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
  8133. return null;
  8134. }
  8135. var arg = Arguments[0];
  8136. if (arg is NamedArgument)
  8137. Error_NamedArgument ((NamedArgument) arg, rc.Report);
  8138. var index = arg.Expr.Resolve (rc);
  8139. if (index == null)
  8140. return null;
  8141. index = ConvertExpressionToArrayIndex (rc, index, true);
  8142. Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, index, type, loc);
  8143. return new Indirection (p, loc);
  8144. }
  8145. protected override Expression DoResolve (ResolveContext rc)
  8146. {
  8147. Expression expr;
  8148. if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
  8149. if (HasConditionalAccess ()) {
  8150. using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
  8151. expr = CreateAccessExpression (rc, true);
  8152. if (expr == null)
  8153. return null;
  8154. return expr.Resolve (rc);
  8155. }
  8156. }
  8157. }
  8158. expr = CreateAccessExpression (rc, false);
  8159. if (expr == null)
  8160. return null;
  8161. return expr.Resolve (rc);
  8162. }
  8163. public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
  8164. {
  8165. var res = CreateAccessExpression (ec, false);
  8166. if (res == null)
  8167. return null;
  8168. return res.ResolveLValue (ec, rhs);
  8169. }
  8170. public override void Emit (EmitContext ec)
  8171. {
  8172. throw new Exception ("Should never be reached");
  8173. }
  8174. public static void Error_NamedArgument (NamedArgument na, Report Report)
  8175. {
  8176. Report.Error (1742, na.Location, "An element access expression cannot use named argument");
  8177. }
  8178. public override void FlowAnalysis (FlowAnalysisContext fc)
  8179. {
  8180. Expr.FlowAnalysis (fc);
  8181. if (ConditionalAccess)
  8182. fc.BranchConditionalAccessDefiniteAssignment ();
  8183. Arguments.FlowAnalysis (fc);
  8184. }
  8185. public override string GetSignatureForError ()
  8186. {
  8187. return Expr.GetSignatureForError ();
  8188. }
  8189. protected override void CloneTo (CloneContext clonectx, Expression t)
  8190. {
  8191. ElementAccess target = (ElementAccess) t;
  8192. target.Expr = Expr.Clone (clonectx);
  8193. if (Arguments != null)
  8194. target.Arguments = Arguments.Clone (clonectx);
  8195. }
  8196. public override object Accept (StructuralVisitor visitor)
  8197. {
  8198. return visitor.Visit (this);
  8199. }
  8200. }
  8201. /// <summary>
  8202. /// Implements array access
  8203. /// </summary>
  8204. public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
  8205. //
  8206. // Points to our "data" repository
  8207. //
  8208. ElementAccess ea;
  8209. LocalTemporary temp;
  8210. bool prepared;
  8211. bool? has_await_args;
  8212. public ArrayAccess (ElementAccess ea_data, Location l)
  8213. {
  8214. ea = ea_data;
  8215. loc = l;
  8216. }
  8217. public bool ConditionalAccess { get; set; }
  8218. public bool ConditionalAccessReceiver { get; set; }
  8219. public void AddressOf (EmitContext ec, AddressOp mode)
  8220. {
  8221. var ac = (ArrayContainer) ea.Expr.Type;
  8222. if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
  8223. LoadInstanceAndArguments (ec, false, true);
  8224. }
  8225. LoadInstanceAndArguments (ec, false, false);
  8226. if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
  8227. ec.Emit (OpCodes.Readonly);
  8228. ec.EmitArrayAddress (ac);
  8229. }
  8230. public override Expression CreateExpressionTree (ResolveContext ec)
  8231. {
  8232. if (ConditionalAccess)
  8233. Error_NullShortCircuitInsideExpressionTree (ec);
  8234. return ea.CreateExpressionTree (ec);
  8235. }
  8236. public override bool ContainsEmitWithAwait ()
  8237. {
  8238. return ea.ContainsEmitWithAwait ();
  8239. }
  8240. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  8241. {
  8242. if (ConditionalAccess)
  8243. throw new NotSupportedException ("null propagating operator assignment");
  8244. return DoResolve (ec);
  8245. }
  8246. protected override Expression DoResolve (ResolveContext ec)
  8247. {
  8248. // dynamic is used per argument in ConvertExpressionToArrayIndex case
  8249. bool dynamic;
  8250. ea.Arguments.Resolve (ec, out dynamic);
  8251. var ac = ea.Expr.Type as ArrayContainer;
  8252. int rank = ea.Arguments.Count;
  8253. if (ac.Rank != rank) {
  8254. ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
  8255. rank.ToString (), ac.Rank.ToString ());
  8256. return null;
  8257. }
  8258. type = ac.Element;
  8259. if (type.IsPointer && !ec.IsUnsafe) {
  8260. UnsafeError (ec, ea.Location);
  8261. }
  8262. if (ConditionalAccessReceiver)
  8263. type = LiftMemberType (ec, type);
  8264. foreach (Argument a in ea.Arguments) {
  8265. var na = a as NamedArgument;
  8266. if (na != null)
  8267. ElementAccess.Error_NamedArgument (na, ec.Report);
  8268. a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
  8269. }
  8270. eclass = ExprClass.Variable;
  8271. return this;
  8272. }
  8273. protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
  8274. {
  8275. ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
  8276. }
  8277. public override void FlowAnalysis (FlowAnalysisContext fc)
  8278. {
  8279. ea.FlowAnalysis (fc);
  8280. }
  8281. //
  8282. // Load the array arguments into the stack.
  8283. //
  8284. void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
  8285. {
  8286. if (prepareAwait) {
  8287. ea.Expr = ea.Expr.EmitToField (ec);
  8288. } else {
  8289. var ie = new InstanceEmitter (ea.Expr, false);
  8290. ie.Emit (ec, ConditionalAccess);
  8291. if (duplicateArguments) {
  8292. ec.Emit (OpCodes.Dup);
  8293. var copy = new LocalTemporary (ea.Expr.Type);
  8294. copy.Store (ec);
  8295. ea.Expr = copy;
  8296. }
  8297. }
  8298. var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
  8299. if (dup_args != null)
  8300. ea.Arguments = dup_args;
  8301. }
  8302. public void Emit (EmitContext ec, bool leave_copy)
  8303. {
  8304. if (prepared) {
  8305. ec.EmitLoadFromPtr (type);
  8306. } else {
  8307. if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
  8308. LoadInstanceAndArguments (ec, false, true);
  8309. }
  8310. if (ConditionalAccessReceiver)
  8311. ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
  8312. var ac = (ArrayContainer) ea.Expr.Type;
  8313. LoadInstanceAndArguments (ec, false, false);
  8314. ec.EmitArrayLoad (ac);
  8315. if (ConditionalAccessReceiver)
  8316. ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
  8317. }
  8318. if (leave_copy) {
  8319. ec.Emit (OpCodes.Dup);
  8320. temp = new LocalTemporary (this.type);
  8321. temp.Store (ec);
  8322. }
  8323. }
  8324. public override void Emit (EmitContext ec)
  8325. {
  8326. Emit (ec, false);
  8327. }
  8328. public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
  8329. {
  8330. var ac = (ArrayContainer) ea.Expr.Type;
  8331. TypeSpec t = source.Type;
  8332. has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
  8333. //
  8334. // When we are dealing with a struct, get the address of it to avoid value copy
  8335. // Same cannot be done for reference type because array covariance and the
  8336. // check in ldelema requires to specify the type of array element stored at the index
  8337. //
  8338. if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
  8339. LoadInstanceAndArguments (ec, false, has_await_args.Value);
  8340. if (has_await_args.Value) {
  8341. if (source.ContainsEmitWithAwait ()) {
  8342. source = source.EmitToField (ec);
  8343. isCompound = false;
  8344. prepared = true;
  8345. }
  8346. LoadInstanceAndArguments (ec, isCompound, false);
  8347. } else {
  8348. prepared = true;
  8349. }
  8350. ec.EmitArrayAddress (ac);
  8351. if (isCompound) {
  8352. ec.Emit (OpCodes.Dup);
  8353. prepared = true;
  8354. }
  8355. } else {
  8356. LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
  8357. if (has_await_args.Value) {
  8358. if (source.ContainsEmitWithAwait ())
  8359. source = source.EmitToField (ec);
  8360. LoadInstanceAndArguments (ec, false, false);
  8361. }
  8362. }
  8363. source.Emit (ec);
  8364. if (isCompound) {
  8365. var lt = ea.Expr as LocalTemporary;
  8366. if (lt != null)
  8367. lt.Release (ec);
  8368. }
  8369. if (leave_copy) {
  8370. ec.Emit (OpCodes.Dup);
  8371. temp = new LocalTemporary (this.type);
  8372. temp.Store (ec);
  8373. }
  8374. if (prepared) {
  8375. ec.EmitStoreFromPtr (t);
  8376. } else {
  8377. ec.EmitArrayStore (ac);
  8378. }
  8379. if (temp != null) {
  8380. temp.Emit (ec);
  8381. temp.Release (ec);
  8382. }
  8383. }
  8384. public override Expression EmitToField (EmitContext ec)
  8385. {
  8386. //
  8387. // Have to be specialized for arrays to get access to
  8388. // underlying element. Instead of another result copy we
  8389. // need direct access to element
  8390. //
  8391. // Consider:
  8392. //
  8393. // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
  8394. //
  8395. ea.Expr = ea.Expr.EmitToField (ec);
  8396. ea.Arguments = ea.Arguments.Emit (ec, false, true);
  8397. return this;
  8398. }
  8399. public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
  8400. {
  8401. #if NET_4_0 || MOBILE_DYNAMIC
  8402. return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
  8403. #else
  8404. throw new NotImplementedException ();
  8405. #endif
  8406. }
  8407. public override SLE.Expression MakeExpression (BuilderContext ctx)
  8408. {
  8409. return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
  8410. }
  8411. SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
  8412. {
  8413. using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
  8414. return Arguments.MakeExpression (ea.Arguments, ctx);
  8415. }
  8416. }
  8417. }
  8418. //
  8419. // Indexer access expression
  8420. //
  8421. class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
  8422. {
  8423. IList<MemberSpec> indexers;
  8424. Arguments arguments;
  8425. TypeSpec queried_type;
  8426. public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
  8427. : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
  8428. {
  8429. }
  8430. public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
  8431. : base (loc)
  8432. {
  8433. this.indexers = indexers;
  8434. this.queried_type = queriedType;
  8435. this.InstanceExpression = instance;
  8436. this.arguments = args;
  8437. }
  8438. #region Properties
  8439. protected override Arguments Arguments {
  8440. get {
  8441. return arguments;
  8442. }
  8443. set {
  8444. arguments = value;
  8445. }
  8446. }
  8447. protected override TypeSpec DeclaringType {
  8448. get {
  8449. return best_candidate.DeclaringType;
  8450. }
  8451. }
  8452. public override bool IsInstance {
  8453. get {
  8454. return true;
  8455. }
  8456. }
  8457. public override bool IsStatic {
  8458. get {
  8459. return false;
  8460. }
  8461. }
  8462. public override string KindName {
  8463. get { return "indexer"; }
  8464. }
  8465. public override string Name {
  8466. get {
  8467. return "this";
  8468. }
  8469. }
  8470. #endregion
  8471. public override bool ContainsEmitWithAwait ()
  8472. {
  8473. return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
  8474. }
  8475. public override Expression CreateExpressionTree (ResolveContext ec)
  8476. {
  8477. if (ConditionalAccess) {
  8478. Error_NullShortCircuitInsideExpressionTree (ec);
  8479. }
  8480. Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
  8481. InstanceExpression.CreateExpressionTree (ec),
  8482. new TypeOfMethod (Getter, loc));
  8483. return CreateExpressionFactoryCall (ec, "Call", args);
  8484. }
  8485. public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
  8486. {
  8487. LocalTemporary await_source_arg = null;
  8488. if (isCompound) {
  8489. emitting_compound_assignment = true;
  8490. if (source is DynamicExpressionStatement) {
  8491. Emit (ec, false);
  8492. } else {
  8493. source.Emit (ec);
  8494. }
  8495. emitting_compound_assignment = false;
  8496. if (has_await_arguments) {
  8497. await_source_arg = new LocalTemporary (Type);
  8498. await_source_arg.Store (ec);
  8499. arguments.Add (new Argument (await_source_arg));
  8500. if (leave_copy) {
  8501. temp = await_source_arg;
  8502. }
  8503. has_await_arguments = false;
  8504. } else {
  8505. arguments = null;
  8506. if (leave_copy) {
  8507. ec.Emit (OpCodes.Dup);
  8508. temp = new LocalTemporary (Type);
  8509. temp.Store (ec);
  8510. }
  8511. }
  8512. } else {
  8513. if (leave_copy) {
  8514. if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
  8515. source = source.EmitToField (ec);
  8516. } else {
  8517. temp = new LocalTemporary (Type);
  8518. source.Emit (ec);
  8519. temp.Store (ec);
  8520. source = temp;
  8521. }
  8522. }
  8523. arguments.Add (new Argument (source));
  8524. }
  8525. var call = new CallEmitter ();
  8526. call.InstanceExpression = InstanceExpression;
  8527. if (arguments == null)
  8528. call.InstanceExpressionOnStack = true;
  8529. call.Emit (ec, Setter, arguments, loc);
  8530. if (temp != null) {
  8531. temp.Emit (ec);
  8532. temp.Release (ec);
  8533. } else if (leave_copy) {
  8534. source.Emit (ec);
  8535. }
  8536. if (await_source_arg != null) {
  8537. await_source_arg.Release (ec);
  8538. }
  8539. }
  8540. public override void FlowAnalysis (FlowAnalysisContext fc)
  8541. {
  8542. base.FlowAnalysis (fc);
  8543. arguments.FlowAnalysis (fc);
  8544. if (conditional_access_receiver)
  8545. fc.ConditionalAccessEnd ();
  8546. }
  8547. public override string GetSignatureForError ()
  8548. {
  8549. return best_candidate.GetSignatureForError ();
  8550. }
  8551. public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
  8552. {
  8553. #if STATIC
  8554. throw new NotSupportedException ();
  8555. #else
  8556. var value = new[] { source.MakeExpression (ctx) };
  8557. var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
  8558. #if NET_4_0 || MOBILE_DYNAMIC
  8559. return SLE.Expression.Block (
  8560. SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
  8561. value [0]);
  8562. #else
  8563. return args.First ();
  8564. #endif
  8565. #endif
  8566. }
  8567. public override SLE.Expression MakeExpression (BuilderContext ctx)
  8568. {
  8569. #if STATIC
  8570. return base.MakeExpression (ctx);
  8571. #else
  8572. var args = Arguments.MakeExpression (arguments, ctx);
  8573. return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
  8574. #endif
  8575. }
  8576. protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
  8577. {
  8578. if (best_candidate != null)
  8579. return this;
  8580. eclass = ExprClass.IndexerAccess;
  8581. bool dynamic;
  8582. arguments.Resolve (rc, out dynamic);
  8583. if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  8584. dynamic = true;
  8585. } else {
  8586. var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
  8587. res.BaseMembersProvider = this;
  8588. res.InstanceQualifier = this;
  8589. // TODO: Do I need 2 argument sets?
  8590. best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
  8591. if (best_candidate != null)
  8592. type = res.BestCandidateReturnType;
  8593. else if (!res.BestCandidateIsDynamic)
  8594. return null;
  8595. }
  8596. //
  8597. // It has dynamic arguments
  8598. //
  8599. if (dynamic) {
  8600. Arguments args = new Arguments (arguments.Count + 1);
  8601. if (IsBase) {
  8602. rc.Report.Error (1972, loc,
  8603. "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
  8604. } else {
  8605. args.Add (new Argument (InstanceExpression));
  8606. }
  8607. args.AddRange (arguments);
  8608. best_candidate = null;
  8609. return new DynamicIndexBinder (args, loc);
  8610. }
  8611. //
  8612. // Try to avoid resolving left expression again
  8613. //
  8614. if (right_side != null)
  8615. ResolveInstanceExpression (rc, right_side);
  8616. return this;
  8617. }
  8618. protected override void CloneTo (CloneContext clonectx, Expression t)
  8619. {
  8620. IndexerExpr target = (IndexerExpr) t;
  8621. if (arguments != null)
  8622. target.arguments = arguments.Clone (clonectx);
  8623. }
  8624. public void SetConditionalAccessReceiver ()
  8625. {
  8626. conditional_access_receiver = true;
  8627. }
  8628. public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
  8629. {
  8630. Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
  8631. }
  8632. #region IBaseMembersProvider Members
  8633. IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
  8634. {
  8635. return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
  8636. }
  8637. IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
  8638. {
  8639. if (queried_type == member.DeclaringType)
  8640. return null;
  8641. var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
  8642. return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
  8643. }
  8644. MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
  8645. {
  8646. return null;
  8647. }
  8648. #endregion
  8649. }
  8650. //
  8651. // A base access expression
  8652. //
  8653. public class BaseThis : This
  8654. {
  8655. public BaseThis (Location loc)
  8656. : base (loc)
  8657. {
  8658. }
  8659. public BaseThis (TypeSpec type, Location loc)
  8660. : base (loc)
  8661. {
  8662. this.type = type;
  8663. eclass = ExprClass.Variable;
  8664. }
  8665. #region Properties
  8666. public override string Name {
  8667. get {
  8668. return "base";
  8669. }
  8670. }
  8671. #endregion
  8672. public override Expression CreateExpressionTree (ResolveContext ec)
  8673. {
  8674. ec.Report.Error (831, loc, "An expression tree may not contain a base access");
  8675. return base.CreateExpressionTree (ec);
  8676. }
  8677. public override void Emit (EmitContext ec)
  8678. {
  8679. base.Emit (ec);
  8680. if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
  8681. var context_type = ec.CurrentType;
  8682. ec.Emit (OpCodes.Ldobj, context_type);
  8683. ec.Emit (OpCodes.Box, context_type);
  8684. }
  8685. }
  8686. protected override void Error_ThisNotAvailable (ResolveContext ec)
  8687. {
  8688. if (ec.IsStatic) {
  8689. ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
  8690. } else {
  8691. ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
  8692. }
  8693. }
  8694. public override void ResolveBase (ResolveContext ec)
  8695. {
  8696. base.ResolveBase (ec);
  8697. type = ec.CurrentType.BaseType;
  8698. }
  8699. public override object Accept (StructuralVisitor visitor)
  8700. {
  8701. return visitor.Visit (this);
  8702. }
  8703. }
  8704. /// <summary>
  8705. /// This class exists solely to pass the Type around and to be a dummy
  8706. /// that can be passed to the conversion functions (this is used by
  8707. /// foreach implementation to typecast the object return value from
  8708. /// get_Current into the proper type. All code has been generated and
  8709. /// we only care about the side effect conversions to be performed
  8710. ///
  8711. /// This is also now used as a placeholder where a no-action expression
  8712. /// is needed (the `New' class).
  8713. /// </summary>
  8714. public class EmptyExpression : Expression
  8715. {
  8716. sealed class OutAccessExpression : EmptyExpression
  8717. {
  8718. public OutAccessExpression (TypeSpec t)
  8719. : base (t)
  8720. {
  8721. }
  8722. public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
  8723. {
  8724. rc.Report.Error (206, right_side.Location,
  8725. "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
  8726. return null;
  8727. }
  8728. }
  8729. public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
  8730. public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
  8731. public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
  8732. public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
  8733. public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
  8734. public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
  8735. public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
  8736. public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
  8737. public EmptyExpression (TypeSpec t)
  8738. {
  8739. type = t;
  8740. eclass = ExprClass.Value;
  8741. loc = Location.Null;
  8742. }
  8743. protected override void CloneTo (CloneContext clonectx, Expression target)
  8744. {
  8745. }
  8746. public override bool ContainsEmitWithAwait ()
  8747. {
  8748. return false;
  8749. }
  8750. public override Expression CreateExpressionTree (ResolveContext ec)
  8751. {
  8752. throw new NotSupportedException ("ET");
  8753. }
  8754. protected override Expression DoResolve (ResolveContext ec)
  8755. {
  8756. return this;
  8757. }
  8758. public override void Emit (EmitContext ec)
  8759. {
  8760. // nothing, as we only exist to not do anything.
  8761. }
  8762. public override void EmitSideEffect (EmitContext ec)
  8763. {
  8764. }
  8765. public override object Accept (StructuralVisitor visitor)
  8766. {
  8767. return visitor.Visit (this);
  8768. }
  8769. }
  8770. sealed class EmptyAwaitExpression : EmptyExpression
  8771. {
  8772. public EmptyAwaitExpression (TypeSpec type)
  8773. : base (type)
  8774. {
  8775. }
  8776. public override bool ContainsEmitWithAwait ()
  8777. {
  8778. return true;
  8779. }
  8780. }
  8781. //
  8782. // Empty statement expression
  8783. //
  8784. public sealed class EmptyExpressionStatement : ExpressionStatement
  8785. {
  8786. public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
  8787. private EmptyExpressionStatement ()
  8788. {
  8789. loc = Location.Null;
  8790. }
  8791. public override bool ContainsEmitWithAwait ()
  8792. {
  8793. return false;
  8794. }
  8795. public override Expression CreateExpressionTree (ResolveContext ec)
  8796. {
  8797. return null;
  8798. }
  8799. public override void EmitStatement (EmitContext ec)
  8800. {
  8801. // Do nothing
  8802. }
  8803. protected override Expression DoResolve (ResolveContext ec)
  8804. {
  8805. eclass = ExprClass.Value;
  8806. type = ec.BuiltinTypes.Object;
  8807. return this;
  8808. }
  8809. public override void Emit (EmitContext ec)
  8810. {
  8811. // Do nothing
  8812. }
  8813. public override object Accept (StructuralVisitor visitor)
  8814. {
  8815. return visitor.Visit (this);
  8816. }
  8817. }
  8818. public class ErrorExpression : EmptyExpression
  8819. {
  8820. public static readonly ErrorExpression Instance = new ErrorExpression ();
  8821. public readonly int ErrorCode;
  8822. public readonly string Error;
  8823. private ErrorExpression ()
  8824. : base (InternalType.ErrorType)
  8825. {
  8826. }
  8827. ErrorExpression (int errorCode, Location location, string error)
  8828. : base (InternalType.ErrorType)
  8829. {
  8830. this.ErrorCode = errorCode;
  8831. base.loc = location;
  8832. this.Error = error;
  8833. }
  8834. public static ErrorExpression Create (int errorCode, Location location, string error)
  8835. {
  8836. return new ErrorExpression (errorCode, location, error);
  8837. }
  8838. public override Expression CreateExpressionTree (ResolveContext ec)
  8839. {
  8840. return this;
  8841. }
  8842. public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
  8843. {
  8844. return this;
  8845. }
  8846. public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
  8847. {
  8848. }
  8849. public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
  8850. {
  8851. }
  8852. public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
  8853. {
  8854. }
  8855. public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
  8856. {
  8857. }
  8858. public override object Accept (StructuralVisitor visitor)
  8859. {
  8860. return visitor.Visit (this);
  8861. }
  8862. }
  8863. public class UserCast : Expression {
  8864. MethodSpec method;
  8865. Expression source;
  8866. public UserCast (MethodSpec method, Expression source, Location l)
  8867. {
  8868. if (source == null)
  8869. throw new ArgumentNullException ("source");
  8870. this.method = method;
  8871. this.source = source;
  8872. type = method.ReturnType;
  8873. loc = l;
  8874. }
  8875. public Expression Source {
  8876. get {
  8877. return source;
  8878. }
  8879. }
  8880. public override bool ContainsEmitWithAwait ()
  8881. {
  8882. return source.ContainsEmitWithAwait ();
  8883. }
  8884. public override Expression CreateExpressionTree (ResolveContext ec)
  8885. {
  8886. Arguments args = new Arguments (3);
  8887. args.Add (new Argument (source.CreateExpressionTree (ec)));
  8888. args.Add (new Argument (new TypeOf (type, loc)));
  8889. args.Add (new Argument (new TypeOfMethod (method, loc)));
  8890. return CreateExpressionFactoryCall (ec, "Convert", args);
  8891. }
  8892. protected override Expression DoResolve (ResolveContext ec)
  8893. {
  8894. ObsoleteAttribute oa = method.GetAttributeObsolete ();
  8895. if (oa != null)
  8896. AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
  8897. eclass = ExprClass.Value;
  8898. return this;
  8899. }
  8900. public override void Emit (EmitContext ec)
  8901. {
  8902. source.Emit (ec);
  8903. ec.MarkCallEntry (loc);
  8904. ec.Emit (OpCodes.Call, method);
  8905. }
  8906. public override void FlowAnalysis (FlowAnalysisContext fc)
  8907. {
  8908. source.FlowAnalysis (fc);
  8909. }
  8910. public override string GetSignatureForError ()
  8911. {
  8912. return TypeManager.CSharpSignature (method);
  8913. }
  8914. public override SLE.Expression MakeExpression (BuilderContext ctx)
  8915. {
  8916. #if STATIC
  8917. return base.MakeExpression (ctx);
  8918. #else
  8919. return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
  8920. #endif
  8921. }
  8922. }
  8923. //
  8924. // Holds additional type specifiers like ?, *, []
  8925. //
  8926. public class ComposedTypeSpecifier
  8927. {
  8928. public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
  8929. public readonly int Dimension;
  8930. public readonly Location Location;
  8931. public ComposedTypeSpecifier (int specifier, Location loc)
  8932. {
  8933. this.Dimension = specifier;
  8934. this.Location = loc;
  8935. }
  8936. #region Properties
  8937. public bool IsNullable {
  8938. get {
  8939. return Dimension == -1;
  8940. }
  8941. }
  8942. public bool IsPointer {
  8943. get {
  8944. return Dimension == -2;
  8945. }
  8946. }
  8947. public ComposedTypeSpecifier Next { get; set; }
  8948. #endregion
  8949. public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
  8950. {
  8951. return new ComposedTypeSpecifier (dimension, loc);
  8952. }
  8953. public static ComposedTypeSpecifier CreateNullable (Location loc)
  8954. {
  8955. return new ComposedTypeSpecifier (-1, loc);
  8956. }
  8957. public static ComposedTypeSpecifier CreatePointer (Location loc)
  8958. {
  8959. return new ComposedTypeSpecifier (-2, loc);
  8960. }
  8961. public string GetSignatureForError ()
  8962. {
  8963. string s =
  8964. IsPointer ? "*" :
  8965. IsNullable ? "?" :
  8966. ArrayContainer.GetPostfixSignature (Dimension);
  8967. return Next != null ? s + Next.GetSignatureForError () : s;
  8968. }
  8969. }
  8970. // <summary>
  8971. // This class is used to "construct" the type during a typecast
  8972. // operation. Since the Type.GetType class in .NET can parse
  8973. // the type specification, we just use this to construct the type
  8974. // one bit at a time.
  8975. // </summary>
  8976. public class ComposedCast : TypeExpr {
  8977. FullNamedExpression left;
  8978. ComposedTypeSpecifier spec;
  8979. public FullNamedExpression Left {
  8980. get { return this.left; }
  8981. }
  8982. public ComposedTypeSpecifier Spec {
  8983. get {
  8984. return this.spec;
  8985. }
  8986. }
  8987. public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
  8988. {
  8989. if (spec == null)
  8990. throw new ArgumentNullException ("spec");
  8991. this.left = left;
  8992. this.spec = spec;
  8993. this.loc = left.Location;
  8994. }
  8995. public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
  8996. {
  8997. type = left.ResolveAsType (ec);
  8998. if (type == null)
  8999. return null;
  9000. eclass = ExprClass.Type;
  9001. var single_spec = spec;
  9002. if (single_spec.IsNullable) {
  9003. type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
  9004. if (type == null)
  9005. return null;
  9006. single_spec = single_spec.Next;
  9007. } else if (single_spec.IsPointer) {
  9008. if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
  9009. return null;
  9010. if (!ec.IsUnsafe) {
  9011. UnsafeError (ec.Module.Compiler.Report, loc);
  9012. }
  9013. do {
  9014. type = PointerContainer.MakeType (ec.Module, type);
  9015. single_spec = single_spec.Next;
  9016. } while (single_spec != null && single_spec.IsPointer);
  9017. }
  9018. if (single_spec != null && single_spec.Dimension > 0) {
  9019. if (type.IsSpecialRuntimeType) {
  9020. ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
  9021. } else if (type.IsStatic) {
  9022. ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
  9023. ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
  9024. type.GetSignatureForError ());
  9025. } else {
  9026. MakeArray (ec.Module, single_spec);
  9027. }
  9028. }
  9029. return type;
  9030. }
  9031. void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
  9032. {
  9033. if (spec.Next != null)
  9034. MakeArray (module, spec.Next);
  9035. type = ArrayContainer.MakeType (module, type, spec.Dimension);
  9036. }
  9037. public override string GetSignatureForError ()
  9038. {
  9039. return left.GetSignatureForError () + spec.GetSignatureForError ();
  9040. }
  9041. public override object Accept (StructuralVisitor visitor)
  9042. {
  9043. return visitor.Visit (this);
  9044. }
  9045. }
  9046. class FixedBufferPtr : Expression
  9047. {
  9048. readonly Expression array;
  9049. public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
  9050. {
  9051. this.type = array_type;
  9052. this.array = array;
  9053. this.loc = l;
  9054. }
  9055. public override bool ContainsEmitWithAwait ()
  9056. {
  9057. throw new NotImplementedException ();
  9058. }
  9059. public override Expression CreateExpressionTree (ResolveContext ec)
  9060. {
  9061. Error_PointerInsideExpressionTree (ec);
  9062. return null;
  9063. }
  9064. public override void Emit(EmitContext ec)
  9065. {
  9066. array.Emit (ec);
  9067. }
  9068. protected override Expression DoResolve (ResolveContext ec)
  9069. {
  9070. type = PointerContainer.MakeType (ec.Module, type);
  9071. eclass = ExprClass.Value;
  9072. return this;
  9073. }
  9074. }
  9075. //
  9076. // This class is used to represent the address of an array, used
  9077. // only by the Fixed statement, this generates "&a [0]" construct
  9078. // for fixed (char *pa = a)
  9079. //
  9080. class ArrayPtr : FixedBufferPtr
  9081. {
  9082. public ArrayPtr (Expression array, TypeSpec array_type, Location l):
  9083. base (array, array_type, l)
  9084. {
  9085. }
  9086. public override void Emit (EmitContext ec)
  9087. {
  9088. base.Emit (ec);
  9089. ec.EmitInt (0);
  9090. ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
  9091. }
  9092. }
  9093. //
  9094. // Encapsulates a conversion rules required for array indexes
  9095. //
  9096. public class ArrayIndexCast : TypeCast
  9097. {
  9098. public ArrayIndexCast (Expression expr, TypeSpec returnType)
  9099. : base (expr, returnType)
  9100. {
  9101. if (expr.Type == returnType) // int -> int
  9102. throw new ArgumentException ("unnecessary array index conversion");
  9103. }
  9104. public override Expression CreateExpressionTree (ResolveContext ec)
  9105. {
  9106. using (ec.Set (ResolveContext.Options.CheckedScope)) {
  9107. return base.CreateExpressionTree (ec);
  9108. }
  9109. }
  9110. public override void Emit (EmitContext ec)
  9111. {
  9112. child.Emit (ec);
  9113. switch (child.Type.BuiltinType) {
  9114. case BuiltinTypeSpec.Type.UInt:
  9115. ec.Emit (OpCodes.Conv_U);
  9116. break;
  9117. case BuiltinTypeSpec.Type.Long:
  9118. ec.Emit (OpCodes.Conv_Ovf_I);
  9119. break;
  9120. case BuiltinTypeSpec.Type.ULong:
  9121. ec.Emit (OpCodes.Conv_Ovf_I_Un);
  9122. break;
  9123. default:
  9124. throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
  9125. }
  9126. }
  9127. }
  9128. //
  9129. // Implements the `stackalloc' keyword
  9130. //
  9131. public class StackAlloc : Expression {
  9132. TypeSpec otype;
  9133. Expression t;
  9134. Expression count;
  9135. public StackAlloc (Expression type, Expression count, Location l)
  9136. {
  9137. t = type;
  9138. this.count = count;
  9139. loc = l;
  9140. }
  9141. public Expression TypeExpression {
  9142. get {
  9143. return this.t;
  9144. }
  9145. }
  9146. public Expression CountExpression {
  9147. get {
  9148. return this.count;
  9149. }
  9150. }
  9151. public override bool ContainsEmitWithAwait ()
  9152. {
  9153. return false;
  9154. }
  9155. public override Expression CreateExpressionTree (ResolveContext ec)
  9156. {
  9157. throw new NotSupportedException ("ET");
  9158. }
  9159. protected override Expression DoResolve (ResolveContext ec)
  9160. {
  9161. count = count.Resolve (ec);
  9162. if (count == null)
  9163. return null;
  9164. if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
  9165. count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
  9166. if (count == null)
  9167. return null;
  9168. }
  9169. Constant c = count as Constant;
  9170. if (c != null && c.IsNegative) {
  9171. ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
  9172. }
  9173. if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
  9174. ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
  9175. }
  9176. otype = t.ResolveAsType (ec);
  9177. if (otype == null)
  9178. return null;
  9179. if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
  9180. return null;
  9181. type = PointerContainer.MakeType (ec.Module, otype);
  9182. eclass = ExprClass.Value;
  9183. return this;
  9184. }
  9185. public override void Emit (EmitContext ec)
  9186. {
  9187. int size = BuiltinTypeSpec.GetSize (otype);
  9188. count.Emit (ec);
  9189. if (size == 0)
  9190. ec.Emit (OpCodes.Sizeof, otype);
  9191. else
  9192. ec.EmitInt (size);
  9193. ec.Emit (OpCodes.Mul_Ovf_Un);
  9194. ec.Emit (OpCodes.Localloc);
  9195. }
  9196. protected override void CloneTo (CloneContext clonectx, Expression t)
  9197. {
  9198. StackAlloc target = (StackAlloc) t;
  9199. target.count = count.Clone (clonectx);
  9200. target.t = t.Clone (clonectx);
  9201. }
  9202. public override object Accept (StructuralVisitor visitor)
  9203. {
  9204. return visitor.Visit (this);
  9205. }
  9206. }
  9207. //
  9208. // An object initializer expression
  9209. //
  9210. public class ElementInitializer : Assign
  9211. {
  9212. public readonly string Name;
  9213. public ElementInitializer (string name, Expression initializer, Location loc)
  9214. : base (null, initializer, loc)
  9215. {
  9216. this.Name = name;
  9217. }
  9218. public bool IsDictionaryInitializer {
  9219. get {
  9220. return Name == null;
  9221. }
  9222. }
  9223. protected override void CloneTo (CloneContext clonectx, Expression t)
  9224. {
  9225. ElementInitializer target = (ElementInitializer) t;
  9226. target.source = source.Clone (clonectx);
  9227. }
  9228. public override Expression CreateExpressionTree (ResolveContext ec)
  9229. {
  9230. Arguments args = new Arguments (2);
  9231. FieldExpr fe = target as FieldExpr;
  9232. if (fe != null)
  9233. args.Add (new Argument (fe.CreateTypeOfExpression ()));
  9234. else
  9235. args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
  9236. string mname;
  9237. Expression arg_expr;
  9238. var cinit = source as CollectionOrObjectInitializers;
  9239. if (cinit == null) {
  9240. mname = "Bind";
  9241. arg_expr = source.CreateExpressionTree (ec);
  9242. } else {
  9243. mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
  9244. arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
  9245. }
  9246. args.Add (new Argument (arg_expr));
  9247. return CreateExpressionFactoryCall (ec, mname, args);
  9248. }
  9249. protected override Expression DoResolve (ResolveContext ec)
  9250. {
  9251. if (source == null)
  9252. return EmptyExpressionStatement.Instance;
  9253. if (!ResolveElement (ec))
  9254. return null;
  9255. if (source is CollectionOrObjectInitializers) {
  9256. Expression previous = ec.CurrentInitializerVariable;
  9257. ec.CurrentInitializerVariable = target;
  9258. source = source.Resolve (ec);
  9259. ec.CurrentInitializerVariable = previous;
  9260. if (source == null)
  9261. return null;
  9262. eclass = source.eclass;
  9263. type = source.Type;
  9264. return this;
  9265. }
  9266. return base.DoResolve (ec);
  9267. }
  9268. public override void EmitStatement (EmitContext ec)
  9269. {
  9270. if (source is CollectionOrObjectInitializers)
  9271. source.Emit (ec);
  9272. else
  9273. base.EmitStatement (ec);
  9274. }
  9275. protected virtual bool ResolveElement (ResolveContext rc)
  9276. {
  9277. var t = rc.CurrentInitializerVariable.Type;
  9278. if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
  9279. Arguments args = new Arguments (1);
  9280. args.Add (new Argument (rc.CurrentInitializerVariable));
  9281. target = new DynamicMemberBinder (Name, args, loc);
  9282. } else {
  9283. var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
  9284. if (member == null) {
  9285. member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
  9286. if (member != null) {
  9287. // TODO: ec.Report.SymbolRelatedToPreviousError (member);
  9288. ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
  9289. return false;
  9290. }
  9291. }
  9292. if (member == null) {
  9293. Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
  9294. return false;
  9295. }
  9296. var me = member as MemberExpr;
  9297. if (me is EventExpr) {
  9298. me = me.ResolveMemberAccess (rc, null, null);
  9299. } else if (!(member is PropertyExpr || member is FieldExpr)) {
  9300. rc.Report.Error (1913, loc,
  9301. "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
  9302. member.GetSignatureForError ());
  9303. return false;
  9304. }
  9305. if (me.IsStatic) {
  9306. rc.Report.Error (1914, loc,
  9307. "Static field or property `{0}' cannot be assigned in an object initializer",
  9308. me.GetSignatureForError ());
  9309. }
  9310. target = me;
  9311. me.InstanceExpression = rc.CurrentInitializerVariable;
  9312. }
  9313. return true;
  9314. }
  9315. }
  9316. //
  9317. // A collection initializer expression
  9318. //
  9319. class CollectionElementInitializer : Invocation
  9320. {
  9321. public readonly bool IsSingle;
  9322. public class ElementInitializerArgument : Argument
  9323. {
  9324. public ElementInitializerArgument (Expression e)
  9325. : base (e)
  9326. {
  9327. }
  9328. }
  9329. sealed class AddMemberAccess : MemberAccess
  9330. {
  9331. public AddMemberAccess (Expression expr, Location loc)
  9332. : base (expr, "Add", loc)
  9333. {
  9334. }
  9335. protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
  9336. {
  9337. if (TypeManager.HasElementType (type))
  9338. return;
  9339. base.Error_TypeDoesNotContainDefinition (ec, type, name);
  9340. }
  9341. }
  9342. public CollectionElementInitializer (Expression argument)
  9343. : base (null, new Arguments (1))
  9344. {
  9345. IsSingle = true;
  9346. base.arguments.Add (new ElementInitializerArgument (argument));
  9347. this.loc = argument.Location;
  9348. }
  9349. public CollectionElementInitializer (List<Expression> arguments, Location loc)
  9350. : base (null, new Arguments (arguments.Count))
  9351. {
  9352. IsSingle = false;
  9353. foreach (Expression e in arguments)
  9354. base.arguments.Add (new ElementInitializerArgument (e));
  9355. this.loc = loc;
  9356. }
  9357. public CollectionElementInitializer (Location loc)
  9358. : base (null, null)
  9359. {
  9360. this.loc = loc;
  9361. }
  9362. public override Expression CreateExpressionTree (ResolveContext ec)
  9363. {
  9364. Arguments args = new Arguments (2);
  9365. args.Add (new Argument (mg.CreateExpressionTree (ec)));
  9366. var expr_initializers = new ArrayInitializer (arguments.Count, loc);
  9367. foreach (Argument a in arguments)
  9368. expr_initializers.Add (a.CreateExpressionTree (ec));
  9369. args.Add (new Argument (new ArrayCreation (
  9370. CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
  9371. return CreateExpressionFactoryCall (ec, "ElementInit", args);
  9372. }
  9373. protected override void CloneTo (CloneContext clonectx, Expression t)
  9374. {
  9375. CollectionElementInitializer target = (CollectionElementInitializer) t;
  9376. if (arguments != null)
  9377. target.arguments = arguments.Clone (clonectx);
  9378. }
  9379. protected override Expression DoResolve (ResolveContext ec)
  9380. {
  9381. base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
  9382. return base.DoResolve (ec);
  9383. }
  9384. }
  9385. class DictionaryElementInitializer : ElementInitializer
  9386. {
  9387. readonly Arguments args;
  9388. public DictionaryElementInitializer (List<Expression> arguments, Expression initializer, Location loc)
  9389. : base (null, initializer, loc)
  9390. {
  9391. this.args = new Arguments (arguments.Count);
  9392. foreach (var arg in arguments)
  9393. this.args.Add (new Argument (arg));
  9394. }
  9395. public override Expression CreateExpressionTree (ResolveContext ec)
  9396. {
  9397. ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
  9398. return null;
  9399. }
  9400. protected override bool ResolveElement (ResolveContext rc)
  9401. {
  9402. var init = rc.CurrentInitializerVariable;
  9403. var type = init.Type;
  9404. var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
  9405. if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
  9406. ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
  9407. return false;
  9408. }
  9409. target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
  9410. return true;
  9411. }
  9412. }
  9413. //
  9414. // A block of object or collection initializers
  9415. //
  9416. public class CollectionOrObjectInitializers : ExpressionStatement
  9417. {
  9418. IList<Expression> initializers;
  9419. bool is_collection_initialization;
  9420. public CollectionOrObjectInitializers (Location loc)
  9421. : this (new Expression[0], loc)
  9422. {
  9423. }
  9424. public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
  9425. {
  9426. this.initializers = initializers;
  9427. this.loc = loc;
  9428. }
  9429. public bool IsEmpty {
  9430. get {
  9431. return initializers.Count == 0;
  9432. }
  9433. }
  9434. public bool IsCollectionInitializer {
  9435. get {
  9436. return is_collection_initialization;
  9437. }
  9438. }
  9439. public IList<Expression> Initializers {
  9440. get {
  9441. return initializers;
  9442. }
  9443. }
  9444. protected override void CloneTo (CloneContext clonectx, Expression target)
  9445. {
  9446. CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
  9447. t.initializers = new List<Expression> (initializers.Count);
  9448. foreach (var e in initializers)
  9449. t.initializers.Add (e.Clone (clonectx));
  9450. }
  9451. public override bool ContainsEmitWithAwait ()
  9452. {
  9453. foreach (var e in initializers) {
  9454. if (e.ContainsEmitWithAwait ())
  9455. return true;
  9456. }
  9457. return false;
  9458. }
  9459. public override Expression CreateExpressionTree (ResolveContext ec)
  9460. {
  9461. return CreateExpressionTree (ec, false);
  9462. }
  9463. public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
  9464. {
  9465. var expr_initializers = new ArrayInitializer (initializers.Count, loc);
  9466. foreach (Expression e in initializers) {
  9467. Expression expr = e.CreateExpressionTree (ec);
  9468. if (expr != null)
  9469. expr_initializers.Add (expr);
  9470. }
  9471. if (inferType)
  9472. return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
  9473. return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
  9474. }
  9475. protected override Expression DoResolve (ResolveContext ec)
  9476. {
  9477. List<string> element_names = null;
  9478. for (int i = 0; i < initializers.Count; ++i) {
  9479. Expression initializer = initializers [i];
  9480. ElementInitializer element_initializer = initializer as ElementInitializer;
  9481. if (i == 0) {
  9482. if (element_initializer != null) {
  9483. element_names = new List<string> (initializers.Count);
  9484. if (!element_initializer.IsDictionaryInitializer)
  9485. element_names.Add (element_initializer.Name);
  9486. } else if (initializer is CompletingExpression) {
  9487. initializer.Resolve (ec);
  9488. throw new InternalErrorException ("This line should never be reached");
  9489. } else {
  9490. var t = ec.CurrentInitializerVariable.Type;
  9491. // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
  9492. if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
  9493. ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
  9494. "object initializer because type `{1}' does not implement `{2}' interface",
  9495. ec.CurrentInitializerVariable.GetSignatureForError (),
  9496. ec.CurrentInitializerVariable.Type.GetSignatureForError (),
  9497. ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
  9498. return null;
  9499. }
  9500. is_collection_initialization = true;
  9501. }
  9502. } else {
  9503. if (is_collection_initialization != (element_initializer == null)) {
  9504. ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
  9505. is_collection_initialization ? "collection initializer" : "object initializer");
  9506. continue;
  9507. }
  9508. if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
  9509. if (element_names.Contains (element_initializer.Name)) {
  9510. ec.Report.Error (1912, element_initializer.Location,
  9511. "An object initializer includes more than one member `{0}' initialization",
  9512. element_initializer.Name);
  9513. } else {
  9514. element_names.Add (element_initializer.Name);
  9515. }
  9516. }
  9517. }
  9518. Expression e = initializer.Resolve (ec);
  9519. if (e == EmptyExpressionStatement.Instance)
  9520. initializers.RemoveAt (i--);
  9521. else
  9522. initializers [i] = e;
  9523. }
  9524. type = ec.CurrentInitializerVariable.Type;
  9525. if (is_collection_initialization) {
  9526. if (TypeManager.HasElementType (type)) {
  9527. ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
  9528. type.GetSignatureForError ());
  9529. }
  9530. }
  9531. eclass = ExprClass.Variable;
  9532. return this;
  9533. }
  9534. public override void Emit (EmitContext ec)
  9535. {
  9536. EmitStatement (ec);
  9537. }
  9538. public override void EmitStatement (EmitContext ec)
  9539. {
  9540. foreach (ExpressionStatement e in initializers) {
  9541. // TODO: need location region
  9542. ec.Mark (e.Location);
  9543. e.EmitStatement (ec);
  9544. }
  9545. }
  9546. public override void FlowAnalysis (FlowAnalysisContext fc)
  9547. {
  9548. foreach (var initializer in initializers) {
  9549. if (initializer != null)
  9550. initializer.FlowAnalysis (fc);
  9551. }
  9552. }
  9553. }
  9554. //
  9555. // New expression with element/object initializers
  9556. //
  9557. public class NewInitialize : New
  9558. {
  9559. //
  9560. // This class serves as a proxy for variable initializer target instances.
  9561. // A real variable is assigned later when we resolve left side of an
  9562. // assignment
  9563. //
  9564. sealed class InitializerTargetExpression : Expression, IMemoryLocation
  9565. {
  9566. NewInitialize new_instance;
  9567. public InitializerTargetExpression (NewInitialize newInstance)
  9568. {
  9569. this.type = newInstance.type;
  9570. this.loc = newInstance.loc;
  9571. this.eclass = newInstance.eclass;
  9572. this.new_instance = newInstance;
  9573. }
  9574. public override bool ContainsEmitWithAwait ()
  9575. {
  9576. return false;
  9577. }
  9578. public override Expression CreateExpressionTree (ResolveContext ec)
  9579. {
  9580. // Should not be reached
  9581. throw new NotSupportedException ("ET");
  9582. }
  9583. protected override Expression DoResolve (ResolveContext ec)
  9584. {
  9585. return this;
  9586. }
  9587. public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
  9588. {
  9589. return this;
  9590. }
  9591. public override void Emit (EmitContext ec)
  9592. {
  9593. Expression e = (Expression) new_instance.instance;
  9594. e.Emit (ec);
  9595. }
  9596. public override Expression EmitToField (EmitContext ec)
  9597. {
  9598. return (Expression) new_instance.instance;
  9599. }
  9600. #region IMemoryLocation Members
  9601. public void AddressOf (EmitContext ec, AddressOp mode)
  9602. {
  9603. new_instance.instance.AddressOf (ec, mode);
  9604. }
  9605. #endregion
  9606. }
  9607. CollectionOrObjectInitializers initializers;
  9608. IMemoryLocation instance;
  9609. DynamicExpressionStatement dynamic;
  9610. public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
  9611. : base (requested_type, arguments, l)
  9612. {
  9613. this.initializers = initializers;
  9614. }
  9615. public CollectionOrObjectInitializers Initializers {
  9616. get {
  9617. return initializers;
  9618. }
  9619. }
  9620. protected override void CloneTo (CloneContext clonectx, Expression t)
  9621. {
  9622. base.CloneTo (clonectx, t);
  9623. NewInitialize target = (NewInitialize) t;
  9624. target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
  9625. }
  9626. public override bool ContainsEmitWithAwait ()
  9627. {
  9628. return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
  9629. }
  9630. public override Expression CreateExpressionTree (ResolveContext ec)
  9631. {
  9632. Arguments args = new Arguments (2);
  9633. args.Add (new Argument (base.CreateExpressionTree (ec)));
  9634. if (!initializers.IsEmpty)
  9635. args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
  9636. return CreateExpressionFactoryCall (ec,
  9637. initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
  9638. args);
  9639. }
  9640. protected override Expression DoResolve (ResolveContext ec)
  9641. {
  9642. Expression e = base.DoResolve (ec);
  9643. if (type == null)
  9644. return null;
  9645. if (type.IsDelegate) {
  9646. ec.Report.Error (1958, Initializers.Location,
  9647. "Object and collection initializers cannot be used to instantiate a delegate");
  9648. }
  9649. Expression previous = ec.CurrentInitializerVariable;
  9650. ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
  9651. initializers.Resolve (ec);
  9652. ec.CurrentInitializerVariable = previous;
  9653. dynamic = e as DynamicExpressionStatement;
  9654. if (dynamic != null)
  9655. return this;
  9656. return e;
  9657. }
  9658. public override void Emit (EmitContext ec)
  9659. {
  9660. if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
  9661. var fe = ec.GetTemporaryField (type);
  9662. if (!Emit (ec, fe))
  9663. fe.Emit (ec);
  9664. return;
  9665. }
  9666. base.Emit (ec);
  9667. }
  9668. public override bool Emit (EmitContext ec, IMemoryLocation target)
  9669. {
  9670. bool left_on_stack;
  9671. if (dynamic != null) {
  9672. dynamic.Emit (ec);
  9673. left_on_stack = true;
  9674. } else {
  9675. left_on_stack = base.Emit (ec, target);
  9676. }
  9677. if (initializers.IsEmpty)
  9678. return left_on_stack;
  9679. LocalTemporary temp = null;
  9680. instance = target as LocalTemporary;
  9681. if (instance == null)
  9682. instance = target as StackFieldExpr;
  9683. if (instance == null) {
  9684. if (!left_on_stack) {
  9685. VariableReference vr = target as VariableReference;
  9686. // FIXME: This still does not work correctly for pre-set variables
  9687. if (vr != null && vr.IsRef)
  9688. target.AddressOf (ec, AddressOp.Load);
  9689. ((Expression) target).Emit (ec);
  9690. left_on_stack = true;
  9691. }
  9692. if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
  9693. instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
  9694. } else {
  9695. temp = new LocalTemporary (type);
  9696. instance = temp;
  9697. }
  9698. }
  9699. if (left_on_stack && temp != null)
  9700. temp.Store (ec);
  9701. initializers.Emit (ec);
  9702. if (left_on_stack) {
  9703. if (temp != null) {
  9704. temp.Emit (ec);
  9705. temp.Release (ec);
  9706. } else {
  9707. ((Expression) instance).Emit (ec);
  9708. }
  9709. }
  9710. return left_on_stack;
  9711. }
  9712. protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
  9713. {
  9714. instance = base.EmitAddressOf (ec, Mode);
  9715. if (!initializers.IsEmpty)
  9716. initializers.Emit (ec);
  9717. return instance;
  9718. }
  9719. public override void FlowAnalysis (FlowAnalysisContext fc)
  9720. {
  9721. base.FlowAnalysis (fc);
  9722. initializers.FlowAnalysis (fc);
  9723. }
  9724. public override object Accept (StructuralVisitor visitor)
  9725. {
  9726. return visitor.Visit (this);
  9727. }
  9728. }
  9729. public class NewAnonymousType : New
  9730. {
  9731. static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
  9732. List<AnonymousTypeParameter> parameters;
  9733. readonly TypeContainer parent;
  9734. AnonymousTypeClass anonymous_type;
  9735. public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
  9736. : base (null, null, loc)
  9737. {
  9738. this.parameters = parameters;
  9739. this.parent = parent;
  9740. }
  9741. public List<AnonymousTypeParameter> Parameters {
  9742. get {
  9743. return this.parameters;
  9744. }
  9745. }
  9746. protected override void CloneTo (CloneContext clonectx, Expression target)
  9747. {
  9748. if (parameters == null)
  9749. return;
  9750. NewAnonymousType t = (NewAnonymousType) target;
  9751. t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
  9752. foreach (AnonymousTypeParameter atp in parameters)
  9753. t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
  9754. }
  9755. AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
  9756. {
  9757. AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
  9758. if (type != null)
  9759. return type;
  9760. type = AnonymousTypeClass.Create (parent, parameters, loc);
  9761. if (type == null)
  9762. return null;
  9763. int errors = ec.Report.Errors;
  9764. type.CreateContainer ();
  9765. type.DefineContainer ();
  9766. type.Define ();
  9767. if ((ec.Report.Errors - errors) == 0) {
  9768. parent.Module.AddAnonymousType (type);
  9769. type.PrepareEmit ();
  9770. }
  9771. return type;
  9772. }
  9773. public override Expression CreateExpressionTree (ResolveContext ec)
  9774. {
  9775. if (parameters == null)
  9776. return base.CreateExpressionTree (ec);
  9777. var init = new ArrayInitializer (parameters.Count, loc);
  9778. foreach (var m in anonymous_type.Members) {
  9779. var p = m as Property;
  9780. if (p != null)
  9781. init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
  9782. }
  9783. var ctor_args = new ArrayInitializer (arguments.Count, loc);
  9784. foreach (Argument a in arguments)
  9785. ctor_args.Add (a.CreateExpressionTree (ec));
  9786. Arguments args = new Arguments (3);
  9787. args.Add (new Argument (new TypeOfMethod (method, loc)));
  9788. args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
  9789. args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
  9790. return CreateExpressionFactoryCall (ec, "New", args);
  9791. }
  9792. protected override Expression DoResolve (ResolveContext ec)
  9793. {
  9794. if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
  9795. ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
  9796. return null;
  9797. }
  9798. if (parameters == null) {
  9799. anonymous_type = CreateAnonymousType (ec, EmptyParameters);
  9800. RequestedType = new TypeExpression (anonymous_type.Definition, loc);
  9801. return base.DoResolve (ec);
  9802. }
  9803. bool error = false;
  9804. arguments = new Arguments (parameters.Count);
  9805. var t_args = new TypeSpec [parameters.Count];
  9806. for (int i = 0; i < parameters.Count; ++i) {
  9807. Expression e = parameters [i].Resolve (ec);
  9808. if (e == null) {
  9809. error = true;
  9810. continue;
  9811. }
  9812. arguments.Add (new Argument (e));
  9813. t_args [i] = e.Type;
  9814. }
  9815. if (error)
  9816. return null;
  9817. anonymous_type = CreateAnonymousType (ec, parameters);
  9818. if (anonymous_type == null)
  9819. return null;
  9820. type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
  9821. method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
  9822. eclass = ExprClass.Value;
  9823. return this;
  9824. }
  9825. public override object Accept (StructuralVisitor visitor)
  9826. {
  9827. return visitor.Visit (this);
  9828. }
  9829. }
  9830. public class AnonymousTypeParameter : ShimExpression
  9831. {
  9832. public readonly string Name;
  9833. public AnonymousTypeParameter (Expression initializer, string name, Location loc)
  9834. : base (initializer)
  9835. {
  9836. this.Name = name;
  9837. this.loc = loc;
  9838. }
  9839. public AnonymousTypeParameter (Parameter parameter)
  9840. : base (new SimpleName (parameter.Name, parameter.Location))
  9841. {
  9842. this.Name = parameter.Name;
  9843. this.loc = parameter.Location;
  9844. }
  9845. public override bool Equals (object o)
  9846. {
  9847. AnonymousTypeParameter other = o as AnonymousTypeParameter;
  9848. return other != null && Name == other.Name;
  9849. }
  9850. public override int GetHashCode ()
  9851. {
  9852. return Name.GetHashCode ();
  9853. }
  9854. protected override Expression DoResolve (ResolveContext ec)
  9855. {
  9856. Expression e = expr.Resolve (ec);
  9857. if (e == null)
  9858. return null;
  9859. if (e.eclass == ExprClass.MethodGroup) {
  9860. Error_InvalidInitializer (ec, e.ExprClassName);
  9861. return null;
  9862. }
  9863. type = e.Type;
  9864. if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
  9865. Error_InvalidInitializer (ec, type.GetSignatureForError ());
  9866. return null;
  9867. }
  9868. return e;
  9869. }
  9870. protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
  9871. {
  9872. ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
  9873. Name, initializer);
  9874. }
  9875. }
  9876. public class CatchFilterExpression : BooleanExpression
  9877. {
  9878. public CatchFilterExpression (Expression expr, Location loc)
  9879. : base (expr)
  9880. {
  9881. this.loc = loc;
  9882. }
  9883. }
  9884. }