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 13 using System; 14 using System.Collections.Generic; 15 using System.Linq; 16 using SLE = System.Linq.Expressions; 17 using System.Text; 18 19 #if STATIC 20 using MetaType = IKVM.Reflection.Type; 21 using IKVM.Reflection; 22 using IKVM.Reflection.Emit; 23 #else 24 using MetaType = System.Type; 25 using System.Reflection; 26 using System.Reflection.Emit; 27 #endif 28 29 namespace Mono.CSharp 30 { 31 // 32 // This is an user operator expression, automatically created during 33 // resolve phase 34 // 35 public class UserOperatorCall : Expression { 36 protected readonly Arguments arguments; 37 protected readonly MethodSpec oper; 38 readonly Func<ResolveContext, Expression, Expression> expr_tree; 39 UserOperatorCall(MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)40 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc) 41 { 42 this.oper = oper; 43 this.arguments = args; 44 this.expr_tree = expr_tree; 45 46 type = oper.ReturnType; 47 eclass = ExprClass.Value; 48 this.loc = loc; 49 } 50 ContainsEmitWithAwait()51 public override bool ContainsEmitWithAwait () 52 { 53 return arguments.ContainsEmitWithAwait (); 54 } 55 CreateExpressionTree(ResolveContext ec)56 public override Expression CreateExpressionTree (ResolveContext ec) 57 { 58 if (expr_tree != null) 59 return expr_tree (ec, new TypeOfMethod (oper, loc)); 60 61 Arguments args = Arguments.CreateForExpressionTree (ec, arguments, 62 new NullLiteral (loc), 63 new TypeOfMethod (oper, loc)); 64 65 return CreateExpressionFactoryCall (ec, "Call", args); 66 } 67 CloneTo(CloneContext context, Expression target)68 protected override void CloneTo (CloneContext context, Expression target) 69 { 70 // Nothing to clone 71 } 72 DoResolve(ResolveContext ec)73 protected override Expression DoResolve (ResolveContext ec) 74 { 75 // 76 // We are born fully resolved 77 // 78 return this; 79 } 80 Emit(EmitContext ec)81 public override void Emit (EmitContext ec) 82 { 83 var call = new CallEmitter (); 84 call.Emit (ec, oper, arguments, loc); 85 } 86 FlowAnalysis(FlowAnalysisContext fc)87 public override void FlowAnalysis (FlowAnalysisContext fc) 88 { 89 arguments.FlowAnalysis (fc); 90 } 91 MakeExpression(BuilderContext ctx)92 public override SLE.Expression MakeExpression (BuilderContext ctx) 93 { 94 #if STATIC 95 return base.MakeExpression (ctx); 96 #else 97 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx)); 98 #endif 99 } 100 } 101 102 public class ParenthesizedExpression : ShimExpression 103 { ParenthesizedExpression(Expression expr, Location loc)104 public ParenthesizedExpression (Expression expr, Location loc) 105 : base (expr) 106 { 107 this.loc = loc; 108 } 109 DoResolve(ResolveContext rc)110 protected override Expression DoResolve (ResolveContext rc) 111 { 112 Expression res = null; 113 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) { 114 res = expr.Resolve (rc); 115 } 116 117 var constant = res as Constant; 118 if (constant != null && constant.IsLiteral) { 119 if (res is NullLiteral) 120 return res; 121 122 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location); 123 } 124 125 return res; 126 } 127 DoResolveLValue(ResolveContext ec, Expression right_side)128 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side) 129 { 130 return expr.DoResolveLValue (ec, right_side); 131 } 132 Accept(StructuralVisitor visitor)133 public override object Accept (StructuralVisitor visitor) 134 { 135 return visitor.Visit (this); 136 } 137 HasConditionalAccess()138 public override bool HasConditionalAccess () 139 { 140 return false; 141 } 142 } 143 144 // 145 // Unary implements unary expressions. 146 // 147 public class Unary : Expression 148 { 149 public enum Operator : byte { 150 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement, 151 AddressOf, TOP 152 } 153 154 public readonly Operator Oper; 155 public Expression Expr; 156 ConvCast.Mode enum_conversion; 157 Unary(Operator op, Expression expr, Location loc)158 public Unary (Operator op, Expression expr, Location loc) 159 { 160 Oper = op; 161 Expr = expr; 162 this.loc = loc; 163 } 164 165 // <summary> 166 // This routine will attempt to simplify the unary expression when the 167 // argument is a constant. 168 // </summary> TryReduceConstant(ResolveContext ec, Constant constant)169 Constant TryReduceConstant (ResolveContext ec, Constant constant) 170 { 171 var e = constant; 172 173 while (e is EmptyConstantCast) 174 e = ((EmptyConstantCast) e).child; 175 176 if (e is SideEffectConstant) { 177 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value); 178 return r == null ? null : new SideEffectConstant (r, e, r.Location); 179 } 180 181 TypeSpec expr_type = e.Type; 182 183 switch (Oper){ 184 case Operator.UnaryPlus: 185 // Unary numeric promotions 186 switch (expr_type.BuiltinType) { 187 case BuiltinTypeSpec.Type.Byte: 188 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location); 189 case BuiltinTypeSpec.Type.SByte: 190 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location); 191 case BuiltinTypeSpec.Type.Short: 192 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location); 193 case BuiltinTypeSpec.Type.UShort: 194 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location); 195 case BuiltinTypeSpec.Type.Char: 196 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location); 197 198 // Predefined operators 199 case BuiltinTypeSpec.Type.Int: 200 case BuiltinTypeSpec.Type.UInt: 201 case BuiltinTypeSpec.Type.Long: 202 case BuiltinTypeSpec.Type.ULong: 203 case BuiltinTypeSpec.Type.Float: 204 case BuiltinTypeSpec.Type.Double: 205 case BuiltinTypeSpec.Type.Decimal: 206 return e; 207 } 208 209 return null; 210 211 case Operator.UnaryNegation: 212 // Unary numeric promotions 213 switch (expr_type.BuiltinType) { 214 case BuiltinTypeSpec.Type.Byte: 215 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location); 216 case BuiltinTypeSpec.Type.SByte: 217 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location); 218 case BuiltinTypeSpec.Type.Short: 219 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location); 220 case BuiltinTypeSpec.Type.UShort: 221 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location); 222 case BuiltinTypeSpec.Type.Char: 223 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location); 224 225 // Predefined operators 226 case BuiltinTypeSpec.Type.Int: 227 int ivalue = ((IntConstant) e).Value; 228 if (ivalue == int.MinValue) { 229 if (ec.ConstantCheckState) { 230 ConstantFold.Error_CompileTimeOverflow (ec, loc); 231 return null; 232 } 233 return e; 234 } 235 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location); 236 237 case BuiltinTypeSpec.Type.Long: 238 long lvalue = ((LongConstant) e).Value; 239 if (lvalue == long.MinValue) { 240 if (ec.ConstantCheckState) { 241 ConstantFold.Error_CompileTimeOverflow (ec, loc); 242 return null; 243 } 244 return e; 245 } 246 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location); 247 248 case BuiltinTypeSpec.Type.UInt: 249 UIntLiteral uil = constant as UIntLiteral; 250 if (uil != null) { 251 if (uil.Value == int.MaxValue + (uint) 1) 252 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location); 253 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location); 254 } 255 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location); 256 257 258 case BuiltinTypeSpec.Type.ULong: 259 ULongLiteral ull = constant as ULongLiteral; 260 if (ull != null && ull.Value == 9223372036854775808) 261 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location); 262 return null; 263 264 case BuiltinTypeSpec.Type.Float: 265 FloatLiteral fl = constant as FloatLiteral; 266 // For better error reporting 267 if (fl != null) 268 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location); 269 270 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location); 271 272 case BuiltinTypeSpec.Type.Double: 273 DoubleLiteral dl = constant as DoubleLiteral; 274 // For better error reporting 275 if (dl != null) 276 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location); 277 278 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location); 279 280 case BuiltinTypeSpec.Type.Decimal: 281 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location); 282 } 283 284 return null; 285 286 case Operator.LogicalNot: 287 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool) 288 return null; 289 290 bool b = (bool)e.GetValue (); 291 return new BoolConstant (ec.BuiltinTypes, !b, e.Location); 292 293 case Operator.OnesComplement: 294 // Unary numeric promotions 295 switch (expr_type.BuiltinType) { 296 case BuiltinTypeSpec.Type.Byte: 297 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location); 298 case BuiltinTypeSpec.Type.SByte: 299 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location); 300 case BuiltinTypeSpec.Type.Short: 301 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location); 302 case BuiltinTypeSpec.Type.UShort: 303 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location); 304 case BuiltinTypeSpec.Type.Char: 305 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location); 306 307 // Predefined operators 308 case BuiltinTypeSpec.Type.Int: 309 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location); 310 case BuiltinTypeSpec.Type.UInt: 311 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location); 312 case BuiltinTypeSpec.Type.Long: 313 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location); 314 case BuiltinTypeSpec.Type.ULong: 315 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location); 316 } 317 if (e is EnumConstant) { 318 var res = TryReduceConstant (ec, ((EnumConstant)e).Child); 319 if (res != null) { 320 // 321 // Numeric promotion upgraded types to int but for enum constant 322 // original underlying constant type is needed 323 // 324 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) { 325 int v = ((IntConstant) res).Value; 326 switch (((EnumConstant) e).Child.Type.BuiltinType) { 327 case BuiltinTypeSpec.Type.UShort: 328 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location); 329 break; 330 case BuiltinTypeSpec.Type.Short: 331 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location); 332 break; 333 case BuiltinTypeSpec.Type.Byte: 334 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location); 335 break; 336 case BuiltinTypeSpec.Type.SByte: 337 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location); 338 break; 339 } 340 } 341 342 res = new EnumConstant (res, expr_type); 343 } 344 return res; 345 } 346 return null; 347 } 348 throw new Exception ("Can not constant fold: " + Oper.ToString()); 349 } 350 ResolveOperator(ResolveContext ec, Expression expr)351 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr) 352 { 353 eclass = ExprClass.Value; 354 355 TypeSpec expr_type = expr.Type; 356 Expression best_expr; 357 358 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper]; 359 360 // 361 // Primitive types first 362 // 363 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) { 364 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined); 365 if (best_expr == null) 366 return null; 367 368 type = best_expr.Type; 369 Expr = best_expr; 370 return this; 371 } 372 373 // 374 // E operator ~(E x); 375 // 376 if (Oper == Operator.OnesComplement && expr_type.IsEnum) 377 return ResolveEnumOperator (ec, expr, predefined); 378 379 return ResolveUserType (ec, expr, predefined); 380 } 381 ResolveEnumOperator(ResolveContext ec, Expression expr, TypeSpec[] predefined)382 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined) 383 { 384 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type); 385 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined); 386 if (best_expr == null) 387 return null; 388 389 Expr = best_expr; 390 enum_conversion = Binary.GetEnumResultCast (underlying_type); 391 type = expr.Type; 392 return EmptyCast.Create (this, type); 393 } 394 ContainsEmitWithAwait()395 public override bool ContainsEmitWithAwait () 396 { 397 return Expr.ContainsEmitWithAwait (); 398 } 399 CreateExpressionTree(ResolveContext ec)400 public override Expression CreateExpressionTree (ResolveContext ec) 401 { 402 return CreateExpressionTree (ec, null); 403 } 404 CreateExpressionTree(ResolveContext ec, Expression user_op)405 Expression CreateExpressionTree (ResolveContext ec, Expression user_op) 406 { 407 string method_name; 408 switch (Oper) { 409 case Operator.AddressOf: 410 Error_PointerInsideExpressionTree (ec); 411 return null; 412 case Operator.UnaryNegation: 413 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type)) 414 method_name = "NegateChecked"; 415 else 416 method_name = "Negate"; 417 break; 418 case Operator.OnesComplement: 419 case Operator.LogicalNot: 420 method_name = "Not"; 421 break; 422 case Operator.UnaryPlus: 423 method_name = "UnaryPlus"; 424 break; 425 default: 426 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ()); 427 } 428 429 Arguments args = new Arguments (2); 430 args.Add (new Argument (Expr.CreateExpressionTree (ec))); 431 if (user_op != null) 432 args.Add (new Argument (user_op)); 433 434 return CreateExpressionFactoryCall (ec, method_name, args); 435 } 436 CreatePredefinedOperatorsTable(BuiltinTypes types)437 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types) 438 { 439 var predefined_operators = new TypeSpec[(int) Operator.TOP][]; 440 441 // 442 // 7.6.1 Unary plus operator 443 // 444 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] { 445 types.Int, types.UInt, 446 types.Long, types.ULong, 447 types.Float, types.Double, 448 types.Decimal 449 }; 450 451 // 452 // 7.6.2 Unary minus operator 453 // 454 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] { 455 types.Int, types.Long, 456 types.Float, types.Double, 457 types.Decimal 458 }; 459 460 // 461 // 7.6.3 Logical negation operator 462 // 463 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] { 464 types.Bool 465 }; 466 467 // 468 // 7.6.4 Bitwise complement operator 469 // 470 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] { 471 types.Int, types.UInt, 472 types.Long, types.ULong 473 }; 474 475 return predefined_operators; 476 } 477 478 // 479 // Unary numeric promotions 480 // DoNumericPromotion(ResolveContext rc, Operator op, Expression expr)481 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr) 482 { 483 TypeSpec expr_type = expr.Type; 484 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) { 485 switch (expr_type.BuiltinType) { 486 case BuiltinTypeSpec.Type.Byte: 487 case BuiltinTypeSpec.Type.SByte: 488 case BuiltinTypeSpec.Type.Short: 489 case BuiltinTypeSpec.Type.UShort: 490 case BuiltinTypeSpec.Type.Char: 491 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int); 492 } 493 } 494 495 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt) 496 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long); 497 498 return expr; 499 } 500 DoResolve(ResolveContext ec)501 protected override Expression DoResolve (ResolveContext ec) 502 { 503 if (Oper == Operator.AddressOf) { 504 return ResolveAddressOf (ec); 505 } 506 507 Expr = Expr.Resolve (ec); 508 if (Expr == null) 509 return null; 510 511 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 512 Arguments args = new Arguments (1); 513 args.Add (new Argument (Expr)); 514 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec); 515 } 516 517 if (Expr.Type.IsNullableType) 518 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec); 519 520 // 521 // Attempt to use a constant folding operation. 522 // 523 Constant cexpr = Expr as Constant; 524 if (cexpr != null) { 525 cexpr = TryReduceConstant (ec, cexpr); 526 if (cexpr != null) 527 return cexpr; 528 } 529 530 Expression expr = ResolveOperator (ec, Expr); 531 if (expr == null) 532 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type); 533 534 // 535 // Reduce unary operator on predefined types 536 // 537 if (expr == this && Oper == Operator.UnaryPlus) 538 return Expr; 539 540 return expr; 541 } 542 DoResolveLValue(ResolveContext ec, Expression right)543 public override Expression DoResolveLValue (ResolveContext ec, Expression right) 544 { 545 return null; 546 } 547 Emit(EmitContext ec)548 public override void Emit (EmitContext ec) 549 { 550 EmitOperator (ec, type); 551 } 552 EmitOperator(EmitContext ec, TypeSpec type)553 protected void EmitOperator (EmitContext ec, TypeSpec type) 554 { 555 switch (Oper) { 556 case Operator.UnaryPlus: 557 Expr.Emit (ec); 558 break; 559 560 case Operator.UnaryNegation: 561 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) { 562 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ()) 563 Expr = Expr.EmitToField (ec); 564 565 ec.EmitInt (0); 566 if (type.BuiltinType == BuiltinTypeSpec.Type.Long) 567 ec.Emit (OpCodes.Conv_U8); 568 Expr.Emit (ec); 569 ec.Emit (OpCodes.Sub_Ovf); 570 } else { 571 Expr.Emit (ec); 572 ec.Emit (OpCodes.Neg); 573 } 574 575 break; 576 577 case Operator.LogicalNot: 578 Expr.Emit (ec); 579 ec.EmitInt (0); 580 ec.Emit (OpCodes.Ceq); 581 break; 582 583 case Operator.OnesComplement: 584 Expr.Emit (ec); 585 ec.Emit (OpCodes.Not); 586 break; 587 588 case Operator.AddressOf: 589 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore); 590 break; 591 592 default: 593 throw new Exception ("This should not happen: Operator = " 594 + Oper.ToString ()); 595 } 596 597 // 598 // Same trick as in Binary expression 599 // 600 if (enum_conversion != 0) { 601 using (ec.With (BuilderContext.Options.CheckedScope, false)) { 602 ConvCast.Emit (ec, enum_conversion); 603 } 604 } 605 } 606 EmitBranchable(EmitContext ec, Label target, bool on_true)607 public override void EmitBranchable (EmitContext ec, Label target, bool on_true) 608 { 609 if (Oper == Operator.LogicalNot) 610 Expr.EmitBranchable (ec, target, !on_true); 611 else 612 base.EmitBranchable (ec, target, on_true); 613 } 614 EmitSideEffect(EmitContext ec)615 public override void EmitSideEffect (EmitContext ec) 616 { 617 Expr.EmitSideEffect (ec); 618 } 619 Error_Ambiguous(ResolveContext rc, string oper, TypeSpec type, Location loc)620 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc) 621 { 622 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'", 623 oper, type.GetSignatureForError ()); 624 } 625 FlowAnalysis(FlowAnalysisContext fc)626 public override void FlowAnalysis (FlowAnalysisContext fc) 627 { 628 FlowAnalysis (fc, false); 629 } 630 FlowAnalysisConditional(FlowAnalysisContext fc)631 public override void FlowAnalysisConditional (FlowAnalysisContext fc) 632 { 633 FlowAnalysis (fc, true); 634 } 635 FlowAnalysis(FlowAnalysisContext fc, bool conditional)636 void FlowAnalysis (FlowAnalysisContext fc, bool conditional) 637 { 638 if (Oper == Operator.AddressOf) { 639 var vr = Expr as VariableReference; 640 if (vr != null && vr.VariableInfo != null) 641 fc.SetVariableAssigned (vr.VariableInfo); 642 643 return; 644 } 645 646 if (Oper == Operator.LogicalNot && conditional) { 647 Expr.FlowAnalysisConditional (fc); 648 649 var temp = fc.DefiniteAssignmentOnTrue; 650 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse; 651 fc.DefiniteAssignmentOnFalse = temp; 652 } else { 653 Expr.FlowAnalysis (fc); 654 } 655 } 656 657 // 658 // Converts operator to System.Linq.Expressions.ExpressionType enum name 659 // GetOperatorExpressionTypeName()660 string GetOperatorExpressionTypeName () 661 { 662 switch (Oper) { 663 case Operator.OnesComplement: 664 return "OnesComplement"; 665 case Operator.LogicalNot: 666 return "Not"; 667 case Operator.UnaryNegation: 668 return "Negate"; 669 case Operator.UnaryPlus: 670 return "UnaryPlus"; 671 default: 672 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ()); 673 } 674 } 675 IsFloat(TypeSpec t)676 static bool IsFloat (TypeSpec t) 677 { 678 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float; 679 } 680 681 // 682 // Returns a stringified representation of the Operator 683 // OperName(Operator oper)684 public static string OperName (Operator oper) 685 { 686 switch (oper) { 687 case Operator.UnaryPlus: 688 return "+"; 689 case Operator.UnaryNegation: 690 return "-"; 691 case Operator.LogicalNot: 692 return "!"; 693 case Operator.OnesComplement: 694 return "~"; 695 case Operator.AddressOf: 696 return "&"; 697 } 698 699 throw new NotImplementedException (oper.ToString ()); 700 } 701 MakeExpression(BuilderContext ctx)702 public override SLE.Expression MakeExpression (BuilderContext ctx) 703 { 704 var expr = Expr.MakeExpression (ctx); 705 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope); 706 707 switch (Oper) { 708 case Operator.UnaryNegation: 709 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr); 710 case Operator.LogicalNot: 711 return SLE.Expression.Not (expr); 712 case Operator.OnesComplement: 713 return SLE.Expression.OnesComplement (expr); 714 default: 715 throw new NotImplementedException (Oper.ToString ()); 716 } 717 } 718 ResolveAddressOf(ResolveContext ec)719 Expression ResolveAddressOf (ResolveContext ec) 720 { 721 if (ec.CurrentIterator != null) { 722 UnsafeInsideIteratorError (ec, loc); 723 } else if (!ec.IsUnsafe) { 724 UnsafeError (ec, loc); 725 } 726 727 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress); 728 if (Expr == null || Expr.eclass != ExprClass.Variable) { 729 ec.Report.Error (211, loc, "Cannot take the address of the given expression"); 730 return null; 731 } 732 733 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) { 734 return null; 735 } 736 737 IVariableReference vr = Expr as IVariableReference; 738 bool is_fixed; 739 if (vr != null) { 740 is_fixed = vr.IsFixed; 741 vr.SetHasAddressTaken (); 742 743 if (vr.IsHoisted && ec.CurrentIterator == null) { 744 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc); 745 } 746 } else { 747 IFixedExpression fe = Expr as IFixedExpression; 748 is_fixed = fe != null && fe.IsFixed; 749 } 750 751 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) { 752 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer"); 753 } 754 755 type = PointerContainer.MakeType (ec.Module, Expr.Type); 756 eclass = ExprClass.Value; 757 return this; 758 } 759 ResolvePrimitivePredefinedType(ResolveContext rc, Expression expr, TypeSpec[] predefined)760 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined) 761 { 762 expr = DoNumericPromotion (rc, Oper, expr); 763 TypeSpec expr_type = expr.Type; 764 foreach (TypeSpec t in predefined) { 765 if (t == expr_type) 766 return expr; 767 } 768 return null; 769 } 770 771 // 772 // Perform user-operator overload resolution 773 // ResolveUserOperator(ResolveContext ec, Expression expr)774 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr) 775 { 776 CSharp.Operator.OpType op_type; 777 switch (Oper) { 778 case Operator.LogicalNot: 779 op_type = CSharp.Operator.OpType.LogicalNot; break; 780 case Operator.OnesComplement: 781 op_type = CSharp.Operator.OpType.OnesComplement; break; 782 case Operator.UnaryNegation: 783 op_type = CSharp.Operator.OpType.UnaryNegation; break; 784 case Operator.UnaryPlus: 785 op_type = CSharp.Operator.OpType.UnaryPlus; break; 786 default: 787 throw new InternalErrorException (Oper.ToString ()); 788 } 789 790 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false); 791 if (methods == null) 792 return null; 793 794 Arguments args = new Arguments (1); 795 args.Add (new Argument (expr)); 796 797 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc); 798 var oper = res.ResolveOperator (ec, ref args); 799 800 if (oper == null) 801 return null; 802 803 Expr = args [0].Expr; 804 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location); 805 } 806 807 // 808 // Unary user type overload resolution 809 // ResolveUserType(ResolveContext ec, Expression expr, TypeSpec[] predefined)810 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined) 811 { 812 Expression best_expr = ResolveUserOperator (ec, expr); 813 if (best_expr != null) 814 return best_expr; 815 816 foreach (TypeSpec t in predefined) { 817 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location); 818 if (oper_expr == null) 819 continue; 820 821 if (oper_expr == ErrorExpression.Instance) 822 return oper_expr; 823 824 // 825 // decimal type is predefined but has user-operators 826 // 827 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) 828 oper_expr = ResolveUserType (ec, oper_expr, predefined); 829 else 830 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined); 831 832 if (oper_expr == null) 833 continue; 834 835 if (best_expr == null) { 836 best_expr = oper_expr; 837 continue; 838 } 839 840 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t); 841 if (result == 0) { 842 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) { 843 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc); 844 } else { 845 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type); 846 } 847 848 break; 849 } 850 851 if (result == 2) 852 best_expr = oper_expr; 853 } 854 855 if (best_expr == null) 856 return null; 857 858 // 859 // HACK: Decimal user-operator is included in standard operators 860 // 861 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) 862 return best_expr; 863 864 Expr = best_expr; 865 type = best_expr.Type; 866 return this; 867 } 868 CloneTo(CloneContext clonectx, Expression t)869 protected override void CloneTo (CloneContext clonectx, Expression t) 870 { 871 Unary target = (Unary) t; 872 873 target.Expr = Expr.Clone (clonectx); 874 } 875 Accept(StructuralVisitor visitor)876 public override object Accept (StructuralVisitor visitor) 877 { 878 return visitor.Visit (this); 879 } 880 881 } 882 883 // 884 // Unary operators are turned into Indirection expressions 885 // after semantic analysis (this is so we can take the address 886 // of an indirection). 887 // 888 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression { 889 Expression expr; 890 LocalTemporary temporary; 891 bool prepared; 892 Indirection(Expression expr, Location l)893 public Indirection (Expression expr, Location l) 894 { 895 this.expr = expr; 896 loc = l; 897 } 898 899 public Expression Expr { 900 get { 901 return expr; 902 } 903 } 904 905 public bool IsFixed { 906 get { return true; } 907 } 908 909 public override Location StartLocation { 910 get { 911 return expr.StartLocation; 912 } 913 } 914 CloneTo(CloneContext clonectx, Expression t)915 protected override void CloneTo (CloneContext clonectx, Expression t) 916 { 917 Indirection target = (Indirection) t; 918 target.expr = expr.Clone (clonectx); 919 } 920 ContainsEmitWithAwait()921 public override bool ContainsEmitWithAwait () 922 { 923 throw new NotImplementedException (); 924 } 925 CreateExpressionTree(ResolveContext ec)926 public override Expression CreateExpressionTree (ResolveContext ec) 927 { 928 Error_PointerInsideExpressionTree (ec); 929 return null; 930 } 931 Emit(EmitContext ec)932 public override void Emit (EmitContext ec) 933 { 934 if (!prepared) 935 expr.Emit (ec); 936 937 ec.EmitLoadFromPtr (Type); 938 } 939 Emit(EmitContext ec, bool leave_copy)940 public void Emit (EmitContext ec, bool leave_copy) 941 { 942 Emit (ec); 943 if (leave_copy) { 944 ec.Emit (OpCodes.Dup); 945 temporary = new LocalTemporary (expr.Type); 946 temporary.Store (ec); 947 } 948 } 949 EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool isCompound)950 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound) 951 { 952 prepared = isCompound; 953 954 expr.Emit (ec); 955 956 if (isCompound) 957 ec.Emit (OpCodes.Dup); 958 959 source.Emit (ec); 960 if (leave_copy) { 961 ec.Emit (OpCodes.Dup); 962 temporary = new LocalTemporary (source.Type); 963 temporary.Store (ec); 964 } 965 966 ec.EmitStoreFromPtr (type); 967 968 if (temporary != null) { 969 temporary.Emit (ec); 970 temporary.Release (ec); 971 } 972 } 973 AddressOf(EmitContext ec, AddressOp Mode)974 public void AddressOf (EmitContext ec, AddressOp Mode) 975 { 976 expr.Emit (ec); 977 } 978 DoResolveLValue(ResolveContext ec, Expression right_side)979 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side) 980 { 981 return DoResolve (ec); 982 } 983 DoResolve(ResolveContext ec)984 protected override Expression DoResolve (ResolveContext ec) 985 { 986 expr = expr.Resolve (ec); 987 if (expr == null) 988 return null; 989 990 if (ec.CurrentIterator != null) { 991 UnsafeInsideIteratorError (ec, loc); 992 } else if (!ec.IsUnsafe) { 993 UnsafeError (ec, loc); 994 } 995 996 var pc = expr.Type as PointerContainer; 997 998 if (pc == null) { 999 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer"); 1000 return null; 1001 } 1002 1003 type = pc.Element; 1004 1005 if (type.Kind == MemberKind.Void) { 1006 Error_VoidPointerOperation (ec); 1007 return null; 1008 } 1009 1010 eclass = ExprClass.Variable; 1011 return this; 1012 } 1013 Accept(StructuralVisitor visitor)1014 public override object Accept (StructuralVisitor visitor) 1015 { 1016 return visitor.Visit (this); 1017 } 1018 } 1019 1020 /// <summary> 1021 /// Unary Mutator expressions (pre and post ++ and --) 1022 /// </summary> 1023 /// 1024 /// <remarks> 1025 /// UnaryMutator implements ++ and -- expressions. It derives from 1026 /// ExpressionStatement becuase the pre/post increment/decrement 1027 /// operators can be used in a statement context. 1028 /// 1029 /// FIXME: Idea, we could split this up in two classes, one simpler 1030 /// for the common case, and one with the extra fields for more complex 1031 /// classes (indexers require temporary access; overloaded require method) 1032 /// 1033 /// </remarks> 1034 public class UnaryMutator : ExpressionStatement 1035 { 1036 class DynamicPostMutator : Expression, IAssignMethod 1037 { 1038 LocalTemporary temp; 1039 Expression expr; 1040 DynamicPostMutator(Expression expr)1041 public DynamicPostMutator (Expression expr) 1042 { 1043 this.expr = expr; 1044 this.type = expr.Type; 1045 this.loc = expr.Location; 1046 } 1047 CreateExpressionTree(ResolveContext ec)1048 public override Expression CreateExpressionTree (ResolveContext ec) 1049 { 1050 throw new NotImplementedException ("ET"); 1051 } 1052 DoResolve(ResolveContext rc)1053 protected override Expression DoResolve (ResolveContext rc) 1054 { 1055 eclass = expr.eclass; 1056 return this; 1057 } 1058 DoResolveLValue(ResolveContext ec, Expression right_side)1059 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side) 1060 { 1061 expr.DoResolveLValue (ec, right_side); 1062 return DoResolve (ec); 1063 } 1064 Emit(EmitContext ec)1065 public override void Emit (EmitContext ec) 1066 { 1067 temp.Emit (ec); 1068 } 1069 Emit(EmitContext ec, bool leave_copy)1070 public void Emit (EmitContext ec, bool leave_copy) 1071 { 1072 throw new NotImplementedException (); 1073 } 1074 1075 // 1076 // Emits target assignment using unmodified source value 1077 // EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool isCompound)1078 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound) 1079 { 1080 // 1081 // Allocate temporary variable to keep original value before it's modified 1082 // 1083 temp = new LocalTemporary (type); 1084 expr.Emit (ec); 1085 temp.Store (ec); 1086 1087 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound); 1088 1089 if (leave_copy) 1090 Emit (ec); 1091 1092 temp.Release (ec); 1093 temp = null; 1094 } 1095 } 1096 1097 [Flags] 1098 public enum Mode : byte { 1099 IsIncrement = 0, 1100 IsDecrement = 1, 1101 IsPre = 0, 1102 IsPost = 2, 1103 1104 PreIncrement = 0, 1105 PreDecrement = IsDecrement, 1106 PostIncrement = IsPost, 1107 PostDecrement = IsPost | IsDecrement 1108 } 1109 1110 Mode mode; 1111 bool is_expr, recurse; 1112 1113 protected Expression expr; 1114 1115 // Holds the real operation 1116 Expression operation; 1117 UnaryMutator(Mode m, Expression e, Location loc)1118 public UnaryMutator (Mode m, Expression e, Location loc) 1119 { 1120 mode = m; 1121 this.loc = loc; 1122 expr = e; 1123 } 1124 1125 public Mode UnaryMutatorMode { 1126 get { 1127 return mode; 1128 } 1129 } 1130 1131 public Expression Expr { 1132 get { 1133 return expr; 1134 } 1135 } 1136 1137 public override Location StartLocation { 1138 get { 1139 return (mode & Mode.IsPost) != 0 ? expr.Location : loc; 1140 } 1141 } 1142 ContainsEmitWithAwait()1143 public override bool ContainsEmitWithAwait () 1144 { 1145 return expr.ContainsEmitWithAwait (); 1146 } 1147 CreateExpressionTree(ResolveContext ec)1148 public override Expression CreateExpressionTree (ResolveContext ec) 1149 { 1150 return new SimpleAssign (this, this).CreateExpressionTree (ec); 1151 } 1152 CreatePredefinedOperatorsTable(BuiltinTypes types)1153 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types) 1154 { 1155 // 1156 // Predefined ++ and -- operators exist for the following types: 1157 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal 1158 // 1159 return new TypeSpec[] { 1160 types.Int, 1161 types.Long, 1162 1163 types.SByte, 1164 types.Byte, 1165 types.Short, 1166 types.UInt, 1167 types.ULong, 1168 types.Char, 1169 types.Float, 1170 types.Double, 1171 types.Decimal 1172 }; 1173 } 1174 DoResolve(ResolveContext ec)1175 protected override Expression DoResolve (ResolveContext ec) 1176 { 1177 expr = expr.Resolve (ec); 1178 1179 if (expr == null || expr.Type == InternalType.ErrorType) 1180 return null; 1181 1182 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 1183 // 1184 // Handle postfix unary operators using local 1185 // temporary variable 1186 // 1187 if ((mode & Mode.IsPost) != 0) 1188 expr = new DynamicPostMutator (expr); 1189 1190 Arguments args = new Arguments (1); 1191 args.Add (new Argument (expr)); 1192 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec); 1193 } 1194 1195 if (expr.Type.IsNullableType) 1196 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec); 1197 1198 return DoResolveOperation (ec); 1199 } 1200 DoResolveOperation(ResolveContext ec)1201 protected Expression DoResolveOperation (ResolveContext ec) 1202 { 1203 eclass = ExprClass.Value; 1204 type = expr.Type; 1205 1206 if (expr is RuntimeValueExpression) { 1207 operation = expr; 1208 } else { 1209 // Use itself at the top of the stack 1210 operation = new EmptyExpression (type); 1211 } 1212 1213 // 1214 // The operand of the prefix/postfix increment decrement operators 1215 // should be an expression that is classified as a variable, 1216 // a property access or an indexer access 1217 // 1218 // TODO: Move to parser, expr is ATypeNameExpression 1219 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) { 1220 expr = expr.ResolveLValue (ec, expr); 1221 } else { 1222 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer"); 1223 return null; 1224 } 1225 1226 // 1227 // Step 1: Try to find a user operator, it has priority over predefined ones 1228 // 1229 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment; 1230 var methods = MemberCache.GetUserOperator (type, user_op, false); 1231 1232 if (methods != null) { 1233 Arguments args = new Arguments (1); 1234 args.Add (new Argument (expr)); 1235 1236 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc); 1237 var method = res.ResolveOperator (ec, ref args); 1238 if (method == null) 1239 return null; 1240 1241 args[0].Expr = operation; 1242 operation = new UserOperatorCall (method, args, null, loc); 1243 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc); 1244 return this; 1245 } 1246 1247 // 1248 // Step 2: Try predefined types 1249 // 1250 1251 Expression source = null; 1252 bool primitive_type; 1253 1254 // 1255 // Predefined without user conversion first for speed-up 1256 // 1257 // Predefined ++ and -- operators exist for the following types: 1258 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal 1259 // 1260 switch (type.BuiltinType) { 1261 case BuiltinTypeSpec.Type.Byte: 1262 case BuiltinTypeSpec.Type.SByte: 1263 case BuiltinTypeSpec.Type.Short: 1264 case BuiltinTypeSpec.Type.UShort: 1265 case BuiltinTypeSpec.Type.Int: 1266 case BuiltinTypeSpec.Type.UInt: 1267 case BuiltinTypeSpec.Type.Long: 1268 case BuiltinTypeSpec.Type.ULong: 1269 case BuiltinTypeSpec.Type.Char: 1270 case BuiltinTypeSpec.Type.Float: 1271 case BuiltinTypeSpec.Type.Double: 1272 case BuiltinTypeSpec.Type.Decimal: 1273 source = operation; 1274 primitive_type = true; 1275 break; 1276 default: 1277 primitive_type = false; 1278 1279 // ++/-- on pointer variables of all types except void* 1280 if (type.IsPointer) { 1281 if (((PointerContainer) type).Element.Kind == MemberKind.Void) { 1282 Error_VoidPointerOperation (ec); 1283 return null; 1284 } 1285 1286 source = operation; 1287 } else { 1288 Expression best_source = null; 1289 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) { 1290 source = Convert.ImplicitUserConversion (ec, operation, t, loc); 1291 1292 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible 1293 if (source == null) 1294 continue; 1295 1296 if (best_source == null) { 1297 best_source = source; 1298 continue; 1299 } 1300 1301 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type); 1302 if (better == 1) 1303 continue; 1304 1305 if (better == 2) { 1306 best_source = source; 1307 continue; 1308 } 1309 1310 Unary.Error_Ambiguous (ec, OperName (mode), type, loc); 1311 break; 1312 } 1313 1314 source = best_source; 1315 } 1316 1317 // ++/-- on enum types 1318 if (source == null && type.IsEnum) 1319 source = operation; 1320 1321 if (source == null) { 1322 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type); 1323 return null; 1324 } 1325 1326 break; 1327 } 1328 1329 var one = new IntConstant (ec.BuiltinTypes, 1, loc); 1330 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition; 1331 operation = new Binary (op, source, one); 1332 operation = operation.Resolve (ec); 1333 if (operation == null) 1334 throw new NotImplementedException ("should not be reached"); 1335 1336 if (operation.Type != type) { 1337 if (primitive_type) 1338 operation = Convert.ExplicitNumericConversion (ec, operation, type); 1339 else 1340 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc); 1341 } 1342 1343 return this; 1344 } 1345 EmitCode(EmitContext ec, bool is_expr)1346 void EmitCode (EmitContext ec, bool is_expr) 1347 { 1348 recurse = true; 1349 this.is_expr = is_expr; 1350 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true); 1351 } 1352 Emit(EmitContext ec)1353 public override void Emit (EmitContext ec) 1354 { 1355 // 1356 // We use recurse to allow ourselfs to be the source 1357 // of an assignment. This little hack prevents us from 1358 // having to allocate another expression 1359 // 1360 if (recurse) { 1361 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement)); 1362 1363 EmitOperation (ec); 1364 1365 recurse = false; 1366 return; 1367 } 1368 1369 EmitCode (ec, true); 1370 } 1371 EmitOperation(EmitContext ec)1372 protected virtual void EmitOperation (EmitContext ec) 1373 { 1374 operation.Emit (ec); 1375 } 1376 EmitStatement(EmitContext ec)1377 public override void EmitStatement (EmitContext ec) 1378 { 1379 EmitCode (ec, false); 1380 } 1381 FlowAnalysis(FlowAnalysisContext fc)1382 public override void FlowAnalysis (FlowAnalysisContext fc) 1383 { 1384 expr.FlowAnalysis (fc); 1385 } 1386 1387 // 1388 // Converts operator to System.Linq.Expressions.ExpressionType enum name 1389 // GetOperatorExpressionTypeName()1390 string GetOperatorExpressionTypeName () 1391 { 1392 return IsDecrement ? "Decrement" : "Increment"; 1393 } 1394 1395 bool IsDecrement { 1396 get { return (mode & Mode.IsDecrement) != 0; } 1397 } 1398 1399 MakeExpression(BuilderContext ctx)1400 public override SLE.Expression MakeExpression (BuilderContext ctx) 1401 { 1402 var target = ((RuntimeValueExpression) expr).MetaObject.Expression; 1403 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type); 1404 return SLE.Expression.Assign (target, source); 1405 } 1406 OperName(Mode oper)1407 public static string OperName (Mode oper) 1408 { 1409 return (oper & Mode.IsDecrement) != 0 ? "--" : "++"; 1410 } 1411 CloneTo(CloneContext clonectx, Expression t)1412 protected override void CloneTo (CloneContext clonectx, Expression t) 1413 { 1414 UnaryMutator target = (UnaryMutator) t; 1415 1416 target.expr = expr.Clone (clonectx); 1417 } 1418 Accept(StructuralVisitor visitor)1419 public override object Accept (StructuralVisitor visitor) 1420 { 1421 return visitor.Visit (this); 1422 } 1423 1424 } 1425 1426 // 1427 // Base class for the `is' and `as' operators 1428 // 1429 public abstract class Probe : Expression 1430 { 1431 public Expression ProbeType; 1432 protected Expression expr; 1433 protected TypeSpec probe_type_expr; 1434 Probe(Expression expr, Expression probe_type, Location l)1435 protected Probe (Expression expr, Expression probe_type, Location l) 1436 { 1437 ProbeType = probe_type; 1438 loc = l; 1439 this.expr = expr; 1440 } 1441 1442 public Expression Expr { 1443 get { 1444 return expr; 1445 } 1446 } 1447 ContainsEmitWithAwait()1448 public override bool ContainsEmitWithAwait () 1449 { 1450 return expr.ContainsEmitWithAwait (); 1451 } 1452 ResolveCommon(ResolveContext rc)1453 protected Expression ResolveCommon (ResolveContext rc) 1454 { 1455 expr = expr.Resolve (rc); 1456 if (expr == null) 1457 return null; 1458 1459 ResolveProbeType (rc); 1460 if (probe_type_expr == null) 1461 return this; 1462 1463 if (probe_type_expr.IsStatic) { 1464 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'", 1465 probe_type_expr.GetSignatureForError ()); 1466 return null; 1467 } 1468 1469 if (expr.Type.IsPointer || probe_type_expr.IsPointer) { 1470 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type", 1471 OperatorName); 1472 return null; 1473 } 1474 1475 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) { 1476 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group", 1477 OperatorName); 1478 return null; 1479 } 1480 1481 if (expr.Type == InternalType.DefaultType) { 1482 Error_OperatorCannotBeApplied (rc, loc, OperatorName, expr.Type); 1483 return null; 1484 } 1485 1486 return this; 1487 } 1488 ResolveProbeType(ResolveContext rc)1489 protected virtual void ResolveProbeType (ResolveContext rc) 1490 { 1491 probe_type_expr = ProbeType.ResolveAsType (rc); 1492 } 1493 EmitSideEffect(EmitContext ec)1494 public override void EmitSideEffect (EmitContext ec) 1495 { 1496 expr.EmitSideEffect (ec); 1497 } 1498 EmitPrepare(EmitContext ec)1499 public override void EmitPrepare (EmitContext ec) 1500 { 1501 expr.EmitPrepare (ec); 1502 } 1503 FlowAnalysis(FlowAnalysisContext fc)1504 public override void FlowAnalysis (FlowAnalysisContext fc) 1505 { 1506 expr.FlowAnalysis (fc); 1507 } 1508 HasConditionalAccess()1509 public override bool HasConditionalAccess () 1510 { 1511 return expr.HasConditionalAccess (); 1512 } 1513 1514 protected abstract string OperatorName { get; } 1515 CloneTo(CloneContext clonectx, Expression t)1516 protected override void CloneTo (CloneContext clonectx, Expression t) 1517 { 1518 Probe target = (Probe) t; 1519 1520 target.expr = expr.Clone (clonectx); 1521 target.ProbeType = ProbeType.Clone (clonectx); 1522 } 1523 1524 } 1525 1526 /// <summary> 1527 /// Implementation of the `is' operator. 1528 /// </summary> 1529 public class Is : Probe 1530 { 1531 Nullable.Unwrap expr_unwrap; 1532 MethodSpec number_mg; 1533 Arguments number_args; 1534 Is(Expression expr, Expression probe_type, Location l)1535 public Is (Expression expr, Expression probe_type, Location l) 1536 : base (expr, probe_type, l) 1537 { 1538 } 1539 1540 protected override string OperatorName { 1541 get { return "is"; } 1542 } 1543 1544 public LocalVariable Variable { get; set; } 1545 CreateExpressionTree(ResolveContext ec)1546 public override Expression CreateExpressionTree (ResolveContext ec) 1547 { 1548 if (Variable != null) 1549 ec.Report.Error (8122, loc, "An expression tree cannot contain a pattern matching operator"); 1550 1551 Arguments args = Arguments.CreateForExpressionTree (ec, null, 1552 expr.CreateExpressionTree (ec), 1553 new TypeOf (probe_type_expr, loc)); 1554 1555 return CreateExpressionFactoryCall (ec, "TypeIs", args); 1556 } 1557 CreateConstantResult(ResolveContext rc, bool result)1558 Expression CreateConstantResult (ResolveContext rc, bool result) 1559 { 1560 if (result) 1561 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type", 1562 probe_type_expr.GetSignatureForError ()); 1563 else 1564 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", 1565 probe_type_expr.GetSignatureForError ()); 1566 1567 var c = new BoolConstant (rc.BuiltinTypes, result, loc); 1568 return expr.IsSideEffectFree ? 1569 ReducedExpression.Create (c, this) : 1570 new SideEffectConstant (c, this, loc); 1571 } 1572 Emit(EmitContext ec)1573 public override void Emit (EmitContext ec) 1574 { 1575 if (probe_type_expr == null) { 1576 if (ProbeType is WildcardPattern) { 1577 expr.EmitSideEffect (ec); 1578 ProbeType.Emit (ec); 1579 } else { 1580 EmitPatternMatch (ec); 1581 } 1582 return; 1583 } 1584 1585 EmitLoad (ec); 1586 1587 if (expr_unwrap == null) { 1588 ec.EmitNull (); 1589 ec.Emit (OpCodes.Cgt_Un); 1590 } 1591 } 1592 EmitBranchable(EmitContext ec, Label target, bool on_true)1593 public override void EmitBranchable (EmitContext ec, Label target, bool on_true) 1594 { 1595 if (probe_type_expr == null) { 1596 EmitPatternMatch (ec); 1597 } else { 1598 EmitLoad (ec); 1599 } 1600 1601 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target); 1602 } 1603 EmitPrepare(EmitContext ec)1604 public override void EmitPrepare (EmitContext ec) 1605 { 1606 base.EmitPrepare (ec); 1607 1608 if (Variable != null) 1609 Variable.CreateBuilder (ec); 1610 } 1611 EmitPatternMatch(EmitContext ec)1612 void EmitPatternMatch (EmitContext ec) 1613 { 1614 var no_match = ec.DefineLabel (); 1615 var end = ec.DefineLabel (); 1616 1617 if (expr_unwrap != null) { 1618 expr_unwrap.EmitCheck (ec); 1619 1620 if (ProbeType.IsNull) { 1621 ec.EmitInt (0); 1622 ec.Emit (OpCodes.Ceq); 1623 return; 1624 } 1625 1626 ec.Emit (OpCodes.Brfalse_S, no_match); 1627 expr_unwrap.Emit (ec); 1628 ProbeType.Emit (ec); 1629 ec.Emit (OpCodes.Ceq); 1630 ec.Emit (OpCodes.Br_S, end); 1631 ec.MarkLabel (no_match); 1632 ec.EmitInt (0); 1633 ec.MarkLabel (end); 1634 return; 1635 } 1636 1637 if (number_args != null && number_args.Count == 3) { 1638 var ce = new CallEmitter (); 1639 ce.Emit (ec, number_mg, number_args, loc); 1640 return; 1641 } 1642 1643 var probe_type = ProbeType.Type; 1644 1645 Expr.Emit (ec); 1646 ec.Emit (OpCodes.Isinst, probe_type); 1647 ec.Emit (OpCodes.Dup); 1648 ec.Emit (OpCodes.Brfalse, no_match); 1649 1650 bool complex_pattern = ProbeType is ComplexPatternExpression; 1651 Label prev = ec.RecursivePatternLabel; 1652 if (complex_pattern) 1653 ec.RecursivePatternLabel = ec.DefineLabel (); 1654 1655 if (number_mg != null) { 1656 var ce = new CallEmitter (); 1657 ce.Emit (ec, number_mg, number_args, loc); 1658 } else { 1659 if (TypeSpec.IsValueType (probe_type)) 1660 ec.Emit (OpCodes.Unbox_Any, probe_type); 1661 1662 ProbeType.Emit (ec); 1663 if (complex_pattern) { 1664 ec.EmitInt (1); 1665 } else { 1666 ec.Emit (OpCodes.Ceq); 1667 } 1668 } 1669 ec.Emit (OpCodes.Br_S, end); 1670 ec.MarkLabel (no_match); 1671 1672 ec.Emit (OpCodes.Pop); 1673 1674 if (complex_pattern) 1675 ec.MarkLabel (ec.RecursivePatternLabel); 1676 1677 ec.RecursivePatternLabel = prev; 1678 1679 ec.EmitInt (0); 1680 ec.MarkLabel (end); 1681 } 1682 EmitLoad(EmitContext ec)1683 void EmitLoad (EmitContext ec) 1684 { 1685 if (expr_unwrap != null) { 1686 expr_unwrap.EmitCheck (ec); 1687 1688 if (Variable == null) 1689 return; 1690 1691 ec.Emit (OpCodes.Dup); 1692 var no_value_label = ec.DefineLabel (); 1693 ec.Emit (OpCodes.Brfalse_S, no_value_label); 1694 1695 if (Variable.HoistedVariant != null) 1696 ec.EmitThis (); 1697 1698 expr_unwrap.Emit (ec); 1699 1700 if (Variable.HoistedVariant != null) { 1701 Variable.HoistedVariant.EmitAssignFromStack (ec); 1702 } else { 1703 // 1704 // It's ok to have variable builder created out of order. It simplifies emit 1705 // of statements like while (condition) { } 1706 // 1707 if (!Variable.Created) 1708 Variable.CreateBuilder (ec); 1709 1710 Variable.EmitAssign (ec); 1711 } 1712 1713 ec.MarkLabel (no_value_label); 1714 return; 1715 } 1716 1717 expr.Emit (ec); 1718 1719 bool vtype_variable = Variable != null && (probe_type_expr.IsGenericParameter || TypeSpec.IsValueType (ProbeType.Type)); 1720 LocalBuilder expr_copy = null; 1721 1722 if (vtype_variable && !ExpressionAnalyzer.IsInexpensiveLoad (expr)) { 1723 expr_copy = ec.GetTemporaryLocal (expr.Type); 1724 ec.Emit (OpCodes.Stloc, expr_copy); 1725 ec.Emit (OpCodes.Ldloc, expr_copy); 1726 } else if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type)) { 1727 // 1728 // Only to make verifier happy 1729 // 1730 ec.Emit (OpCodes.Box, expr.Type); 1731 } 1732 1733 ec.Emit (OpCodes.Isinst, probe_type_expr); 1734 1735 if (Variable != null) { 1736 ec.Emit (OpCodes.Dup); 1737 1738 var nonmatching_label = ec.DefineLabel (); 1739 ec.Emit (OpCodes.Brfalse_S, nonmatching_label); 1740 1741 if (vtype_variable) { 1742 if (expr_copy != null) { 1743 ec.Emit (OpCodes.Ldloc, expr_copy); 1744 ec.FreeTemporaryLocal (expr_copy, expr.Type); 1745 } else { 1746 expr.Emit (ec); 1747 } 1748 1749 ec.Emit (OpCodes.Unbox_Any, probe_type_expr); 1750 } else { 1751 // Already on the stack 1752 } 1753 1754 if (Variable.HoistedVariant != null) { 1755 var temp = new LocalTemporary (ProbeType.Type); 1756 temp.Store (ec); 1757 Variable.HoistedVariant.EmitAssign (ec, temp, false, false); 1758 temp.Release (ec); 1759 1760 if (!vtype_variable) 1761 Variable.HoistedVariant.Emit (ec); 1762 } else { 1763 // 1764 // It's ok to have variable builder created out of order. It simplifies emit 1765 // of statements like while (condition) { } 1766 // 1767 if (!Variable.Created) 1768 Variable.CreateBuilder (ec); 1769 1770 Variable.EmitAssign (ec); 1771 1772 if (!vtype_variable) 1773 Variable.Emit (ec); 1774 } 1775 1776 ec.MarkLabel (nonmatching_label); 1777 } 1778 } 1779 DoResolve(ResolveContext rc)1780 protected override Expression DoResolve (ResolveContext rc) 1781 { 1782 if (ResolveCommon (rc) == null) 1783 return null; 1784 1785 type = rc.BuiltinTypes.Bool; 1786 eclass = ExprClass.Value; 1787 1788 if (probe_type_expr == null) 1789 return ResolveMatchingExpression (rc); 1790 1791 var res = ResolveResultExpression (rc); 1792 if (Variable != null) { 1793 if (res is Constant) 1794 throw new NotImplementedException ("constant in type pattern matching"); 1795 1796 Variable.Type = probe_type_expr; 1797 var bc = rc as BlockContext; 1798 if (bc != null) 1799 Variable.PrepareAssignmentAnalysis (bc); 1800 } 1801 1802 return res; 1803 } 1804 FlowAnalysis(FlowAnalysisContext fc)1805 public override void FlowAnalysis (FlowAnalysisContext fc) 1806 { 1807 base.FlowAnalysis (fc); 1808 1809 if (Variable != null) 1810 fc.SetVariableAssigned (Variable.VariableInfo, true); 1811 } 1812 FlowAnalysisConditional(FlowAnalysisContext fc)1813 public override void FlowAnalysisConditional (FlowAnalysisContext fc) 1814 { 1815 if (Variable == null) { 1816 base.FlowAnalysisConditional (fc); 1817 return; 1818 } 1819 1820 expr.FlowAnalysis (fc); 1821 1822 fc.DefiniteAssignmentOnTrue = fc.BranchDefiniteAssignment (); 1823 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment; 1824 1825 fc.SetVariableAssigned (Variable.VariableInfo, fc.DefiniteAssignmentOnTrue); 1826 } 1827 ResolveProbeType(ResolveContext rc)1828 protected override void ResolveProbeType (ResolveContext rc) 1829 { 1830 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) { 1831 if (ProbeType is PatternExpression) { 1832 ProbeType.Resolve (rc); 1833 return; 1834 } 1835 1836 // 1837 // Have to use session recording because we don't have reliable type probing 1838 // mechanism (similar issue as in attributes resolving) 1839 // 1840 // TODO: This is still wrong because ResolveAsType can be destructive 1841 // 1842 var type_printer = new SessionReportPrinter (); 1843 var prev_recorder = rc.Report.SetPrinter (type_printer); 1844 1845 probe_type_expr = ProbeType.ResolveAsType (rc); 1846 type_printer.EndSession (); 1847 1848 if (probe_type_expr != null) { 1849 type_printer.Merge (rc.Report.Printer); 1850 rc.Report.SetPrinter (prev_recorder); 1851 return; 1852 } 1853 1854 var vexpr = ProbeType as VarExpr; 1855 if (vexpr != null && vexpr.InferType (rc, expr)) { 1856 probe_type_expr = vexpr.Type; 1857 rc.Report.SetPrinter (prev_recorder); 1858 return; 1859 } 1860 1861 var expr_printer = new SessionReportPrinter (); 1862 rc.Report.SetPrinter (expr_printer); 1863 ProbeType = ProbeType.Resolve (rc); 1864 expr_printer.EndSession (); 1865 1866 if (ProbeType != null) { 1867 expr_printer.Merge (rc.Report.Printer); 1868 } else { 1869 type_printer.Merge (rc.Report.Printer); 1870 } 1871 1872 rc.Report.SetPrinter (prev_recorder); 1873 return; 1874 } 1875 1876 base.ResolveProbeType (rc); 1877 } 1878 ResolveMatchingExpression(ResolveContext rc)1879 Expression ResolveMatchingExpression (ResolveContext rc) 1880 { 1881 var mc = ProbeType as Constant; 1882 if (mc != null) { 1883 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) { 1884 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false); 1885 return null; 1886 } 1887 1888 if (mc.IsNull) 1889 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc); 1890 1891 var c = Expr as Constant; 1892 if (c != null) { 1893 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc); 1894 if (c != null) 1895 return c; 1896 } 1897 1898 if (Expr.Type.IsNullableType) { 1899 expr_unwrap = new Nullable.Unwrap (Expr); 1900 expr_unwrap.Resolve (rc); 1901 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc); 1902 } else if (ProbeType.Type == Expr.Type) { 1903 // TODO: Better error handling 1904 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc); 1905 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) { 1906 var helper = rc.Module.CreatePatterMatchingHelper (); 1907 number_mg = helper.NumberMatcher.Spec; 1908 1909 // 1910 // There are actually 3 arguments but the first one is already on the stack 1911 // 1912 number_args = new Arguments (3); 1913 if (!ProbeType.Type.IsEnum) 1914 number_args.Add (new Argument (Expr)); 1915 1916 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc))); 1917 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc))); 1918 } 1919 1920 return this; 1921 } 1922 1923 if (ProbeType is PatternExpression) { 1924 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) { 1925 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false); 1926 } 1927 1928 return this; 1929 } 1930 1931 // TODO: Better error message 1932 rc.Report.Error (150, ProbeType.Location, "A constant value is expected"); 1933 return this; 1934 } 1935 ResolveResultExpression(ResolveContext ec)1936 Expression ResolveResultExpression (ResolveContext ec) 1937 { 1938 if (Variable != null) { 1939 if (expr is NullLiteral) { 1940 ec.Report.Error (8117, loc, "Cannot use null as pattern matching operand"); 1941 return this; 1942 } 1943 1944 CheckExpressionVariable (ec); 1945 } 1946 1947 TypeSpec d = expr.Type; 1948 bool d_is_nullable = false; 1949 1950 // 1951 // If E is a method group or the null literal, or if the type of E is a reference 1952 // type or a nullable type and the value of E is null, the result is false 1953 // 1954 if (expr.IsNull) 1955 return CreateConstantResult (ec, false); 1956 1957 if (d.IsNullableType) { 1958 var ut = Nullable.NullableInfo.GetUnderlyingType (d); 1959 if (!ut.IsGenericParameter) { 1960 d = ut; 1961 d_is_nullable = true; 1962 } 1963 } 1964 1965 TypeSpec t = probe_type_expr; 1966 bool t_is_nullable = false; 1967 if (t.IsNullableType) { 1968 if (Variable != null) { 1969 ec.Report.Error (8116, loc, "The nullable type `{0}' pattern matching is not allowed. Consider using underlying type `{1}'", 1970 t.GetSignatureForError (), Nullable.NullableInfo.GetUnderlyingType (t).GetSignatureForError ()); 1971 } 1972 1973 var ut = Nullable.NullableInfo.GetUnderlyingType (t); 1974 if (!ut.IsGenericParameter) { 1975 t = ut; 1976 t_is_nullable = true; 1977 } 1978 } 1979 1980 if (t.IsStruct) { 1981 if (d == t) { 1982 // 1983 // D and T are the same value types but D can be null 1984 // 1985 if (d_is_nullable && !t_is_nullable) { 1986 expr_unwrap = Nullable.Unwrap.Create (expr, true); 1987 return this; 1988 } 1989 1990 // 1991 // The result is true if D and T are the same value types 1992 // 1993 return CreateConstantResult (ec, true); 1994 } 1995 1996 var tp = d as TypeParameterSpec; 1997 if (tp != null) 1998 return ResolveGenericParameter (ec, t, tp); 1999 2000 // 2001 // An unboxing conversion exists 2002 // 2003 if (Convert.ExplicitReferenceConversionExists (d, t)) 2004 return this; 2005 2006 // 2007 // open generic type 2008 // 2009 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d)) 2010 return this; 2011 } else { 2012 var tps = t as TypeParameterSpec; 2013 if (tps != null) 2014 return ResolveGenericParameter (ec, d, tps); 2015 2016 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 2017 if (Variable != null) { 2018 ec.Report.Error (8208, loc, "The type `{0}' pattern matching is not allowed", t.GetSignatureForError ()); 2019 } else { 2020 ec.Report.Warning (1981, 3, loc, 2021 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'", 2022 OperatorName, t.GetSignatureForError ()); 2023 } 2024 } 2025 2026 if (TypeManager.IsGenericParameter (d)) 2027 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d); 2028 2029 if (TypeSpec.IsValueType (d)) { 2030 if (Convert.ImplicitBoxingConversion (null, d, t) != null) { 2031 if (d_is_nullable && !t_is_nullable) { 2032 expr_unwrap = Nullable.Unwrap.Create (expr, false); 2033 return this; 2034 } 2035 2036 return CreateConstantResult (ec, true); 2037 } 2038 } else { 2039 if (Convert.ImplicitReferenceConversionExists (d, t)) { 2040 var c = expr as Constant; 2041 if (c != null) 2042 return CreateConstantResult (ec, !c.IsNull); 2043 2044 // 2045 // Do not optimize for imported type or dynamic type 2046 // 2047 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None && 2048 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) { 2049 return this; 2050 } 2051 2052 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic) 2053 return this; 2054 2055 // 2056 // Turn is check into simple null check for implicitly convertible reference types 2057 // 2058 return ReducedExpression.Create ( 2059 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec), 2060 this).Resolve (ec); 2061 } 2062 2063 if (Convert.ExplicitReferenceConversionExists (d, t)) 2064 return this; 2065 2066 // 2067 // open generic type 2068 // 2069 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d)) 2070 return this; 2071 } 2072 } 2073 2074 return CreateConstantResult (ec, false); 2075 } 2076 ResolveGenericParameter(ResolveContext ec, TypeSpec d, TypeParameterSpec t)2077 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t) 2078 { 2079 if (t.IsReferenceType) { 2080 if (d.IsStruct) 2081 return CreateConstantResult (ec, false); 2082 } 2083 2084 if (expr.Type.IsGenericParameter) { 2085 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d)) 2086 return CreateConstantResult (ec, true); 2087 2088 expr = new BoxedCast (expr, d); 2089 } 2090 2091 return this; 2092 } 2093 Accept(StructuralVisitor visitor)2094 public override object Accept (StructuralVisitor visitor) 2095 { 2096 return visitor.Visit (this); 2097 } 2098 } 2099 2100 class WildcardPattern : PatternExpression 2101 { WildcardPattern(Location loc)2102 public WildcardPattern (Location loc) 2103 : base (loc) 2104 { 2105 } 2106 DoResolve(ResolveContext rc)2107 protected override Expression DoResolve (ResolveContext rc) 2108 { 2109 eclass = ExprClass.Value; 2110 type = rc.BuiltinTypes.Object; 2111 return this; 2112 } 2113 Emit(EmitContext ec)2114 public override void Emit (EmitContext ec) 2115 { 2116 ec.EmitInt (1); 2117 } 2118 } 2119 2120 class RecursivePattern : ComplexPatternExpression 2121 { 2122 MethodGroupExpr operator_mg; 2123 Arguments operator_args; 2124 RecursivePattern(ATypeNameExpression typeExpresion, Arguments arguments, Location loc)2125 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc) 2126 : base (typeExpresion, loc) 2127 { 2128 Arguments = arguments; 2129 } 2130 2131 public Arguments Arguments { get; private set; } 2132 DoResolve(ResolveContext rc)2133 protected override Expression DoResolve (ResolveContext rc) 2134 { 2135 type = TypeExpression.ResolveAsType (rc); 2136 if (type == null) 2137 return null; 2138 2139 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true); 2140 if (operators == null) { 2141 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator"); 2142 return null; 2143 } 2144 2145 var ops = FindMatchingOverloads (operators); 2146 if (ops == null) { 2147 // TODO: better error message 2148 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator"); 2149 return null; 2150 } 2151 2152 bool dynamic_args; 2153 Arguments.Resolve (rc, out dynamic_args); 2154 if (dynamic_args) 2155 throw new NotImplementedException ("dynamic argument"); 2156 2157 var op = FindBestOverload (rc, ops); 2158 if (op == null) { 2159 // TODO: better error message 2160 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator"); 2161 return null; 2162 } 2163 2164 var op_types = op.Parameters.Types; 2165 operator_args = new Arguments (op_types.Length); 2166 operator_args.Add (new Argument (new EmptyExpression (type))); 2167 2168 for (int i = 0; i < Arguments.Count; ++i) { 2169 // TODO: Needs releasing optimization 2170 var lt = new LocalTemporary (op_types [i + 1]); 2171 operator_args.Add (new Argument (lt, Argument.AType.Out)); 2172 2173 if (comparisons == null) 2174 comparisons = new Expression[Arguments.Count]; 2175 2176 int arg_comp_index; 2177 Expression expr; 2178 2179 var arg = Arguments [i]; 2180 var named = arg as NamedArgument; 2181 if (named != null) { 2182 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1; 2183 expr = Arguments [arg_comp_index].Expr; 2184 } else { 2185 arg_comp_index = i; 2186 expr = arg.Expr; 2187 } 2188 2189 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt); 2190 } 2191 2192 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc); 2193 2194 eclass = ExprClass.Value; 2195 return this; 2196 } 2197 FindMatchingOverloads(IList<MemberSpec> members)2198 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members) 2199 { 2200 int arg_count = Arguments.Count + 1; 2201 List<MethodSpec> best = null; 2202 foreach (MethodSpec method in members) { 2203 var pm = method.Parameters; 2204 if (pm.Count != arg_count) 2205 continue; 2206 2207 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time 2208 bool ok = true; 2209 for (int ii = 1; ii < pm.Count; ++ii) { 2210 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) { 2211 ok = false; 2212 break; 2213 } 2214 } 2215 2216 if (!ok) 2217 continue; 2218 2219 if (best == null) 2220 best = new List<MethodSpec> (); 2221 2222 best.Add (method); 2223 } 2224 2225 return best; 2226 } 2227 FindBestOverload(ResolveContext rc, List<MethodSpec> methods)2228 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods) 2229 { 2230 for (int ii = 0; ii < Arguments.Count; ++ii) { 2231 var arg = Arguments [ii]; 2232 var expr = arg.Expr; 2233 if (expr is WildcardPattern) 2234 continue; 2235 2236 var na = arg as NamedArgument; 2237 for (int i = 0; i < methods.Count; ++i) { 2238 var pd = methods [i].Parameters; 2239 2240 int index; 2241 if (na != null) { 2242 index = pd.GetParameterIndexByName (na.Name); 2243 if (index < 1) { 2244 methods.RemoveAt (i--); 2245 continue; 2246 } 2247 } else { 2248 index = ii + 1; 2249 } 2250 2251 var m = pd.Types [index]; 2252 if (!Convert.ImplicitConversionExists (rc, expr, m)) 2253 methods.RemoveAt (i--); 2254 } 2255 } 2256 2257 if (methods.Count != 1) 2258 return null; 2259 2260 return methods [0]; 2261 } 2262 EmitBranchable(EmitContext ec, Label target, bool on_true)2263 public override void EmitBranchable (EmitContext ec, Label target, bool on_true) 2264 { 2265 operator_mg.EmitCall (ec, operator_args, false); 2266 ec.Emit (OpCodes.Brfalse, target); 2267 2268 base.EmitBranchable (ec, target, on_true); 2269 } 2270 ResolveComparison(ResolveContext rc, Expression expr, LocalTemporary lt)2271 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt) 2272 { 2273 if (expr is WildcardPattern) 2274 return new EmptyExpression (expr.Type); 2275 2276 var recursive = expr as RecursivePattern; 2277 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location); 2278 if (expr == null) 2279 return null; 2280 2281 if (recursive != null) { 2282 recursive.SetParentInstance (lt); 2283 return expr; 2284 } 2285 2286 // TODO: Better error handling 2287 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc); 2288 } 2289 SetParentInstance(Expression instance)2290 public void SetParentInstance (Expression instance) 2291 { 2292 operator_args [0] = new Argument (instance); 2293 } 2294 } 2295 2296 class PropertyPattern : ComplexPatternExpression 2297 { 2298 LocalTemporary instance; 2299 PropertyPattern(ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)2300 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc) 2301 : base (typeExpresion, loc) 2302 { 2303 Members = members; 2304 } 2305 2306 public List<PropertyPatternMember> Members { get; private set; } 2307 DoResolve(ResolveContext rc)2308 protected override Expression DoResolve (ResolveContext rc) 2309 { 2310 type = TypeExpression.ResolveAsType (rc); 2311 if (type == null) 2312 return null; 2313 2314 comparisons = new Expression[Members.Count]; 2315 2316 // TODO: optimize when source is VariableReference, it'd save dup+pop 2317 instance = new LocalTemporary (type); 2318 2319 for (int i = 0; i < Members.Count; i++) { 2320 var lookup = Members [i]; 2321 2322 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc); 2323 if (member == null) { 2324 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc); 2325 if (member != null) { 2326 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc); 2327 continue; 2328 } 2329 } 2330 2331 if (member == null) { 2332 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name); 2333 continue; 2334 } 2335 2336 var pe = member as PropertyExpr; 2337 if (pe == null || member is FieldExpr) { 2338 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name); 2339 continue; 2340 } 2341 2342 // TODO: Obsolete checks 2343 // TODO: check accessibility 2344 if (pe != null && !pe.PropertyInfo.HasGet) { 2345 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ()); 2346 continue; 2347 } 2348 2349 var expr = lookup.Expr.Resolve (rc); 2350 if (expr == null) 2351 continue; 2352 2353 var me = (MemberExpr)member; 2354 me.InstanceExpression = instance; 2355 2356 comparisons [i] = ResolveComparison (rc, expr, me); 2357 } 2358 2359 eclass = ExprClass.Value; 2360 return this; 2361 } 2362 ResolveComparison(ResolveContext rc, Expression expr, Expression instance)2363 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance) 2364 { 2365 if (expr is WildcardPattern) 2366 return new EmptyExpression (expr.Type); 2367 2368 return new Is (instance, expr, expr.Location).Resolve (rc); 2369 } 2370 EmitBranchable(EmitContext ec, Label target, bool on_true)2371 public override void EmitBranchable (EmitContext ec, Label target, bool on_true) 2372 { 2373 instance.Store (ec); 2374 2375 base.EmitBranchable (ec, target, on_true); 2376 } 2377 } 2378 2379 class PropertyPatternMember 2380 { PropertyPatternMember(string name, Expression expr, Location loc)2381 public PropertyPatternMember (string name, Expression expr, Location loc) 2382 { 2383 Name = name; 2384 Expr = expr; 2385 Location = loc; 2386 } 2387 2388 public string Name { get; private set; } 2389 public Expression Expr { get; private set; } 2390 public Location Location { get; private set; } 2391 } 2392 2393 abstract class PatternExpression : Expression 2394 { PatternExpression(Location loc)2395 protected PatternExpression (Location loc) 2396 { 2397 this.loc = loc; 2398 } 2399 CreateExpressionTree(ResolveContext ec)2400 public override Expression CreateExpressionTree (ResolveContext ec) 2401 { 2402 throw new NotImplementedException (); 2403 } 2404 } 2405 2406 abstract class ComplexPatternExpression : PatternExpression 2407 { 2408 protected Expression[] comparisons; 2409 ComplexPatternExpression(ATypeNameExpression typeExpresion, Location loc)2410 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc) 2411 : base (loc) 2412 { 2413 TypeExpression = typeExpresion; 2414 } 2415 2416 public ATypeNameExpression TypeExpression { get; private set; } 2417 Emit(EmitContext ec)2418 public override void Emit (EmitContext ec) 2419 { 2420 EmitBranchable (ec, ec.RecursivePatternLabel, false); 2421 } 2422 EmitBranchable(EmitContext ec, Label target, bool on_true)2423 public override void EmitBranchable (EmitContext ec, Label target, bool on_true) 2424 { 2425 if (comparisons != null) { 2426 foreach (var comp in comparisons) { 2427 comp.EmitBranchable (ec, target, false); 2428 } 2429 } 2430 } 2431 } 2432 2433 /// <summary> 2434 /// Implementation of the `as' operator. 2435 /// </summary> 2436 public class As : Probe { 2437 As(Expression expr, Expression probe_type, Location l)2438 public As (Expression expr, Expression probe_type, Location l) 2439 : base (expr, probe_type, l) 2440 { 2441 } 2442 2443 protected override string OperatorName { 2444 get { return "as"; } 2445 } 2446 CreateExpressionTree(ResolveContext ec)2447 public override Expression CreateExpressionTree (ResolveContext ec) 2448 { 2449 Arguments args = Arguments.CreateForExpressionTree (ec, null, 2450 expr.CreateExpressionTree (ec), 2451 new TypeOf (probe_type_expr, loc)); 2452 2453 return CreateExpressionFactoryCall (ec, "TypeAs", args); 2454 } 2455 Emit(EmitContext ec)2456 public override void Emit (EmitContext ec) 2457 { 2458 expr.Emit (ec); 2459 2460 ec.Emit (OpCodes.Isinst, type); 2461 2462 if (TypeManager.IsGenericParameter (type) || type.IsNullableType) 2463 ec.Emit (OpCodes.Unbox_Any, type); 2464 } 2465 DoResolve(ResolveContext ec)2466 protected override Expression DoResolve (ResolveContext ec) 2467 { 2468 if (ResolveCommon (ec) == null) 2469 return null; 2470 2471 type = probe_type_expr; 2472 eclass = ExprClass.Value; 2473 TypeSpec etype = expr.Type; 2474 2475 if (expr is TupleLiteral && TupleLiteral.ContainsNoTypeElement (etype)) { 2476 ec.Report.Error (8307, expr.Location, "The first operand of an `as' operator may not be a tuple literal without a natural type"); 2477 type = InternalType.ErrorType; 2478 return this; 2479 } 2480 2481 if (type == null) { 2482 type = InternalType.ErrorType; 2483 return this; 2484 } 2485 2486 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) { 2487 if (TypeManager.IsGenericParameter (type)) { 2488 ec.Report.Error (413, loc, 2489 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint", 2490 probe_type_expr.GetSignatureForError ()); 2491 } else { 2492 ec.Report.Error (77, loc, 2493 "The `as' operator cannot be used with a non-nullable value type `{0}'", 2494 type.GetSignatureForError ()); 2495 } 2496 return null; 2497 } 2498 2499 if (expr.IsNull && type.IsNullableType) { 2500 return Nullable.LiftedNull.CreateFromExpression (ec, this); 2501 } 2502 2503 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound 2504 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 2505 return this; 2506 } 2507 2508 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc); 2509 if (e != null) { 2510 e = EmptyCast.Create (e, type); 2511 return ReducedExpression.Create (e, this).Resolve (ec); 2512 } 2513 2514 if (Convert.ExplicitReferenceConversionExists (etype, type)){ 2515 if (TypeManager.IsGenericParameter (etype)) 2516 expr = new BoxedCast (expr, etype); 2517 2518 return this; 2519 } 2520 2521 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) { 2522 expr = new BoxedCast (expr, etype); 2523 return this; 2524 } 2525 2526 if (etype != InternalType.ErrorType) { 2527 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion", 2528 etype.GetSignatureForError (), type.GetSignatureForError ()); 2529 } 2530 2531 return null; 2532 } 2533 Accept(StructuralVisitor visitor)2534 public override object Accept (StructuralVisitor visitor) 2535 { 2536 return visitor.Visit (this); 2537 } 2538 } 2539 2540 // 2541 // This represents a typecast in the source language. 2542 // 2543 public class Cast : ShimExpression { 2544 Expression target_type; 2545 Cast(Expression cast_type, Expression expr, Location loc)2546 public Cast (Expression cast_type, Expression expr, Location loc) 2547 : base (expr) 2548 { 2549 this.target_type = cast_type; 2550 this.loc = loc; 2551 } 2552 2553 public Expression TargetType { 2554 get { return target_type; } 2555 } 2556 DoResolve(ResolveContext ec)2557 protected override Expression DoResolve (ResolveContext ec) 2558 { 2559 expr = expr.Resolve (ec); 2560 if (expr == null) 2561 return null; 2562 2563 type = target_type.ResolveAsType (ec); 2564 if (type == null) 2565 return null; 2566 2567 if (type.IsStatic) { 2568 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ()); 2569 return null; 2570 } 2571 2572 if (type.IsPointer) { 2573 if (ec.CurrentIterator != null) { 2574 UnsafeInsideIteratorError (ec, loc); 2575 } else if (!ec.IsUnsafe) { 2576 UnsafeError (ec, loc); 2577 } 2578 } 2579 2580 eclass = ExprClass.Value; 2581 2582 Constant c = expr as Constant; 2583 if (c != null) { 2584 c = c.Reduce (ec, type); 2585 if (c != null) 2586 return c; 2587 } 2588 2589 var res = Convert.ExplicitConversion (ec, expr, type, loc); 2590 if (res == expr) 2591 return EmptyCast.Create (res, type); 2592 2593 return res; 2594 } 2595 CloneTo(CloneContext clonectx, Expression t)2596 protected override void CloneTo (CloneContext clonectx, Expression t) 2597 { 2598 Cast target = (Cast) t; 2599 2600 target.target_type = target_type.Clone (clonectx); 2601 target.expr = expr.Clone (clonectx); 2602 } 2603 Accept(StructuralVisitor visitor)2604 public override object Accept (StructuralVisitor visitor) 2605 { 2606 return visitor.Visit (this); 2607 } 2608 } 2609 2610 public class ImplicitCast : ShimExpression 2611 { 2612 bool arrayAccess; 2613 ImplicitCast(Expression expr, TypeSpec target, bool arrayAccess)2614 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess) 2615 : base (expr) 2616 { 2617 this.loc = expr.Location; 2618 this.type = target; 2619 this.arrayAccess = arrayAccess; 2620 } 2621 DoResolve(ResolveContext ec)2622 protected override Expression DoResolve (ResolveContext ec) 2623 { 2624 expr = expr.Resolve (ec); 2625 if (expr == null) 2626 return null; 2627 2628 if (arrayAccess) 2629 expr = ConvertExpressionToArrayIndex (ec, expr); 2630 else 2631 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc); 2632 2633 return expr; 2634 } 2635 } 2636 2637 public class DeclarationExpression : Expression, IMemoryLocation 2638 { 2639 LocalVariableReference lvr; 2640 DeclarationExpression(FullNamedExpression variableType, LocalVariable variable)2641 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable) 2642 { 2643 VariableType = variableType; 2644 Variable = variable; 2645 this.loc = variable.Location; 2646 } 2647 2648 public LocalVariable Variable { get; set; } 2649 public Expression Initializer { get; set; } 2650 public FullNamedExpression VariableType { get; set; } 2651 AddressOf(EmitContext ec, AddressOp mode)2652 public void AddressOf (EmitContext ec, AddressOp mode) 2653 { 2654 if (!Variable.Created) 2655 Variable.CreateBuilder (ec); 2656 2657 if (Initializer != null) { 2658 lvr.EmitAssign (ec, Initializer, false, false); 2659 } 2660 2661 lvr.AddressOf (ec, mode); 2662 } 2663 CloneTo(CloneContext clonectx, Expression t)2664 protected override void CloneTo (CloneContext clonectx, Expression t) 2665 { 2666 var target = (DeclarationExpression) t; 2667 2668 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx); 2669 2670 if (Initializer != null) 2671 target.Initializer = Initializer.Clone (clonectx); 2672 } 2673 CreateExpressionTree(ResolveContext rc)2674 public override Expression CreateExpressionTree (ResolveContext rc) 2675 { 2676 rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration"); 2677 return null; 2678 } 2679 DoResolveCommon(ResolveContext rc)2680 bool DoResolveCommon (ResolveContext rc) 2681 { 2682 CheckExpressionVariable (rc); 2683 2684 var var_expr = VariableType as VarExpr; 2685 if (var_expr != null) { 2686 type = InternalType.VarOutType; 2687 } else { 2688 type = VariableType.ResolveAsType (rc); 2689 if (type == null) 2690 return false; 2691 } 2692 2693 if (Initializer != null) { 2694 Initializer = Initializer.Resolve (rc); 2695 2696 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) { 2697 type = var_expr.Type; 2698 } 2699 } 2700 2701 Variable.Type = type; 2702 lvr = new LocalVariableReference (Variable, loc); 2703 2704 eclass = ExprClass.Variable; 2705 return true; 2706 } 2707 DoResolve(ResolveContext rc)2708 protected override Expression DoResolve (ResolveContext rc) 2709 { 2710 if (DoResolveCommon (rc)) 2711 lvr.Resolve (rc); 2712 2713 return this; 2714 } 2715 DoResolveLValue(ResolveContext rc, Expression right_side)2716 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) 2717 { 2718 if (lvr == null && DoResolveCommon (rc)) 2719 lvr.ResolveLValue (rc, right_side); 2720 2721 return this; 2722 } 2723 Emit(EmitContext ec)2724 public override void Emit (EmitContext ec) 2725 { 2726 throw new NotImplementedException (); 2727 } 2728 EmitPrepare(EmitContext ec)2729 public override void EmitPrepare (EmitContext ec) 2730 { 2731 Variable.CreateBuilder (ec); 2732 } 2733 } 2734 2735 // 2736 // C# 2.0 Default value expression 2737 // 2738 public class DefaultValueExpression : Expression 2739 { 2740 Expression expr; 2741 DefaultValueExpression(Expression expr, Location loc)2742 public DefaultValueExpression (Expression expr, Location loc) 2743 { 2744 this.expr = expr; 2745 this.loc = loc; 2746 } 2747 2748 public Expression Expr { 2749 get { 2750 return this.expr; 2751 } 2752 } 2753 2754 public override bool IsSideEffectFree { 2755 get { 2756 return true; 2757 } 2758 } 2759 ContainsEmitWithAwait()2760 public override bool ContainsEmitWithAwait () 2761 { 2762 return false; 2763 } 2764 CreateExpressionTree(ResolveContext ec)2765 public override Expression CreateExpressionTree (ResolveContext ec) 2766 { 2767 Arguments args = new Arguments (2); 2768 args.Add (new Argument (this)); 2769 args.Add (new Argument (new TypeOf (type, loc))); 2770 return CreateExpressionFactoryCall (ec, "Constant", args); 2771 } 2772 DoResolve(ResolveContext ec)2773 protected override Expression DoResolve (ResolveContext ec) 2774 { 2775 type = expr.ResolveAsType (ec); 2776 if (type == null) 2777 return null; 2778 2779 if (type.IsStatic) { 2780 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type"); 2781 } 2782 2783 if (type.IsPointer) 2784 return new NullLiteral (Location).ConvertImplicitly (type); 2785 2786 if (TypeSpec.IsReferenceType (type)) 2787 return new NullConstant (type, loc); 2788 2789 Constant c = New.Constantify (type, expr.Location); 2790 if (c != null) 2791 return c; 2792 2793 eclass = ExprClass.Variable; 2794 return this; 2795 } 2796 Emit(EmitContext ec)2797 public override void Emit (EmitContext ec) 2798 { 2799 LocalTemporary temp_storage = new LocalTemporary(type); 2800 2801 temp_storage.AddressOf(ec, AddressOp.LoadStore); 2802 ec.Emit(OpCodes.Initobj, type); 2803 temp_storage.Emit(ec); 2804 temp_storage.Release (ec); 2805 } 2806 2807 #if !STATIC MakeExpression(BuilderContext ctx)2808 public override SLE.Expression MakeExpression (BuilderContext ctx) 2809 { 2810 return SLE.Expression.Default (type.GetMetaInfo ()); 2811 } 2812 #endif 2813 CloneTo(CloneContext clonectx, Expression t)2814 protected override void CloneTo (CloneContext clonectx, Expression t) 2815 { 2816 DefaultValueExpression target = (DefaultValueExpression) t; 2817 2818 target.expr = expr.Clone (clonectx); 2819 } 2820 Accept(StructuralVisitor visitor)2821 public override object Accept (StructuralVisitor visitor) 2822 { 2823 return visitor.Visit (this); 2824 } 2825 } 2826 2827 /// <summary> 2828 /// Binary operators 2829 /// </summary> 2830 public class Binary : Expression, IDynamicBinder 2831 { 2832 public class PredefinedOperator 2833 { 2834 protected readonly TypeSpec left; 2835 protected readonly TypeSpec right; 2836 protected readonly TypeSpec left_unwrap; 2837 protected readonly TypeSpec right_unwrap; 2838 public readonly Operator OperatorsMask; 2839 public TypeSpec ReturnType; 2840 PredefinedOperator(TypeSpec ltype, TypeSpec rtype, Operator op_mask)2841 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask) 2842 : this (ltype, rtype, op_mask, ltype) 2843 { 2844 } 2845 PredefinedOperator(TypeSpec type, Operator op_mask, TypeSpec return_type)2846 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type) 2847 : this (type, type, op_mask, return_type) 2848 { 2849 } 2850 PredefinedOperator(TypeSpec type, Operator op_mask)2851 public PredefinedOperator (TypeSpec type, Operator op_mask) 2852 : this (type, type, op_mask, type) 2853 { 2854 } 2855 PredefinedOperator(TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)2856 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type) 2857 { 2858 if ((op_mask & Operator.ValuesOnlyMask) != 0) 2859 throw new InternalErrorException ("Only masked values can be used"); 2860 2861 if ((op_mask & Operator.NullableMask) != 0) { 2862 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype); 2863 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype); 2864 } else { 2865 left_unwrap = ltype; 2866 right_unwrap = rtype; 2867 } 2868 2869 this.left = ltype; 2870 this.right = rtype; 2871 this.OperatorsMask = op_mask; 2872 this.ReturnType = return_type; 2873 } 2874 2875 public bool IsLifted { 2876 get { 2877 return (OperatorsMask & Operator.NullableMask) != 0; 2878 } 2879 } 2880 ConvertResult(ResolveContext rc, Binary b)2881 public virtual Expression ConvertResult (ResolveContext rc, Binary b) 2882 { 2883 Constant c; 2884 2885 var left_expr = b.left; 2886 var right_expr = b.right; 2887 2888 b.type = ReturnType; 2889 2890 if (IsLifted) { 2891 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) { 2892 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location); 2893 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location); 2894 } 2895 2896 if (right_expr.IsNull) { 2897 if ((b.oper & Operator.EqualityMask) != 0) { 2898 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type)) 2899 return b.CreateLiftedValueTypeResult (rc, left_expr.Type); 2900 } else if ((b.oper & Operator.BitwiseMask) != 0) { 2901 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool) 2902 return Nullable.LiftedNull.CreateFromExpression (rc, b); 2903 } else { 2904 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location); 2905 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location); 2906 2907 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0) 2908 return Nullable.LiftedNull.CreateFromExpression (rc, b); 2909 2910 return b.CreateLiftedValueTypeResult (rc, left); 2911 } 2912 } else if (left_expr.IsNull) { 2913 if ((b.oper & Operator.EqualityMask) != 0) { 2914 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type)) 2915 return b.CreateLiftedValueTypeResult (rc, right_expr.Type); 2916 } else if ((b.oper & Operator.BitwiseMask) != 0) { 2917 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool) 2918 return Nullable.LiftedNull.CreateFromExpression (rc, b); 2919 } else { 2920 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location); 2921 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location); 2922 2923 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0) 2924 return Nullable.LiftedNull.CreateFromExpression (rc, b); 2925 2926 return b.CreateLiftedValueTypeResult (rc, right); 2927 } 2928 } 2929 } 2930 2931 // 2932 // A user operators does not support multiple user conversions, but decimal type 2933 // is considered to be predefined type therefore we apply predefined operators rules 2934 // and then look for decimal user-operator implementation 2935 // 2936 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) { 2937 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location); 2938 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location); 2939 2940 return b.ResolveUserOperator (rc, b.left, b.right); 2941 } 2942 2943 c = right_expr as Constant; 2944 if (c != null) { 2945 if (c.IsDefaultValue) { 2946 // 2947 // Optimizes 2948 // 2949 // (expr + 0) to expr 2950 // (expr - 0) to expr 2951 // (bool? | false) to bool? 2952 // 2953 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction || 2954 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) { 2955 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location); 2956 return ReducedExpression.Create (b.left, b).Resolve (rc); 2957 } 2958 2959 // 2960 // Optimizes (value &/&& 0) to 0 2961 // 2962 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) { 2963 Constant side_effect = new SideEffectConstant (c, b.left, c.Location); 2964 return ReducedExpression.Create (side_effect, b); 2965 } 2966 } else { 2967 // 2968 // Optimizes (bool? & true) to bool? 2969 // 2970 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) { 2971 return ReducedExpression.Create (b.left, b).Resolve (rc); 2972 } 2973 } 2974 2975 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger) 2976 return ReducedExpression.Create (b.left, b).Resolve (rc); 2977 2978 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) { 2979 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location); 2980 } 2981 } 2982 2983 c = b.left as Constant; 2984 if (c != null) { 2985 if (c.IsDefaultValue) { 2986 // 2987 // Optimizes 2988 // 2989 // (0 + expr) to expr 2990 // (false | bool?) to bool? 2991 // 2992 if (b.oper == Operator.Addition || 2993 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) { 2994 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location); 2995 return ReducedExpression.Create (b.right, b).Resolve (rc); 2996 } 2997 2998 // 2999 // Optimizes (false && expr) to false 3000 // 3001 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) { 3002 // No rhs side-effects 3003 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation); 3004 return ReducedExpression.Create (c, b); 3005 } 3006 3007 // 3008 // Optimizes (0 & value) to 0 3009 // 3010 if (b.oper == Operator.BitwiseAnd && !IsLifted) { 3011 Constant side_effect = new SideEffectConstant (c, b.right, c.Location); 3012 return ReducedExpression.Create (side_effect, b); 3013 } 3014 } else { 3015 // 3016 // Optimizes (true & bool?) to bool? 3017 // 3018 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) { 3019 return ReducedExpression.Create (b.right, b).Resolve (rc); 3020 } 3021 3022 // 3023 // Optimizes (true || expr) to true 3024 // 3025 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) { 3026 // No rhs side-effects 3027 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation); 3028 return ReducedExpression.Create (c, b); 3029 } 3030 } 3031 3032 if (b.oper == Operator.Multiply && c.IsOneInteger) 3033 return ReducedExpression.Create (b.right, b).Resolve (rc); 3034 } 3035 3036 if (IsLifted) { 3037 var lifted = new Nullable.LiftedBinaryOperator (b); 3038 3039 TypeSpec ltype, rtype; 3040 if (b.left.Type.IsNullableType) { 3041 lifted.UnwrapLeft = new Nullable.Unwrap (b.left); 3042 ltype = left_unwrap; 3043 } else { 3044 ltype = left; 3045 } 3046 3047 if (b.right.Type.IsNullableType) { 3048 lifted.UnwrapRight = new Nullable.Unwrap (b.right); 3049 rtype = right_unwrap; 3050 } else { 3051 rtype = right; 3052 } 3053 3054 lifted.Left = b.left.IsNull ? 3055 Nullable.LiftedNull.Create (ltype, b.left.Location) : 3056 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location); 3057 3058 lifted.Right = b.right.IsNull ? 3059 Nullable.LiftedNull.Create (rtype, b.right.Location) : 3060 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location); 3061 3062 return lifted.Resolve (rc); 3063 } 3064 3065 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location); 3066 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location); 3067 3068 return b; 3069 } 3070 IsPrimitiveApplicable(TypeSpec ltype, TypeSpec rtype)3071 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype) 3072 { 3073 // 3074 // We are dealing with primitive types only 3075 // 3076 return left == ltype && ltype == rtype; 3077 } 3078 IsApplicable(ResolveContext ec, Expression lexpr, Expression rexpr)3079 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr) 3080 { 3081 // Quick path 3082 if (left == lexpr.Type && right == rexpr.Type) 3083 return true; 3084 3085 return Convert.ImplicitConversionExists (ec, lexpr, left) && 3086 Convert.ImplicitConversionExists (ec, rexpr, right); 3087 } 3088 ResolveBetterOperator(ResolveContext ec, PredefinedOperator best_operator)3089 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator) 3090 { 3091 if ((OperatorsMask & Operator.DecomposedMask) != 0) 3092 return best_operator; 3093 3094 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0) 3095 return this; 3096 3097 int result = 0; 3098 if (left != null && best_operator.left != null) { 3099 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap); 3100 } 3101 3102 // 3103 // When second argument is same as the first one, the result is same 3104 // 3105 if (right != null && (left != right || best_operator.left != best_operator.right)) { 3106 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap); 3107 } 3108 3109 if (result == 0 || result > 2) 3110 return null; 3111 3112 return result == 1 ? best_operator : this; 3113 } 3114 } 3115 3116 sealed class PredefinedStringOperator : PredefinedOperator 3117 { PredefinedStringOperator(TypeSpec type, Operator op_mask, TypeSpec retType)3118 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType) 3119 : base (type, type, op_mask, retType) 3120 { 3121 } 3122 PredefinedStringOperator(TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)3123 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType) 3124 : base (ltype, rtype, op_mask, retType) 3125 { 3126 } 3127 ConvertResult(ResolveContext ec, Binary b)3128 public override Expression ConvertResult (ResolveContext ec, Binary b) 3129 { 3130 // 3131 // Use original expression for nullable arguments 3132 // 3133 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap; 3134 if (unwrap != null) 3135 b.left = unwrap.Original; 3136 3137 unwrap = b.right as Nullable.Unwrap; 3138 if (unwrap != null) 3139 b.right = unwrap.Original; 3140 3141 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location); 3142 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location); 3143 3144 // 3145 // Start a new concat expression using converted expression 3146 // 3147 return StringConcat.Create (ec, b.left, b.right, b.loc); 3148 } 3149 } 3150 3151 sealed class PredefinedEqualityOperator : PredefinedOperator 3152 { 3153 MethodSpec equal_method, inequal_method; 3154 PredefinedEqualityOperator(TypeSpec arg, TypeSpec retType)3155 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType) 3156 : base (arg, arg, Operator.EqualityMask, retType) 3157 { 3158 } 3159 ConvertResult(ResolveContext ec, Binary b)3160 public override Expression ConvertResult (ResolveContext ec, Binary b) 3161 { 3162 b.type = ReturnType; 3163 3164 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location); 3165 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location); 3166 3167 Arguments args = new Arguments (2); 3168 args.Add (new Argument (b.left)); 3169 args.Add (new Argument (b.right)); 3170 3171 MethodSpec method; 3172 if (b.oper == Operator.Equality) { 3173 if (equal_method == null) { 3174 if (left.BuiltinType == BuiltinTypeSpec.Type.String) 3175 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc); 3176 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate) 3177 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc); 3178 else 3179 throw new NotImplementedException (left.GetSignatureForError ()); 3180 } 3181 3182 method = equal_method; 3183 } else { 3184 if (inequal_method == null) { 3185 if (left.BuiltinType == BuiltinTypeSpec.Type.String) 3186 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc); 3187 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate) 3188 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc); 3189 else 3190 throw new NotImplementedException (left.GetSignatureForError ()); 3191 } 3192 3193 method = inequal_method; 3194 } 3195 3196 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc); 3197 } 3198 } 3199 3200 class PredefinedPointerOperator : PredefinedOperator 3201 { PredefinedPointerOperator(TypeSpec ltype, TypeSpec rtype, Operator op_mask)3202 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask) 3203 : base (ltype, rtype, op_mask) 3204 { 3205 } 3206 PredefinedPointerOperator(TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)3207 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType) 3208 : base (ltype, rtype, op_mask, retType) 3209 { 3210 } 3211 PredefinedPointerOperator(TypeSpec type, Operator op_mask, TypeSpec return_type)3212 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type) 3213 : base (type, op_mask, return_type) 3214 { 3215 } 3216 IsApplicable(ResolveContext ec, Expression lexpr, Expression rexpr)3217 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr) 3218 { 3219 if (left == null) { 3220 if (!lexpr.Type.IsPointer) 3221 return false; 3222 } else { 3223 if (!Convert.ImplicitConversionExists (ec, lexpr, left)) 3224 return false; 3225 } 3226 3227 if (right == null) { 3228 if (!rexpr.Type.IsPointer) 3229 return false; 3230 } else { 3231 if (!Convert.ImplicitConversionExists (ec, rexpr, right)) 3232 return false; 3233 } 3234 3235 return true; 3236 } 3237 ConvertResult(ResolveContext ec, Binary b)3238 public override Expression ConvertResult (ResolveContext ec, Binary b) 3239 { 3240 if (left != null) { 3241 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left); 3242 } else if (right != null) { 3243 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right); 3244 } 3245 3246 TypeSpec r_type = ReturnType; 3247 Expression left_arg, right_arg; 3248 if (r_type == null) { 3249 if (left == null) { 3250 left_arg = b.left; 3251 right_arg = b.right; 3252 r_type = b.left.Type; 3253 } else { 3254 left_arg = b.right; 3255 right_arg = b.left; 3256 r_type = b.right.Type; 3257 } 3258 } else { 3259 left_arg = b.left; 3260 right_arg = b.right; 3261 } 3262 3263 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec); 3264 } 3265 } 3266 3267 [Flags] 3268 public enum Operator { 3269 Multiply = 0 | ArithmeticMask, 3270 Division = 1 | ArithmeticMask, 3271 Modulus = 2 | ArithmeticMask, 3272 Addition = 3 | ArithmeticMask | AdditionMask, 3273 Subtraction = 4 | ArithmeticMask | SubtractionMask, 3274 3275 LeftShift = 5 | ShiftMask, 3276 RightShift = 6 | ShiftMask, 3277 3278 LessThan = 7 | ComparisonMask | RelationalMask, 3279 GreaterThan = 8 | ComparisonMask | RelationalMask, 3280 LessThanOrEqual = 9 | ComparisonMask | RelationalMask, 3281 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask, 3282 Equality = 11 | ComparisonMask | EqualityMask, 3283 Inequality = 12 | ComparisonMask | EqualityMask, 3284 3285 BitwiseAnd = 13 | BitwiseMask, 3286 ExclusiveOr = 14 | BitwiseMask, 3287 BitwiseOr = 15 | BitwiseMask, 3288 3289 LogicalAnd = 16 | LogicalMask, 3290 LogicalOr = 17 | LogicalMask, 3291 3292 // 3293 // Operator masks 3294 // 3295 ValuesOnlyMask = ArithmeticMask - 1, 3296 ArithmeticMask = 1 << 5, 3297 ShiftMask = 1 << 6, 3298 ComparisonMask = 1 << 7, 3299 EqualityMask = 1 << 8, 3300 BitwiseMask = 1 << 9, 3301 LogicalMask = 1 << 10, 3302 AdditionMask = 1 << 11, 3303 SubtractionMask = 1 << 12, 3304 RelationalMask = 1 << 13, 3305 3306 DecomposedMask = 1 << 19, 3307 NullableMask = 1 << 20 3308 } 3309 3310 [Flags] 3311 public enum State : byte 3312 { 3313 None = 0, 3314 Compound = 1 << 1, 3315 UserOperatorsExcluded = 1 << 2 3316 } 3317 3318 readonly Operator oper; 3319 Expression left, right; 3320 State state; 3321 ConvCast.Mode enum_conversion; 3322 Binary(Operator oper, Expression left, Expression right, bool isCompound)3323 public Binary (Operator oper, Expression left, Expression right, bool isCompound) 3324 : this (oper, left, right, State.Compound) 3325 { 3326 } 3327 Binary(Operator oper, Expression left, Expression right, State state)3328 public Binary (Operator oper, Expression left, Expression right, State state) 3329 : this (oper, left, right) 3330 { 3331 this.state = state; 3332 } 3333 Binary(Operator oper, Expression left, Expression right)3334 public Binary (Operator oper, Expression left, Expression right) 3335 : this (oper, left, right, left.Location) 3336 { 3337 } 3338 Binary(Operator oper, Expression left, Expression right, Location loc)3339 public Binary (Operator oper, Expression left, Expression right, Location loc) 3340 { 3341 this.oper = oper; 3342 this.left = left; 3343 this.right = right; 3344 this.loc = loc; 3345 } 3346 3347 #region Properties 3348 3349 public bool IsCompound { 3350 get { 3351 return (state & State.Compound) != 0; 3352 } 3353 } 3354 3355 public Operator Oper { 3356 get { 3357 return oper; 3358 } 3359 } 3360 3361 public Expression Left { 3362 get { 3363 return this.left; 3364 } 3365 } 3366 3367 public Expression Right { 3368 get { 3369 return this.right; 3370 } 3371 } 3372 3373 public override Location StartLocation { 3374 get { 3375 return left.StartLocation; 3376 } 3377 } 3378 3379 #endregion 3380 3381 /// <summary> 3382 /// Returns a stringified representation of the Operator 3383 /// </summary> OperName(Operator oper)3384 string OperName (Operator oper) 3385 { 3386 string s; 3387 switch (oper){ 3388 case Operator.Multiply: 3389 s = "*"; 3390 break; 3391 case Operator.Division: 3392 s = "/"; 3393 break; 3394 case Operator.Modulus: 3395 s = "%"; 3396 break; 3397 case Operator.Addition: 3398 s = "+"; 3399 break; 3400 case Operator.Subtraction: 3401 s = "-"; 3402 break; 3403 case Operator.LeftShift: 3404 s = "<<"; 3405 break; 3406 case Operator.RightShift: 3407 s = ">>"; 3408 break; 3409 case Operator.LessThan: 3410 s = "<"; 3411 break; 3412 case Operator.GreaterThan: 3413 s = ">"; 3414 break; 3415 case Operator.LessThanOrEqual: 3416 s = "<="; 3417 break; 3418 case Operator.GreaterThanOrEqual: 3419 s = ">="; 3420 break; 3421 case Operator.Equality: 3422 s = "=="; 3423 break; 3424 case Operator.Inequality: 3425 s = "!="; 3426 break; 3427 case Operator.BitwiseAnd: 3428 s = "&"; 3429 break; 3430 case Operator.BitwiseOr: 3431 s = "|"; 3432 break; 3433 case Operator.ExclusiveOr: 3434 s = "^"; 3435 break; 3436 case Operator.LogicalOr: 3437 s = "||"; 3438 break; 3439 case Operator.LogicalAnd: 3440 s = "&&"; 3441 break; 3442 default: 3443 s = oper.ToString (); 3444 break; 3445 } 3446 3447 if (IsCompound) 3448 return s + "="; 3449 3450 return s; 3451 } 3452 Error_OperatorCannotBeApplied(ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)3453 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc) 3454 { 3455 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right); 3456 } 3457 Error_OperatorCannotBeApplied(ResolveContext ec, Expression left, Expression right, string oper, Location loc)3458 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc) 3459 { 3460 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType) 3461 return; 3462 3463 string l, r; 3464 l = left.Type.GetSignatureForError (); 3465 r = right.Type.GetSignatureForError (); 3466 3467 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'", 3468 oper, l, r); 3469 } 3470 Error_OperatorCannotBeApplied(ResolveContext ec, Expression left, Expression right)3471 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right) 3472 { 3473 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc); 3474 } 3475 FlowAnalysis(FlowAnalysisContext fc)3476 public override void FlowAnalysis (FlowAnalysisContext fc) 3477 { 3478 // 3479 // Optimized version when on-true/on-false data are not needed 3480 // 3481 if ((oper & Operator.LogicalMask) == 0) { 3482 left.FlowAnalysis (fc); 3483 right.FlowAnalysis (fc); 3484 return; 3485 } 3486 3487 left.FlowAnalysisConditional (fc); 3488 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue; 3489 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse; 3490 3491 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet ( 3492 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue); 3493 right.FlowAnalysisConditional (fc); 3494 3495 if (oper == Operator.LogicalOr) 3496 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue; 3497 else 3498 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse; 3499 } 3500 FlowAnalysisConditional(FlowAnalysisContext fc)3501 public override void FlowAnalysisConditional (FlowAnalysisContext fc) 3502 { 3503 if ((oper & Operator.LogicalMask) == 0) { 3504 base.FlowAnalysisConditional (fc); 3505 return; 3506 } 3507 3508 left.FlowAnalysisConditional (fc); 3509 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue; 3510 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse; 3511 3512 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet ( 3513 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue); 3514 right.FlowAnalysisConditional (fc); 3515 3516 var lc = left as Constant; 3517 if (oper == Operator.LogicalOr) { 3518 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse; 3519 if (lc != null && lc.IsDefaultValue) 3520 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse; 3521 else 3522 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue)); 3523 } else { 3524 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue; 3525 if (lc != null && !lc.IsDefaultValue) 3526 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue; 3527 else 3528 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse); 3529 } 3530 } 3531 3532 // 3533 // Converts operator to System.Linq.Expressions.ExpressionType enum name 3534 // GetOperatorExpressionTypeName()3535 string GetOperatorExpressionTypeName () 3536 { 3537 switch (oper) { 3538 case Operator.Addition: 3539 return IsCompound ? "AddAssign" : "Add"; 3540 case Operator.BitwiseAnd: 3541 return IsCompound ? "AndAssign" : "And"; 3542 case Operator.BitwiseOr: 3543 return IsCompound ? "OrAssign" : "Or"; 3544 case Operator.Division: 3545 return IsCompound ? "DivideAssign" : "Divide"; 3546 case Operator.ExclusiveOr: 3547 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr"; 3548 case Operator.Equality: 3549 return "Equal"; 3550 case Operator.GreaterThan: 3551 return "GreaterThan"; 3552 case Operator.GreaterThanOrEqual: 3553 return "GreaterThanOrEqual"; 3554 case Operator.Inequality: 3555 return "NotEqual"; 3556 case Operator.LeftShift: 3557 return IsCompound ? "LeftShiftAssign" : "LeftShift"; 3558 case Operator.LessThan: 3559 return "LessThan"; 3560 case Operator.LessThanOrEqual: 3561 return "LessThanOrEqual"; 3562 case Operator.LogicalAnd: 3563 return "And"; 3564 case Operator.LogicalOr: 3565 return "Or"; 3566 case Operator.Modulus: 3567 return IsCompound ? "ModuloAssign" : "Modulo"; 3568 case Operator.Multiply: 3569 return IsCompound ? "MultiplyAssign" : "Multiply"; 3570 case Operator.RightShift: 3571 return IsCompound ? "RightShiftAssign" : "RightShift"; 3572 case Operator.Subtraction: 3573 return IsCompound ? "SubtractAssign" : "Subtract"; 3574 default: 3575 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ()); 3576 } 3577 } 3578 ConvertBinaryToUserOperator(Operator op)3579 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op) 3580 { 3581 switch (op) { 3582 case Operator.Addition: 3583 return CSharp.Operator.OpType.Addition; 3584 case Operator.BitwiseAnd: 3585 case Operator.LogicalAnd: 3586 return CSharp.Operator.OpType.BitwiseAnd; 3587 case Operator.BitwiseOr: 3588 case Operator.LogicalOr: 3589 return CSharp.Operator.OpType.BitwiseOr; 3590 case Operator.Division: 3591 return CSharp.Operator.OpType.Division; 3592 case Operator.Equality: 3593 return CSharp.Operator.OpType.Equality; 3594 case Operator.ExclusiveOr: 3595 return CSharp.Operator.OpType.ExclusiveOr; 3596 case Operator.GreaterThan: 3597 return CSharp.Operator.OpType.GreaterThan; 3598 case Operator.GreaterThanOrEqual: 3599 return CSharp.Operator.OpType.GreaterThanOrEqual; 3600 case Operator.Inequality: 3601 return CSharp.Operator.OpType.Inequality; 3602 case Operator.LeftShift: 3603 return CSharp.Operator.OpType.LeftShift; 3604 case Operator.LessThan: 3605 return CSharp.Operator.OpType.LessThan; 3606 case Operator.LessThanOrEqual: 3607 return CSharp.Operator.OpType.LessThanOrEqual; 3608 case Operator.Modulus: 3609 return CSharp.Operator.OpType.Modulus; 3610 case Operator.Multiply: 3611 return CSharp.Operator.OpType.Multiply; 3612 case Operator.RightShift: 3613 return CSharp.Operator.OpType.RightShift; 3614 case Operator.Subtraction: 3615 return CSharp.Operator.OpType.Subtraction; 3616 default: 3617 throw new InternalErrorException (op.ToString ()); 3618 } 3619 } 3620 ContainsEmitWithAwait()3621 public override bool ContainsEmitWithAwait () 3622 { 3623 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait (); 3624 } 3625 EmitOperatorOpcode(EmitContext ec, Operator oper, TypeSpec l, Expression right)3626 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right) 3627 { 3628 OpCode opcode; 3629 3630 switch (oper){ 3631 case Operator.Multiply: 3632 if (ec.HasSet (EmitContext.Options.CheckedScope)) { 3633 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long) 3634 opcode = OpCodes.Mul_Ovf; 3635 else if (!IsFloat (l)) 3636 opcode = OpCodes.Mul_Ovf_Un; 3637 else 3638 opcode = OpCodes.Mul; 3639 } else 3640 opcode = OpCodes.Mul; 3641 3642 break; 3643 3644 case Operator.Division: 3645 if (IsUnsigned (l)) 3646 opcode = OpCodes.Div_Un; 3647 else 3648 opcode = OpCodes.Div; 3649 break; 3650 3651 case Operator.Modulus: 3652 if (IsUnsigned (l)) 3653 opcode = OpCodes.Rem_Un; 3654 else 3655 opcode = OpCodes.Rem; 3656 break; 3657 3658 case Operator.Addition: 3659 if (ec.HasSet (EmitContext.Options.CheckedScope)) { 3660 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long) 3661 opcode = OpCodes.Add_Ovf; 3662 else if (!IsFloat (l)) 3663 opcode = OpCodes.Add_Ovf_Un; 3664 else 3665 opcode = OpCodes.Add; 3666 } else 3667 opcode = OpCodes.Add; 3668 break; 3669 3670 case Operator.Subtraction: 3671 if (ec.HasSet (EmitContext.Options.CheckedScope)) { 3672 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long) 3673 opcode = OpCodes.Sub_Ovf; 3674 else if (!IsFloat (l)) 3675 opcode = OpCodes.Sub_Ovf_Un; 3676 else 3677 opcode = OpCodes.Sub; 3678 } else 3679 opcode = OpCodes.Sub; 3680 break; 3681 3682 case Operator.RightShift: 3683 if (!(right is IntConstant)) { 3684 ec.EmitInt (GetShiftMask (l)); 3685 ec.Emit (OpCodes.And); 3686 } 3687 3688 if (IsUnsigned (l)) 3689 opcode = OpCodes.Shr_Un; 3690 else 3691 opcode = OpCodes.Shr; 3692 break; 3693 3694 case Operator.LeftShift: 3695 if (!(right is IntConstant)) { 3696 ec.EmitInt (GetShiftMask (l)); 3697 ec.Emit (OpCodes.And); 3698 } 3699 3700 opcode = OpCodes.Shl; 3701 break; 3702 3703 case Operator.Equality: 3704 opcode = OpCodes.Ceq; 3705 break; 3706 3707 case Operator.Inequality: 3708 ec.Emit (OpCodes.Ceq); 3709 ec.EmitInt (0); 3710 3711 opcode = OpCodes.Ceq; 3712 break; 3713 3714 case Operator.LessThan: 3715 if (IsUnsigned (l)) 3716 opcode = OpCodes.Clt_Un; 3717 else 3718 opcode = OpCodes.Clt; 3719 break; 3720 3721 case Operator.GreaterThan: 3722 if (IsUnsigned (l)) 3723 opcode = OpCodes.Cgt_Un; 3724 else 3725 opcode = OpCodes.Cgt; 3726 break; 3727 3728 case Operator.LessThanOrEqual: 3729 if (IsUnsigned (l) || IsFloat (l)) 3730 ec.Emit (OpCodes.Cgt_Un); 3731 else 3732 ec.Emit (OpCodes.Cgt); 3733 ec.EmitInt (0); 3734 3735 opcode = OpCodes.Ceq; 3736 break; 3737 3738 case Operator.GreaterThanOrEqual: 3739 if (IsUnsigned (l) || IsFloat (l)) 3740 ec.Emit (OpCodes.Clt_Un); 3741 else 3742 ec.Emit (OpCodes.Clt); 3743 3744 ec.EmitInt (0); 3745 3746 opcode = OpCodes.Ceq; 3747 break; 3748 3749 case Operator.BitwiseOr: 3750 opcode = OpCodes.Or; 3751 break; 3752 3753 case Operator.BitwiseAnd: 3754 opcode = OpCodes.And; 3755 break; 3756 3757 case Operator.ExclusiveOr: 3758 opcode = OpCodes.Xor; 3759 break; 3760 3761 default: 3762 throw new InternalErrorException (oper.ToString ()); 3763 } 3764 3765 ec.Emit (opcode); 3766 } 3767 GetShiftMask(TypeSpec type)3768 static int GetShiftMask (TypeSpec type) 3769 { 3770 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f; 3771 } 3772 IsUnsigned(TypeSpec t)3773 static bool IsUnsigned (TypeSpec t) 3774 { 3775 switch (t.BuiltinType) { 3776 case BuiltinTypeSpec.Type.Char: 3777 case BuiltinTypeSpec.Type.UInt: 3778 case BuiltinTypeSpec.Type.ULong: 3779 case BuiltinTypeSpec.Type.UShort: 3780 case BuiltinTypeSpec.Type.Byte: 3781 return true; 3782 } 3783 3784 return t.IsPointer; 3785 } 3786 IsFloat(TypeSpec t)3787 static bool IsFloat (TypeSpec t) 3788 { 3789 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double; 3790 } 3791 ResolveOperator(ResolveContext rc)3792 public Expression ResolveOperator (ResolveContext rc) 3793 { 3794 eclass = ExprClass.Value; 3795 3796 TypeSpec l = left.Type; 3797 TypeSpec r = right.Type; 3798 Expression expr; 3799 bool primitives_only = false; 3800 3801 // 3802 // Handles predefined primitive types 3803 // 3804 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) && 3805 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) { 3806 if ((oper & Operator.ShiftMask) == 0) { 3807 if (!DoBinaryOperatorPromotion (rc)) 3808 return null; 3809 3810 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r); 3811 } 3812 } else { 3813 // Pointers 3814 if (l.IsPointer || r.IsPointer) 3815 return ResolveOperatorPointer (rc, l, r); 3816 3817 // User operators 3818 if ((state & State.UserOperatorsExcluded) == 0) { 3819 expr = ResolveUserOperator (rc, left, right); 3820 if (expr != null) 3821 return expr; 3822 } 3823 3824 bool lenum = l.IsEnum; 3825 bool renum = r.IsEnum; 3826 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) { 3827 // 3828 // Enumerations 3829 // 3830 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) { 3831 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r); 3832 3833 if (expr == null) 3834 return null; 3835 3836 if ((oper & Operator.BitwiseMask) != 0) { 3837 expr = EmptyCast.Create (expr, type); 3838 enum_conversion = GetEnumResultCast (type); 3839 3840 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) { 3841 expr = OptimizeAndOperation (expr); 3842 } 3843 } 3844 3845 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType); 3846 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType); 3847 return expr; 3848 } 3849 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) { 3850 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) { 3851 // 3852 // Enumerations 3853 // 3854 expr = ResolveEnumOperators (rc, lenum, renum, l, r); 3855 3856 // 3857 // We cannot break here there is also Enum + String possible match 3858 // which is not ambiguous with predefined enum operators 3859 // 3860 if (expr != null) { 3861 left = ConvertEnumOperandToUnderlyingType (rc, left, false); 3862 right = ConvertEnumOperandToUnderlyingType (rc, right, false); 3863 3864 return expr; 3865 } 3866 } else if (l.IsDelegate || r.IsDelegate) { 3867 // 3868 // Delegates 3869 // 3870 expr = ResolveOperatorDelegate (rc, l, r); 3871 3872 // TODO: Can this be ambiguous 3873 if (expr != null) 3874 return expr; 3875 } 3876 } 3877 } 3878 3879 // 3880 // Equality operators are more complicated 3881 // 3882 if ((oper & Operator.EqualityMask) != 0) { 3883 return ResolveEquality (rc, l, r, primitives_only); 3884 } 3885 3886 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only); 3887 if (expr != null) 3888 return expr; 3889 3890 if (primitives_only) 3891 return null; 3892 3893 // 3894 // Lifted operators have lower priority 3895 // 3896 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false); 3897 } 3898 IsEnumOrNullableEnum(TypeSpec type)3899 static bool IsEnumOrNullableEnum (TypeSpec type) 3900 { 3901 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum); 3902 } 3903 3904 3905 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...) 3906 // if 'left' is not an enumeration constant, create one from the type of 'right' EnumLiftUp(ResolveContext ec, Constant left, Constant right)3907 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right) 3908 { 3909 switch (oper) { 3910 case Operator.BitwiseOr: 3911 case Operator.BitwiseAnd: 3912 case Operator.ExclusiveOr: 3913 case Operator.Equality: 3914 case Operator.Inequality: 3915 case Operator.LessThan: 3916 case Operator.LessThanOrEqual: 3917 case Operator.GreaterThan: 3918 case Operator.GreaterThanOrEqual: 3919 if (left.Type.IsEnum) 3920 return left; 3921 3922 if (left.IsZeroInteger) 3923 return left.Reduce (ec, right.Type); 3924 3925 break; 3926 3927 case Operator.Addition: 3928 case Operator.Subtraction: 3929 return left; 3930 3931 case Operator.Multiply: 3932 case Operator.Division: 3933 case Operator.Modulus: 3934 case Operator.LeftShift: 3935 case Operator.RightShift: 3936 if (right.Type.IsEnum || left.Type.IsEnum) 3937 break; 3938 return left; 3939 } 3940 3941 return null; 3942 } 3943 3944 // 3945 // The `|' operator used on types which were extended is dangerous 3946 // CheckBitwiseOrOnSignExtended(ResolveContext ec)3947 void CheckBitwiseOrOnSignExtended (ResolveContext ec) 3948 { 3949 OpcodeCast lcast = left as OpcodeCast; 3950 if (lcast != null) { 3951 if (IsUnsigned (lcast.UnderlyingType)) 3952 lcast = null; 3953 } 3954 3955 OpcodeCast rcast = right as OpcodeCast; 3956 if (rcast != null) { 3957 if (IsUnsigned (rcast.UnderlyingType)) 3958 rcast = null; 3959 } 3960 3961 if (lcast == null && rcast == null) 3962 return; 3963 3964 // FIXME: consider constants 3965 3966 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType; 3967 ec.Report.Warning (675, 3, loc, 3968 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first", 3969 ltype.GetSignatureForError ()); 3970 } 3971 CreatePointerOperatorsTable(BuiltinTypes types)3972 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types) 3973 { 3974 return new PredefinedOperator[] { 3975 // 3976 // Pointer arithmetic: 3977 // 3978 // T* operator + (T* x, int y); T* operator - (T* x, int y); 3979 // T* operator + (T* x, uint y); T* operator - (T* x, uint y); 3980 // T* operator + (T* x, long y); T* operator - (T* x, long y); 3981 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y); 3982 // 3983 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask), 3984 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask), 3985 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask), 3986 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask), 3987 3988 // 3989 // T* operator + (int y, T* x); 3990 // T* operator + (uint y, T *x); 3991 // T* operator + (long y, T *x); 3992 // T* operator + (ulong y, T *x); 3993 // 3994 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null), 3995 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null), 3996 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null), 3997 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null), 3998 3999 // 4000 // long operator - (T* x, T *y) 4001 // 4002 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long) 4003 }; 4004 } 4005 CreateStandardOperatorsTable(BuiltinTypes types)4006 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types) 4007 { 4008 TypeSpec bool_type = types.Bool; 4009 4010 return new [] { 4011 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask), 4012 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask), 4013 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask), 4014 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask), 4015 new PredefinedOperator (types.Float, Operator.ArithmeticMask), 4016 new PredefinedOperator (types.Double, Operator.ArithmeticMask), 4017 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask), 4018 4019 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type), 4020 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type), 4021 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type), 4022 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type), 4023 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type), 4024 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type), 4025 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type), 4026 4027 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String), 4028 // Remaining string operators are in lifted tables 4029 4030 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type), 4031 4032 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask), 4033 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask), 4034 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask) 4035 }; 4036 4037 } CreateStandardLiftedOperatorsTable(ModuleContainer module)4038 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module) 4039 { 4040 var types = module.Compiler.BuiltinTypes; 4041 4042 // 4043 // Not strictly lifted but need to be in second group otherwise expressions like 4044 // int + null would resolve to +(object, string) instead of +(int?, int?) 4045 // 4046 var string_operators = new [] { 4047 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String), 4048 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String), 4049 }; 4050 4051 var nullable = module.PredefinedTypes.Nullable.TypeSpec; 4052 if (nullable == null) 4053 return string_operators; 4054 4055 var bool_type = types.Bool; 4056 4057 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type }); 4058 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int }); 4059 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt }); 4060 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long }); 4061 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong }); 4062 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float }); 4063 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double }); 4064 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal }); 4065 4066 return new[] { 4067 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask), 4068 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask), 4069 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask), 4070 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask), 4071 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask), 4072 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask), 4073 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask), 4074 4075 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type), 4076 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type), 4077 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type), 4078 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type), 4079 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type), 4080 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type), 4081 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type), 4082 4083 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool), 4084 4085 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask), 4086 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask), 4087 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask), 4088 4089 string_operators [0], 4090 string_operators [1] 4091 }; 4092 } 4093 CreateEqualityOperatorsTable(BuiltinTypes types)4094 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types) 4095 { 4096 TypeSpec bool_type = types.Bool; 4097 4098 return new[] { 4099 new PredefinedEqualityOperator (types.String, bool_type), 4100 new PredefinedEqualityOperator (types.Delegate, bool_type), 4101 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type), 4102 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type), 4103 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type), 4104 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type), 4105 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type), 4106 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type), 4107 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type), 4108 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type), 4109 }; 4110 } 4111 CreateEqualityLiftedOperatorsTable(ModuleContainer module)4112 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module) 4113 { 4114 var nullable = module.PredefinedTypes.Nullable.TypeSpec; 4115 4116 if (nullable == null) 4117 return new PredefinedOperator [0]; 4118 4119 var types = module.Compiler.BuiltinTypes; 4120 var bool_type = types.Bool; 4121 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type }); 4122 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int }); 4123 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt }); 4124 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long }); 4125 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong }); 4126 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float }); 4127 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double }); 4128 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal }); 4129 4130 return new [] { 4131 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type), 4132 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type), 4133 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type), 4134 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type), 4135 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type), 4136 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type), 4137 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type), 4138 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type) 4139 }; 4140 } 4141 4142 // 4143 // 7.2.6.2 Binary numeric promotions 4144 // DoBinaryOperatorPromotion(ResolveContext rc)4145 bool DoBinaryOperatorPromotion (ResolveContext rc) 4146 { 4147 TypeSpec ltype = left.Type; 4148 if (ltype.IsNullableType) { 4149 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype); 4150 } 4151 4152 // 4153 // This is numeric promotion code only 4154 // 4155 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool) 4156 return true; 4157 4158 TypeSpec rtype = right.Type; 4159 if (rtype.IsNullableType) { 4160 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype); 4161 } 4162 4163 var lb = ltype.BuiltinType; 4164 var rb = rtype.BuiltinType; 4165 TypeSpec type; 4166 Expression expr; 4167 4168 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) { 4169 type = rc.BuiltinTypes.Decimal; 4170 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) { 4171 type = rc.BuiltinTypes.Double; 4172 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) { 4173 type = rc.BuiltinTypes.Float; 4174 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) { 4175 type = rc.BuiltinTypes.ULong; 4176 4177 if (IsSignedType (lb)) { 4178 expr = ConvertSignedConstant (left, type); 4179 if (expr == null) 4180 return false; 4181 left = expr; 4182 } else if (IsSignedType (rb)) { 4183 expr = ConvertSignedConstant (right, type); 4184 if (expr == null) 4185 return false; 4186 right = expr; 4187 } 4188 4189 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) { 4190 type = rc.BuiltinTypes.Long; 4191 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) { 4192 type = rc.BuiltinTypes.UInt; 4193 4194 if (IsSignedType (lb)) { 4195 expr = ConvertSignedConstant (left, type); 4196 if (expr == null) 4197 type = rc.BuiltinTypes.Long; 4198 } else if (IsSignedType (rb)) { 4199 expr = ConvertSignedConstant (right, type); 4200 if (expr == null) 4201 type = rc.BuiltinTypes.Long; 4202 } 4203 } else { 4204 type = rc.BuiltinTypes.Int; 4205 } 4206 4207 if (ltype != type) { 4208 expr = PromoteExpression (rc, left, type); 4209 if (expr == null) 4210 return false; 4211 4212 left = expr; 4213 } 4214 4215 if (rtype != type) { 4216 expr = PromoteExpression (rc, right, type); 4217 if (expr == null) 4218 return false; 4219 4220 right = expr; 4221 } 4222 4223 return true; 4224 } 4225 IsSignedType(BuiltinTypeSpec.Type type)4226 static bool IsSignedType (BuiltinTypeSpec.Type type) 4227 { 4228 switch (type) { 4229 case BuiltinTypeSpec.Type.Int: 4230 case BuiltinTypeSpec.Type.Short: 4231 case BuiltinTypeSpec.Type.SByte: 4232 case BuiltinTypeSpec.Type.Long: 4233 return true; 4234 default: 4235 return false; 4236 } 4237 } 4238 ConvertSignedConstant(Expression expr, TypeSpec type)4239 static Expression ConvertSignedConstant (Expression expr, TypeSpec type) 4240 { 4241 var c = expr as Constant; 4242 if (c == null) 4243 return null; 4244 4245 return c.ConvertImplicitly (type); 4246 } 4247 PromoteExpression(ResolveContext rc, Expression expr, TypeSpec type)4248 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type) 4249 { 4250 if (expr.Type.IsNullableType) { 4251 return Convert.ImplicitConversionStandard (rc, expr, 4252 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location); 4253 } 4254 4255 var c = expr as Constant; 4256 if (c != null) 4257 return c.ConvertImplicitly (type); 4258 4259 return Convert.ImplicitNumericConversion (expr, type); 4260 } 4261 DoResolve(ResolveContext ec)4262 protected override Expression DoResolve (ResolveContext ec) 4263 { 4264 if (left == null) 4265 return null; 4266 4267 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) { 4268 left = ((ParenthesizedExpression) left).Expr; 4269 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type); 4270 if (left == null) 4271 return null; 4272 4273 if (left.eclass == ExprClass.Type) { 4274 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses"); 4275 return null; 4276 } 4277 } else 4278 left = left.Resolve (ec); 4279 4280 if (left == null) 4281 return null; 4282 4283 right = right.Resolve (ec); 4284 if (right == null) 4285 return null; 4286 4287 Constant lc = left as Constant; 4288 Constant rc = right as Constant; 4289 4290 // The conversion rules are ignored in enum context but why 4291 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) { 4292 lc = EnumLiftUp (ec, lc, rc); 4293 if (lc != null) 4294 rc = EnumLiftUp (ec, rc, lc); 4295 } 4296 4297 if (rc != null && lc != null) { 4298 int prev_e = ec.Report.Errors; 4299 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc); 4300 if (e != null || ec.Report.Errors != prev_e) 4301 return e; 4302 } 4303 4304 // Comparison warnings 4305 if ((oper & Operator.ComparisonMask) != 0) { 4306 if (left.Equals (right)) { 4307 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?"); 4308 } 4309 CheckOutOfRangeComparison (ec, lc, right.Type); 4310 CheckOutOfRangeComparison (ec, rc, left.Type); 4311 } 4312 4313 var ltype = left.Type; 4314 var rtype = right.Type; 4315 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Dynamic || rtype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) 4316 return DoResolveDynamic (ec); 4317 4318 // 4319 // Only default with == and != is explicitly allowed 4320 // 4321 if (ltype == InternalType.DefaultType || rtype == InternalType.DefaultType) { 4322 if ((Oper & Operator.EqualityMask) == 0) { 4323 ec.Report.Error (8310, loc, "Operator `{0}' cannot be applied to operand `default'", OperName (Oper)); 4324 return null; 4325 } 4326 4327 if (ltype == rtype) { 4328 ec.Report.Error (8315, loc, "Operator `{0}' is ambiguous on operands `default' and `default'", OperName (Oper)); 4329 return null; 4330 } 4331 4332 if (rtype == InternalType.DefaultType) { 4333 right = new DefaultValueExpression (new TypeExpression (ltype, right.Location), right.Location).Resolve (ec); 4334 } else { 4335 left = new DefaultValueExpression (new TypeExpression (rtype, left.Location), left.Location).Resolve (ec); 4336 } 4337 } 4338 4339 return DoResolveCore (ec, left, right); 4340 } 4341 DoResolveDynamic(ResolveContext rc)4342 Expression DoResolveDynamic (ResolveContext rc) 4343 { 4344 var lt = left.Type; 4345 var rt = right.Type; 4346 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod || 4347 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) { 4348 Error_OperatorCannotBeApplied (rc, left, right); 4349 return null; 4350 } 4351 4352 Arguments args; 4353 4354 // 4355 // Special handling for logical boolean operators which require rhs not to be 4356 // evaluated based on lhs value 4357 // 4358 if ((oper & Operator.LogicalMask) != 0) { 4359 Expression cond_left, cond_right, expr; 4360 4361 args = new Arguments (2); 4362 4363 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 4364 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc); 4365 4366 var cond_args = new Arguments (1); 4367 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc))); 4368 4369 // 4370 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right; 4371 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right; 4372 // 4373 left = temp.CreateReferenceExpression (rc, loc); 4374 if (oper == Operator.LogicalAnd) { 4375 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc); 4376 cond_left = left; 4377 } else { 4378 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc); 4379 cond_left = left; 4380 } 4381 4382 args.Add (new Argument (left)); 4383 args.Add (new Argument (right)); 4384 cond_right = new DynamicExpressionStatement (this, args, loc); 4385 } else { 4386 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc); 4387 4388 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) { 4389 rc.Report.Error (7083, left.Location, 4390 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'", 4391 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true"); 4392 return null; 4393 } 4394 4395 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc))); 4396 args.Add (new Argument (right)); 4397 right = new DynamicExpressionStatement (this, args, loc); 4398 4399 // 4400 // bool && dynamic => (temp = left) ? temp && right : temp; 4401 // bool || dynamic => (temp = left) ? temp : temp || right; 4402 // 4403 if (oper == Operator.LogicalAnd) { 4404 cond_left = right; 4405 cond_right = temp.CreateReferenceExpression (rc, loc); 4406 } else { 4407 cond_left = temp.CreateReferenceExpression (rc, loc); 4408 cond_right = right; 4409 } 4410 4411 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left)); 4412 } 4413 4414 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc); 4415 } 4416 4417 args = new Arguments (2); 4418 args.Add (new Argument (left)); 4419 args.Add (new Argument (right)); 4420 return new DynamicExpressionStatement (this, args, loc).Resolve (rc); 4421 } 4422 DoResolveCore(ResolveContext ec, Expression left_orig, Expression right_orig)4423 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig) 4424 { 4425 Expression expr = ResolveOperator (ec); 4426 if (expr == null) 4427 Error_OperatorCannotBeApplied (ec, left_orig, right_orig); 4428 4429 if (left == null || right == null) 4430 throw new InternalErrorException ("Invalid conversion"); 4431 4432 if (oper == Operator.BitwiseOr) 4433 CheckBitwiseOrOnSignExtended (ec); 4434 4435 return expr; 4436 } 4437 MakeExpression(BuilderContext ctx)4438 public override SLE.Expression MakeExpression (BuilderContext ctx) 4439 { 4440 return MakeExpression (ctx, left, right); 4441 } 4442 MakeExpression(BuilderContext ctx, Expression left, Expression right)4443 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right) 4444 { 4445 var le = left.MakeExpression (ctx); 4446 var re = right.MakeExpression (ctx); 4447 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope); 4448 4449 switch (oper) { 4450 case Operator.Addition: 4451 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re); 4452 case Operator.BitwiseAnd: 4453 return SLE.Expression.And (le, re); 4454 case Operator.BitwiseOr: 4455 return SLE.Expression.Or (le, re); 4456 case Operator.Division: 4457 return SLE.Expression.Divide (le, re); 4458 case Operator.Equality: 4459 return SLE.Expression.Equal (le, re); 4460 case Operator.ExclusiveOr: 4461 return SLE.Expression.ExclusiveOr (le, re); 4462 case Operator.GreaterThan: 4463 return SLE.Expression.GreaterThan (le, re); 4464 case Operator.GreaterThanOrEqual: 4465 return SLE.Expression.GreaterThanOrEqual (le, re); 4466 case Operator.Inequality: 4467 return SLE.Expression.NotEqual (le, re); 4468 case Operator.LeftShift: 4469 return SLE.Expression.LeftShift (le, re); 4470 case Operator.LessThan: 4471 return SLE.Expression.LessThan (le, re); 4472 case Operator.LessThanOrEqual: 4473 return SLE.Expression.LessThanOrEqual (le, re); 4474 case Operator.LogicalAnd: 4475 return SLE.Expression.AndAlso (le, re); 4476 case Operator.LogicalOr: 4477 return SLE.Expression.OrElse (le, re); 4478 case Operator.Modulus: 4479 return SLE.Expression.Modulo (le, re); 4480 case Operator.Multiply: 4481 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re); 4482 case Operator.RightShift: 4483 return SLE.Expression.RightShift (le, re); 4484 case Operator.Subtraction: 4485 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re); 4486 default: 4487 throw new NotImplementedException (oper.ToString ()); 4488 } 4489 } 4490 4491 // 4492 // D operator + (D x, D y) 4493 // D operator - (D x, D y) 4494 // ResolveOperatorDelegate(ResolveContext ec, TypeSpec l, TypeSpec r)4495 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r) 4496 { 4497 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) { 4498 Expression tmp; 4499 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) { 4500 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc); 4501 if (tmp == null) 4502 return null; 4503 right = tmp; 4504 r = right.Type; 4505 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) { 4506 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc); 4507 if (tmp == null) 4508 return null; 4509 left = tmp; 4510 l = left.Type; 4511 } else { 4512 return null; 4513 } 4514 } 4515 4516 MethodSpec method = null; 4517 Arguments args = new Arguments (2); 4518 args.Add (new Argument (left)); 4519 args.Add (new Argument (right)); 4520 4521 if (oper == Operator.Addition) { 4522 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc); 4523 } else if (oper == Operator.Subtraction) { 4524 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc); 4525 } 4526 4527 if (method == null) 4528 return new EmptyExpression (ec.BuiltinTypes.Decimal); 4529 4530 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc); 4531 return new ClassCast (expr, l); 4532 } 4533 4534 // 4535 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too 4536 // ResolveSingleEnumOperators(ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)4537 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype) 4538 { 4539 // 4540 // bool operator == (E x, E y); 4541 // bool operator != (E x, E y); 4542 // bool operator < (E x, E y); 4543 // bool operator > (E x, E y); 4544 // bool operator <= (E x, E y); 4545 // bool operator >= (E x, E y); 4546 // 4547 // E operator & (E x, E y); 4548 // E operator | (E x, E y); 4549 // E operator ^ (E x, E y); 4550 // 4551 Expression expr; 4552 if ((oper & Operator.ComparisonMask) != 0) { 4553 type = rc.BuiltinTypes.Bool; 4554 } else { 4555 if (lenum) 4556 type = ltype; 4557 else if (renum) 4558 type = rtype; 4559 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) 4560 type = ltype; 4561 else 4562 type = rtype; 4563 } 4564 4565 if (ltype == rtype) { 4566 if (lenum || renum) 4567 return this; 4568 4569 var lifted = new Nullable.LiftedBinaryOperator (this); 4570 lifted.Left = left; 4571 lifted.Right = right; 4572 return lifted.Resolve (rc); 4573 } 4574 4575 if (renum && !ltype.IsNullableType) { 4576 expr = Convert.ImplicitConversion (rc, left, rtype, loc); 4577 if (expr != null) { 4578 left = expr; 4579 return this; 4580 } 4581 } else if (lenum && !rtype.IsNullableType) { 4582 expr = Convert.ImplicitConversion (rc, right, ltype, loc); 4583 if (expr != null) { 4584 right = expr; 4585 return this; 4586 } 4587 } 4588 4589 // 4590 // Now try lifted version of predefined operator 4591 // 4592 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec; 4593 if (nullable_type != null) { 4594 if (renum && !ltype.IsNullableType) { 4595 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype }); 4596 4597 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc); 4598 if (expr != null) { 4599 left = expr; 4600 right = Convert.ImplicitConversion (rc, right, lifted_type, loc); 4601 } 4602 4603 if ((oper & Operator.BitwiseMask) != 0) 4604 type = lifted_type; 4605 4606 if (left.IsNull) { 4607 if ((oper & Operator.BitwiseMask) != 0) 4608 return Nullable.LiftedNull.CreateFromExpression (rc, this); 4609 4610 return CreateLiftedValueTypeResult (rc, rtype); 4611 } 4612 4613 if (expr != null) { 4614 var lifted = new Nullable.LiftedBinaryOperator (this); 4615 lifted.Left = expr; 4616 lifted.Right = right; 4617 return lifted.Resolve (rc); 4618 } 4619 } else if (lenum && !rtype.IsNullableType) { 4620 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype }); 4621 4622 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc); 4623 if (expr != null) { 4624 right = expr; 4625 left = Convert.ImplicitConversion (rc, left, lifted_type, loc); 4626 } 4627 4628 if ((oper & Operator.BitwiseMask) != 0) 4629 type = lifted_type; 4630 4631 if (right.IsNull) { 4632 if ((oper & Operator.BitwiseMask) != 0) 4633 return Nullable.LiftedNull.CreateFromExpression (rc, this); 4634 4635 return CreateLiftedValueTypeResult (rc, ltype); 4636 } 4637 4638 if (expr != null) { 4639 var lifted = new Nullable.LiftedBinaryOperator (this); 4640 lifted.Left = left; 4641 lifted.Right = expr; 4642 return lifted.Resolve (rc); 4643 } 4644 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) { 4645 Nullable.Unwrap unwrap = null; 4646 if (left.IsNull || right.IsNull) { 4647 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) 4648 left = Convert.ImplicitConversion (rc, left, rtype, left.Location); 4649 4650 if ((oper & Operator.RelationalMask) != 0) 4651 return CreateLiftedValueTypeResult (rc, rtype); 4652 4653 if ((oper & Operator.BitwiseMask) != 0) 4654 return Nullable.LiftedNull.CreateFromExpression (rc, this); 4655 4656 if (right.IsNull) 4657 return CreateLiftedValueTypeResult (rc, left.Type); 4658 4659 // Equality operators are valid between E? and null 4660 expr = left; 4661 unwrap = new Nullable.Unwrap (right); 4662 } else { 4663 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc); 4664 if (expr == null) 4665 return null; 4666 4667 if ((oper & Operator.BitwiseMask) != 0) 4668 type = rtype; 4669 } 4670 4671 if (expr != null) { 4672 var lifted = new Nullable.LiftedBinaryOperator (this); 4673 lifted.Left = expr; 4674 lifted.Right = right; 4675 lifted.UnwrapRight = unwrap; 4676 return lifted.Resolve (rc); 4677 } 4678 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) { 4679 Nullable.Unwrap unwrap = null; 4680 if (right.IsNull || left.IsNull) { 4681 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) 4682 right = Convert.ImplicitConversion (rc, right, ltype, right.Location); 4683 4684 if ((oper & Operator.RelationalMask) != 0) 4685 return CreateLiftedValueTypeResult (rc, ltype); 4686 4687 if ((oper & Operator.BitwiseMask) != 0) 4688 return Nullable.LiftedNull.CreateFromExpression (rc, this); 4689 4690 if (left.IsNull) 4691 return CreateLiftedValueTypeResult (rc, right.Type); 4692 4693 // Equality operators are valid between E? and null 4694 expr = right; 4695 unwrap = new Nullable.Unwrap (left); 4696 } else { 4697 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc); 4698 if (expr == null) 4699 return null; 4700 4701 if ((oper & Operator.BitwiseMask) != 0) 4702 type = ltype; 4703 } 4704 4705 if (expr != null) { 4706 var lifted = new Nullable.LiftedBinaryOperator (this); 4707 lifted.Left = left; 4708 lifted.UnwrapLeft = unwrap; 4709 lifted.Right = expr; 4710 return lifted.Resolve (rc); 4711 } 4712 } 4713 } 4714 4715 return null; 4716 } 4717 ConvertEnumOperandToUnderlyingType(ResolveContext rc, Expression expr, bool liftType)4718 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType) 4719 { 4720 TypeSpec underlying_type; 4721 if (expr.Type.IsNullableType) { 4722 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type); 4723 if (nt.IsEnum) 4724 underlying_type = EnumSpec.GetUnderlyingType (nt); 4725 else 4726 underlying_type = nt; 4727 } else if (expr.Type.IsEnum) { 4728 underlying_type = EnumSpec.GetUnderlyingType (expr.Type); 4729 } else { 4730 underlying_type = expr.Type; 4731 } 4732 4733 switch (underlying_type.BuiltinType) { 4734 case BuiltinTypeSpec.Type.SByte: 4735 case BuiltinTypeSpec.Type.Byte: 4736 case BuiltinTypeSpec.Type.Short: 4737 case BuiltinTypeSpec.Type.UShort: 4738 underlying_type = rc.BuiltinTypes.Int; 4739 break; 4740 } 4741 4742 if (expr.Type.IsNullableType || liftType) 4743 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type }); 4744 4745 if (expr.Type == underlying_type) 4746 return expr; 4747 4748 return EmptyCast.Create (expr, underlying_type); 4749 } 4750 ResolveEnumOperators(ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)4751 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype) 4752 { 4753 // 4754 // U operator - (E e, E f) 4755 // E operator - (E e, U x) // Internal decomposition operator 4756 // E operator - (U x, E e) // Internal decomposition operator 4757 // 4758 // E operator + (E e, U x) 4759 // E operator + (U x, E e) 4760 // 4761 4762 TypeSpec enum_type; 4763 4764 if (lenum) 4765 enum_type = ltype; 4766 else if (renum) 4767 enum_type = rtype; 4768 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) 4769 enum_type = ltype; 4770 else 4771 enum_type = rtype; 4772 4773 Expression expr; 4774 if (!enum_type.IsNullableType) { 4775 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false); 4776 if (expr != null) { 4777 if (oper == Operator.Subtraction) 4778 expr = ConvertEnumSubtractionResult (rc, expr); 4779 else 4780 expr = ConvertEnumAdditionalResult (expr, enum_type); 4781 4782 enum_conversion = GetEnumResultCast (expr.Type); 4783 4784 return expr; 4785 } 4786 4787 var nullable = rc.Module.PredefinedTypes.Nullable; 4788 4789 // 4790 // Don't try nullable version when nullable type is undefined 4791 // 4792 if (!nullable.IsDefined) 4793 return null; 4794 4795 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type }); 4796 } 4797 4798 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false); 4799 if (expr != null) { 4800 if (oper == Operator.Subtraction) 4801 expr = ConvertEnumSubtractionResult (rc, expr); 4802 else 4803 expr = ConvertEnumAdditionalResult (expr, enum_type); 4804 4805 enum_conversion = GetEnumResultCast (expr.Type); 4806 } 4807 4808 return expr; 4809 } 4810 ConvertEnumAdditionalResult(Expression expr, TypeSpec enumType)4811 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType) 4812 { 4813 return EmptyCast.Create (expr, enumType); 4814 } 4815 ConvertEnumSubtractionResult(ResolveContext rc, Expression expr)4816 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr) 4817 { 4818 // 4819 // Enumeration subtraction has different result type based on 4820 // best overload 4821 // 4822 TypeSpec result_type; 4823 if (left.Type == right.Type) { 4824 var c = right as EnumConstant; 4825 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) { 4826 // 4827 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is 4828 // E which is not what expressions E - 1 or 0 - E return 4829 // 4830 result_type = left.Type; 4831 } else { 4832 result_type = left.Type.IsNullableType ? 4833 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) : 4834 EnumSpec.GetUnderlyingType (left.Type); 4835 } 4836 } else { 4837 if (IsEnumOrNullableEnum (left.Type)) { 4838 result_type = left.Type; 4839 } else { 4840 result_type = right.Type; 4841 } 4842 4843 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType) 4844 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type }); 4845 } 4846 4847 return EmptyCast.Create (expr, result_type); 4848 } 4849 GetEnumResultCast(TypeSpec type)4850 public static ConvCast.Mode GetEnumResultCast (TypeSpec type) 4851 { 4852 if (type.IsNullableType) 4853 type = Nullable.NullableInfo.GetUnderlyingType (type); 4854 4855 if (type.IsEnum) 4856 type = EnumSpec.GetUnderlyingType (type); 4857 4858 switch (type.BuiltinType) { 4859 case BuiltinTypeSpec.Type.SByte: 4860 return ConvCast.Mode.I4_I1; 4861 case BuiltinTypeSpec.Type.Byte: 4862 return ConvCast.Mode.I4_U1; 4863 case BuiltinTypeSpec.Type.Short: 4864 return ConvCast.Mode.I4_I2; 4865 case BuiltinTypeSpec.Type.UShort: 4866 return ConvCast.Mode.I4_U2; 4867 } 4868 4869 return 0; 4870 } 4871 4872 // 4873 // Equality operators rules 4874 // ResolveEquality(ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)4875 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only) 4876 { 4877 Expression result; 4878 type = ec.BuiltinTypes.Bool; 4879 bool no_arg_conv = false; 4880 4881 if (!primitives_only) { 4882 4883 // 4884 // a, Both operands are reference-type values or the value null 4885 // b, One operand is a value of type T where T is a type-parameter and 4886 // the other operand is the value null. Furthermore T does not have the 4887 // value type constraint 4888 // 4889 // LAMESPEC: Very confusing details in the specification, basically any 4890 // reference like type-parameter is allowed 4891 // 4892 var tparam_l = l as TypeParameterSpec; 4893 var tparam_r = r as TypeParameterSpec; 4894 if (tparam_l != null) { 4895 if (right is NullLiteral) { 4896 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType) 4897 return null; 4898 4899 left = new BoxedCast (left, ec.BuiltinTypes.Object); 4900 return this; 4901 } 4902 4903 if (!tparam_l.IsReferenceType) 4904 return null; 4905 4906 l = tparam_l.GetEffectiveBase (); 4907 left = new BoxedCast (left, l); 4908 } else if (left is NullLiteral && tparam_r == null) { 4909 if (TypeSpec.IsReferenceType (r)) 4910 return this; 4911 4912 if (r.Kind == MemberKind.InternalCompilerType) 4913 return null; 4914 } 4915 4916 if (tparam_r != null) { 4917 if (left is NullLiteral) { 4918 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType) 4919 return null; 4920 4921 right = new BoxedCast (right, ec.BuiltinTypes.Object); 4922 return this; 4923 } 4924 4925 if (!tparam_r.IsReferenceType) 4926 return null; 4927 4928 r = tparam_r.GetEffectiveBase (); 4929 right = new BoxedCast (right, r); 4930 } else if (right is NullLiteral) { 4931 if (TypeSpec.IsReferenceType (l)) 4932 return this; 4933 4934 if (l.Kind == MemberKind.InternalCompilerType) 4935 return null; 4936 } 4937 4938 // 4939 // LAMESPEC: method groups can be compared when they convert to other side delegate 4940 // 4941 if (l.IsDelegate) { 4942 if (right.eclass == ExprClass.MethodGroup) { 4943 result = Convert.ImplicitConversion (ec, right, l, loc); 4944 if (result == null) 4945 return null; 4946 4947 right = result; 4948 r = l; 4949 } else if (r.IsDelegate && l != r) { 4950 return null; 4951 } 4952 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) { 4953 result = Convert.ImplicitConversionRequired (ec, left, r, loc); 4954 if (result == null) 4955 return null; 4956 4957 left = result; 4958 l = r; 4959 } else { 4960 no_arg_conv = l == r && !l.IsStruct; 4961 } 4962 } 4963 4964 // 4965 // bool operator != (string a, string b) 4966 // bool operator == (string a, string b) 4967 // 4968 // bool operator != (Delegate a, Delegate b) 4969 // bool operator == (Delegate a, Delegate b) 4970 // 4971 // bool operator != (bool a, bool b) 4972 // bool operator == (bool a, bool b) 4973 // 4974 // LAMESPEC: Reference equality comparison can apply to value/reference types when 4975 // they implement an implicit conversion to any of types above. This does 4976 // not apply when both operands are of same reference type 4977 // 4978 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) { 4979 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv); 4980 if (result != null) 4981 return result; 4982 4983 // 4984 // Now try lifted version of predefined operators 4985 // 4986 if (no_arg_conv && !l.IsNullableType) { 4987 // 4988 // Optimizes cases which won't match 4989 // 4990 } else { 4991 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv); 4992 if (result != null) 4993 return result; 4994 } 4995 4996 // 4997 // The == and != operators permit one operand to be a value of a nullable 4998 // type and the other to be the null literal, even if no predefined or user-defined 4999 // operator (in unlifted or lifted form) exists for the operation. 5000 // 5001 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) { 5002 var lifted = new Nullable.LiftedBinaryOperator (this); 5003 lifted.Left = left; 5004 lifted.Right = right; 5005 return lifted.Resolve (ec); 5006 } 5007 } 5008 5009 // 5010 // bool operator != (object a, object b) 5011 // bool operator == (object a, object b) 5012 // 5013 // An explicit reference conversion exists from the 5014 // type of either operand to the type of the other operand. 5015 // 5016 5017 // Optimize common path 5018 if (l == r) { 5019 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this; 5020 } 5021 5022 if (!Convert.ExplicitReferenceConversionExists (l, r) && 5023 !Convert.ExplicitReferenceConversionExists (r, l)) 5024 return null; 5025 5026 // Reject allowed explicit conversions like int->object 5027 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r)) 5028 return null; 5029 5030 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null) 5031 ec.Report.Warning (253, 2, loc, 5032 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison", 5033 l.GetSignatureForError ()); 5034 5035 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null) 5036 ec.Report.Warning (252, 2, loc, 5037 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison", 5038 r.GetSignatureForError ()); 5039 5040 return this; 5041 } 5042 5043 ResolveOperatorPointer(ResolveContext ec, TypeSpec l, TypeSpec r)5044 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r) 5045 { 5046 // 5047 // bool operator == (void* x, void* y); 5048 // bool operator != (void* x, void* y); 5049 // bool operator < (void* x, void* y); 5050 // bool operator > (void* x, void* y); 5051 // bool operator <= (void* x, void* y); 5052 // bool operator >= (void* x, void* y); 5053 // 5054 if ((oper & Operator.ComparisonMask) != 0) { 5055 Expression temp; 5056 if (!l.IsPointer) { 5057 temp = Convert.ImplicitConversion (ec, left, r, left.Location); 5058 if (temp == null) 5059 return null; 5060 left = temp; 5061 } 5062 5063 if (!r.IsPointer) { 5064 temp = Convert.ImplicitConversion (ec, right, l, right.Location); 5065 if (temp == null) 5066 return null; 5067 right = temp; 5068 } 5069 5070 type = ec.BuiltinTypes.Bool; 5071 return this; 5072 } 5073 5074 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false); 5075 } 5076 5077 // 5078 // Build-in operators method overloading 5079 // ResolveOperatorPredefined(ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)5080 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only) 5081 { 5082 PredefinedOperator best_operator = null; 5083 TypeSpec l = left.Type; 5084 TypeSpec r = right.Type; 5085 Operator oper_mask = oper & ~Operator.ValuesOnlyMask; 5086 5087 foreach (PredefinedOperator po in operators) { 5088 if ((po.OperatorsMask & oper_mask) == 0) 5089 continue; 5090 5091 if (primitives_only) { 5092 if (!po.IsPrimitiveApplicable (l, r)) 5093 continue; 5094 } else { 5095 if (!po.IsApplicable (ec, left, right)) 5096 continue; 5097 } 5098 5099 if (best_operator == null) { 5100 best_operator = po; 5101 if (primitives_only) 5102 break; 5103 5104 continue; 5105 } 5106 5107 best_operator = po.ResolveBetterOperator (ec, best_operator); 5108 5109 if (best_operator == null) { 5110 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'", 5111 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ()); 5112 5113 best_operator = po; 5114 break; 5115 } 5116 } 5117 5118 if (best_operator == null) 5119 return null; 5120 5121 return best_operator.ConvertResult (ec, this); 5122 } 5123 5124 // 5125 // Optimize & constant expressions with 0 value 5126 // OptimizeAndOperation(Expression expr)5127 Expression OptimizeAndOperation (Expression expr) 5128 { 5129 Constant rc = right as Constant; 5130 Constant lc = left as Constant; 5131 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) { 5132 // 5133 // The result is a constant with side-effect 5134 // 5135 Constant side_effect = rc == null ? 5136 new SideEffectConstant (lc, right, loc) : 5137 new SideEffectConstant (rc, left, loc); 5138 5139 return ReducedExpression.Create (side_effect, expr); 5140 } 5141 5142 return expr; 5143 } 5144 5145 // 5146 // Value types can be compared with the null literal because of the lifting 5147 // language rules. However the result is always true or false. 5148 // CreateLiftedValueTypeResult(ResolveContext rc, TypeSpec valueType)5149 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType) 5150 { 5151 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) { 5152 type = rc.BuiltinTypes.Bool; 5153 return this; 5154 } 5155 5156 // FIXME: Handle side effect constants 5157 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc); 5158 5159 if ((Oper & Operator.EqualityMask) != 0) { 5160 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'", 5161 valueType.GetSignatureForError (), c.GetValueAsLiteral ()); 5162 } else { 5163 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'", 5164 valueType.GetSignatureForError (), c.GetValueAsLiteral ()); 5165 } 5166 5167 return c; 5168 } 5169 5170 // 5171 // Performs user-operator overloading 5172 // ResolveUserOperator(ResolveContext rc, Expression left, Expression right)5173 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right) 5174 { 5175 Expression oper_expr; 5176 5177 var op = ConvertBinaryToUserOperator (oper); 5178 var l = left.Type; 5179 if (l.IsNullableType) 5180 l = Nullable.NullableInfo.GetUnderlyingType (l); 5181 var r = right.Type; 5182 if (r.IsNullableType) 5183 r = Nullable.NullableInfo.GetUnderlyingType (r); 5184 5185 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false); 5186 IList<MemberSpec> right_operators = null; 5187 5188 if (l != r) { 5189 right_operators = MemberCache.GetUserOperator (r, op, false); 5190 if (right_operators == null && left_operators == null) 5191 return null; 5192 } else if (left_operators == null) { 5193 return null; 5194 } 5195 5196 Arguments args = new Arguments (2); 5197 Argument larg = new Argument (left); 5198 args.Add (larg); 5199 Argument rarg = new Argument (right); 5200 args.Add (rarg); 5201 5202 // 5203 // User-defined operator implementations always take precedence 5204 // over predefined operator implementations 5205 // 5206 if (left_operators != null && right_operators != null) { 5207 left_operators = CombineUserOperators (left_operators, right_operators); 5208 } else if (right_operators != null) { 5209 left_operators = right_operators; 5210 } 5211 5212 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly | 5213 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded; 5214 5215 var res = new OverloadResolver (left_operators, restr, loc); 5216 5217 var oper_method = res.ResolveOperator (rc, ref args); 5218 if (oper_method == null) { 5219 // 5220 // Logical && and || cannot be lifted 5221 // 5222 if ((oper & Operator.LogicalMask) != 0) 5223 return null; 5224 5225 // 5226 // Apply lifted user operators only for liftable types. Implicit conversion 5227 // to nullable types is not allowed 5228 // 5229 if (!IsLiftedOperatorApplicable ()) 5230 return null; 5231 5232 // TODO: Cache the result in module container 5233 var lifted_methods = CreateLiftedOperators (rc, left_operators); 5234 if (lifted_methods == null) 5235 return null; 5236 5237 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc); 5238 5239 oper_method = res.ResolveOperator (rc, ref args); 5240 if (oper_method == null) 5241 return null; 5242 5243 MethodSpec best_original = null; 5244 foreach (MethodSpec ms in left_operators) { 5245 if (ms.MemberDefinition == oper_method.MemberDefinition) { 5246 best_original = ms; 5247 break; 5248 } 5249 } 5250 5251 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) { 5252 // 5253 // Expression trees use lifted notation in this case 5254 // 5255 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location); 5256 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location); 5257 } 5258 5259 var ptypes = best_original.Parameters.Types; 5260 5261 if (left.IsNull || right.IsNull) { 5262 // 5263 // The lifted operator produces a null value if one or both operands are null 5264 // 5265 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) { 5266 type = oper_method.ReturnType; 5267 return Nullable.LiftedNull.CreateFromExpression (rc, this); 5268 } 5269 5270 // 5271 // The lifted operator produces the value false if one or both operands are null for 5272 // relational operators. 5273 // 5274 if ((oper & Operator.RelationalMask) != 0) { 5275 // 5276 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong 5277 // because return type is actually bool 5278 // 5279 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]); 5280 } 5281 5282 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) { 5283 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]); 5284 } 5285 } 5286 5287 type = oper_method.ReturnType; 5288 var lifted = new Nullable.LiftedBinaryOperator (this); 5289 lifted.UserOperator = best_original; 5290 5291 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) { 5292 lifted.UnwrapLeft = new Nullable.Unwrap (left); 5293 } 5294 5295 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) { 5296 lifted.UnwrapRight = new Nullable.Unwrap (right); 5297 } 5298 5299 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location); 5300 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location); 5301 5302 return lifted.Resolve (rc); 5303 } 5304 5305 if ((oper & Operator.LogicalMask) != 0) { 5306 // TODO: CreateExpressionTree is allocated every time 5307 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree, 5308 oper == Operator.LogicalAnd, loc).Resolve (rc); 5309 } else { 5310 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc); 5311 } 5312 5313 this.left = larg.Expr; 5314 this.right = rarg.Expr; 5315 5316 return oper_expr; 5317 } 5318 IsLiftedOperatorApplicable()5319 bool IsLiftedOperatorApplicable () 5320 { 5321 if (left.Type.IsNullableType) { 5322 if ((oper & Operator.EqualityMask) != 0) 5323 return !right.IsNull; 5324 5325 return true; 5326 } 5327 5328 if (right.Type.IsNullableType) { 5329 if ((oper & Operator.EqualityMask) != 0) 5330 return !left.IsNull; 5331 5332 return true; 5333 } 5334 5335 if (TypeSpec.IsValueType (left.Type)) 5336 return right.IsNull; 5337 5338 if (TypeSpec.IsValueType (right.Type)) 5339 return left.IsNull; 5340 5341 return false; 5342 } 5343 CreateLiftedOperators(ResolveContext rc, IList<MemberSpec> operators)5344 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators) 5345 { 5346 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec; 5347 if (nullable_type == null) 5348 return null; 5349 5350 // 5351 // Lifted operators permit predefined and user-defined operators that operate 5352 // on non-nullable value types to also be used with nullable forms of those types. 5353 // Lifted operators are constructed from predefined and user-defined operators 5354 // that meet certain requirements 5355 // 5356 List<MemberSpec> lifted = null; 5357 foreach (MethodSpec oper in operators) { 5358 TypeSpec rt; 5359 if ((Oper & Operator.ComparisonMask) != 0) { 5360 // 5361 // Result type must be of type bool for lifted comparison operators 5362 // 5363 rt = oper.ReturnType; 5364 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool) 5365 continue; 5366 } else { 5367 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType)) 5368 continue; 5369 5370 rt = null; 5371 } 5372 5373 var ptypes = oper.Parameters.Types; 5374 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1])) 5375 continue; 5376 5377 // 5378 // LAMESPEC: I am not sure why but for equality operators to be lifted 5379 // both types have to match 5380 // 5381 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1]) 5382 continue; 5383 5384 if (lifted == null) 5385 lifted = new List<MemberSpec> (); 5386 5387 // 5388 // The lifted form is constructed by adding a single ? modifier to each operand and 5389 // result type except for comparison operators where return type is bool 5390 // 5391 if (rt == null) 5392 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType }); 5393 5394 var parameters = ParametersCompiled.CreateFullyResolved ( 5395 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }), 5396 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] })); 5397 5398 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition, 5399 rt, parameters, oper.Modifiers); 5400 5401 lifted.Add (lifted_op); 5402 } 5403 5404 return lifted; 5405 } 5406 5407 // 5408 // Merge two sets of user operators into one, they are mostly distinguish 5409 // except when they share base type and it contains an operator 5410 // CombineUserOperators(IList<MemberSpec> left, IList<MemberSpec> right)5411 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right) 5412 { 5413 var combined = new List<MemberSpec> (left.Count + right.Count); 5414 combined.AddRange (left); 5415 foreach (var r in right) { 5416 bool same = false; 5417 foreach (var l in left) { 5418 if (l.DeclaringType == r.DeclaringType) { 5419 same = true; 5420 break; 5421 } 5422 } 5423 5424 if (!same) 5425 combined.Add (r); 5426 } 5427 5428 return combined; 5429 } 5430 CheckOutOfRangeComparison(ResolveContext ec, Constant c, TypeSpec type)5431 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type) 5432 { 5433 if (c is IntegralConstant || c is CharConstant) { 5434 try { 5435 c.ConvertExplicitly (true, type); 5436 } catch (OverflowException) { 5437 ec.Report.Warning (652, 2, loc, 5438 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'", 5439 type.GetSignatureForError ()); 5440 } 5441 } 5442 } 5443 5444 /// <remarks> 5445 /// EmitBranchable is called from Statement.EmitBoolExpression in the 5446 /// context of a conditional bool expression. This function will return 5447 /// false if it is was possible to use EmitBranchable, or true if it was. 5448 /// 5449 /// The expression's code is generated, and we will generate a branch to `target' 5450 /// if the resulting expression value is equal to isTrue 5451 /// </remarks> EmitBranchable(EmitContext ec, Label target, bool on_true)5452 public override void EmitBranchable (EmitContext ec, Label target, bool on_true) 5453 { 5454 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) { 5455 left = left.EmitToField (ec); 5456 5457 if ((oper & Operator.LogicalMask) == 0) { 5458 right = right.EmitToField (ec); 5459 } 5460 } 5461 5462 // 5463 // This is more complicated than it looks, but its just to avoid 5464 // duplicated tests: basically, we allow ==, !=, >, <, >= and <= 5465 // but on top of that we want for == and != to use a special path 5466 // if we are comparing against null 5467 // 5468 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) { 5469 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true; 5470 5471 // 5472 // put the constant on the rhs, for simplicity 5473 // 5474 if (left is Constant) { 5475 Expression swap = right; 5476 right = left; 5477 left = swap; 5478 } 5479 5480 // 5481 // brtrue/brfalse works with native int only 5482 // 5483 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) { 5484 left.EmitBranchable (ec, target, my_on_true); 5485 return; 5486 } 5487 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) { 5488 // right is a boolean, and it's not 'false' => it is 'true' 5489 left.EmitBranchable (ec, target, !my_on_true); 5490 return; 5491 } 5492 5493 } else if (oper == Operator.LogicalAnd) { 5494 5495 if (on_true) { 5496 Label tests_end = ec.DefineLabel (); 5497 5498 left.EmitBranchable (ec, tests_end, false); 5499 right.EmitBranchable (ec, target, true); 5500 ec.MarkLabel (tests_end); 5501 } else { 5502 // 5503 // This optimizes code like this 5504 // if (true && i > 4) 5505 // 5506 if (!(left is Constant)) 5507 left.EmitBranchable (ec, target, false); 5508 5509 if (!(right is Constant)) 5510 right.EmitBranchable (ec, target, false); 5511 } 5512 5513 return; 5514 5515 } else if (oper == Operator.LogicalOr){ 5516 if (on_true) { 5517 left.EmitBranchable (ec, target, true); 5518 right.EmitBranchable (ec, target, true); 5519 5520 } else { 5521 Label tests_end = ec.DefineLabel (); 5522 left.EmitBranchable (ec, tests_end, true); 5523 right.EmitBranchable (ec, target, false); 5524 ec.MarkLabel (tests_end); 5525 } 5526 5527 return; 5528 5529 } else if ((oper & Operator.ComparisonMask) == 0) { 5530 base.EmitBranchable (ec, target, on_true); 5531 return; 5532 } 5533 5534 left.Emit (ec); 5535 right.Emit (ec); 5536 5537 TypeSpec t = left.Type; 5538 bool is_float = IsFloat (t); 5539 bool is_unsigned = is_float || IsUnsigned (t); 5540 5541 switch (oper){ 5542 case Operator.Equality: 5543 if (on_true) 5544 ec.Emit (OpCodes.Beq, target); 5545 else 5546 ec.Emit (OpCodes.Bne_Un, target); 5547 break; 5548 5549 case Operator.Inequality: 5550 if (on_true) 5551 ec.Emit (OpCodes.Bne_Un, target); 5552 else 5553 ec.Emit (OpCodes.Beq, target); 5554 break; 5555 5556 case Operator.LessThan: 5557 if (on_true) 5558 if (is_unsigned && !is_float) 5559 ec.Emit (OpCodes.Blt_Un, target); 5560 else 5561 ec.Emit (OpCodes.Blt, target); 5562 else 5563 if (is_unsigned) 5564 ec.Emit (OpCodes.Bge_Un, target); 5565 else 5566 ec.Emit (OpCodes.Bge, target); 5567 break; 5568 5569 case Operator.GreaterThan: 5570 if (on_true) 5571 if (is_unsigned && !is_float) 5572 ec.Emit (OpCodes.Bgt_Un, target); 5573 else 5574 ec.Emit (OpCodes.Bgt, target); 5575 else 5576 if (is_unsigned) 5577 ec.Emit (OpCodes.Ble_Un, target); 5578 else 5579 ec.Emit (OpCodes.Ble, target); 5580 break; 5581 5582 case Operator.LessThanOrEqual: 5583 if (on_true) 5584 if (is_unsigned && !is_float) 5585 ec.Emit (OpCodes.Ble_Un, target); 5586 else 5587 ec.Emit (OpCodes.Ble, target); 5588 else 5589 if (is_unsigned) 5590 ec.Emit (OpCodes.Bgt_Un, target); 5591 else 5592 ec.Emit (OpCodes.Bgt, target); 5593 break; 5594 5595 5596 case Operator.GreaterThanOrEqual: 5597 if (on_true) 5598 if (is_unsigned && !is_float) 5599 ec.Emit (OpCodes.Bge_Un, target); 5600 else 5601 ec.Emit (OpCodes.Bge, target); 5602 else 5603 if (is_unsigned) 5604 ec.Emit (OpCodes.Blt_Un, target); 5605 else 5606 ec.Emit (OpCodes.Blt, target); 5607 break; 5608 default: 5609 throw new InternalErrorException (oper.ToString ()); 5610 } 5611 } 5612 Emit(EmitContext ec)5613 public override void Emit (EmitContext ec) 5614 { 5615 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) { 5616 left = left.EmitToField (ec); 5617 5618 if ((oper & Operator.LogicalMask) == 0) { 5619 right = right.EmitToField (ec); 5620 } 5621 } 5622 5623 // 5624 // Handle short-circuit operators differently 5625 // than the rest 5626 // 5627 if ((oper & Operator.LogicalMask) != 0) { 5628 Label load_result = ec.DefineLabel (); 5629 Label end = ec.DefineLabel (); 5630 5631 bool is_or = oper == Operator.LogicalOr; 5632 left.EmitBranchable (ec, load_result, is_or); 5633 right.Emit (ec); 5634 ec.Emit (OpCodes.Br_S, end); 5635 5636 ec.MarkLabel (load_result); 5637 ec.EmitInt (is_or ? 1 : 0); 5638 ec.MarkLabel (end); 5639 return; 5640 } 5641 5642 // 5643 // Optimize zero-based operations which cannot be optimized at expression level 5644 // 5645 if (oper == Operator.Subtraction) { 5646 var lc = left as IntegralConstant; 5647 if (lc != null && lc.IsDefaultValue) { 5648 right.Emit (ec); 5649 ec.Emit (OpCodes.Neg); 5650 return; 5651 } 5652 } 5653 5654 EmitOperator (ec, left, right); 5655 } 5656 EmitOperator(EmitContext ec, Expression left, Expression right)5657 public void EmitOperator (EmitContext ec, Expression left, Expression right) 5658 { 5659 left.Emit (ec); 5660 right.Emit (ec); 5661 5662 EmitOperatorOpcode (ec, oper, left.Type, right); 5663 5664 // 5665 // Emit result enumerable conversion this way because it's quite complicated get it 5666 // to resolved tree because expression tree cannot see it. 5667 // 5668 if (enum_conversion != 0) 5669 ConvCast.Emit (ec, enum_conversion); 5670 } 5671 EmitSideEffect(EmitContext ec)5672 public override void EmitSideEffect (EmitContext ec) 5673 { 5674 if ((oper & Operator.LogicalMask) != 0 || 5675 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) { 5676 base.EmitSideEffect (ec); 5677 } else { 5678 left.EmitSideEffect (ec); 5679 right.EmitSideEffect (ec); 5680 } 5681 } 5682 EmitToField(EmitContext ec)5683 public override Expression EmitToField (EmitContext ec) 5684 { 5685 if ((oper & Operator.LogicalMask) == 0) { 5686 var await_expr = left as Await; 5687 if (await_expr != null && right.IsSideEffectFree) { 5688 await_expr.Statement.EmitPrologue (ec); 5689 left = await_expr.Statement.GetResultExpression (ec); 5690 return this; 5691 } 5692 5693 await_expr = right as Await; 5694 if (await_expr != null && left.IsSideEffectFree) { 5695 await_expr.Statement.EmitPrologue (ec); 5696 right = await_expr.Statement.GetResultExpression (ec); 5697 return this; 5698 } 5699 } 5700 5701 return base.EmitToField (ec); 5702 } 5703 CloneTo(CloneContext clonectx, Expression t)5704 protected override void CloneTo (CloneContext clonectx, Expression t) 5705 { 5706 Binary target = (Binary) t; 5707 5708 target.left = left.Clone (clonectx); 5709 target.right = right.Clone (clonectx); 5710 } 5711 CreateCallSiteBinder(ResolveContext ec, Arguments args)5712 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args) 5713 { 5714 Arguments binder_args = new Arguments (4); 5715 5716 MemberAccess sle = new MemberAccess (new MemberAccess ( 5717 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc); 5718 5719 CSharpBinderFlags flags = 0; 5720 if (ec.HasSet (ResolveContext.Options.CheckedScope)) 5721 flags = CSharpBinderFlags.CheckedContext; 5722 5723 if ((oper & Operator.LogicalMask) != 0) 5724 flags |= CSharpBinderFlags.BinaryOperationLogical; 5725 5726 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ()))); 5727 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc))); 5728 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc))); 5729 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc))); 5730 5731 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args); 5732 } 5733 CreateExpressionTree(ResolveContext ec)5734 public override Expression CreateExpressionTree (ResolveContext ec) 5735 { 5736 return CreateExpressionTree (ec, null); 5737 } 5738 CreateExpressionTree(ResolveContext ec, Expression method)5739 public Expression CreateExpressionTree (ResolveContext ec, Expression method) 5740 { 5741 string method_name; 5742 bool lift_arg = false; 5743 5744 switch (oper) { 5745 case Operator.Addition: 5746 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type)) 5747 method_name = "AddChecked"; 5748 else 5749 method_name = "Add"; 5750 break; 5751 case Operator.BitwiseAnd: 5752 method_name = "And"; 5753 break; 5754 case Operator.BitwiseOr: 5755 method_name = "Or"; 5756 break; 5757 case Operator.Division: 5758 method_name = "Divide"; 5759 break; 5760 case Operator.Equality: 5761 method_name = "Equal"; 5762 lift_arg = true; 5763 break; 5764 case Operator.ExclusiveOr: 5765 method_name = "ExclusiveOr"; 5766 break; 5767 case Operator.GreaterThan: 5768 method_name = "GreaterThan"; 5769 lift_arg = true; 5770 break; 5771 case Operator.GreaterThanOrEqual: 5772 method_name = "GreaterThanOrEqual"; 5773 lift_arg = true; 5774 break; 5775 case Operator.Inequality: 5776 method_name = "NotEqual"; 5777 lift_arg = true; 5778 break; 5779 case Operator.LeftShift: 5780 method_name = "LeftShift"; 5781 break; 5782 case Operator.LessThan: 5783 method_name = "LessThan"; 5784 lift_arg = true; 5785 break; 5786 case Operator.LessThanOrEqual: 5787 method_name = "LessThanOrEqual"; 5788 lift_arg = true; 5789 break; 5790 case Operator.LogicalAnd: 5791 method_name = "AndAlso"; 5792 break; 5793 case Operator.LogicalOr: 5794 method_name = "OrElse"; 5795 break; 5796 case Operator.Modulus: 5797 method_name = "Modulo"; 5798 break; 5799 case Operator.Multiply: 5800 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type)) 5801 method_name = "MultiplyChecked"; 5802 else 5803 method_name = "Multiply"; 5804 break; 5805 case Operator.RightShift: 5806 method_name = "RightShift"; 5807 break; 5808 case Operator.Subtraction: 5809 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type)) 5810 method_name = "SubtractChecked"; 5811 else 5812 method_name = "Subtract"; 5813 break; 5814 5815 default: 5816 throw new InternalErrorException ("Unknown expression tree binary operator " + oper); 5817 } 5818 5819 Arguments args = new Arguments (2); 5820 args.Add (new Argument (left.CreateExpressionTree (ec))); 5821 args.Add (new Argument (right.CreateExpressionTree (ec))); 5822 if (method != null) { 5823 if (lift_arg) 5824 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc))); 5825 5826 args.Add (new Argument (method)); 5827 } 5828 5829 return CreateExpressionFactoryCall (ec, method_name, args); 5830 } 5831 Accept(StructuralVisitor visitor)5832 public override object Accept (StructuralVisitor visitor) 5833 { 5834 return visitor.Visit (this); 5835 } 5836 5837 } 5838 5839 // 5840 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string 5841 // b, c, d... may be strings or objects. 5842 // 5843 public class StringConcat : Expression 5844 { 5845 Arguments arguments; 5846 StringConcat(Location loc)5847 StringConcat (Location loc) 5848 { 5849 this.loc = loc; 5850 arguments = new Arguments (2); 5851 } 5852 ContainsEmitWithAwait()5853 public override bool ContainsEmitWithAwait () 5854 { 5855 return arguments.ContainsEmitWithAwait (); 5856 } 5857 Create(ResolveContext rc, Expression left, Expression right, Location loc)5858 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc) 5859 { 5860 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved) 5861 throw new ArgumentException (); 5862 5863 var s = new StringConcat (loc); 5864 s.type = rc.BuiltinTypes.String; 5865 s.eclass = ExprClass.Value; 5866 5867 s.Append (rc, left); 5868 s.Append (rc, right); 5869 return s; 5870 } 5871 CreateExpressionTree(ResolveContext ec)5872 public override Expression CreateExpressionTree (ResolveContext ec) 5873 { 5874 Argument arg = arguments [0]; 5875 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1); 5876 } 5877 5878 // 5879 // Creates nested calls tree from an array of arguments used for IL emit 5880 // CreateExpressionAddCall(ResolveContext ec, Argument left, Expression left_etree, int pos)5881 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos) 5882 { 5883 Arguments concat_args = new Arguments (2); 5884 Arguments add_args = new Arguments (3); 5885 5886 concat_args.Add (left); 5887 add_args.Add (new Argument (left_etree)); 5888 5889 concat_args.Add (arguments [pos]); 5890 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec))); 5891 5892 var methods = GetConcatMethodCandidates (); 5893 if (methods == null) 5894 return null; 5895 5896 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc); 5897 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args); 5898 if (method == null) 5899 return null; 5900 5901 add_args.Add (new Argument (new TypeOfMethod (method, loc))); 5902 5903 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args); 5904 if (++pos == arguments.Count) 5905 return expr; 5906 5907 left = new Argument (new EmptyExpression (method.ReturnType)); 5908 return CreateExpressionAddCall (ec, left, expr, pos); 5909 } 5910 DoResolve(ResolveContext ec)5911 protected override Expression DoResolve (ResolveContext ec) 5912 { 5913 return this; 5914 } 5915 Append(ResolveContext rc, Expression operand)5916 void Append (ResolveContext rc, Expression operand) 5917 { 5918 // 5919 // Constant folding 5920 // 5921 StringConstant sc = operand as StringConstant; 5922 if (sc != null) { 5923 if (arguments.Count != 0) { 5924 Argument last_argument = arguments [arguments.Count - 1]; 5925 StringConstant last_expr_constant = last_argument.Expr as StringConstant; 5926 if (last_expr_constant != null) { 5927 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location); 5928 return; 5929 } 5930 } 5931 } else { 5932 // 5933 // Multiple (3+) concatenation are resolved as multiple StringConcat instances 5934 // 5935 StringConcat concat_oper = operand as StringConcat; 5936 if (concat_oper != null) { 5937 arguments.AddRange (concat_oper.arguments); 5938 return; 5939 } 5940 } 5941 5942 arguments.Add (new Argument (operand)); 5943 } 5944 GetConcatMethodCandidates()5945 IList<MemberSpec> GetConcatMethodCandidates () 5946 { 5947 return MemberCache.FindMembers (type, "Concat", true); 5948 } 5949 Emit(EmitContext ec)5950 public override void Emit (EmitContext ec) 5951 { 5952 // Optimize by removing any extra null arguments, they are no-op 5953 for (int i = 0; i < arguments.Count; ++i) { 5954 if (arguments[i].Expr is NullConstant) 5955 arguments.RemoveAt (i--); 5956 } 5957 5958 var members = GetConcatMethodCandidates (); 5959 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc); 5960 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments); 5961 if (method != null) { 5962 var call = new CallEmitter (); 5963 call.EmitPredefined (ec, method, arguments, false); 5964 } 5965 } 5966 FlowAnalysis(FlowAnalysisContext fc)5967 public override void FlowAnalysis (FlowAnalysisContext fc) 5968 { 5969 arguments.FlowAnalysis (fc); 5970 } 5971 MakeExpression(BuilderContext ctx)5972 public override SLE.Expression MakeExpression (BuilderContext ctx) 5973 { 5974 if (arguments.Count != 2) 5975 throw new NotImplementedException ("arguments.Count != 2"); 5976 5977 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) }); 5978 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat); 5979 } 5980 } 5981 5982 // 5983 // User-defined conditional logical operator 5984 // 5985 public class ConditionalLogicalOperator : UserOperatorCall 5986 { 5987 readonly bool is_and; 5988 Expression oper_expr; 5989 ConditionalLogicalOperator(MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)5990 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc) 5991 : base (oper, arguments, expr_tree, loc) 5992 { 5993 this.is_and = is_and; 5994 eclass = ExprClass.Unresolved; 5995 } 5996 DoResolve(ResolveContext ec)5997 protected override Expression DoResolve (ResolveContext ec) 5998 { 5999 AParametersCollection pd = oper.Parameters; 6000 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) { 6001 ec.Report.Error (217, loc, 6002 "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", 6003 oper.GetSignatureForError ()); 6004 return null; 6005 } 6006 6007 Expression left_dup = new EmptyExpression (type); 6008 Expression op_true = GetOperatorTrue (ec, left_dup, loc); 6009 Expression op_false = GetOperatorFalse (ec, left_dup, loc); 6010 if (op_true == null || op_false == null) { 6011 ec.Report.Error (218, loc, 6012 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator", 6013 type.GetSignatureForError (), oper.GetSignatureForError ()); 6014 return null; 6015 } 6016 6017 oper_expr = is_and ? op_false : op_true; 6018 eclass = ExprClass.Value; 6019 return this; 6020 } 6021 Emit(EmitContext ec)6022 public override void Emit (EmitContext ec) 6023 { 6024 Label end_target = ec.DefineLabel (); 6025 6026 // 6027 // Emit and duplicate left argument 6028 // 6029 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait (); 6030 if (right_contains_await) { 6031 arguments[0] = arguments[0].EmitToField (ec, false); 6032 arguments[0].Expr.Emit (ec); 6033 } else { 6034 arguments[0].Expr.Emit (ec); 6035 ec.Emit (OpCodes.Dup); 6036 arguments.RemoveAt (0); 6037 } 6038 6039 oper_expr.EmitBranchable (ec, end_target, true); 6040 6041 base.Emit (ec); 6042 6043 if (right_contains_await) { 6044 // 6045 // Special handling when right expression contains await and left argument 6046 // could not be left on stack before logical branch 6047 // 6048 Label skip_left_load = ec.DefineLabel (); 6049 ec.Emit (OpCodes.Br_S, skip_left_load); 6050 ec.MarkLabel (end_target); 6051 arguments[0].Expr.Emit (ec); 6052 ec.MarkLabel (skip_left_load); 6053 } else { 6054 ec.MarkLabel (end_target); 6055 } 6056 } 6057 } 6058 6059 public class PointerArithmetic : Expression { 6060 Expression left, right; 6061 readonly Binary.Operator op; 6062 6063 // 6064 // We assume that `l' is always a pointer 6065 // PointerArithmetic(Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)6066 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc) 6067 { 6068 type = t; 6069 this.loc = loc; 6070 left = l; 6071 right = r; 6072 this.op = op; 6073 } 6074 ContainsEmitWithAwait()6075 public override bool ContainsEmitWithAwait () 6076 { 6077 throw new NotImplementedException (); 6078 } 6079 CreateExpressionTree(ResolveContext ec)6080 public override Expression CreateExpressionTree (ResolveContext ec) 6081 { 6082 Error_PointerInsideExpressionTree (ec); 6083 return null; 6084 } 6085 DoResolve(ResolveContext ec)6086 protected override Expression DoResolve (ResolveContext ec) 6087 { 6088 eclass = ExprClass.Variable; 6089 6090 var pc = left.Type as PointerContainer; 6091 if (pc != null && pc.Element.Kind == MemberKind.Void) { 6092 Error_VoidPointerOperation (ec); 6093 return null; 6094 } 6095 6096 return this; 6097 } 6098 Emit(EmitContext ec)6099 public override void Emit (EmitContext ec) 6100 { 6101 TypeSpec op_type = left.Type; 6102 6103 // It must be either array or fixed buffer 6104 TypeSpec element; 6105 if (TypeManager.HasElementType (op_type)) { 6106 element = TypeManager.GetElementType (op_type); 6107 } else { 6108 FieldExpr fe = left as FieldExpr; 6109 if (fe != null) 6110 element = ((FixedFieldSpec) (fe.Spec)).ElementType; 6111 else 6112 element = op_type; 6113 } 6114 6115 int size = BuiltinTypeSpec.GetSize(element); 6116 TypeSpec rtype = right.Type; 6117 6118 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){ 6119 // 6120 // handle (pointer - pointer) 6121 // 6122 left.Emit (ec); 6123 right.Emit (ec); 6124 ec.Emit (OpCodes.Sub); 6125 6126 if (size != 1){ 6127 if (size == 0) 6128 ec.Emit (OpCodes.Sizeof, element); 6129 else 6130 ec.EmitInt (size); 6131 ec.Emit (OpCodes.Div); 6132 } 6133 ec.Emit (OpCodes.Conv_I8); 6134 } else { 6135 // 6136 // handle + and - on (pointer op int) 6137 // 6138 Constant left_const = left as Constant; 6139 if (left_const != null) { 6140 // 6141 // Optimize ((T*)null) pointer operations 6142 // 6143 if (left_const.IsDefaultValue) { 6144 left = EmptyExpression.Null; 6145 } else { 6146 left_const = null; 6147 } 6148 } 6149 6150 left.Emit (ec); 6151 6152 var right_const = right as Constant; 6153 if (right_const != null) { 6154 // 6155 // Optimize 0-based arithmetic 6156 // 6157 if (right_const.IsDefaultValue) 6158 return; 6159 6160 if (size != 0) 6161 right = new IntConstant (ec.BuiltinTypes, size, right.Location); 6162 else 6163 right = new SizeOf (new TypeExpression (element, right.Location), right.Location); 6164 6165 // TODO: Should be the checks resolve context sensitive? 6166 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope); 6167 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc); 6168 if (right == null) 6169 return; 6170 } 6171 6172 right.Emit (ec); 6173 if (right_const == null) { 6174 switch (rtype.BuiltinType) { 6175 case BuiltinTypeSpec.Type.SByte: 6176 case BuiltinTypeSpec.Type.Byte: 6177 case BuiltinTypeSpec.Type.Short: 6178 case BuiltinTypeSpec.Type.UShort: 6179 case BuiltinTypeSpec.Type.Int: 6180 ec.Emit (OpCodes.Conv_I); 6181 break; 6182 case BuiltinTypeSpec.Type.UInt: 6183 ec.Emit (OpCodes.Conv_U); 6184 break; 6185 } 6186 } 6187 6188 if (right_const == null && size != 1){ 6189 if (size == 0) 6190 ec.Emit (OpCodes.Sizeof, element); 6191 else 6192 ec.EmitInt (size); 6193 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong) 6194 ec.Emit (OpCodes.Conv_I8); 6195 6196 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right); 6197 } 6198 6199 if (left_const == null) { 6200 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long) 6201 ec.Emit (OpCodes.Conv_I); 6202 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong) 6203 ec.Emit (OpCodes.Conv_U); 6204 6205 Binary.EmitOperatorOpcode (ec, op, op_type, right); 6206 } 6207 } 6208 } 6209 } 6210 6211 // 6212 // A boolean-expression is an expression that yields a result 6213 // of type bool 6214 // 6215 public class BooleanExpression : ShimExpression 6216 { BooleanExpression(Expression expr)6217 public BooleanExpression (Expression expr) 6218 : base (expr) 6219 { 6220 this.loc = expr.Location; 6221 } 6222 CreateExpressionTree(ResolveContext ec)6223 public override Expression CreateExpressionTree (ResolveContext ec) 6224 { 6225 // TODO: We should emit IsTrue (v4) instead of direct user operator 6226 // call but that would break csc compatibility 6227 return base.CreateExpressionTree (ec); 6228 } 6229 DoResolve(ResolveContext ec)6230 protected override Expression DoResolve (ResolveContext ec) 6231 { 6232 // A boolean-expression is required to be of a type 6233 // that can be implicitly converted to bool or of 6234 // a type that implements operator true 6235 6236 expr = expr.Resolve (ec); 6237 if (expr == null) 6238 return null; 6239 6240 Assign ass = expr as Assign; 6241 if (ass != null && ass.Source is Constant) { 6242 ec.Report.Warning (665, 3, loc, 6243 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?"); 6244 } 6245 6246 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) 6247 return expr; 6248 6249 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 6250 Arguments args = new Arguments (1); 6251 args.Add (new Argument (expr)); 6252 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec); 6253 } 6254 6255 type = ec.BuiltinTypes.Bool; 6256 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc); 6257 if (converted != null) 6258 return converted; 6259 6260 // 6261 // If no implicit conversion to bool exists, try using `operator true' 6262 // 6263 converted = GetOperatorTrue (ec, expr, loc); 6264 if (converted == null) { 6265 expr.Error_ValueCannotBeConverted (ec, type, false); 6266 return null; 6267 } 6268 6269 return converted; 6270 } 6271 Accept(StructuralVisitor visitor)6272 public override object Accept (StructuralVisitor visitor) 6273 { 6274 return visitor.Visit (this); 6275 } 6276 } 6277 6278 public class BooleanExpressionFalse : Unary 6279 { BooleanExpressionFalse(Expression expr)6280 public BooleanExpressionFalse (Expression expr) 6281 : base (Operator.LogicalNot, expr, expr.Location) 6282 { 6283 } 6284 ResolveOperator(ResolveContext ec, Expression expr)6285 protected override Expression ResolveOperator (ResolveContext ec, Expression expr) 6286 { 6287 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr); 6288 } 6289 } 6290 6291 /// <summary> 6292 /// Implements the ternary conditional operator (?:) 6293 /// </summary> 6294 public class Conditional : Expression { 6295 Expression expr, true_expr, false_expr; 6296 Conditional(Expression expr, Expression true_expr, Expression false_expr, Location loc)6297 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc) 6298 { 6299 this.expr = expr; 6300 this.true_expr = true_expr; 6301 this.false_expr = false_expr; 6302 this.loc = loc; 6303 } 6304 6305 #region Properties 6306 6307 public Expression Expr { 6308 get { 6309 return expr; 6310 } 6311 } 6312 6313 public Expression TrueExpr { 6314 get { 6315 return true_expr; 6316 } 6317 } 6318 6319 public Expression FalseExpr { 6320 get { 6321 return false_expr; 6322 } 6323 } 6324 6325 #endregion 6326 ContainsEmitWithAwait()6327 public override bool ContainsEmitWithAwait () 6328 { 6329 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait (); 6330 } 6331 CreateExpressionTree(ResolveContext ec)6332 public override Expression CreateExpressionTree (ResolveContext ec) 6333 { 6334 Arguments args = new Arguments (3); 6335 args.Add (new Argument (expr.CreateExpressionTree (ec))); 6336 args.Add (new Argument (true_expr.CreateExpressionTree (ec))); 6337 args.Add (new Argument (false_expr.CreateExpressionTree (ec))); 6338 return CreateExpressionFactoryCall (ec, "Condition", args); 6339 } 6340 DoResolve(ResolveContext ec)6341 protected override Expression DoResolve (ResolveContext ec) 6342 { 6343 expr = expr.Resolve (ec); 6344 true_expr = true_expr.Resolve (ec); 6345 false_expr = false_expr.Resolve (ec); 6346 6347 if (true_expr == null || false_expr == null || expr == null) 6348 return null; 6349 6350 eclass = ExprClass.Value; 6351 TypeSpec true_type = true_expr.Type; 6352 TypeSpec false_type = false_expr.Type; 6353 type = true_type; 6354 6355 // 6356 // First, if an implicit conversion exists from true_expr 6357 // to false_expr, then the result type is of type false_expr.Type 6358 // 6359 if (!TypeSpecComparer.IsEqual (true_type, false_type)) { 6360 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc); 6361 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) { 6362 // 6363 // Check if both can convert implicitly to each other's type 6364 // 6365 type = false_type; 6366 6367 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) { 6368 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc); 6369 // 6370 // LAMESPEC: There seems to be hardcoded promotition to int type when 6371 // both sides are numeric constants and one side is int constant and 6372 // other side is numeric constant convertible to int. 6373 // 6374 // var res = condition ? (short)1 : 1; 6375 // 6376 // Type of res is int even if according to the spec the conversion is 6377 // ambiguous because 1 literal can be converted to short. 6378 // 6379 if (conv_false_expr != null) { 6380 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) { 6381 type = true_type; 6382 conv_false_expr = null; 6383 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) { 6384 conv_false_expr = null; 6385 } 6386 } 6387 6388 if (conv_false_expr != null) { 6389 ec.Report.Error (172, true_expr.Location, 6390 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other", 6391 true_type.GetSignatureForError (), false_type.GetSignatureForError ()); 6392 } 6393 } 6394 6395 true_expr = conv; 6396 if (true_expr.Type != type) 6397 true_expr = EmptyCast.Create (true_expr, type); 6398 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) { 6399 false_expr = conv; 6400 } else { 6401 if (false_type != InternalType.ErrorType) { 6402 ec.Report.Error (173, true_expr.Location, 6403 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'", 6404 true_type.GetSignatureForError (), false_type.GetSignatureForError ()); 6405 } 6406 return null; 6407 } 6408 } 6409 6410 Constant c = expr as Constant; 6411 if (c != null) { 6412 bool is_false = c.IsDefaultValue; 6413 6414 // 6415 // Don't issue the warning for constant expressions 6416 // 6417 if (!(is_false ? true_expr is Constant : false_expr is Constant)) { 6418 // CSC: Missing warning 6419 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location); 6420 } 6421 6422 return ReducedExpression.Create ( 6423 is_false ? false_expr : true_expr, this, 6424 false_expr is Constant && true_expr is Constant).Resolve (ec); 6425 } 6426 6427 return this; 6428 } 6429 Emit(EmitContext ec)6430 public override void Emit (EmitContext ec) 6431 { 6432 Label false_target = ec.DefineLabel (); 6433 Label end_target = ec.DefineLabel (); 6434 6435 expr.EmitBranchable (ec, false_target, false); 6436 true_expr.Emit (ec); 6437 6438 // 6439 // Verifier doesn't support interface merging. When there are two types on 6440 // the stack without common type hint and the common type is an interface. 6441 // Use temporary local to give verifier hint on what type to unify the stack 6442 // 6443 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) { 6444 var temp = ec.GetTemporaryLocal (type); 6445 ec.Emit (OpCodes.Stloc, temp); 6446 ec.Emit (OpCodes.Ldloc, temp); 6447 ec.FreeTemporaryLocal (temp, type); 6448 } 6449 6450 ec.Emit (OpCodes.Br, end_target); 6451 ec.MarkLabel (false_target); 6452 false_expr.Emit (ec); 6453 ec.MarkLabel (end_target); 6454 } 6455 FlowAnalysis(FlowAnalysisContext fc)6456 public override void FlowAnalysis (FlowAnalysisContext fc) 6457 { 6458 expr.FlowAnalysisConditional (fc); 6459 var expr_true = fc.DefiniteAssignmentOnTrue; 6460 var expr_false = fc.DefiniteAssignmentOnFalse; 6461 6462 fc.BranchDefiniteAssignment (expr_true); 6463 true_expr.FlowAnalysis (fc); 6464 var true_fc = fc.DefiniteAssignment; 6465 6466 fc.BranchDefiniteAssignment (expr_false); 6467 false_expr.FlowAnalysis (fc); 6468 6469 fc.DefiniteAssignment &= true_fc; 6470 } 6471 FlowAnalysisConditional(FlowAnalysisContext fc)6472 public override void FlowAnalysisConditional (FlowAnalysisContext fc) 6473 { 6474 expr.FlowAnalysisConditional (fc); 6475 var expr_true = fc.DefiniteAssignmentOnTrue; 6476 var expr_false = fc.DefiniteAssignmentOnFalse; 6477 6478 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true); 6479 true_expr.FlowAnalysisConditional (fc); 6480 var true_fc = fc.DefiniteAssignment; 6481 var true_da_true = fc.DefiniteAssignmentOnTrue; 6482 var true_da_false = fc.DefiniteAssignmentOnFalse; 6483 6484 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false); 6485 false_expr.FlowAnalysisConditional (fc); 6486 6487 fc.DefiniteAssignment &= true_fc; 6488 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue; 6489 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse; 6490 } 6491 CloneTo(CloneContext clonectx, Expression t)6492 protected override void CloneTo (CloneContext clonectx, Expression t) 6493 { 6494 Conditional target = (Conditional) t; 6495 6496 target.expr = expr.Clone (clonectx); 6497 target.true_expr = true_expr.Clone (clonectx); 6498 target.false_expr = false_expr.Clone (clonectx); 6499 } 6500 } 6501 6502 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference 6503 { 6504 LocalTemporary temp; 6505 6506 #region Abstract GetHoistedVariable(AnonymousExpression ae)6507 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae); SetHasAddressTaken()6508 public abstract void SetHasAddressTaken (); 6509 6510 public abstract bool IsLockedByStatement { get; set; } 6511 6512 public abstract bool IsFixed { get; } 6513 public abstract bool IsRef { get; } 6514 public abstract string Name { get; } 6515 6516 // 6517 // Variable IL data, it has to be protected to encapsulate hoisted variables 6518 // 6519 protected abstract ILocalVariable Variable { get; } 6520 6521 // 6522 // Variable flow-analysis data 6523 // 6524 public abstract VariableInfo VariableInfo { get; } 6525 #endregion 6526 AddressOf(EmitContext ec, AddressOp mode)6527 public virtual void AddressOf (EmitContext ec, AddressOp mode) 6528 { 6529 HoistedVariable hv = GetHoistedVariable (ec); 6530 if (hv != null) { 6531 hv.AddressOf (ec, mode); 6532 return; 6533 } 6534 6535 Variable.EmitAddressOf (ec); 6536 } 6537 ContainsEmitWithAwait()6538 public override bool ContainsEmitWithAwait () 6539 { 6540 return false; 6541 } 6542 CreateExpressionTree(ResolveContext ec)6543 public override Expression CreateExpressionTree (ResolveContext ec) 6544 { 6545 HoistedVariable hv = GetHoistedVariable (ec); 6546 if (hv != null) 6547 return hv.CreateExpressionTree (); 6548 6549 Arguments arg = new Arguments (1); 6550 arg.Add (new Argument (this)); 6551 return CreateExpressionFactoryCall (ec, "Constant", arg); 6552 } 6553 DoResolveLValue(ResolveContext rc, Expression right_side)6554 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) 6555 { 6556 if (IsLockedByStatement) { 6557 rc.Report.Warning (728, 2, loc, 6558 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement", 6559 Name); 6560 } 6561 6562 return this; 6563 } 6564 Emit(EmitContext ec)6565 public override void Emit (EmitContext ec) 6566 { 6567 Emit (ec, false); 6568 } 6569 EmitSideEffect(EmitContext ec)6570 public override void EmitSideEffect (EmitContext ec) 6571 { 6572 // do nothing 6573 } 6574 6575 // 6576 // This method is used by parameters that are references, that are 6577 // being passed as references: we only want to pass the pointer (that 6578 // is already stored in the parameter, not the address of the pointer, 6579 // and not the value of the variable). 6580 // EmitLoad(EmitContext ec)6581 public void EmitLoad (EmitContext ec) 6582 { 6583 Variable.Emit (ec); 6584 } 6585 Emit(EmitContext ec, bool leave_copy)6586 public void Emit (EmitContext ec, bool leave_copy) 6587 { 6588 HoistedVariable hv = GetHoistedVariable (ec); 6589 if (hv != null) { 6590 hv.Emit (ec, leave_copy); 6591 return; 6592 } 6593 6594 EmitLoad (ec); 6595 6596 if (IsRef) { 6597 // 6598 // If we are a reference, we loaded on the stack a pointer 6599 // Now lets load the real value 6600 // 6601 ec.EmitLoadFromPtr (type); 6602 } 6603 6604 if (leave_copy) { 6605 ec.Emit (OpCodes.Dup); 6606 6607 if (IsRef) { 6608 temp = new LocalTemporary (Type); 6609 temp.Store (ec); 6610 } 6611 } 6612 } 6613 EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)6614 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, 6615 bool prepare_for_load) 6616 { 6617 HoistedVariable hv = GetHoistedVariable (ec); 6618 if (hv != null) { 6619 hv.EmitAssign (ec, source, leave_copy, prepare_for_load); 6620 return; 6621 } 6622 6623 bool dereference = IsRef && !(source is ReferenceExpression); 6624 New n_source = source as New; 6625 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) { 6626 if (!n_source.Emit (ec, this)) { 6627 if (leave_copy) { 6628 EmitLoad (ec); 6629 if (dereference) 6630 ec.EmitLoadFromPtr (type); 6631 } 6632 return; 6633 } 6634 } else { 6635 if (dereference) 6636 EmitLoad (ec); 6637 6638 source.Emit (ec); 6639 } 6640 6641 if (leave_copy) { 6642 ec.Emit (OpCodes.Dup); 6643 if (dereference) { 6644 temp = new LocalTemporary (Type); 6645 temp.Store (ec); 6646 } 6647 } 6648 6649 if (dereference) 6650 ec.EmitStoreFromPtr (type); 6651 else 6652 Variable.EmitAssign (ec); 6653 6654 if (temp != null) { 6655 temp.Emit (ec); 6656 temp.Release (ec); 6657 } 6658 } 6659 EmitToField(EmitContext ec)6660 public override Expression EmitToField (EmitContext ec) 6661 { 6662 HoistedVariable hv = GetHoistedVariable (ec); 6663 if (hv != null) { 6664 return hv.EmitToField (ec); 6665 } 6666 6667 return base.EmitToField (ec); 6668 } 6669 GetHoistedVariable(ResolveContext rc)6670 public HoistedVariable GetHoistedVariable (ResolveContext rc) 6671 { 6672 return GetHoistedVariable (rc.CurrentAnonymousMethod); 6673 } 6674 GetHoistedVariable(EmitContext ec)6675 public HoistedVariable GetHoistedVariable (EmitContext ec) 6676 { 6677 return GetHoistedVariable (ec.CurrentAnonymousMethod); 6678 } 6679 GetSignatureForError()6680 public override string GetSignatureForError () 6681 { 6682 return Name; 6683 } 6684 6685 public bool IsHoisted { 6686 get { return GetHoistedVariable ((AnonymousExpression) null) != null; } 6687 } 6688 } 6689 6690 // 6691 // Resolved reference to a local variable 6692 // 6693 public class LocalVariableReference : VariableReference 6694 { 6695 public LocalVariable local_info; 6696 LocalVariableReference(LocalVariable li, Location l)6697 public LocalVariableReference (LocalVariable li, Location l) 6698 { 6699 this.local_info = li; 6700 loc = l; 6701 } 6702 6703 public override VariableInfo VariableInfo { 6704 get { return local_info.VariableInfo; } 6705 } 6706 GetHoistedVariable(AnonymousExpression ae)6707 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae) 6708 { 6709 return local_info.HoistedVariant; 6710 } 6711 6712 #region Properties 6713 6714 // 6715 // A local variable is always fixed 6716 // 6717 public override bool IsFixed { 6718 get { 6719 return true; 6720 } 6721 } 6722 6723 public override bool IsLockedByStatement { 6724 get { 6725 return local_info.IsLocked; 6726 } 6727 set { 6728 local_info.IsLocked = value; 6729 } 6730 } 6731 6732 public override bool IsRef { 6733 get { return local_info.IsByRef; } 6734 } 6735 6736 public override string Name { 6737 get { return local_info.Name; } 6738 } 6739 6740 #endregion 6741 FlowAnalysis(FlowAnalysisContext fc)6742 public override void FlowAnalysis (FlowAnalysisContext fc) 6743 { 6744 VariableInfo variable_info = VariableInfo; 6745 if (variable_info == null) 6746 return; 6747 6748 if (fc.IsDefinitelyAssigned (variable_info)) 6749 return; 6750 6751 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name); 6752 variable_info.SetAssigned (fc.DefiniteAssignment, true); 6753 } 6754 SetHasAddressTaken()6755 public override void SetHasAddressTaken () 6756 { 6757 local_info.SetHasAddressTaken (); 6758 } 6759 DoResolveBase(ResolveContext ec)6760 void DoResolveBase (ResolveContext ec) 6761 { 6762 eclass = ExprClass.Variable; 6763 type = local_info.Type; 6764 6765 // 6766 // If we are referencing a variable from the external block 6767 // flag it for capturing 6768 // 6769 if (ec.MustCaptureVariable (local_info)) { 6770 if (local_info.AddressTaken) { 6771 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc); 6772 } else if (local_info.IsFixed) { 6773 ec.Report.Error (1764, loc, 6774 "Cannot use fixed variable `{0}' inside an anonymous method, lambda expression or query expression", 6775 GetSignatureForError ()); 6776 } else if (local_info.IsByRef || local_info.Type.IsByRefLike) { 6777 if (ec.CurrentAnonymousMethod is StateMachineInitializer) { 6778 // It's reported later as 4012/4013 6779 } else { 6780 ec.Report.Error (8175, loc, 6781 "Cannot use by-reference variable `{0}' inside an anonymous method, lambda expression, or query expression", 6782 GetSignatureForError ()); 6783 } 6784 } 6785 6786 if (ec.IsVariableCapturingRequired) { 6787 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec); 6788 storey.CaptureLocalVariable (ec, local_info); 6789 } 6790 } 6791 } 6792 DoResolve(ResolveContext ec)6793 protected override Expression DoResolve (ResolveContext ec) 6794 { 6795 local_info.SetIsUsed (); 6796 6797 DoResolveBase (ec); 6798 6799 if (local_info.Type == InternalType.VarOutType) { 6800 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'", 6801 GetSignatureForError ()); 6802 6803 type = InternalType.ErrorType; 6804 } 6805 6806 return this; 6807 } 6808 DoResolveLValue(ResolveContext ec, Expression rhs)6809 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs) 6810 { 6811 // 6812 // Don't be too pedantic when variable is used as out param or for some broken code 6813 // which uses property/indexer access to run some initialization 6814 // 6815 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess) 6816 local_info.SetIsUsed (); 6817 6818 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) { 6819 if (local_info.IsByRef) { 6820 // OK because it cannot be reassigned 6821 } else if (rhs == EmptyExpression.LValueMemberAccess) { 6822 // CS1654 already reported 6823 } else { 6824 int code; 6825 string msg; 6826 if (rhs == EmptyExpression.OutAccess) { 6827 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'"; 6828 } else if (rhs == EmptyExpression.LValueMemberOutAccess) { 6829 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'"; 6830 } else if (rhs == EmptyExpression.UnaryAddress) { 6831 code = 459; msg = "Cannot take the address of {1} `{0}'"; 6832 } else { 6833 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'"; 6834 } 6835 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ()); 6836 } 6837 } 6838 6839 if (eclass == ExprClass.Unresolved) 6840 DoResolveBase (ec); 6841 6842 return base.DoResolveLValue (ec, rhs); 6843 } 6844 GetHashCode()6845 public override int GetHashCode () 6846 { 6847 return local_info.GetHashCode (); 6848 } 6849 Equals(object obj)6850 public override bool Equals (object obj) 6851 { 6852 LocalVariableReference lvr = obj as LocalVariableReference; 6853 if (lvr == null) 6854 return false; 6855 6856 return local_info == lvr.local_info; 6857 } 6858 6859 protected override ILocalVariable Variable { 6860 get { return local_info; } 6861 } 6862 ToString()6863 public override string ToString () 6864 { 6865 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc); 6866 } 6867 CloneTo(CloneContext clonectx, Expression t)6868 protected override void CloneTo (CloneContext clonectx, Expression t) 6869 { 6870 // Nothing 6871 } 6872 } 6873 6874 /// <summary> 6875 /// This represents a reference to a parameter in the intermediate 6876 /// representation. 6877 /// </summary> 6878 public class ParameterReference : VariableReference 6879 { 6880 protected ParametersBlock.ParameterInfo pi; 6881 ParameterReference(ParametersBlock.ParameterInfo pi, Location loc)6882 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc) 6883 { 6884 this.pi = pi; 6885 this.loc = loc; 6886 } 6887 6888 #region Properties 6889 6890 public override bool IsLockedByStatement { 6891 get { 6892 return pi.IsLocked; 6893 } 6894 set { 6895 pi.IsLocked = value; 6896 } 6897 } 6898 6899 public override bool IsRef { 6900 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; } 6901 } 6902 6903 bool HasOutModifier { 6904 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; } 6905 } 6906 GetHoistedVariable(AnonymousExpression ae)6907 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae) 6908 { 6909 return pi.Parameter.HoistedVariant; 6910 } 6911 6912 // 6913 // A ref or out parameter is classified as a moveable variable, even 6914 // if the argument given for the parameter is a fixed variable 6915 // 6916 public override bool IsFixed { 6917 get { return !IsRef; } 6918 } 6919 6920 public override string Name { 6921 get { return Parameter.Name; } 6922 } 6923 6924 public Parameter Parameter { 6925 get { return pi.Parameter; } 6926 } 6927 6928 public override VariableInfo VariableInfo { 6929 get { return pi.VariableInfo; } 6930 } 6931 6932 protected override ILocalVariable Variable { 6933 get { return Parameter; } 6934 } 6935 6936 #endregion 6937 AddressOf(EmitContext ec, AddressOp mode)6938 public override void AddressOf (EmitContext ec, AddressOp mode) 6939 { 6940 // 6941 // ParameterReferences might already be a reference 6942 // 6943 if (IsRef) { 6944 EmitLoad (ec); 6945 return; 6946 } 6947 6948 base.AddressOf (ec, mode); 6949 } 6950 SetHasAddressTaken()6951 public override void SetHasAddressTaken () 6952 { 6953 Parameter.HasAddressTaken = true; 6954 } 6955 DoResolveBase(ResolveContext ec)6956 bool DoResolveBase (ResolveContext ec) 6957 { 6958 if (eclass != ExprClass.Unresolved) 6959 return true; 6960 6961 type = pi.ParameterType; 6962 eclass = ExprClass.Variable; 6963 6964 // 6965 // If we are referencing a parameter from the external block 6966 // flag it for capturing 6967 // 6968 if (ec.MustCaptureVariable (pi)) { 6969 if (Parameter.HasAddressTaken) 6970 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc); 6971 6972 if (IsRef) { 6973 ec.Report.Error (1628, loc, 6974 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier", 6975 Name, ec.CurrentAnonymousMethod.ContainerType); 6976 } 6977 6978 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) { 6979 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec); 6980 storey.CaptureParameter (ec, pi, this); 6981 } 6982 } 6983 6984 return true; 6985 } 6986 GetHashCode()6987 public override int GetHashCode () 6988 { 6989 return Name.GetHashCode (); 6990 } 6991 Equals(object obj)6992 public override bool Equals (object obj) 6993 { 6994 ParameterReference pr = obj as ParameterReference; 6995 if (pr == null) 6996 return false; 6997 6998 return Name == pr.Name; 6999 } 7000 CloneTo(CloneContext clonectx, Expression target)7001 protected override void CloneTo (CloneContext clonectx, Expression target) 7002 { 7003 // Nothing to clone 7004 return; 7005 } 7006 CreateExpressionTree(ResolveContext ec)7007 public override Expression CreateExpressionTree (ResolveContext ec) 7008 { 7009 HoistedVariable hv = GetHoistedVariable (ec); 7010 if (hv != null) 7011 return hv.CreateExpressionTree (); 7012 7013 return Parameter.ExpressionTreeVariableReference (); 7014 } 7015 DoResolve(ResolveContext ec)7016 protected override Expression DoResolve (ResolveContext ec) 7017 { 7018 if (!DoResolveBase (ec)) 7019 return null; 7020 7021 return this; 7022 } 7023 DoResolveLValue(ResolveContext ec, Expression right_side)7024 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side) 7025 { 7026 if (!DoResolveBase (ec)) 7027 return null; 7028 7029 if (Parameter.HoistedVariant != null) 7030 Parameter.HoistedVariant.IsAssigned = true; 7031 7032 return base.DoResolveLValue (ec, right_side); 7033 } 7034 FlowAnalysis(FlowAnalysisContext fc)7035 public override void FlowAnalysis (FlowAnalysisContext fc) 7036 { 7037 VariableInfo variable_info = VariableInfo; 7038 if (variable_info == null) 7039 return; 7040 7041 if (fc.IsDefinitelyAssigned (variable_info)) 7042 return; 7043 7044 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name); 7045 fc.SetVariableAssigned (variable_info); 7046 } 7047 } 7048 7049 /// <summary> 7050 /// Invocation of methods or delegates. 7051 /// </summary> 7052 public class Invocation : ExpressionStatement 7053 { 7054 public class Predefined : Invocation 7055 { Predefined(MethodGroupExpr expr, Arguments arguments)7056 public Predefined (MethodGroupExpr expr, Arguments arguments) 7057 : base (expr, arguments) 7058 { 7059 this.mg = expr; 7060 } 7061 DoResolveOverload(ResolveContext rc)7062 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc) 7063 { 7064 mg.BestCandidate.CheckObsoleteness (rc, loc); 7065 7066 return mg; 7067 } 7068 } 7069 7070 protected Arguments arguments; 7071 protected Expression expr; 7072 protected MethodGroupExpr mg; 7073 bool conditional_access_receiver; 7074 Invocation(Expression expr, Arguments arguments)7075 public Invocation (Expression expr, Arguments arguments) 7076 { 7077 this.expr = expr; 7078 this.arguments = arguments; 7079 if (expr != null) { 7080 loc = expr.Location; 7081 } 7082 } 7083 7084 #region Properties 7085 public Arguments Arguments { 7086 get { 7087 return arguments; 7088 } 7089 } 7090 7091 public Expression Exp { 7092 get { 7093 return expr; 7094 } 7095 } 7096 7097 public MethodGroupExpr MethodGroup { 7098 get { 7099 return mg; 7100 } 7101 } 7102 7103 public override Location StartLocation { 7104 get { 7105 return expr.StartLocation; 7106 } 7107 } 7108 7109 #endregion 7110 CanReduceLambda(AnonymousMethodBody body)7111 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body) 7112 { 7113 if (MethodGroup == null) 7114 return null; 7115 7116 var candidate = MethodGroup.BestCandidate; 7117 if (candidate == null || !(candidate.IsStatic || Exp is This)) 7118 return null; 7119 7120 var args_count = arguments == null ? 0 : arguments.Count; 7121 if (args_count != body.Parameters.Count) 7122 return null; 7123 7124 var lambda_parameters = body.Block.Parameters.FixedParameters; 7125 for (int i = 0; i < args_count; ++i) { 7126 var pr = arguments[i].Expr as ParameterReference; 7127 if (pr == null) 7128 return null; 7129 7130 if (lambda_parameters[i] != pr.Parameter) 7131 return null; 7132 7133 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask)) 7134 return null; 7135 } 7136 7137 var emg = MethodGroup as ExtensionMethodGroupExpr; 7138 if (emg != null) { 7139 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location); 7140 if (candidate.IsGeneric) { 7141 var targs = new TypeExpression [candidate.Arity]; 7142 for (int i = 0; i < targs.Length; ++i) { 7143 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location); 7144 } 7145 7146 mg.SetTypeArguments (null, new TypeArguments (targs)); 7147 } 7148 7149 return mg; 7150 } 7151 7152 return MethodGroup; 7153 } 7154 CloneTo(CloneContext clonectx, Expression t)7155 protected override void CloneTo (CloneContext clonectx, Expression t) 7156 { 7157 Invocation target = (Invocation) t; 7158 7159 if (arguments != null) 7160 target.arguments = arguments.Clone (clonectx); 7161 7162 target.expr = expr.Clone (clonectx); 7163 } 7164 ContainsEmitWithAwait()7165 public override bool ContainsEmitWithAwait () 7166 { 7167 if (arguments != null && arguments.ContainsEmitWithAwait ()) 7168 return true; 7169 7170 return mg.ContainsEmitWithAwait (); 7171 } 7172 CreateExpressionTree(ResolveContext ec)7173 public override Expression CreateExpressionTree (ResolveContext ec) 7174 { 7175 Expression instance = mg.IsInstance ? 7176 mg.InstanceExpression.CreateExpressionTree (ec) : 7177 new NullLiteral (loc); 7178 7179 var args = Arguments.CreateForExpressionTree (ec, arguments, 7180 instance, 7181 mg.CreateExpressionTree (ec)); 7182 7183 return CreateExpressionFactoryCall (ec, "Call", args); 7184 } 7185 ResolveConditionalAccessReceiver(ResolveContext rc)7186 void ResolveConditionalAccessReceiver (ResolveContext rc) 7187 { 7188 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) { 7189 conditional_access_receiver = true; 7190 } 7191 } 7192 7193 bool statement_resolve; ResolveStatement(BlockContext bc)7194 public override ExpressionStatement ResolveStatement (BlockContext bc) 7195 { 7196 statement_resolve = true; 7197 var es = base.ResolveStatement (bc); 7198 statement_resolve = false; 7199 7200 return es; 7201 } 7202 DoResolve(ResolveContext rc)7203 protected override Expression DoResolve (ResolveContext rc) 7204 { 7205 ResolveConditionalAccessReceiver (rc); 7206 return DoResolveInvocation (rc, null); 7207 } 7208 DoResolveLValue(ResolveContext rc, Expression right_side)7209 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) 7210 { 7211 var sn = expr as SimpleName; 7212 if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) { 7213 var variables = new List<BlockVariable> (arguments.Count); 7214 foreach (var arg in arguments) { 7215 var arg_sn = arg.Expr as SimpleName; 7216 if (arg_sn == null || arg_sn.Arity != 0) { 7217 rc.Report.Error (8199, loc, "The syntax `var (...)' as an lvalue is reserved"); 7218 return ErrorExpression.Instance; 7219 } 7220 7221 var lv = new LocalVariable (rc.CurrentBlock, arg_sn.Name, arg.Expr.Location); 7222 rc.CurrentBlock.AddLocalName (lv); 7223 variables.Add (new BlockVariable (new VarExpr (lv.Location), lv)); 7224 } 7225 7226 var res = new TupleDeconstruct (variables, right_side, loc); 7227 return res.Resolve (rc); 7228 } 7229 7230 if (right_side != null) { 7231 if (eclass != ExprClass.Unresolved) 7232 return this; 7233 7234 var res = DoResolveInvocation (rc, right_side); 7235 if (res == null) 7236 return null; 7237 7238 return res; 7239 } 7240 7241 return base.DoResolveLValue (rc, right_side); 7242 } 7243 DoResolveInvocation(ResolveContext ec, Expression rhs)7244 Expression DoResolveInvocation (ResolveContext ec, Expression rhs) 7245 { 7246 Expression member_expr; 7247 var atn = expr as ATypeNameExpression; 7248 7249 var flags = default (ResolveContext.FlagsHandle); 7250 if (conditional_access_receiver) 7251 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver); 7252 7253 if (atn != null) { 7254 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess); 7255 if (member_expr != null) { 7256 var name_of = member_expr as NameOf; 7257 if (name_of != null) { 7258 return name_of.ResolveOverload (ec, arguments); 7259 } 7260 7261 member_expr = member_expr.Resolve (ec); 7262 } 7263 } else { 7264 member_expr = expr.Resolve (ec); 7265 } 7266 7267 if (conditional_access_receiver) 7268 flags.Dispose (); 7269 7270 if (member_expr == null) 7271 return null; 7272 7273 // 7274 // Next, evaluate all the expressions in the argument list 7275 // 7276 bool dynamic_arg = false; 7277 if (arguments != null) { 7278 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) { 7279 arguments.Resolve (ec, out dynamic_arg); 7280 } 7281 } 7282 7283 TypeSpec expr_type = member_expr.Type; 7284 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) 7285 return DoResolveDynamic (ec, member_expr); 7286 7287 mg = member_expr as MethodGroupExpr; 7288 Expression invoke = null; 7289 7290 if (mg == null) { 7291 if (expr_type != null && expr_type.IsDelegate) { 7292 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc); 7293 invoke = invoke.Resolve (ec); 7294 if (invoke == null || !dynamic_arg) 7295 return invoke; 7296 } else { 7297 if (member_expr is RuntimeValueExpression) { 7298 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'", 7299 member_expr.Type.GetSignatureForError ()); 7300 return null; 7301 } 7302 7303 MemberExpr me = member_expr as MemberExpr; 7304 if (me == null) { 7305 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc); 7306 return null; 7307 } 7308 7309 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate", 7310 member_expr.GetSignatureForError ()); 7311 return null; 7312 } 7313 } 7314 7315 if (invoke == null) { 7316 mg = DoResolveOverload (ec); 7317 if (mg == null) 7318 return null; 7319 } 7320 7321 if (dynamic_arg) 7322 return DoResolveDynamic (ec, member_expr); 7323 7324 var method = mg.BestCandidate; 7325 type = mg.BestCandidateReturnType; 7326 if (conditional_access_receiver && !statement_resolve) 7327 type = LiftMemberType (ec, type); 7328 7329 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) { 7330 if (mg.IsBase) 7331 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor"); 7332 else 7333 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available"); 7334 return null; 7335 } 7336 7337 IsSpecialMethodInvocation (ec, method, loc); 7338 7339 eclass = ExprClass.Value; 7340 7341 if (type.Kind == MemberKind.ByRef && rhs != EmptyExpression.OutAccess) 7342 return ByRefDereference.Create (this).Resolve (ec); 7343 7344 return this; 7345 } 7346 DoResolveDynamic(ResolveContext ec, Expression memberExpr)7347 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr) 7348 { 7349 Arguments args; 7350 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder; 7351 if (dmb != null) { 7352 args = dmb.Arguments; 7353 if (arguments != null) 7354 args.AddRange (arguments); 7355 } else if (mg == null) { 7356 if (arguments == null) 7357 args = new Arguments (1); 7358 else 7359 args = arguments; 7360 7361 args.Insert (0, new Argument (memberExpr)); 7362 this.expr = null; 7363 } else { 7364 if (mg.IsBase) { 7365 ec.Report.Error (1971, loc, 7366 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access", 7367 mg.Name); 7368 return null; 7369 } 7370 7371 if (arguments == null) 7372 args = new Arguments (1); 7373 else 7374 args = arguments; 7375 7376 MemberAccess ma = expr as MemberAccess; 7377 if (ma != null) { 7378 var inst = mg.InstanceExpression; 7379 var left_type = inst as TypeExpr; 7380 if (left_type != null) { 7381 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName)); 7382 } else if (inst != null) { 7383 // 7384 // Any value type has to be pass as by-ref to get back the same 7385 // instance on which the member was called 7386 // 7387 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ? 7388 Argument.AType.Ref : Argument.AType.None; 7389 args.Insert (0, new Argument (inst.Resolve (ec), mod)); 7390 } 7391 } else { // is SimpleName 7392 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) { 7393 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName)); 7394 } else { 7395 args.Insert (0, new Argument (new This (loc).Resolve (ec))); 7396 } 7397 } 7398 } 7399 7400 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec); 7401 } 7402 DoResolveOverload(ResolveContext ec)7403 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec) 7404 { 7405 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None); 7406 } 7407 FlowAnalysis(FlowAnalysisContext fc)7408 public override void FlowAnalysis (FlowAnalysisContext fc) 7409 { 7410 if (mg.IsConditionallyExcluded) 7411 return; 7412 7413 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null; 7414 7415 mg.FlowAnalysis (fc); 7416 7417 if (arguments != null) 7418 arguments.FlowAnalysis (fc); 7419 7420 if (conditional_access_receiver) 7421 fc.DefiniteAssignment = da; 7422 } 7423 GetSignatureForError()7424 public override string GetSignatureForError () 7425 { 7426 return mg.GetSignatureForError (); 7427 } 7428 HasConditionalAccess()7429 public override bool HasConditionalAccess () 7430 { 7431 return expr.HasConditionalAccess (); 7432 } 7433 7434 // 7435 // If a member is a method or event, or if it is a constant, field or property of either a delegate type 7436 // or the type dynamic, then the member is invocable 7437 // IsMemberInvocable(MemberSpec member)7438 public static bool IsMemberInvocable (MemberSpec member) 7439 { 7440 switch (member.Kind) { 7441 case MemberKind.Event: 7442 return true; 7443 case MemberKind.Field: 7444 case MemberKind.Property: 7445 var m = member as IInterfaceMemberSpec; 7446 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic; 7447 default: 7448 return false; 7449 } 7450 } 7451 IsSpecialMethodInvocation(ResolveContext ec, MethodSpec method, Location loc)7452 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc) 7453 { 7454 if (!method.IsReservedMethod) 7455 return false; 7456 7457 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated) 7458 return false; 7459 7460 ec.Report.SymbolRelatedToPreviousError (method); 7461 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor", 7462 method.GetSignatureForError ()); 7463 7464 return true; 7465 } 7466 Emit(EmitContext ec)7467 public override void Emit (EmitContext ec) 7468 { 7469 if (mg.IsConditionallyExcluded) 7470 return; 7471 7472 if (conditional_access_receiver) 7473 mg.EmitCall (ec, arguments, type, false); 7474 else 7475 mg.EmitCall (ec, arguments, false); 7476 } 7477 EmitPrepare(EmitContext ec)7478 public override void EmitPrepare (EmitContext ec) 7479 { 7480 mg.EmitPrepare (ec); 7481 7482 arguments?.EmitPrepare (ec); 7483 } 7484 EmitStatement(EmitContext ec)7485 public override void EmitStatement (EmitContext ec) 7486 { 7487 if (mg.IsConditionallyExcluded) 7488 return; 7489 7490 if (conditional_access_receiver) 7491 mg.EmitCall (ec, arguments, type, true); 7492 else 7493 mg.EmitCall (ec, arguments, true); 7494 } 7495 MakeExpression(BuilderContext ctx)7496 public override SLE.Expression MakeExpression (BuilderContext ctx) 7497 { 7498 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments); 7499 } 7500 MakeExpression(BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)7501 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args) 7502 { 7503 #if STATIC 7504 throw new NotSupportedException (); 7505 #else 7506 var instance_expr = instance == null ? null : instance.MakeExpression (ctx); 7507 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx)); 7508 #endif 7509 } 7510 Accept(StructuralVisitor visitor)7511 public override object Accept (StructuralVisitor visitor) 7512 { 7513 return visitor.Visit (this); 7514 } 7515 } 7516 7517 // 7518 // Implements simple new expression 7519 // 7520 public class New : ExpressionStatement, IMemoryLocation 7521 { 7522 protected Arguments arguments; 7523 7524 // 7525 // During bootstrap, it contains the RequestedType, 7526 // but if `type' is not null, it *might* contain a NewDelegate 7527 // (because of field multi-initialization) 7528 // 7529 protected Expression RequestedType; 7530 7531 protected MethodSpec method; 7532 New(Expression requested_type, Arguments arguments, Location l)7533 public New (Expression requested_type, Arguments arguments, Location l) 7534 { 7535 RequestedType = requested_type; 7536 this.arguments = arguments; 7537 loc = l; 7538 } 7539 7540 #region Properties 7541 public Arguments Arguments { 7542 get { 7543 return arguments; 7544 } 7545 } 7546 7547 // 7548 // Returns true for resolved `new S()' when S does not declare parameterless constructor 7549 // 7550 public bool IsGeneratedStructConstructor { 7551 get { 7552 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New); 7553 } 7554 } 7555 7556 public Expression TypeExpression { 7557 get { 7558 return RequestedType; 7559 } 7560 } 7561 7562 #endregion 7563 7564 /// <summary> 7565 /// Converts complex core type syntax like 'new int ()' to simple constant 7566 /// </summary> Constantify(TypeSpec t, Location loc)7567 public static Constant Constantify (TypeSpec t, Location loc) 7568 { 7569 switch (t.BuiltinType) { 7570 case BuiltinTypeSpec.Type.Int: 7571 return new IntConstant (t, 0, loc); 7572 case BuiltinTypeSpec.Type.UInt: 7573 return new UIntConstant (t, 0, loc); 7574 case BuiltinTypeSpec.Type.Long: 7575 return new LongConstant (t, 0, loc); 7576 case BuiltinTypeSpec.Type.ULong: 7577 return new ULongConstant (t, 0, loc); 7578 case BuiltinTypeSpec.Type.Float: 7579 return new FloatConstant (t, 0, loc); 7580 case BuiltinTypeSpec.Type.Double: 7581 return new DoubleConstant (t, 0, loc); 7582 case BuiltinTypeSpec.Type.Short: 7583 return new ShortConstant (t, 0, loc); 7584 case BuiltinTypeSpec.Type.UShort: 7585 return new UShortConstant (t, 0, loc); 7586 case BuiltinTypeSpec.Type.SByte: 7587 return new SByteConstant (t, 0, loc); 7588 case BuiltinTypeSpec.Type.Byte: 7589 return new ByteConstant (t, 0, loc); 7590 case BuiltinTypeSpec.Type.Char: 7591 return new CharConstant (t, '\0', loc); 7592 case BuiltinTypeSpec.Type.Bool: 7593 return new BoolConstant (t, false, loc); 7594 case BuiltinTypeSpec.Type.Decimal: 7595 return new DecimalConstant (t, 0, loc); 7596 } 7597 7598 if (t.IsEnum) 7599 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t); 7600 7601 if (t.IsNullableType) 7602 return Nullable.LiftedNull.Create (t, loc); 7603 7604 return null; 7605 } 7606 ContainsEmitWithAwait()7607 public override bool ContainsEmitWithAwait () 7608 { 7609 return arguments != null && arguments.ContainsEmitWithAwait (); 7610 } 7611 7612 // 7613 // Checks whether the type is an interface that has the 7614 // [ComImport, CoClass] attributes and must be treated 7615 // specially 7616 // CheckComImport(ResolveContext ec)7617 public Expression CheckComImport (ResolveContext ec) 7618 { 7619 if (!type.IsInterface) 7620 return null; 7621 7622 // 7623 // Turn the call into: 7624 // (the-interface-stated) (new class-referenced-in-coclassattribute ()) 7625 // 7626 var real_class = type.MemberDefinition.GetAttributeCoClass (); 7627 if (real_class == null) 7628 return null; 7629 7630 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc); 7631 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc); 7632 return cast.Resolve (ec); 7633 } 7634 CreateExpressionTree(ResolveContext ec)7635 public override Expression CreateExpressionTree (ResolveContext ec) 7636 { 7637 Arguments args; 7638 if (method == null) { 7639 args = new Arguments (1); 7640 args.Add (new Argument (new TypeOf (type, loc))); 7641 } else { 7642 args = Arguments.CreateForExpressionTree (ec, 7643 arguments, new TypeOfMethod (method, loc)); 7644 } 7645 7646 return CreateExpressionFactoryCall (ec, "New", args); 7647 } 7648 DoResolve(ResolveContext ec)7649 protected override Expression DoResolve (ResolveContext ec) 7650 { 7651 if (RequestedType is TupleTypeExpr) { 7652 ec.Report.Error (8181, loc, "Tuple type cannot be used in an object creation expression. Use a tuple literal expression instead."); 7653 } 7654 7655 type = RequestedType.ResolveAsType (ec); 7656 if (type == null) 7657 return null; 7658 7659 eclass = ExprClass.Value; 7660 7661 if (type.IsPointer) { 7662 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression", 7663 type.GetSignatureForError ()); 7664 return null; 7665 } 7666 7667 if (arguments == null) { 7668 Constant c = Constantify (type, RequestedType.Location); 7669 if (c != null) 7670 return ReducedExpression.Create (c, this); 7671 } 7672 7673 if (type.IsDelegate) { 7674 return (new NewDelegate (type, arguments, loc)).Resolve (ec); 7675 } 7676 7677 var tparam = type as TypeParameterSpec; 7678 if (tparam != null) { 7679 // 7680 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides 7681 // where type parameter constraint is inflated to struct 7682 // 7683 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) { 7684 ec.Report.Error (304, loc, 7685 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint", 7686 type.GetSignatureForError ()); 7687 } 7688 7689 if ((arguments != null) && (arguments.Count != 0)) { 7690 ec.Report.Error (417, loc, 7691 "`{0}': cannot provide arguments when creating an instance of a variable type", 7692 type.GetSignatureForError ()); 7693 } 7694 7695 return this; 7696 } 7697 7698 if (type.IsStatic) { 7699 ec.Report.SymbolRelatedToPreviousError (type); 7700 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ()); 7701 return null; 7702 } 7703 7704 if (type.IsInterface || type.IsAbstract){ 7705 if (!TypeManager.IsGenericType (type)) { 7706 RequestedType = CheckComImport (ec); 7707 if (RequestedType != null) 7708 return RequestedType; 7709 } 7710 7711 ec.Report.SymbolRelatedToPreviousError (type); 7712 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ()); 7713 return null; 7714 } 7715 7716 bool dynamic; 7717 if (arguments != null) { 7718 arguments.Resolve (ec, out dynamic); 7719 } else { 7720 dynamic = false; 7721 } 7722 7723 method = ConstructorLookup (ec, type, ref arguments, loc); 7724 7725 if (dynamic) { 7726 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName)); 7727 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec); 7728 } 7729 7730 return this; 7731 } 7732 DoEmitTypeParameter(EmitContext ec)7733 void DoEmitTypeParameter (EmitContext ec) 7734 { 7735 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc); 7736 if (m == null) 7737 return; 7738 7739 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type); 7740 ec.Emit (OpCodes.Call, ctor_factory); 7741 } 7742 7743 // 7744 // This Emit can be invoked in two contexts: 7745 // * As a mechanism that will leave a value on the stack (new object) 7746 // * As one that wont (init struct) 7747 // 7748 // If we are dealing with a ValueType, we have a few 7749 // situations to deal with: 7750 // 7751 // * The target is a ValueType, and we have been provided 7752 // the instance (this is easy, we are being assigned). 7753 // 7754 // * The target of New is being passed as an argument, 7755 // to a boxing operation or a function that takes a 7756 // ValueType. 7757 // 7758 // In this case, we need to create a temporary variable 7759 // that is the argument of New. 7760 // 7761 // Returns whether a value is left on the stack 7762 // 7763 // *** Implementation note *** 7764 // 7765 // To benefit from this optimization, each assignable expression 7766 // has to manually cast to New and call this Emit. 7767 // 7768 // TODO: It's worth to implement it for arrays and fields 7769 // Emit(EmitContext ec, IMemoryLocation target)7770 public virtual bool Emit (EmitContext ec, IMemoryLocation target) 7771 { 7772 bool is_value_type = type.IsStructOrEnum; 7773 VariableReference vr = target as VariableReference; 7774 7775 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true; 7776 7777 if (target != null && is_value_type && (vr != null || method == null)) { 7778 if (prepare_await) { 7779 arguments = arguments.Emit (ec, false, true); 7780 prepare_await = false; 7781 } 7782 7783 target.AddressOf (ec, AddressOp.Store); 7784 } else if (vr != null && vr.IsRef) { 7785 vr.EmitLoad (ec); 7786 } 7787 7788 if (arguments != null) { 7789 if (prepare_await) 7790 arguments = arguments.Emit (ec, false, true); 7791 7792 arguments.Emit (ec); 7793 } 7794 7795 if (is_value_type) { 7796 if (method == null) { 7797 ec.Emit (OpCodes.Initobj, type); 7798 return false; 7799 } 7800 7801 if (vr != null) { 7802 ec.MarkCallEntry (loc); 7803 ec.Emit (OpCodes.Call, method); 7804 return false; 7805 } 7806 } 7807 7808 if (type is TypeParameterSpec) { 7809 DoEmitTypeParameter (ec); 7810 return true; 7811 } 7812 7813 ec.MarkCallEntry (loc); 7814 ec.Emit (OpCodes.Newobj, method); 7815 return true; 7816 } 7817 Emit(EmitContext ec)7818 public override void Emit (EmitContext ec) 7819 { 7820 LocalTemporary v = null; 7821 if (method == null && type.IsStructOrEnum) { 7822 // TODO: Use temporary variable from pool 7823 v = new LocalTemporary (type); 7824 } 7825 7826 if (!Emit (ec, v)) 7827 v.Emit (ec); 7828 } 7829 EmitStatement(EmitContext ec)7830 public override void EmitStatement (EmitContext ec) 7831 { 7832 LocalTemporary v = null; 7833 if (method == null && TypeSpec.IsValueType (type)) { 7834 // TODO: Use temporary variable from pool 7835 v = new LocalTemporary (type); 7836 } 7837 7838 if (Emit (ec, v)) 7839 ec.Emit (OpCodes.Pop); 7840 } 7841 CanEmitOptimizedLocalTarget(EmitContext ec)7842 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec) 7843 { 7844 return true; 7845 } 7846 FlowAnalysis(FlowAnalysisContext fc)7847 public override void FlowAnalysis (FlowAnalysisContext fc) 7848 { 7849 if (arguments != null) 7850 arguments.FlowAnalysis (fc); 7851 } 7852 AddressOf(EmitContext ec, AddressOp mode)7853 public void AddressOf (EmitContext ec, AddressOp mode) 7854 { 7855 EmitAddressOf (ec, mode); 7856 } 7857 EmitAddressOf(EmitContext ec, AddressOp mode)7858 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode) 7859 { 7860 LocalTemporary value_target = new LocalTemporary (type); 7861 7862 if (type is TypeParameterSpec) { 7863 DoEmitTypeParameter (ec); 7864 value_target.Store (ec); 7865 value_target.AddressOf (ec, mode); 7866 return value_target; 7867 } 7868 7869 value_target.AddressOf (ec, AddressOp.Store); 7870 7871 if (method == null) { 7872 ec.Emit (OpCodes.Initobj, type); 7873 } else { 7874 if (arguments != null) 7875 arguments.Emit (ec); 7876 7877 ec.Emit (OpCodes.Call, method); 7878 } 7879 7880 value_target.AddressOf (ec, mode); 7881 return value_target; 7882 } 7883 CloneTo(CloneContext clonectx, Expression t)7884 protected override void CloneTo (CloneContext clonectx, Expression t) 7885 { 7886 New target = (New) t; 7887 7888 target.RequestedType = RequestedType.Clone (clonectx); 7889 if (arguments != null){ 7890 target.arguments = arguments.Clone (clonectx); 7891 } 7892 } 7893 MakeExpression(BuilderContext ctx)7894 public override SLE.Expression MakeExpression (BuilderContext ctx) 7895 { 7896 #if STATIC 7897 return base.MakeExpression (ctx); 7898 #else 7899 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx)); 7900 #endif 7901 } 7902 Accept(StructuralVisitor visitor)7903 public override object Accept (StructuralVisitor visitor) 7904 { 7905 return visitor.Visit (this); 7906 } 7907 } 7908 7909 // 7910 // Array initializer expression, the expression is allowed in 7911 // variable or field initialization only which makes it tricky as 7912 // the type has to be infered based on the context either from field 7913 // type or variable type (think of multiple declarators) 7914 // 7915 public class ArrayInitializer : Expression 7916 { 7917 List<Expression> elements; 7918 BlockVariable variable; 7919 ArrayInitializer(List<Expression> init, Location loc)7920 public ArrayInitializer (List<Expression> init, Location loc) 7921 { 7922 elements = init; 7923 this.loc = loc; 7924 } 7925 ArrayInitializer(int count, Location loc)7926 public ArrayInitializer (int count, Location loc) 7927 : this (new List<Expression> (count), loc) 7928 { 7929 } 7930 ArrayInitializer(Location loc)7931 public ArrayInitializer (Location loc) 7932 : this (4, loc) 7933 { 7934 } 7935 7936 #region Properties 7937 7938 public int Count { 7939 get { return elements.Count; } 7940 } 7941 7942 public List<Expression> Elements { 7943 get { 7944 return elements; 7945 } 7946 } 7947 7948 public Expression this [int index] { 7949 get { 7950 return elements [index]; 7951 } 7952 } 7953 7954 public BlockVariable VariableDeclaration { 7955 get { 7956 return variable; 7957 } 7958 set { 7959 variable = value; 7960 } 7961 } 7962 7963 #endregion 7964 Add(Expression expr)7965 public void Add (Expression expr) 7966 { 7967 elements.Add (expr); 7968 } 7969 ContainsEmitWithAwait()7970 public override bool ContainsEmitWithAwait () 7971 { 7972 throw new NotSupportedException (); 7973 } 7974 CreateExpressionTree(ResolveContext ec)7975 public override Expression CreateExpressionTree (ResolveContext ec) 7976 { 7977 throw new NotSupportedException ("ET"); 7978 } 7979 CloneTo(CloneContext clonectx, Expression t)7980 protected override void CloneTo (CloneContext clonectx, Expression t) 7981 { 7982 var target = (ArrayInitializer) t; 7983 7984 target.elements = new List<Expression> (elements.Count); 7985 foreach (var element in elements) 7986 target.elements.Add (element.Clone (clonectx)); 7987 } 7988 DoResolve(ResolveContext rc)7989 protected override Expression DoResolve (ResolveContext rc) 7990 { 7991 var current_field = rc.CurrentMemberDefinition as FieldBase; 7992 TypeExpression type; 7993 if (current_field != null && rc.CurrentAnonymousMethod == null) { 7994 type = new TypeExpression (current_field.MemberType, current_field.Location); 7995 } else if (variable != null) { 7996 if (variable.TypeExpression is VarExpr) { 7997 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer"); 7998 return EmptyExpression.Null; 7999 } 8000 8001 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location); 8002 } else { 8003 throw new NotImplementedException ("Unexpected array initializer context"); 8004 } 8005 8006 return new ArrayCreation (type, this).Resolve (rc); 8007 } 8008 Emit(EmitContext ec)8009 public override void Emit (EmitContext ec) 8010 { 8011 throw new InternalErrorException ("Missing Resolve call"); 8012 } 8013 FlowAnalysis(FlowAnalysisContext fc)8014 public override void FlowAnalysis (FlowAnalysisContext fc) 8015 { 8016 throw new InternalErrorException ("Missing Resolve call"); 8017 } 8018 Accept(StructuralVisitor visitor)8019 public override object Accept (StructuralVisitor visitor) 8020 { 8021 return visitor.Visit (this); 8022 } 8023 } 8024 8025 /// <summary> 8026 /// 14.5.10.2: Represents an array creation expression. 8027 /// </summary> 8028 /// 8029 /// <remarks> 8030 /// There are two possible scenarios here: one is an array creation 8031 /// expression that specifies the dimensions and optionally the 8032 /// initialization data and the other which does not need dimensions 8033 /// specified but where initialization data is mandatory. 8034 /// </remarks> 8035 public class ArrayCreation : Expression 8036 { 8037 FullNamedExpression requested_base_type; 8038 ArrayInitializer initializers; 8039 8040 // 8041 // The list of Argument types. 8042 // This is used to construct the `newarray' or constructor signature 8043 // 8044 protected List<Expression> arguments; 8045 8046 protected TypeSpec array_element_type; 8047 int num_arguments; 8048 protected int dimensions; 8049 protected readonly ComposedTypeSpecifier rank; 8050 Expression first_emit; 8051 LocalTemporary first_emit_temp; 8052 8053 protected List<Expression> array_data; 8054 8055 Dictionary<int, int> bounds; 8056 8057 #if STATIC 8058 // The number of constants in array initializers 8059 int const_initializers_count; 8060 bool only_constant_initializers; 8061 #endif ArrayCreation(FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)8062 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l) 8063 : this (requested_base_type, rank, initializers, l) 8064 { 8065 arguments = new List<Expression> (exprs); 8066 num_arguments = arguments.Count; 8067 } 8068 8069 // 8070 // For expressions like int[] foo = new int[] { 1, 2, 3 }; 8071 // ArrayCreation(FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)8072 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc) 8073 { 8074 this.requested_base_type = requested_base_type; 8075 this.rank = rank; 8076 this.initializers = initializers; 8077 this.loc = loc; 8078 8079 if (rank != null) 8080 num_arguments = rank.Dimension; 8081 } 8082 8083 // 8084 // For compiler generated single dimensional arrays only 8085 // ArrayCreation(FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)8086 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc) 8087 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc) 8088 { 8089 } 8090 8091 // 8092 // For expressions like int[] foo = { 1, 2, 3 }; 8093 // ArrayCreation(FullNamedExpression requested_base_type, ArrayInitializer initializers)8094 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers) 8095 : this (requested_base_type, null, initializers, initializers.Location) 8096 { 8097 } 8098 8099 public bool NoEmptyInterpolation { get; set; } 8100 8101 public ComposedTypeSpecifier Rank { 8102 get { 8103 return this.rank; 8104 } 8105 } 8106 8107 public FullNamedExpression TypeExpression { 8108 get { 8109 return this.requested_base_type; 8110 } 8111 } 8112 8113 public ArrayInitializer Initializers { 8114 get { 8115 return this.initializers; 8116 } 8117 } 8118 CheckIndices(ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)8119 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds) 8120 { 8121 if (initializers != null && bounds == null) { 8122 // 8123 // We use this to store all the data values in the order in which we 8124 // will need to store them in the byte blob later 8125 // 8126 array_data = new List<Expression> (probe.Count); 8127 bounds = new Dictionary<int, int> (); 8128 } 8129 8130 if (specified_dims) { 8131 Expression a = arguments [idx]; 8132 a = a.Resolve (ec); 8133 if (a == null) 8134 return false; 8135 8136 a = ConvertExpressionToArrayIndex (ec, a); 8137 if (a == null) 8138 return false; 8139 8140 arguments[idx] = a; 8141 8142 if (initializers != null) { 8143 Constant c = a as Constant; 8144 if (c == null && a is ArrayIndexCast) 8145 c = ((ArrayIndexCast) a).Child as Constant; 8146 8147 if (c == null) { 8148 ec.Report.Error (150, a.Location, "A constant value is expected"); 8149 return false; 8150 } 8151 8152 int value; 8153 try { 8154 value = System.Convert.ToInt32 (c.GetValue ()); 8155 } catch { 8156 ec.Report.Error (150, a.Location, "A constant value is expected"); 8157 return false; 8158 } 8159 8160 // TODO: probe.Count does not fit ulong in 8161 if (value != probe.Count) { 8162 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ()); 8163 return false; 8164 } 8165 8166 bounds[idx] = value; 8167 } 8168 } 8169 8170 if (initializers == null) 8171 return true; 8172 8173 for (int i = 0; i < probe.Count; ++i) { 8174 var o = probe [i]; 8175 if (o is ArrayInitializer) { 8176 var sub_probe = o as ArrayInitializer; 8177 if (idx + 1 >= dimensions){ 8178 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead"); 8179 return false; 8180 } 8181 8182 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level 8183 if (!bounds.ContainsKey(idx + 1)) 8184 bounds[idx + 1] = sub_probe.Count; 8185 8186 if (bounds[idx + 1] != sub_probe.Count) { 8187 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString()); 8188 return false; 8189 } 8190 8191 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1); 8192 if (!ret) 8193 return false; 8194 } else if (child_bounds > 1) { 8195 ec.Report.Error (846, o.Location, "A nested array initializer was expected"); 8196 } else { 8197 Expression element = ResolveArrayElement (ec, o); 8198 if (element == null) 8199 continue; 8200 #if STATIC 8201 // Initializers with the default values can be ignored 8202 Constant c = element as Constant; 8203 if (c != null) { 8204 if (!c.IsDefaultInitializer (array_element_type)) { 8205 ++const_initializers_count; 8206 } 8207 } else { 8208 only_constant_initializers = false; 8209 } 8210 #endif 8211 array_data.Add (element); 8212 } 8213 } 8214 8215 return true; 8216 } 8217 ContainsEmitWithAwait()8218 public override bool ContainsEmitWithAwait () 8219 { 8220 foreach (var arg in arguments) { 8221 if (arg.ContainsEmitWithAwait ()) 8222 return true; 8223 } 8224 8225 return InitializersContainAwait (); 8226 } 8227 CreateExpressionTree(ResolveContext ec)8228 public override Expression CreateExpressionTree (ResolveContext ec) 8229 { 8230 Arguments args; 8231 8232 if (array_data == null) { 8233 args = new Arguments (arguments.Count + 1); 8234 args.Add (new Argument (new TypeOf (array_element_type, loc))); 8235 foreach (Expression a in arguments) 8236 args.Add (new Argument (a.CreateExpressionTree (ec))); 8237 8238 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args); 8239 } 8240 8241 if (dimensions > 1) { 8242 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer"); 8243 return null; 8244 } 8245 8246 args = new Arguments (array_data == null ? 1 : array_data.Count + 1); 8247 args.Add (new Argument (new TypeOf (array_element_type, loc))); 8248 if (array_data != null) { 8249 for (int i = 0; i < array_data.Count; ++i) { 8250 Expression e = array_data [i]; 8251 args.Add (new Argument (e.CreateExpressionTree (ec))); 8252 } 8253 } 8254 8255 return CreateExpressionFactoryCall (ec, "NewArrayInit", args); 8256 } 8257 UpdateIndices(ResolveContext rc)8258 void UpdateIndices (ResolveContext rc) 8259 { 8260 int i = 0; 8261 for (var probe = initializers; probe != null;) { 8262 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null); 8263 arguments.Add (e); 8264 bounds[i++] = probe.Count; 8265 8266 if (probe.Count > 0 && probe [0] is ArrayInitializer) { 8267 probe = (ArrayInitializer) probe[0]; 8268 } else if (dimensions > i) { 8269 continue; 8270 } else { 8271 return; 8272 } 8273 } 8274 } 8275 Error_NegativeArrayIndex(ResolveContext ec, Location loc)8276 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc) 8277 { 8278 ec.Report.Error (248, loc, "Cannot create an array with a negative size"); 8279 } 8280 FlowAnalysis(FlowAnalysisContext fc)8281 public override void FlowAnalysis (FlowAnalysisContext fc) 8282 { 8283 foreach (var arg in arguments) 8284 arg.FlowAnalysis (fc); 8285 8286 if (array_data != null) { 8287 foreach (var ad in array_data) 8288 ad.FlowAnalysis (fc); 8289 } 8290 } 8291 InitializersContainAwait()8292 bool InitializersContainAwait () 8293 { 8294 if (array_data == null) 8295 return false; 8296 8297 foreach (var expr in array_data) { 8298 if (expr.ContainsEmitWithAwait ()) 8299 return true; 8300 } 8301 8302 return false; 8303 } 8304 ResolveArrayElement(ResolveContext ec, Expression element)8305 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element) 8306 { 8307 element = element.Resolve (ec); 8308 if (element == null) 8309 return null; 8310 8311 var te = element as CompoundAssign.TargetExpression; 8312 if (te != null) { 8313 for (int i = 1; i < initializers.Count; ++i) { 8314 if (initializers [i].ContainsEmitWithAwait ()) { 8315 te.RequiresEmitWithAwait = true; 8316 break; 8317 } 8318 } 8319 8320 if (!te.RequiresEmitWithAwait) { 8321 if (first_emit != null) 8322 throw new InternalErrorException ("Can only handle one mutator at a time"); 8323 first_emit = element; 8324 element = first_emit_temp = new LocalTemporary (element.Type); 8325 } 8326 } 8327 8328 return Convert.ImplicitConversionRequired ( 8329 ec, element, array_element_type, loc); 8330 } 8331 ResolveInitializers(ResolveContext ec)8332 protected bool ResolveInitializers (ResolveContext ec) 8333 { 8334 #if STATIC 8335 only_constant_initializers = true; 8336 #endif 8337 8338 if (arguments != null) { 8339 bool res = true; 8340 for (int i = 0; i < arguments.Count; ++i) { 8341 res &= CheckIndices (ec, initializers, i, true, dimensions); 8342 if (initializers != null) 8343 break; 8344 } 8345 8346 return res; 8347 } 8348 8349 arguments = new List<Expression> (); 8350 8351 if (!CheckIndices (ec, initializers, 0, false, dimensions)) 8352 return false; 8353 8354 UpdateIndices (ec); 8355 8356 return true; 8357 } 8358 8359 // 8360 // Resolved the type of the array 8361 // ResolveArrayType(ResolveContext ec)8362 bool ResolveArrayType (ResolveContext ec) 8363 { 8364 // 8365 // Lookup the type 8366 // 8367 FullNamedExpression array_type_expr; 8368 if (num_arguments > 0) { 8369 array_type_expr = new ComposedCast (requested_base_type, rank); 8370 } else { 8371 array_type_expr = requested_base_type; 8372 } 8373 8374 type = array_type_expr.ResolveAsType (ec); 8375 if (array_type_expr == null) 8376 return false; 8377 8378 var ac = type as ArrayContainer; 8379 if (ac == null) { 8380 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead"); 8381 return false; 8382 } 8383 8384 array_element_type = ac.Element; 8385 dimensions = ac.Rank; 8386 8387 return true; 8388 } 8389 DoResolve(ResolveContext ec)8390 protected override Expression DoResolve (ResolveContext ec) 8391 { 8392 if (type != null) 8393 return this; 8394 8395 if (!ResolveArrayType (ec)) 8396 return null; 8397 8398 // 8399 // validate the initializers and fill in any missing bits 8400 // 8401 if (!ResolveInitializers (ec)) 8402 return null; 8403 8404 eclass = ExprClass.Value; 8405 return this; 8406 } 8407 MakeByteBlob()8408 byte [] MakeByteBlob () 8409 { 8410 int factor; 8411 byte [] data; 8412 byte [] element; 8413 int count = array_data.Count; 8414 8415 TypeSpec element_type = array_element_type; 8416 if (element_type.IsEnum) 8417 element_type = EnumSpec.GetUnderlyingType (element_type); 8418 8419 factor = BuiltinTypeSpec.GetSize (element_type); 8420 if (factor == 0) 8421 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type); 8422 8423 data = new byte [(count * factor + 3) & ~3]; 8424 int idx = 0; 8425 8426 for (int i = 0; i < count; ++i) { 8427 var c = array_data[i] as Constant; 8428 if (c == null) { 8429 idx += factor; 8430 continue; 8431 } 8432 8433 object v = c.GetValue (); 8434 8435 switch (element_type.BuiltinType) { 8436 case BuiltinTypeSpec.Type.Long: 8437 long lval = (long) v; 8438 8439 for (int j = 0; j < factor; ++j) { 8440 data[idx + j] = (byte) (lval & 0xFF); 8441 lval = (lval >> 8); 8442 } 8443 break; 8444 case BuiltinTypeSpec.Type.ULong: 8445 ulong ulval = (ulong) v; 8446 8447 for (int j = 0; j < factor; ++j) { 8448 data[idx + j] = (byte) (ulval & 0xFF); 8449 ulval = (ulval >> 8); 8450 } 8451 break; 8452 case BuiltinTypeSpec.Type.Float: 8453 var fval = SingleConverter.SingleToInt32Bits((float) v); 8454 8455 data[idx] = (byte) (fval & 0xff); 8456 data[idx + 1] = (byte) ((fval >> 8) & 0xff); 8457 data[idx + 2] = (byte) ((fval >> 16) & 0xff); 8458 data[idx + 3] = (byte) (fval >> 24); 8459 break; 8460 case BuiltinTypeSpec.Type.Double: 8461 element = BitConverter.GetBytes ((double) v); 8462 8463 for (int j = 0; j < factor; ++j) 8464 data[idx + j] = element[j]; 8465 8466 // FIXME: Handle the ARM float format. 8467 if (!BitConverter.IsLittleEndian) 8468 System.Array.Reverse (data, idx, 8); 8469 break; 8470 case BuiltinTypeSpec.Type.Char: 8471 int chval = (int) ((char) v); 8472 8473 data[idx] = (byte) (chval & 0xff); 8474 data[idx + 1] = (byte) (chval >> 8); 8475 break; 8476 case BuiltinTypeSpec.Type.Short: 8477 int sval = (int) ((short) v); 8478 8479 data[idx] = (byte) (sval & 0xff); 8480 data[idx + 1] = (byte) (sval >> 8); 8481 break; 8482 case BuiltinTypeSpec.Type.UShort: 8483 int usval = (int) ((ushort) v); 8484 8485 data[idx] = (byte) (usval & 0xff); 8486 data[idx + 1] = (byte) (usval >> 8); 8487 break; 8488 case BuiltinTypeSpec.Type.Int: 8489 int val = (int) v; 8490 8491 data[idx] = (byte) (val & 0xff); 8492 data[idx + 1] = (byte) ((val >> 8) & 0xff); 8493 data[idx + 2] = (byte) ((val >> 16) & 0xff); 8494 data[idx + 3] = (byte) (val >> 24); 8495 break; 8496 case BuiltinTypeSpec.Type.UInt: 8497 uint uval = (uint) v; 8498 8499 data[idx] = (byte) (uval & 0xff); 8500 data[idx + 1] = (byte) ((uval >> 8) & 0xff); 8501 data[idx + 2] = (byte) ((uval >> 16) & 0xff); 8502 data[idx + 3] = (byte) (uval >> 24); 8503 break; 8504 case BuiltinTypeSpec.Type.SByte: 8505 data[idx] = (byte) (sbyte) v; 8506 break; 8507 case BuiltinTypeSpec.Type.Byte: 8508 data[idx] = (byte) v; 8509 break; 8510 case BuiltinTypeSpec.Type.Bool: 8511 data[idx] = (byte) ((bool) v ? 1 : 0); 8512 break; 8513 case BuiltinTypeSpec.Type.Decimal: 8514 int[] bits = Decimal.GetBits ((decimal) v); 8515 int p = idx; 8516 8517 // FIXME: For some reason, this doesn't work on the MS runtime. 8518 int[] nbits = new int[4]; 8519 nbits[0] = bits[3]; 8520 nbits[1] = bits[2]; 8521 nbits[2] = bits[0]; 8522 nbits[3] = bits[1]; 8523 8524 for (int j = 0; j < 4; j++) { 8525 data[p++] = (byte) (nbits[j] & 0xff); 8526 data[p++] = (byte) ((nbits[j] >> 8) & 0xff); 8527 data[p++] = (byte) ((nbits[j] >> 16) & 0xff); 8528 data[p++] = (byte) (nbits[j] >> 24); 8529 } 8530 break; 8531 default: 8532 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type); 8533 } 8534 8535 idx += factor; 8536 } 8537 8538 return data; 8539 } 8540 MakeExpression(BuilderContext ctx)8541 public override SLE.Expression MakeExpression (BuilderContext ctx) 8542 { 8543 #if STATIC 8544 return base.MakeExpression (ctx); 8545 #else 8546 var initializers = new SLE.Expression [array_data.Count]; 8547 for (var i = 0; i < initializers.Length; i++) { 8548 if (array_data [i] == null) 8549 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ()); 8550 else 8551 initializers [i] = array_data [i].MakeExpression (ctx); 8552 } 8553 8554 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers); 8555 #endif 8556 } 8557 #if STATIC 8558 // 8559 // Emits the initializers for the array 8560 // EmitStaticInitializers(EmitContext ec, FieldExpr stackArray)8561 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray) 8562 { 8563 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc); 8564 if (m == null) 8565 return; 8566 8567 // 8568 // First, the static data 8569 // 8570 byte [] data = MakeByteBlob (); 8571 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc); 8572 8573 if (stackArray == null) { 8574 ec.Emit (OpCodes.Dup); 8575 } else { 8576 stackArray.Emit (ec); 8577 } 8578 8579 ec.Emit (OpCodes.Ldtoken, fb); 8580 ec.Emit (OpCodes.Call, m); 8581 } 8582 #endif 8583 8584 // 8585 // Emits pieces of the array that can not be computed at compile 8586 // time (variables and string locations). 8587 // 8588 // This always expect the top value on the stack to be the array 8589 // EmitDynamicInitializers(EmitContext ec, bool emitConstants, StackFieldExpr stackArray)8590 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray) 8591 { 8592 int dims = bounds.Count; 8593 var current_pos = new int [dims]; 8594 8595 for (int i = 0; i < array_data.Count; i++){ 8596 8597 Expression e = array_data [i]; 8598 var c = e as Constant; 8599 8600 // Constant can be initialized via StaticInitializer 8601 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) { 8602 8603 var etype = e.Type; 8604 8605 if (stackArray != null) { 8606 if (e.ContainsEmitWithAwait ()) { 8607 e = e.EmitToField (ec); 8608 } 8609 8610 stackArray.EmitLoad (ec); 8611 } else { 8612 ec.Emit (OpCodes.Dup); 8613 } 8614 8615 for (int idx = 0; idx < dims; idx++) 8616 ec.EmitInt (current_pos [idx]); 8617 8618 // 8619 // If we are dealing with a struct, get the 8620 // address of it, so we can store it. 8621 // 8622 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype)) 8623 ec.Emit (OpCodes.Ldelema, etype); 8624 8625 e.Emit (ec); 8626 8627 ec.EmitArrayStore ((ArrayContainer) type); 8628 } 8629 8630 // 8631 // Advance counter 8632 // 8633 for (int j = dims - 1; j >= 0; j--){ 8634 current_pos [j]++; 8635 if (current_pos [j] < bounds [j]) 8636 break; 8637 current_pos [j] = 0; 8638 } 8639 } 8640 8641 if (stackArray != null) 8642 stackArray.PrepareCleanup (ec); 8643 } 8644 Emit(EmitContext ec)8645 public override void Emit (EmitContext ec) 8646 { 8647 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec)) 8648 return; 8649 8650 var await_field = EmitToFieldSource (ec); 8651 if (await_field != null) 8652 await_field.Emit (ec); 8653 } 8654 EmitOptimizedEmpty(EmitContext ec)8655 bool EmitOptimizedEmpty (EmitContext ec) 8656 { 8657 if (arguments.Count != 1 || dimensions != 1) 8658 return false; 8659 8660 var c = arguments [0] as Constant; 8661 if (c == null || !c.IsZeroInteger) 8662 return false; 8663 8664 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get (); 8665 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly) 8666 return false; 8667 8668 m = m.MakeGenericMethod (ec.MemberContext, array_element_type); 8669 ec.Emit (OpCodes.Call, m); 8670 return true; 8671 } 8672 EmitToFieldSource(EmitContext ec)8673 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec) 8674 { 8675 if (first_emit != null) { 8676 first_emit.Emit (ec); 8677 first_emit_temp.Store (ec); 8678 } 8679 8680 StackFieldExpr await_stack_field; 8681 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) { 8682 await_stack_field = ec.GetTemporaryField (type); 8683 ec.EmitThis (); 8684 } else { 8685 await_stack_field = null; 8686 } 8687 8688 EmitExpressionsList (ec, arguments); 8689 8690 ec.EmitArrayNew ((ArrayContainer) type); 8691 8692 if (initializers == null) 8693 return await_stack_field; 8694 8695 if (await_stack_field != null) 8696 await_stack_field.EmitAssignFromStack (ec); 8697 8698 #if STATIC 8699 // 8700 // Emit static initializer for arrays which contain more than 2 items and 8701 // the static initializer will initialize at least 25% of array values or there 8702 // is more than 10 items to be initialized 8703 // 8704 // NOTE: const_initializers_count does not contain default constant values. 8705 // 8706 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) && 8707 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) { 8708 EmitStaticInitializers (ec, await_stack_field); 8709 8710 if (!only_constant_initializers) 8711 EmitDynamicInitializers (ec, false, await_stack_field); 8712 } else 8713 #endif 8714 { 8715 EmitDynamicInitializers (ec, true, await_stack_field); 8716 } 8717 8718 if (first_emit_temp != null) 8719 first_emit_temp.Release (ec); 8720 8721 return await_stack_field; 8722 } 8723 EncodeAttributeValue(IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)8724 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType) 8725 { 8726 // no multi dimensional or jagged arrays 8727 if (arguments.Count != 1 || array_element_type.IsArray) { 8728 base.EncodeAttributeValue (rc, enc, targetType, parameterType); 8729 return; 8730 } 8731 8732 // No array covariance, except for array -> object 8733 if (type != targetType) { 8734 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) { 8735 base.EncodeAttributeValue (rc, enc, targetType, parameterType); 8736 return; 8737 } 8738 8739 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) { 8740 Attribute.Error_AttributeArgumentIsDynamic (rc, loc); 8741 return; 8742 } 8743 } 8744 8745 // Single dimensional array of 0 size 8746 if (array_data == null) { 8747 IntConstant ic = arguments[0] as IntConstant; 8748 if (ic == null || !ic.IsDefaultValue) { 8749 base.EncodeAttributeValue (rc, enc, targetType, parameterType); 8750 } else { 8751 enc.Encode (0); 8752 } 8753 8754 return; 8755 } 8756 8757 enc.Encode (array_data.Count); 8758 foreach (var element in array_data) { 8759 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType); 8760 } 8761 } 8762 CloneTo(CloneContext clonectx, Expression t)8763 protected override void CloneTo (CloneContext clonectx, Expression t) 8764 { 8765 ArrayCreation target = (ArrayCreation) t; 8766 8767 if (requested_base_type != null) 8768 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx); 8769 8770 if (arguments != null){ 8771 target.arguments = new List<Expression> (arguments.Count); 8772 foreach (Expression e in arguments) 8773 target.arguments.Add (e.Clone (clonectx)); 8774 } 8775 8776 if (initializers != null) 8777 target.initializers = (ArrayInitializer) initializers.Clone (clonectx); 8778 } 8779 Accept(StructuralVisitor visitor)8780 public override object Accept (StructuralVisitor visitor) 8781 { 8782 return visitor.Visit (this); 8783 } 8784 } 8785 8786 // 8787 // Represents an implicitly typed array epxression 8788 // 8789 class ImplicitlyTypedArrayCreation : ArrayCreation 8790 { 8791 TypeInferenceContext best_type_inference; 8792 ImplicitlyTypedArrayCreation(ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)8793 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc) 8794 : base (null, rank, initializers, loc) 8795 { 8796 } 8797 ImplicitlyTypedArrayCreation(ArrayInitializer initializers, Location loc)8798 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc) 8799 : base (null, initializers, loc) 8800 { 8801 } 8802 DoResolve(ResolveContext ec)8803 protected override Expression DoResolve (ResolveContext ec) 8804 { 8805 if (type != null) 8806 return this; 8807 8808 dimensions = rank.Dimension; 8809 8810 best_type_inference = new TypeInferenceContext (); 8811 8812 if (!ResolveInitializers (ec)) 8813 return null; 8814 8815 best_type_inference.FixAllTypes (ec); 8816 array_element_type = best_type_inference.InferredTypeArguments[0]; 8817 best_type_inference = null; 8818 8819 if (array_element_type == null || InternalType.HasNoType (array_element_type) || arguments.Count != rank.Dimension) { 8820 ec.Report.Error (826, loc, 8821 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly"); 8822 return null; 8823 } 8824 8825 // 8826 // At this point we found common base type for all initializer elements 8827 // but we have to be sure that all static initializer elements are of 8828 // same type 8829 // 8830 UnifyInitializerElement (ec); 8831 8832 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions); 8833 eclass = ExprClass.Value; 8834 return this; 8835 } 8836 8837 // 8838 // Converts static initializer only 8839 // UnifyInitializerElement(ResolveContext ec)8840 void UnifyInitializerElement (ResolveContext ec) 8841 { 8842 for (int i = 0; i < array_data.Count; ++i) { 8843 Expression e = array_data[i]; 8844 if (e != null) 8845 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null); 8846 } 8847 } 8848 ResolveArrayElement(ResolveContext ec, Expression element)8849 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element) 8850 { 8851 element = element.Resolve (ec); 8852 if (element != null) 8853 best_type_inference.AddCommonTypeBound (element.Type); 8854 8855 return element; 8856 } 8857 } 8858 8859 sealed class CompilerGeneratedThis : This 8860 { CompilerGeneratedThis(TypeSpec type, Location loc)8861 public CompilerGeneratedThis (TypeSpec type, Location loc) 8862 : base (loc) 8863 { 8864 this.type = type; 8865 } 8866 DoResolve(ResolveContext rc)8867 protected override Expression DoResolve (ResolveContext rc) 8868 { 8869 eclass = ExprClass.Variable; 8870 8871 var block = rc.CurrentBlock; 8872 if (block != null) { 8873 var top = block.ParametersBlock.TopBlock; 8874 if (top.ThisVariable != null) 8875 variable_info = top.ThisVariable.VariableInfo; 8876 8877 } 8878 8879 return this; 8880 } 8881 DoResolveLValue(ResolveContext rc, Expression right_side)8882 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) 8883 { 8884 return DoResolve (rc); 8885 } 8886 GetHoistedVariable(AnonymousExpression ae)8887 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae) 8888 { 8889 return null; 8890 } 8891 } 8892 8893 /// <summary> 8894 /// Represents the `this' construct 8895 /// </summary> 8896 8897 public class This : VariableReference 8898 { 8899 sealed class ThisVariable : ILocalVariable 8900 { 8901 public static readonly ILocalVariable Instance = new ThisVariable (); 8902 Emit(EmitContext ec)8903 public void Emit (EmitContext ec) 8904 { 8905 ec.EmitThis (); 8906 } 8907 EmitAssign(EmitContext ec)8908 public void EmitAssign (EmitContext ec) 8909 { 8910 throw new InvalidOperationException (); 8911 } 8912 EmitAddressOf(EmitContext ec)8913 public void EmitAddressOf (EmitContext ec) 8914 { 8915 ec.EmitThis (); 8916 } 8917 } 8918 8919 protected VariableInfo variable_info; 8920 This(Location loc)8921 public This (Location loc) 8922 { 8923 this.loc = loc; 8924 } 8925 8926 #region Properties 8927 8928 public override string Name { 8929 get { return "this"; } 8930 } 8931 8932 public override bool IsLockedByStatement { 8933 get { 8934 return false; 8935 } 8936 set { 8937 } 8938 } 8939 8940 public override bool IsRef { 8941 get { return type.IsStruct; } 8942 } 8943 8944 public override bool IsSideEffectFree { 8945 get { 8946 return true; 8947 } 8948 } 8949 8950 protected override ILocalVariable Variable { 8951 get { return ThisVariable.Instance; } 8952 } 8953 8954 public override VariableInfo VariableInfo { 8955 get { return variable_info; } 8956 } 8957 8958 public override bool IsFixed { 8959 get { return false; } 8960 } 8961 8962 #endregion 8963 CheckStructThisDefiniteAssignment(FlowAnalysisContext fc)8964 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc) 8965 { 8966 // 8967 // It's null for all cases when we don't need to check `this' 8968 // definitive assignment 8969 // 8970 if (variable_info == null) 8971 return; 8972 8973 if (fc.IsDefinitelyAssigned (variable_info)) 8974 return; 8975 8976 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to"); 8977 } 8978 Error_ThisNotAvailable(ResolveContext ec)8979 protected virtual void Error_ThisNotAvailable (ResolveContext ec) 8980 { 8981 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) { 8982 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer"); 8983 } else if (ec.CurrentAnonymousMethod != null) { 8984 ec.Report.Error (1673, loc, 8985 "Anonymous methods inside structs cannot access instance members of `this'. " + 8986 "Consider copying `this' to a local variable outside the anonymous method and using the local instead"); 8987 } else { 8988 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context"); 8989 } 8990 } 8991 FlowAnalysis(FlowAnalysisContext fc)8992 public override void FlowAnalysis (FlowAnalysisContext fc) 8993 { 8994 CheckStructThisDefiniteAssignment (fc); 8995 } 8996 GetHoistedVariable(AnonymousExpression ae)8997 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae) 8998 { 8999 if (ae == null) 9000 return null; 9001 9002 AnonymousMethodStorey storey = ae.Storey; 9003 return storey != null ? storey.HoistedThis : null; 9004 } 9005 IsThisAvailable(ResolveContext ec, bool ignoreAnonymous)9006 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous) 9007 { 9008 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope)) 9009 return false; 9010 9011 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null) 9012 return true; 9013 9014 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer)) 9015 return false; 9016 9017 return true; 9018 } 9019 ResolveBase(ResolveContext ec)9020 public virtual void ResolveBase (ResolveContext ec) 9021 { 9022 eclass = ExprClass.Variable; 9023 type = ec.CurrentType; 9024 9025 if (!IsThisAvailable (ec, false)) { 9026 Error_ThisNotAvailable (ec); 9027 return; 9028 } 9029 9030 var block = ec.CurrentBlock; 9031 if (block != null) { 9032 var top = block.ParametersBlock.TopBlock; 9033 if (top.ThisVariable != null) 9034 variable_info = top.ThisVariable.VariableInfo; 9035 9036 AnonymousExpression am = ec.CurrentAnonymousMethod; 9037 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) { 9038 // 9039 // Hoisted this is almost like hoisted variable but not exactly. When 9040 // there is no variable hoisted we can simply emit an instance method 9041 // without lifting this into a storey. Unfotunatelly this complicates 9042 // things in other cases because we don't know where this will be hoisted 9043 // until top-level block is fully resolved 9044 // 9045 top.AddThisReferenceFromChildrenBlock (block.Explicit); 9046 am.SetHasThisAccess (); 9047 } 9048 } 9049 } 9050 DoResolve(ResolveContext ec)9051 protected override Expression DoResolve (ResolveContext ec) 9052 { 9053 ResolveBase (ec); 9054 return this; 9055 } 9056 DoResolveLValue(ResolveContext ec, Expression right_side)9057 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side) 9058 { 9059 if (eclass == ExprClass.Unresolved) 9060 ResolveBase (ec); 9061 9062 if (type.IsClass || (type.IsReadOnly && !ec.HasSet (ResolveContext.Options.ConstructorScope))) { 9063 if (right_side == EmptyExpression.UnaryAddress) 9064 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only"); 9065 else if (right_side == EmptyExpression.OutAccess) 9066 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only"); 9067 else 9068 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only"); 9069 } 9070 9071 return this; 9072 } 9073 GetHashCode()9074 public override int GetHashCode() 9075 { 9076 throw new NotImplementedException (); 9077 } 9078 Equals(object obj)9079 public override bool Equals (object obj) 9080 { 9081 This t = obj as This; 9082 if (t == null) 9083 return false; 9084 9085 return true; 9086 } 9087 CloneTo(CloneContext clonectx, Expression t)9088 protected override void CloneTo (CloneContext clonectx, Expression t) 9089 { 9090 // Nothing 9091 } 9092 SetHasAddressTaken()9093 public override void SetHasAddressTaken () 9094 { 9095 // Nothing 9096 } 9097 Accept(StructuralVisitor visitor)9098 public override object Accept (StructuralVisitor visitor) 9099 { 9100 return visitor.Visit (this); 9101 } 9102 } 9103 9104 /// <summary> 9105 /// Represents the `__arglist' construct 9106 /// </summary> 9107 public class ArglistAccess : Expression 9108 { ArglistAccess(Location loc)9109 public ArglistAccess (Location loc) 9110 { 9111 this.loc = loc; 9112 } 9113 CloneTo(CloneContext clonectx, Expression target)9114 protected override void CloneTo (CloneContext clonectx, Expression target) 9115 { 9116 // nothing. 9117 } 9118 ContainsEmitWithAwait()9119 public override bool ContainsEmitWithAwait () 9120 { 9121 return false; 9122 } 9123 CreateExpressionTree(ResolveContext ec)9124 public override Expression CreateExpressionTree (ResolveContext ec) 9125 { 9126 throw new NotSupportedException ("ET"); 9127 } 9128 DoResolve(ResolveContext ec)9129 protected override Expression DoResolve (ResolveContext ec) 9130 { 9131 eclass = ExprClass.Variable; 9132 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve (); 9133 9134 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) { 9135 ec.Report.Error (190, loc, 9136 "The __arglist construct is valid only within a variable argument method"); 9137 } 9138 9139 return this; 9140 } 9141 Emit(EmitContext ec)9142 public override void Emit (EmitContext ec) 9143 { 9144 ec.Emit (OpCodes.Arglist); 9145 } 9146 Accept(StructuralVisitor visitor)9147 public override object Accept (StructuralVisitor visitor) 9148 { 9149 return visitor.Visit (this); 9150 } 9151 } 9152 9153 /// <summary> 9154 /// Represents the `__arglist (....)' construct 9155 /// </summary> 9156 public class Arglist : Expression 9157 { 9158 Arguments arguments; 9159 Arglist(Location loc)9160 public Arglist (Location loc) 9161 : this (null, loc) 9162 { 9163 } 9164 Arglist(Arguments args, Location l)9165 public Arglist (Arguments args, Location l) 9166 { 9167 arguments = args; 9168 loc = l; 9169 } 9170 9171 public Arguments Arguments { 9172 get { 9173 return arguments; 9174 } 9175 } 9176 9177 public MetaType[] ArgumentTypes { 9178 get { 9179 if (arguments == null) 9180 return MetaType.EmptyTypes; 9181 9182 var retval = new MetaType[arguments.Count]; 9183 for (int i = 0; i < retval.Length; i++) 9184 retval[i] = arguments[i].Expr.Type.GetMetaInfo (); 9185 9186 return retval; 9187 } 9188 } 9189 ContainsEmitWithAwait()9190 public override bool ContainsEmitWithAwait () 9191 { 9192 throw new NotImplementedException (); 9193 } 9194 CreateExpressionTree(ResolveContext ec)9195 public override Expression CreateExpressionTree (ResolveContext ec) 9196 { 9197 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments"); 9198 return null; 9199 } 9200 DoResolve(ResolveContext ec)9201 protected override Expression DoResolve (ResolveContext ec) 9202 { 9203 eclass = ExprClass.Variable; 9204 type = InternalType.Arglist; 9205 if (arguments != null) { 9206 bool dynamic; // Can be ignored as there is always only 1 overload 9207 arguments.Resolve (ec, out dynamic); 9208 } 9209 9210 return this; 9211 } 9212 Emit(EmitContext ec)9213 public override void Emit (EmitContext ec) 9214 { 9215 if (arguments != null) 9216 arguments.Emit (ec); 9217 } 9218 CloneTo(CloneContext clonectx, Expression t)9219 protected override void CloneTo (CloneContext clonectx, Expression t) 9220 { 9221 Arglist target = (Arglist) t; 9222 9223 if (arguments != null) 9224 target.arguments = arguments.Clone (clonectx); 9225 } 9226 Accept(StructuralVisitor visitor)9227 public override object Accept (StructuralVisitor visitor) 9228 { 9229 return visitor.Visit (this); 9230 } 9231 } 9232 9233 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation 9234 { 9235 FullNamedExpression texpr; 9236 RefValueExpr(Expression expr, FullNamedExpression texpr, Location loc)9237 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc) 9238 : base (expr) 9239 { 9240 this.texpr = texpr; 9241 this.loc = loc; 9242 } 9243 9244 public FullNamedExpression TypeExpression { 9245 get { 9246 return texpr; 9247 } 9248 } 9249 ContainsEmitWithAwait()9250 public override bool ContainsEmitWithAwait () 9251 { 9252 return false; 9253 } 9254 AddressOf(EmitContext ec, AddressOp mode)9255 public void AddressOf (EmitContext ec, AddressOp mode) 9256 { 9257 expr.Emit (ec); 9258 ec.Emit (OpCodes.Refanyval, type); 9259 } 9260 DoResolve(ResolveContext rc)9261 protected override Expression DoResolve (ResolveContext rc) 9262 { 9263 expr = expr.Resolve (rc); 9264 type = texpr.ResolveAsType (rc); 9265 if (expr == null || type == null) 9266 return null; 9267 9268 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc); 9269 eclass = ExprClass.Variable; 9270 return this; 9271 } 9272 DoResolveLValue(ResolveContext rc, Expression right_side)9273 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) 9274 { 9275 return DoResolve (rc); 9276 } 9277 Emit(EmitContext ec)9278 public override void Emit (EmitContext ec) 9279 { 9280 expr.Emit (ec); 9281 ec.Emit (OpCodes.Refanyval, type); 9282 ec.EmitLoadFromPtr (type); 9283 } 9284 Emit(EmitContext ec, bool leave_copy)9285 public void Emit (EmitContext ec, bool leave_copy) 9286 { 9287 throw new NotImplementedException (); 9288 } 9289 EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool isCompound)9290 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound) 9291 { 9292 expr.Emit (ec); 9293 ec.Emit (OpCodes.Refanyval, type); 9294 source.Emit (ec); 9295 9296 LocalTemporary temporary = null; 9297 if (leave_copy) { 9298 ec.Emit (OpCodes.Dup); 9299 temporary = new LocalTemporary (source.Type); 9300 temporary.Store (ec); 9301 } 9302 9303 ec.EmitStoreFromPtr (type); 9304 9305 if (temporary != null) { 9306 temporary.Emit (ec); 9307 temporary.Release (ec); 9308 } 9309 } 9310 Accept(StructuralVisitor visitor)9311 public override object Accept (StructuralVisitor visitor) 9312 { 9313 return visitor.Visit (this); 9314 } 9315 } 9316 9317 public class RefTypeExpr : ShimExpression 9318 { RefTypeExpr(Expression expr, Location loc)9319 public RefTypeExpr (Expression expr, Location loc) 9320 : base (expr) 9321 { 9322 this.loc = loc; 9323 } 9324 DoResolve(ResolveContext rc)9325 protected override Expression DoResolve (ResolveContext rc) 9326 { 9327 expr = expr.Resolve (rc); 9328 if (expr == null) 9329 return null; 9330 9331 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc); 9332 if (expr == null) 9333 return null; 9334 9335 type = rc.BuiltinTypes.Type; 9336 eclass = ExprClass.Value; 9337 return this; 9338 } 9339 Emit(EmitContext ec)9340 public override void Emit (EmitContext ec) 9341 { 9342 expr.Emit (ec); 9343 ec.Emit (OpCodes.Refanytype); 9344 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc); 9345 if (m != null) 9346 ec.Emit (OpCodes.Call, m); 9347 } 9348 Accept(StructuralVisitor visitor)9349 public override object Accept (StructuralVisitor visitor) 9350 { 9351 return visitor.Visit (this); 9352 } 9353 } 9354 9355 public class MakeRefExpr : ShimExpression 9356 { MakeRefExpr(Expression expr, Location loc)9357 public MakeRefExpr (Expression expr, Location loc) 9358 : base (expr) 9359 { 9360 this.loc = loc; 9361 } 9362 ContainsEmitWithAwait()9363 public override bool ContainsEmitWithAwait () 9364 { 9365 throw new NotImplementedException (); 9366 } 9367 DoResolve(ResolveContext rc)9368 protected override Expression DoResolve (ResolveContext rc) 9369 { 9370 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess); 9371 type = rc.Module.PredefinedTypes.TypedReference.Resolve (); 9372 eclass = ExprClass.Value; 9373 return this; 9374 } 9375 Emit(EmitContext ec)9376 public override void Emit (EmitContext ec) 9377 { 9378 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load); 9379 ec.Emit (OpCodes.Mkrefany, expr.Type); 9380 } 9381 Accept(StructuralVisitor visitor)9382 public override object Accept (StructuralVisitor visitor) 9383 { 9384 return visitor.Visit (this); 9385 } 9386 } 9387 9388 /// <summary> 9389 /// Implements the typeof operator 9390 /// </summary> 9391 public class TypeOf : Expression { 9392 FullNamedExpression QueriedType; 9393 TypeSpec typearg; 9394 TypeOf(FullNamedExpression queried_type, Location l)9395 public TypeOf (FullNamedExpression queried_type, Location l) 9396 { 9397 QueriedType = queried_type; 9398 loc = l; 9399 } 9400 9401 // 9402 // Use this constructor for any compiler generated typeof expression 9403 // TypeOf(TypeSpec type, Location loc)9404 public TypeOf (TypeSpec type, Location loc) 9405 { 9406 this.typearg = type; 9407 this.loc = loc; 9408 } 9409 9410 #region Properties 9411 9412 public override bool IsSideEffectFree { 9413 get { 9414 return true; 9415 } 9416 } 9417 9418 public TypeSpec TypeArgument { 9419 get { 9420 return typearg; 9421 } 9422 } 9423 9424 public FullNamedExpression TypeExpression { 9425 get { 9426 return QueriedType; 9427 } 9428 } 9429 9430 #endregion 9431 9432 CloneTo(CloneContext clonectx, Expression t)9433 protected override void CloneTo (CloneContext clonectx, Expression t) 9434 { 9435 TypeOf target = (TypeOf) t; 9436 if (QueriedType != null) 9437 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx); 9438 } 9439 ContainsEmitWithAwait()9440 public override bool ContainsEmitWithAwait () 9441 { 9442 return false; 9443 } 9444 CreateExpressionTree(ResolveContext ec)9445 public override Expression CreateExpressionTree (ResolveContext ec) 9446 { 9447 Arguments args = new Arguments (2); 9448 args.Add (new Argument (this)); 9449 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc))); 9450 return CreateExpressionFactoryCall (ec, "Constant", args); 9451 } 9452 DoResolve(ResolveContext ec)9453 protected override Expression DoResolve (ResolveContext ec) 9454 { 9455 if (eclass != ExprClass.Unresolved) 9456 return this; 9457 9458 if (typearg == null) { 9459 // 9460 // Pointer types are allowed without explicit unsafe, they are just tokens 9461 // 9462 using (ec.Set (ResolveContext.Options.UnsafeScope)) { 9463 typearg = QueriedType.ResolveAsType (ec, true); 9464 } 9465 9466 if (typearg == null) 9467 return null; 9468 9469 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 9470 ec.Report.Error (1962, QueriedType.Location, 9471 "The typeof operator cannot be used on the dynamic type"); 9472 } 9473 } 9474 9475 type = ec.BuiltinTypes.Type; 9476 9477 // Even though what is returned is a type object, it's treated as a value by the compiler. 9478 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'. 9479 eclass = ExprClass.Value; 9480 return this; 9481 } 9482 ContainsDynamicType(TypeSpec type)9483 static bool ContainsDynamicType (TypeSpec type) 9484 { 9485 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) 9486 return true; 9487 9488 var element_container = type as ElementTypeSpec; 9489 if (element_container != null) 9490 return ContainsDynamicType (element_container.Element); 9491 9492 foreach (var t in type.TypeArguments) { 9493 if (ContainsDynamicType (t)) { 9494 return true; 9495 } 9496 } 9497 9498 return false; 9499 } 9500 EncodeAttributeValue(IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)9501 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType) 9502 { 9503 // Target type is not System.Type therefore must be object 9504 // and we need to use different encoding sequence 9505 if (targetType != type) 9506 enc.Encode (type); 9507 9508 if (typearg is InflatedTypeSpec) { 9509 var gt = typearg; 9510 do { 9511 if (InflatedTypeSpec.ContainsTypeParameter (gt)) { 9512 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters", 9513 typearg.GetSignatureForError ()); 9514 return; 9515 } 9516 9517 gt = gt.DeclaringType; 9518 } while (gt != null); 9519 } 9520 9521 if (ContainsDynamicType (typearg)) { 9522 Attribute.Error_AttributeArgumentIsDynamic (rc, loc); 9523 return; 9524 } 9525 9526 enc.EncodeTypeName (typearg); 9527 } 9528 Emit(EmitContext ec)9529 public override void Emit (EmitContext ec) 9530 { 9531 ec.Emit (OpCodes.Ldtoken, typearg); 9532 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc); 9533 if (m != null) 9534 ec.Emit (OpCodes.Call, m); 9535 } 9536 Accept(StructuralVisitor visitor)9537 public override object Accept (StructuralVisitor visitor) 9538 { 9539 return visitor.Visit (this); 9540 } 9541 } 9542 9543 sealed class TypeOfMethod : TypeOfMember<MethodSpec> 9544 { TypeOfMethod(MethodSpec method, Location loc)9545 public TypeOfMethod (MethodSpec method, Location loc) 9546 : base (method, loc) 9547 { 9548 } 9549 DoResolve(ResolveContext ec)9550 protected override Expression DoResolve (ResolveContext ec) 9551 { 9552 if (member.IsConstructor) { 9553 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve (); 9554 } else { 9555 type = ec.Module.PredefinedTypes.MethodInfo.Resolve (); 9556 } 9557 9558 if (type == null) 9559 return null; 9560 9561 return base.DoResolve (ec); 9562 } 9563 Emit(EmitContext ec)9564 public override void Emit (EmitContext ec) 9565 { 9566 ec.Emit (OpCodes.Ldtoken, member); 9567 9568 base.Emit (ec); 9569 ec.Emit (OpCodes.Castclass, type); 9570 } 9571 GetTypeFromHandle(EmitContext ec)9572 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec) 9573 { 9574 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle; 9575 } 9576 GetTypeFromHandleGeneric(EmitContext ec)9577 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec) 9578 { 9579 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2; 9580 } 9581 } 9582 9583 abstract class TypeOfMember<T> : Expression where T : MemberSpec 9584 { 9585 protected readonly T member; 9586 TypeOfMember(T member, Location loc)9587 protected TypeOfMember (T member, Location loc) 9588 { 9589 this.member = member; 9590 this.loc = loc; 9591 } 9592 9593 public override bool IsSideEffectFree { 9594 get { 9595 return true; 9596 } 9597 } 9598 ContainsEmitWithAwait()9599 public override bool ContainsEmitWithAwait () 9600 { 9601 return false; 9602 } 9603 CreateExpressionTree(ResolveContext ec)9604 public override Expression CreateExpressionTree (ResolveContext ec) 9605 { 9606 Arguments args = new Arguments (2); 9607 args.Add (new Argument (this)); 9608 args.Add (new Argument (new TypeOf (type, loc))); 9609 return CreateExpressionFactoryCall (ec, "Constant", args); 9610 } 9611 DoResolve(ResolveContext ec)9612 protected override Expression DoResolve (ResolveContext ec) 9613 { 9614 eclass = ExprClass.Value; 9615 return this; 9616 } 9617 Emit(EmitContext ec)9618 public override void Emit (EmitContext ec) 9619 { 9620 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric; 9621 PredefinedMember<MethodSpec> p; 9622 if (is_generic) { 9623 p = GetTypeFromHandleGeneric (ec); 9624 ec.Emit (OpCodes.Ldtoken, member.DeclaringType); 9625 } else { 9626 p = GetTypeFromHandle (ec); 9627 } 9628 9629 var mi = p.Resolve (loc); 9630 if (mi != null) 9631 ec.Emit (OpCodes.Call, mi); 9632 } 9633 GetTypeFromHandle(EmitContext ec)9634 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec); GetTypeFromHandleGeneric(EmitContext ec)9635 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec); 9636 } 9637 9638 sealed class TypeOfField : TypeOfMember<FieldSpec> 9639 { TypeOfField(FieldSpec field, Location loc)9640 public TypeOfField (FieldSpec field, Location loc) 9641 : base (field, loc) 9642 { 9643 } 9644 DoResolve(ResolveContext ec)9645 protected override Expression DoResolve (ResolveContext ec) 9646 { 9647 type = ec.Module.PredefinedTypes.FieldInfo.Resolve (); 9648 if (type == null) 9649 return null; 9650 9651 return base.DoResolve (ec); 9652 } 9653 Emit(EmitContext ec)9654 public override void Emit (EmitContext ec) 9655 { 9656 ec.Emit (OpCodes.Ldtoken, member); 9657 base.Emit (ec); 9658 } 9659 GetTypeFromHandle(EmitContext ec)9660 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec) 9661 { 9662 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle; 9663 } 9664 GetTypeFromHandleGeneric(EmitContext ec)9665 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec) 9666 { 9667 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2; 9668 } 9669 } 9670 9671 /// <summary> 9672 /// Implements the sizeof expression 9673 /// </summary> 9674 public class SizeOf : Expression { 9675 readonly Expression texpr; 9676 TypeSpec type_queried; 9677 SizeOf(Expression queried_type, Location l)9678 public SizeOf (Expression queried_type, Location l) 9679 { 9680 this.texpr = queried_type; 9681 loc = l; 9682 } 9683 9684 public override bool IsSideEffectFree { 9685 get { 9686 return true; 9687 } 9688 } 9689 9690 public Expression TypeExpression { 9691 get { 9692 return texpr; 9693 } 9694 } 9695 ContainsEmitWithAwait()9696 public override bool ContainsEmitWithAwait () 9697 { 9698 return false; 9699 } 9700 CreateExpressionTree(ResolveContext ec)9701 public override Expression CreateExpressionTree (ResolveContext ec) 9702 { 9703 Error_PointerInsideExpressionTree (ec); 9704 return null; 9705 } 9706 DoResolve(ResolveContext ec)9707 protected override Expression DoResolve (ResolveContext ec) 9708 { 9709 type_queried = texpr.ResolveAsType (ec); 9710 if (type_queried == null) 9711 return null; 9712 9713 if (type_queried.IsEnum) 9714 type_queried = EnumSpec.GetUnderlyingType (type_queried); 9715 9716 int size_of = BuiltinTypeSpec.GetSize (type_queried); 9717 if (size_of > 0) { 9718 return new IntConstant (ec.BuiltinTypes, size_of, loc); 9719 } 9720 9721 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){ 9722 return null; 9723 } 9724 9725 if (!ec.IsUnsafe) { 9726 ec.Report.Error (233, loc, 9727 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)", 9728 type_queried.GetSignatureForError ()); 9729 } 9730 9731 type = ec.BuiltinTypes.Int; 9732 eclass = ExprClass.Value; 9733 return this; 9734 } 9735 Emit(EmitContext ec)9736 public override void Emit (EmitContext ec) 9737 { 9738 ec.Emit (OpCodes.Sizeof, type_queried); 9739 } 9740 CloneTo(CloneContext clonectx, Expression t)9741 protected override void CloneTo (CloneContext clonectx, Expression t) 9742 { 9743 } 9744 Accept(StructuralVisitor visitor)9745 public override object Accept (StructuralVisitor visitor) 9746 { 9747 return visitor.Visit (this); 9748 } 9749 } 9750 9751 /// <summary> 9752 /// Implements the qualified-alias-member (::) expression. 9753 /// </summary> 9754 public class QualifiedAliasMember : MemberAccess 9755 { 9756 readonly string alias; 9757 public static readonly string GlobalAlias = "global"; 9758 QualifiedAliasMember(string alias, string identifier, Location l)9759 public QualifiedAliasMember (string alias, string identifier, Location l) 9760 : base (null, identifier, l) 9761 { 9762 this.alias = alias; 9763 } 9764 QualifiedAliasMember(string alias, string identifier, TypeArguments targs, Location l)9765 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l) 9766 : base (null, identifier, targs, l) 9767 { 9768 this.alias = alias; 9769 } 9770 QualifiedAliasMember(string alias, string identifier, int arity, Location l)9771 public QualifiedAliasMember (string alias, string identifier, int arity, Location l) 9772 : base (null, identifier, arity, l) 9773 { 9774 this.alias = alias; 9775 } 9776 9777 public string Alias { 9778 get { 9779 return alias; 9780 } 9781 } 9782 CreateExpressionFromAlias(IMemberContext mc)9783 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc) 9784 { 9785 if (alias == GlobalAlias) 9786 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc); 9787 9788 int errors = mc.Module.Compiler.Report.Errors; 9789 var expr = mc.LookupNamespaceAlias (alias); 9790 if (expr == null) { 9791 if (errors == mc.Module.Compiler.Report.Errors) 9792 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias); 9793 9794 return null; 9795 } 9796 9797 return expr; 9798 } 9799 ResolveAsTypeOrNamespace(IMemberContext mc, bool allowUnboundTypeArguments)9800 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments) 9801 { 9802 expr = CreateExpressionFromAlias (mc); 9803 if (expr == null) 9804 return null; 9805 9806 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments); 9807 } 9808 DoResolve(ResolveContext rc)9809 protected override Expression DoResolve (ResolveContext rc) 9810 { 9811 return ResolveAsTypeOrNamespace (rc, false); 9812 } 9813 GetSignatureForError()9814 public override string GetSignatureForError () 9815 { 9816 string name = Name; 9817 if (targs != null) { 9818 name = Name + "<" + targs.GetSignatureForError () + ">"; 9819 } 9820 9821 return alias + "::" + name; 9822 } 9823 HasConditionalAccess()9824 public override bool HasConditionalAccess () 9825 { 9826 return false; 9827 } 9828 LookupNameExpression(ResolveContext rc, MemberLookupRestrictions restrictions)9829 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions) 9830 { 9831 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) { 9832 rc.Module.Compiler.Report.Error (687, loc, 9833 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead", 9834 GetSignatureForError ()); 9835 9836 return null; 9837 } 9838 9839 return DoResolve (rc); 9840 } 9841 CloneTo(CloneContext clonectx, Expression t)9842 protected override void CloneTo (CloneContext clonectx, Expression t) 9843 { 9844 // Nothing 9845 } 9846 Accept(StructuralVisitor visitor)9847 public override object Accept (StructuralVisitor visitor) 9848 { 9849 return visitor.Visit (this); 9850 } 9851 } 9852 9853 /// <summary> 9854 /// Implements the member access expression 9855 /// </summary> 9856 public class MemberAccess : ATypeNameExpression 9857 { 9858 protected Expression expr; 9859 MemberAccess(Expression expr, string id)9860 public MemberAccess (Expression expr, string id) 9861 : base (id, expr.Location) 9862 { 9863 this.expr = expr; 9864 } 9865 MemberAccess(Expression expr, string identifier, Location loc)9866 public MemberAccess (Expression expr, string identifier, Location loc) 9867 : base (identifier, loc) 9868 { 9869 this.expr = expr; 9870 } 9871 MemberAccess(Expression expr, string identifier, TypeArguments args, Location loc)9872 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc) 9873 : base (identifier, args, loc) 9874 { 9875 this.expr = expr; 9876 } 9877 MemberAccess(Expression expr, string identifier, int arity, Location loc)9878 public MemberAccess (Expression expr, string identifier, int arity, Location loc) 9879 : base (identifier, arity, loc) 9880 { 9881 this.expr = expr; 9882 } 9883 9884 public Expression LeftExpression { 9885 get { 9886 return expr; 9887 } 9888 } 9889 9890 public override Location StartLocation { 9891 get { 9892 return expr == null ? loc : expr.StartLocation; 9893 } 9894 } 9895 DoResolve(ResolveContext rc)9896 protected override Expression DoResolve (ResolveContext rc) 9897 { 9898 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess); 9899 if (e != null) 9900 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup); 9901 9902 return e; 9903 } 9904 DoResolveLValue(ResolveContext rc, Expression rhs)9905 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs) 9906 { 9907 var e = LookupNameExpression (rc, MemberLookupRestrictions.None); 9908 9909 if (e is TypeExpr) { 9910 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc); 9911 return null; 9912 } 9913 9914 if (e != null) 9915 e = e.ResolveLValue (rc, rhs); 9916 9917 return e; 9918 } 9919 Error_OperatorCannotBeApplied(ResolveContext rc, TypeSpec type)9920 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type) 9921 { 9922 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder) 9923 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value"); 9924 else 9925 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type); 9926 } 9927 HasConditionalAccess()9928 public override bool HasConditionalAccess () 9929 { 9930 return LeftExpression.HasConditionalAccess (); 9931 } 9932 IsValidDotExpression(TypeSpec type)9933 public static bool IsValidDotExpression (TypeSpec type) 9934 { 9935 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum | 9936 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType | MemberKind.ByRef; 9937 9938 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; 9939 } 9940 LookupNameExpression(ResolveContext rc, MemberLookupRestrictions restrictions)9941 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions) 9942 { 9943 var sn = expr as SimpleName; 9944 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type; 9945 9946 if (sn != null) { 9947 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity); 9948 9949 // 9950 // Resolve expression which does have type set as we need expression type 9951 // with disable flow analysis as we don't know whether left side expression 9952 // is used as variable or type 9953 // 9954 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) { 9955 expr = expr.Resolve (rc); 9956 } else if (expr is TypeParameterExpr) { 9957 expr.Error_UnexpectedKind (rc, flags, sn.Location); 9958 expr = null; 9959 } 9960 } else { 9961 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) { 9962 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) { 9963 expr = expr.Resolve (rc, flags); 9964 } 9965 } else { 9966 expr = expr.Resolve (rc, flags); 9967 } 9968 } 9969 9970 if (expr == null) 9971 return null; 9972 9973 var ns = expr as NamespaceExpression; 9974 if (ns != null) { 9975 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc); 9976 9977 if (retval == null) { 9978 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc); 9979 return null; 9980 } 9981 9982 if (Arity > 0) { 9983 if (HasTypeArguments) 9984 return new GenericTypeExpr (retval.Type, targs, loc); 9985 9986 targs.Resolve (rc, false); 9987 } 9988 9989 return retval; 9990 } 9991 9992 var cma = this as ConditionalMemberAccess; 9993 9994 MemberExpr me; 9995 TypeSpec expr_type = expr.Type; 9996 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 9997 me = expr as MemberExpr; 9998 if (me != null) 9999 me.ResolveInstanceExpression (rc, null); 10000 10001 Arguments args = new Arguments (1); 10002 args.Add (new Argument (expr)); 10003 10004 if (cma != null) 10005 return new DynamicConditionalMemberBinder (Name, args, loc); 10006 10007 return new DynamicMemberBinder (Name, args, loc); 10008 } 10009 10010 if (cma != null) { 10011 if (!IsNullPropagatingValid (expr.Type)) { 10012 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type); 10013 return null; 10014 } 10015 10016 if (expr_type.IsNullableType) { 10017 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true); 10018 expr_type = expr.Type; 10019 } 10020 } 10021 10022 if (!IsValidDotExpression (expr_type)) { 10023 Error_OperatorCannotBeApplied (rc, expr_type); 10024 return null; 10025 } 10026 10027 var lookup_arity = Arity; 10028 bool errorMode = false; 10029 Expression member_lookup; 10030 while (true) { 10031 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc); 10032 if (member_lookup == null) { 10033 // 10034 // Try to look for extension method when member lookup failed 10035 // 10036 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) { 10037 var methods = rc.LookupExtensionMethod (Name, lookup_arity); 10038 if (methods != null) { 10039 var emg = new ExtensionMethodGroupExpr (methods, expr, loc); 10040 if (HasTypeArguments) { 10041 if (!targs.Resolve (rc, false)) 10042 return null; 10043 10044 emg.SetTypeArguments (rc, targs); 10045 } 10046 10047 if (cma != null) 10048 emg.ConditionalAccess = true; 10049 10050 // TODO: it should really skip the checks bellow 10051 return emg.Resolve (rc); 10052 } 10053 } 10054 } 10055 10056 if (errorMode) { 10057 if (member_lookup == null) { 10058 var dep = expr_type.GetMissingDependencies (); 10059 if (dep != null) { 10060 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc); 10061 } else if (expr is TypeExpr) { 10062 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name); 10063 } else { 10064 Error_TypeDoesNotContainDefinition (rc, expr_type, Name); 10065 } 10066 10067 return null; 10068 } 10069 10070 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) { 10071 // Leave it to overload resolution to report correct error 10072 } else if (!(member_lookup is TypeExpr)) { 10073 // TODO: rc.SymbolRelatedToPreviousError 10074 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc); 10075 } 10076 break; 10077 } 10078 10079 if (member_lookup != null) 10080 break; 10081 10082 lookup_arity = 0; 10083 restrictions &= ~MemberLookupRestrictions.InvocableOnly; 10084 errorMode = true; 10085 } 10086 10087 TypeExpr texpr = member_lookup as TypeExpr; 10088 if (texpr != null) { 10089 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) { 10090 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead", 10091 Name, texpr.GetSignatureForError ()); 10092 } 10093 10094 if (!texpr.Type.IsAccessible (rc)) { 10095 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type); 10096 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc); 10097 return null; 10098 } 10099 10100 if (HasTypeArguments) { 10101 return new GenericTypeExpr (member_lookup.Type, targs, loc); 10102 } 10103 10104 return member_lookup; 10105 } 10106 10107 me = member_lookup as MemberExpr; 10108 10109 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) { 10110 sn = null; 10111 } 10112 10113 if (cma != null) { 10114 me.ConditionalAccess = true; 10115 } 10116 10117 me = me.ResolveMemberAccess (rc, expr, sn); 10118 10119 if (Arity > 0) { 10120 if (!targs.Resolve (rc, false)) 10121 return null; 10122 10123 me.SetTypeArguments (rc, targs); 10124 } 10125 10126 return me; 10127 } 10128 ResolveAsTypeOrNamespace(IMemberContext rc, bool allowUnboundTypeArguments)10129 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments) 10130 { 10131 FullNamedExpression fexpr = expr as FullNamedExpression; 10132 if (fexpr == null) { 10133 expr.ResolveAsType (rc); 10134 return null; 10135 } 10136 10137 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments); 10138 10139 if (expr_resolved == null) 10140 return null; 10141 10142 var ns = expr_resolved as NamespaceExpression; 10143 if (ns != null) { 10144 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc); 10145 10146 if (retval == null) { 10147 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc); 10148 } else if (Arity > 0) { 10149 if (HasTypeArguments) { 10150 retval = new GenericTypeExpr (retval.Type, targs, loc); 10151 if (retval.ResolveAsType (rc) == null) 10152 return null; 10153 } else { 10154 targs.Resolve (rc, allowUnboundTypeArguments); 10155 10156 retval = new GenericOpenTypeExpr (retval.Type, loc); 10157 } 10158 } 10159 10160 return retval; 10161 } 10162 10163 var tnew_expr = expr_resolved.ResolveAsType (rc); 10164 if (tnew_expr == null) 10165 return null; 10166 10167 TypeSpec expr_type = tnew_expr; 10168 if (TypeManager.IsGenericParameter (expr_type)) { 10169 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'", 10170 tnew_expr.GetSignatureForError ()); 10171 return null; 10172 } 10173 10174 var qam = this as QualifiedAliasMember; 10175 if (qam != null) { 10176 rc.Module.Compiler.Report.Error (431, loc, 10177 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'", 10178 qam.Alias); 10179 10180 } 10181 10182 TypeSpec nested = null; 10183 while (expr_type != null) { 10184 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false); 10185 if (nested == null) { 10186 if (expr_type == tnew_expr) { 10187 Error_IdentifierNotFound (rc, expr_type); 10188 return null; 10189 } 10190 10191 expr_type = tnew_expr; 10192 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false); 10193 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc); 10194 break; 10195 } 10196 10197 if (nested.IsAccessible (rc)) 10198 break; 10199 10200 // 10201 // Keep looking after inaccessible candidate but only if 10202 // we are not in same context as the definition itself 10203 // 10204 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition) 10205 break; 10206 10207 expr_type = expr_type.BaseType; 10208 } 10209 10210 TypeExpr texpr; 10211 if (Arity > 0) { 10212 if (HasTypeArguments) { 10213 texpr = new GenericTypeExpr (nested, targs, loc); 10214 } else { 10215 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr)); 10216 10217 texpr = new GenericOpenTypeExpr (nested, loc); 10218 } 10219 } else if (expr_resolved is GenericOpenTypeExpr) { 10220 texpr = new GenericOpenTypeExpr (nested, loc); 10221 } else { 10222 texpr = new TypeExpression (nested, loc); 10223 } 10224 10225 if (texpr.ResolveAsType (rc) == null) 10226 return null; 10227 10228 return texpr; 10229 } 10230 Error_IdentifierNotFound(IMemberContext rc, TypeSpec expr_type)10231 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type) 10232 { 10233 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false); 10234 10235 if (nested != null) { 10236 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location); 10237 return; 10238 } 10239 10240 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc); 10241 if (any_other_member != null) { 10242 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc); 10243 return; 10244 } 10245 10246 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'", 10247 Name, expr_type.GetSignatureForError ()); 10248 } 10249 Error_InvalidExpressionStatement(Report report, Location loc)10250 protected override void Error_InvalidExpressionStatement (Report report, Location loc) 10251 { 10252 base.Error_InvalidExpressionStatement (report, LeftExpression.Location); 10253 } 10254 Error_TypeDoesNotContainDefinition(ResolveContext ec, TypeSpec type, string name)10255 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name) 10256 { 10257 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) { 10258 ec.Report.SymbolRelatedToPreviousError (type); 10259 10260 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity); 10261 string missing; 10262 // a using directive or an assembly reference 10263 if (cand != null) { 10264 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive"; 10265 } else { 10266 missing = "an assembly reference"; 10267 } 10268 10269 ec.Report.Error (1061, loc, 10270 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?", 10271 type.GetSignatureForError (), name, missing); 10272 return; 10273 } 10274 10275 base.Error_TypeDoesNotContainDefinition (ec, type, name); 10276 } 10277 GetSignatureForError()10278 public override string GetSignatureForError () 10279 { 10280 return expr.GetSignatureForError () + "." + base.GetSignatureForError (); 10281 } 10282 CloneTo(CloneContext clonectx, Expression t)10283 protected override void CloneTo (CloneContext clonectx, Expression t) 10284 { 10285 MemberAccess target = (MemberAccess) t; 10286 10287 target.expr = expr.Clone (clonectx); 10288 } 10289 Accept(StructuralVisitor visitor)10290 public override object Accept (StructuralVisitor visitor) 10291 { 10292 return visitor.Visit (this); 10293 } 10294 } 10295 10296 public class ConditionalMemberAccess : MemberAccess 10297 { ConditionalMemberAccess(Expression expr, string identifier, TypeArguments args, Location loc)10298 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc) 10299 : base (expr, identifier, args, loc) 10300 { 10301 } 10302 HasConditionalAccess()10303 public override bool HasConditionalAccess () 10304 { 10305 return true; 10306 } 10307 } 10308 10309 /// <summary> 10310 /// Implements checked expressions 10311 /// </summary> 10312 public class CheckedExpr : Expression { 10313 10314 public Expression Expr; 10315 CheckedExpr(Expression e, Location l)10316 public CheckedExpr (Expression e, Location l) 10317 { 10318 Expr = e; 10319 loc = l; 10320 } 10321 ContainsEmitWithAwait()10322 public override bool ContainsEmitWithAwait () 10323 { 10324 return Expr.ContainsEmitWithAwait (); 10325 } 10326 CreateExpressionTree(ResolveContext ec)10327 public override Expression CreateExpressionTree (ResolveContext ec) 10328 { 10329 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true)) 10330 return Expr.CreateExpressionTree (ec); 10331 } 10332 DoResolve(ResolveContext ec)10333 protected override Expression DoResolve (ResolveContext ec) 10334 { 10335 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true)) 10336 Expr = Expr.Resolve (ec); 10337 10338 if (Expr == null) 10339 return null; 10340 10341 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression) 10342 return Expr; 10343 10344 eclass = Expr.eclass; 10345 type = Expr.Type; 10346 return this; 10347 } 10348 Emit(EmitContext ec)10349 public override void Emit (EmitContext ec) 10350 { 10351 using (ec.With (EmitContext.Options.CheckedScope, true)) 10352 Expr.Emit (ec); 10353 } 10354 EmitBranchable(EmitContext ec, Label target, bool on_true)10355 public override void EmitBranchable (EmitContext ec, Label target, bool on_true) 10356 { 10357 using (ec.With (EmitContext.Options.CheckedScope, true)) 10358 Expr.EmitBranchable (ec, target, on_true); 10359 } 10360 FlowAnalysis(FlowAnalysisContext fc)10361 public override void FlowAnalysis (FlowAnalysisContext fc) 10362 { 10363 Expr.FlowAnalysis (fc); 10364 } 10365 MakeExpression(BuilderContext ctx)10366 public override SLE.Expression MakeExpression (BuilderContext ctx) 10367 { 10368 using (ctx.With (BuilderContext.Options.CheckedScope, true)) { 10369 return Expr.MakeExpression (ctx); 10370 } 10371 } 10372 CloneTo(CloneContext clonectx, Expression t)10373 protected override void CloneTo (CloneContext clonectx, Expression t) 10374 { 10375 CheckedExpr target = (CheckedExpr) t; 10376 10377 target.Expr = Expr.Clone (clonectx); 10378 } 10379 Accept(StructuralVisitor visitor)10380 public override object Accept (StructuralVisitor visitor) 10381 { 10382 return visitor.Visit (this); 10383 } 10384 } 10385 10386 /// <summary> 10387 /// Implements the unchecked expression 10388 /// </summary> 10389 public class UnCheckedExpr : Expression { 10390 10391 public Expression Expr; 10392 UnCheckedExpr(Expression e, Location l)10393 public UnCheckedExpr (Expression e, Location l) 10394 { 10395 Expr = e; 10396 loc = l; 10397 } 10398 ContainsEmitWithAwait()10399 public override bool ContainsEmitWithAwait () 10400 { 10401 return Expr.ContainsEmitWithAwait (); 10402 } 10403 CreateExpressionTree(ResolveContext ec)10404 public override Expression CreateExpressionTree (ResolveContext ec) 10405 { 10406 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false)) 10407 return Expr.CreateExpressionTree (ec); 10408 } 10409 DoResolve(ResolveContext ec)10410 protected override Expression DoResolve (ResolveContext ec) 10411 { 10412 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false)) 10413 Expr = Expr.Resolve (ec); 10414 10415 if (Expr == null) 10416 return null; 10417 10418 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression) 10419 return Expr; 10420 10421 eclass = Expr.eclass; 10422 type = Expr.Type; 10423 return this; 10424 } 10425 Emit(EmitContext ec)10426 public override void Emit (EmitContext ec) 10427 { 10428 using (ec.With (EmitContext.Options.CheckedScope, false)) 10429 Expr.Emit (ec); 10430 } 10431 EmitBranchable(EmitContext ec, Label target, bool on_true)10432 public override void EmitBranchable (EmitContext ec, Label target, bool on_true) 10433 { 10434 using (ec.With (EmitContext.Options.CheckedScope, false)) 10435 Expr.EmitBranchable (ec, target, on_true); 10436 } 10437 FlowAnalysis(FlowAnalysisContext fc)10438 public override void FlowAnalysis (FlowAnalysisContext fc) 10439 { 10440 Expr.FlowAnalysis (fc); 10441 } 10442 CloneTo(CloneContext clonectx, Expression t)10443 protected override void CloneTo (CloneContext clonectx, Expression t) 10444 { 10445 UnCheckedExpr target = (UnCheckedExpr) t; 10446 10447 target.Expr = Expr.Clone (clonectx); 10448 } 10449 Accept(StructuralVisitor visitor)10450 public override object Accept (StructuralVisitor visitor) 10451 { 10452 return visitor.Visit (this); 10453 } 10454 } 10455 10456 /// <summary> 10457 /// An Element Access expression. 10458 /// 10459 /// During semantic analysis these are transformed into 10460 /// IndexerAccess, ArrayAccess or a PointerArithmetic. 10461 /// </summary> 10462 public class ElementAccess : Expression 10463 { 10464 public Arguments Arguments; 10465 public Expression Expr; 10466 bool conditional_access_receiver; 10467 ElementAccess(Expression e, Arguments args, Location loc)10468 public ElementAccess (Expression e, Arguments args, Location loc) 10469 { 10470 Expr = e; 10471 this.loc = loc; 10472 this.Arguments = args; 10473 } 10474 10475 public bool ConditionalAccess { get; set; } 10476 10477 public override Location StartLocation { 10478 get { 10479 return Expr.StartLocation; 10480 } 10481 } 10482 ContainsEmitWithAwait()10483 public override bool ContainsEmitWithAwait () 10484 { 10485 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait (); 10486 } 10487 10488 // 10489 // We perform some simple tests, and then to "split" the emit and store 10490 // code we create an instance of a different class, and return that. 10491 // CreateAccessExpression(ResolveContext ec, bool conditionalAccessReceiver)10492 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver) 10493 { 10494 if (conditionalAccessReceiver) 10495 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver); 10496 10497 Expr = Expr.Resolve (ec); 10498 10499 if (conditionalAccessReceiver) 10500 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false); 10501 10502 if (Expr == null) 10503 return null; 10504 10505 type = Expr.Type; 10506 10507 if (ConditionalAccess && !IsNullPropagatingValid (type)) { 10508 Error_OperatorCannotBeApplied (ec, loc, "?", type); 10509 return null; 10510 } 10511 10512 if (type.IsArray) { 10513 var aa = new ArrayAccess (this, loc) { 10514 ConditionalAccess = ConditionalAccess, 10515 }; 10516 10517 if (conditionalAccessReceiver) 10518 aa.SetConditionalAccessReceiver (); 10519 10520 return aa; 10521 } 10522 10523 if (type.IsPointer) 10524 return Expr.MakePointerAccess (ec, type, Arguments); 10525 10526 FieldExpr fe = Expr as FieldExpr; 10527 if (fe != null) { 10528 var ff = fe.Spec as FixedFieldSpec; 10529 if (ff != null) { 10530 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments); 10531 } 10532 } 10533 10534 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false); 10535 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 10536 var indexer = new IndexerExpr (indexers, type, this) { 10537 ConditionalAccess = ConditionalAccess 10538 }; 10539 10540 if (conditionalAccessReceiver) 10541 indexer.SetConditionalAccessReceiver (); 10542 10543 return indexer; 10544 } 10545 10546 Error_CannotApplyIndexing (ec, type, loc); 10547 10548 return null; 10549 } 10550 CreateExpressionTree(ResolveContext ec)10551 public override Expression CreateExpressionTree (ResolveContext ec) 10552 { 10553 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments, 10554 Expr.CreateExpressionTree (ec)); 10555 10556 return CreateExpressionFactoryCall (ec, "ArrayIndex", args); 10557 } 10558 Error_CannotApplyIndexing(ResolveContext rc, TypeSpec type, Location loc)10559 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc) 10560 { 10561 if (type != InternalType.ErrorType) { 10562 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'", 10563 type.GetSignatureForError ()); 10564 } 10565 } 10566 HasConditionalAccess()10567 public override bool HasConditionalAccess () 10568 { 10569 return ConditionalAccess || Expr.HasConditionalAccess (); 10570 } 10571 ResolveConditionalAccessReceiver(ResolveContext rc)10572 void ResolveConditionalAccessReceiver (ResolveContext rc) 10573 { 10574 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) { 10575 conditional_access_receiver = true; 10576 } 10577 } 10578 DoResolve(ResolveContext rc)10579 protected override Expression DoResolve (ResolveContext rc) 10580 { 10581 ResolveConditionalAccessReceiver (rc); 10582 10583 var expr = CreateAccessExpression (rc, conditional_access_receiver); 10584 if (expr == null) 10585 return null; 10586 10587 return expr.Resolve (rc); 10588 } 10589 DoResolveLValue(ResolveContext ec, Expression rhs)10590 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs) 10591 { 10592 var res = CreateAccessExpression (ec, false); 10593 if (res == null) 10594 return null; 10595 10596 return res.ResolveLValue (ec, rhs); 10597 } 10598 Emit(EmitContext ec)10599 public override void Emit (EmitContext ec) 10600 { 10601 throw new Exception ("Should never be reached"); 10602 } 10603 FlowAnalysis(FlowAnalysisContext fc)10604 public override void FlowAnalysis (FlowAnalysisContext fc) 10605 { 10606 Expr.FlowAnalysis (fc); 10607 10608 Arguments.FlowAnalysis (fc); 10609 } 10610 GetSignatureForError()10611 public override string GetSignatureForError () 10612 { 10613 return Expr.GetSignatureForError (); 10614 } 10615 CloneTo(CloneContext clonectx, Expression t)10616 protected override void CloneTo (CloneContext clonectx, Expression t) 10617 { 10618 ElementAccess target = (ElementAccess) t; 10619 10620 target.Expr = Expr.Clone (clonectx); 10621 if (Arguments != null) 10622 target.Arguments = Arguments.Clone (clonectx); 10623 } 10624 Accept(StructuralVisitor visitor)10625 public override object Accept (StructuralVisitor visitor) 10626 { 10627 return visitor.Visit (this); 10628 } 10629 } 10630 10631 /// <summary> 10632 /// Implements array access 10633 /// </summary> 10634 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation { 10635 // 10636 // Points to our "data" repository 10637 // 10638 ElementAccess ea; 10639 10640 LocalTemporary temp; 10641 bool prepared; 10642 bool? has_await_args; 10643 bool conditional_access_receiver; 10644 ArrayAccess(ElementAccess ea_data, Location l)10645 public ArrayAccess (ElementAccess ea_data, Location l) 10646 { 10647 ea = ea_data; 10648 loc = l; 10649 } 10650 10651 public bool ConditionalAccess { get; set; } 10652 AddressOf(EmitContext ec, AddressOp mode)10653 public void AddressOf (EmitContext ec, AddressOp mode) 10654 { 10655 var ac = (ArrayContainer) ea.Expr.Type; 10656 10657 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) { 10658 LoadInstanceAndArguments (ec, false, true); 10659 } 10660 10661 LoadInstanceAndArguments (ec, false, false); 10662 10663 if (ac.Element.IsGenericParameter && mode == AddressOp.Load) 10664 ec.Emit (OpCodes.Readonly); 10665 10666 ec.EmitArrayAddress (ac); 10667 } 10668 CreateExpressionTree(ResolveContext ec)10669 public override Expression CreateExpressionTree (ResolveContext ec) 10670 { 10671 if (ConditionalAccess) 10672 Error_NullShortCircuitInsideExpressionTree (ec); 10673 10674 return ea.CreateExpressionTree (ec); 10675 } 10676 ContainsEmitWithAwait()10677 public override bool ContainsEmitWithAwait () 10678 { 10679 return ea.ContainsEmitWithAwait (); 10680 } 10681 DoResolveLValue(ResolveContext ec, Expression right_side)10682 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side) 10683 { 10684 if (HasConditionalAccess ()) 10685 Error_NullPropagatingLValue (ec); 10686 10687 return DoResolve (ec); 10688 } 10689 DoResolve(ResolveContext ec)10690 protected override Expression DoResolve (ResolveContext ec) 10691 { 10692 // dynamic is used per argument in ConvertExpressionToArrayIndex case 10693 bool dynamic; 10694 ea.Arguments.Resolve (ec, out dynamic); 10695 10696 var ac = ea.Expr.Type as ArrayContainer; 10697 int rank = ea.Arguments.Count; 10698 if (ac.Rank != rank) { 10699 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'", 10700 rank.ToString (), ac.Rank.ToString ()); 10701 return null; 10702 } 10703 10704 type = ac.Element; 10705 if (type.IsPointer) { 10706 if (ec.CurrentIterator != null) { 10707 UnsafeInsideIteratorError (ec, ea.Location); 10708 } else if (!ec.IsUnsafe) { 10709 UnsafeError (ec, ea.Location); 10710 } 10711 } 10712 10713 if (conditional_access_receiver) 10714 type = LiftMemberType (ec, type); 10715 10716 foreach (Argument a in ea.Arguments) { 10717 var na = a as NamedArgument; 10718 if (na != null) 10719 ElementAccess.Error_NamedArgument (na, ec.Report); 10720 10721 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr); 10722 } 10723 10724 eclass = ExprClass.Variable; 10725 10726 return this; 10727 } 10728 Error_NegativeArrayIndex(ResolveContext ec, Location loc)10729 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc) 10730 { 10731 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)"); 10732 } 10733 FlowAnalysis(FlowAnalysisContext fc)10734 public override void FlowAnalysis (FlowAnalysisContext fc) 10735 { 10736 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null; 10737 10738 ea.FlowAnalysis (fc); 10739 10740 if (conditional_access_receiver) 10741 fc.DefiniteAssignment = da; 10742 } 10743 HasConditionalAccess()10744 public override bool HasConditionalAccess () 10745 { 10746 return ConditionalAccess || ea.Expr.HasConditionalAccess (); 10747 } 10748 10749 // 10750 // Load the array arguments into the stack. 10751 // LoadInstanceAndArguments(EmitContext ec, bool duplicateArguments, bool prepareAwait)10752 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait) 10753 { 10754 if (prepareAwait) { 10755 ea.Expr = ea.Expr.EmitToField (ec); 10756 } else { 10757 var ie = new InstanceEmitter (ea.Expr, false); 10758 ie.Emit (ec, ConditionalAccess); 10759 10760 if (duplicateArguments) { 10761 ec.Emit (OpCodes.Dup); 10762 10763 var copy = new LocalTemporary (ea.Expr.Type); 10764 copy.Store (ec); 10765 ea.Expr = copy; 10766 } 10767 } 10768 10769 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait); 10770 if (dup_args != null) 10771 ea.Arguments = dup_args; 10772 } 10773 Emit(EmitContext ec, bool leave_copy)10774 public void Emit (EmitContext ec, bool leave_copy) 10775 { 10776 if (prepared) { 10777 ec.EmitLoadFromPtr (type); 10778 } else { 10779 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) { 10780 LoadInstanceAndArguments (ec, false, true); 10781 } 10782 10783 if (conditional_access_receiver) 10784 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ()); 10785 10786 var ac = (ArrayContainer) ea.Expr.Type; 10787 LoadInstanceAndArguments (ec, false, false); 10788 ec.EmitArrayLoad (ac); 10789 10790 if (conditional_access_receiver) 10791 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null); 10792 } 10793 10794 if (leave_copy) { 10795 ec.Emit (OpCodes.Dup); 10796 temp = new LocalTemporary (this.type); 10797 temp.Store (ec); 10798 } 10799 } 10800 Emit(EmitContext ec)10801 public override void Emit (EmitContext ec) 10802 { 10803 Emit (ec, false); 10804 } 10805 EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool isCompound)10806 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound) 10807 { 10808 var ac = (ArrayContainer) ea.Expr.Type; 10809 TypeSpec t = source.Type; 10810 10811 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ()); 10812 10813 // 10814 // When we are dealing with a struct, get the address of it to avoid value copy 10815 // Same cannot be done for reference type because array covariance and the 10816 // check in ldelema requires to specify the type of array element stored at the index 10817 // 10818 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) { 10819 LoadInstanceAndArguments (ec, false, has_await_args.Value); 10820 10821 if (has_await_args.Value) { 10822 if (source.ContainsEmitWithAwait ()) { 10823 source = source.EmitToField (ec); 10824 isCompound = false; 10825 prepared = true; 10826 } 10827 10828 LoadInstanceAndArguments (ec, isCompound, false); 10829 } else { 10830 prepared = true; 10831 } 10832 10833 ec.EmitArrayAddress (ac); 10834 10835 if (isCompound) { 10836 ec.Emit (OpCodes.Dup); 10837 prepared = true; 10838 } 10839 } else { 10840 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value); 10841 10842 if (has_await_args.Value) { 10843 if (source.ContainsEmitWithAwait ()) 10844 source = source.EmitToField (ec); 10845 10846 LoadInstanceAndArguments (ec, false, false); 10847 } 10848 } 10849 10850 source.Emit (ec); 10851 10852 if (isCompound) { 10853 var lt = ea.Expr as LocalTemporary; 10854 if (lt != null) 10855 lt.Release (ec); 10856 } 10857 10858 if (leave_copy) { 10859 ec.Emit (OpCodes.Dup); 10860 temp = new LocalTemporary (this.type); 10861 temp.Store (ec); 10862 } 10863 10864 if (prepared) { 10865 ec.EmitStoreFromPtr (t); 10866 } else { 10867 ec.EmitArrayStore (ac); 10868 } 10869 10870 if (temp != null) { 10871 temp.Emit (ec); 10872 temp.Release (ec); 10873 } 10874 } 10875 EmitToField(EmitContext ec)10876 public override Expression EmitToField (EmitContext ec) 10877 { 10878 // 10879 // Have to be specialized for arrays to get access to 10880 // underlying element. Instead of another result copy we 10881 // need direct access to element 10882 // 10883 // Consider: 10884 // 10885 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]); 10886 // 10887 ea.Expr = ea.Expr.EmitToField (ec); 10888 ea.Arguments = ea.Arguments.Emit (ec, false, true); 10889 return this; 10890 } 10891 MakeAssignExpression(BuilderContext ctx, Expression source)10892 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source) 10893 { 10894 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx)); 10895 } 10896 MakeExpression(BuilderContext ctx)10897 public override SLE.Expression MakeExpression (BuilderContext ctx) 10898 { 10899 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx)); 10900 } 10901 MakeExpressionArguments(BuilderContext ctx)10902 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx) 10903 { 10904 using (ctx.With (BuilderContext.Options.CheckedScope, true)) { 10905 return Arguments.MakeExpression (ea.Arguments, ctx); 10906 } 10907 } 10908 SetConditionalAccessReceiver()10909 public void SetConditionalAccessReceiver () 10910 { 10911 conditional_access_receiver = true; 10912 } 10913 } 10914 10915 // 10916 // Indexer access expression 10917 // 10918 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider 10919 { 10920 IList<MemberSpec> indexers; 10921 Arguments arguments; 10922 TypeSpec queried_type; 10923 IndexerExpr(IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)10924 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea) 10925 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location) 10926 { 10927 } 10928 IndexerExpr(IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)10929 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc) 10930 : base (loc) 10931 { 10932 this.indexers = indexers; 10933 this.queried_type = queriedType; 10934 this.InstanceExpression = instance; 10935 this.arguments = args; 10936 } 10937 10938 #region Properties 10939 10940 protected override Arguments Arguments { 10941 get { 10942 return arguments; 10943 } 10944 set { 10945 arguments = value; 10946 } 10947 } 10948 10949 protected override TypeSpec DeclaringType { 10950 get { 10951 return best_candidate.DeclaringType; 10952 } 10953 } 10954 10955 public override bool IsInstance { 10956 get { 10957 return true; 10958 } 10959 } 10960 10961 public override bool IsStatic { 10962 get { 10963 return false; 10964 } 10965 } 10966 10967 public override string KindName { 10968 get { return "indexer"; } 10969 } 10970 10971 public override string Name { 10972 get { 10973 return "this"; 10974 } 10975 } 10976 10977 #endregion 10978 ContainsEmitWithAwait()10979 public override bool ContainsEmitWithAwait () 10980 { 10981 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait (); 10982 } 10983 CreateExpressionTree(ResolveContext ec)10984 public override Expression CreateExpressionTree (ResolveContext ec) 10985 { 10986 if (ConditionalAccess) { 10987 Error_NullShortCircuitInsideExpressionTree (ec); 10988 } 10989 10990 Arguments args = Arguments.CreateForExpressionTree (ec, arguments, 10991 InstanceExpression.CreateExpressionTree (ec), 10992 new TypeOfMethod (Getter, loc)); 10993 10994 return CreateExpressionFactoryCall (ec, "Call", args); 10995 } 10996 EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool isCompound)10997 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound) 10998 { 10999 LocalTemporary await_source_arg = null; 11000 11001 if (isCompound) { 11002 emitting_compound_assignment = true; 11003 if (source is DynamicExpressionStatement) { 11004 Emit (ec, false); 11005 } else { 11006 source.Emit (ec); 11007 } 11008 emitting_compound_assignment = false; 11009 11010 if (has_await_arguments) { 11011 await_source_arg = new LocalTemporary (Type); 11012 await_source_arg.Store (ec); 11013 11014 arguments.Add (new Argument (await_source_arg)); 11015 11016 if (leave_copy) { 11017 temp = await_source_arg; 11018 } 11019 11020 has_await_arguments = false; 11021 } else { 11022 arguments = null; 11023 11024 if (leave_copy) { 11025 ec.Emit (OpCodes.Dup); 11026 temp = new LocalTemporary (Type); 11027 temp.Store (ec); 11028 } 11029 } 11030 } else { 11031 if (leave_copy) { 11032 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) { 11033 source = source.EmitToField (ec); 11034 } else { 11035 temp = new LocalTemporary (Type); 11036 source.Emit (ec); 11037 temp.Store (ec); 11038 source = temp; 11039 } 11040 } 11041 11042 arguments.Add (new Argument (source)); 11043 } 11044 11045 var call = new CallEmitter (); 11046 call.InstanceExpression = InstanceExpression; 11047 if (arguments == null) 11048 call.InstanceExpressionOnStack = true; 11049 11050 call.Emit (ec, Setter, arguments, loc); 11051 11052 if (temp != null) { 11053 temp.Emit (ec); 11054 temp.Release (ec); 11055 } else if (leave_copy) { 11056 source.Emit (ec); 11057 } 11058 11059 if (await_source_arg != null) { 11060 await_source_arg.Release (ec); 11061 } 11062 } 11063 FlowAnalysis(FlowAnalysisContext fc)11064 public override void FlowAnalysis (FlowAnalysisContext fc) 11065 { 11066 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null; 11067 11068 base.FlowAnalysis (fc); 11069 arguments.FlowAnalysis (fc); 11070 11071 if (conditional_access_receiver) 11072 fc.DefiniteAssignment = da; 11073 } 11074 GetSignatureForError()11075 public override string GetSignatureForError () 11076 { 11077 return best_candidate.GetSignatureForError (); 11078 } 11079 MakeAssignExpression(BuilderContext ctx, Expression source)11080 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source) 11081 { 11082 #if STATIC 11083 throw new NotSupportedException (); 11084 #else 11085 var value = new[] { source.MakeExpression (ctx) }; 11086 var args = Arguments.MakeExpression (arguments, ctx).Concat (value); 11087 return SLE.Expression.Block ( 11088 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args), 11089 value [0]); 11090 #endif 11091 } 11092 MakeExpression(BuilderContext ctx)11093 public override SLE.Expression MakeExpression (BuilderContext ctx) 11094 { 11095 #if STATIC 11096 return base.MakeExpression (ctx); 11097 #else 11098 var args = Arguments.MakeExpression (arguments, ctx); 11099 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args); 11100 #endif 11101 } 11102 OverloadResolve(ResolveContext rc, Expression right_side)11103 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side) 11104 { 11105 if (best_candidate != null) 11106 return this; 11107 11108 eclass = ExprClass.IndexerAccess; 11109 11110 bool dynamic; 11111 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) { 11112 arguments.Resolve (rc, out dynamic); 11113 } 11114 11115 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 11116 dynamic = true; 11117 } else { 11118 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc); 11119 res.BaseMembersProvider = this; 11120 res.InstanceQualifier = this; 11121 11122 // TODO: Do I need 2 argument sets? 11123 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments); 11124 if (best_candidate != null) 11125 type = res.BestCandidateReturnType; 11126 else if (!res.BestCandidateIsDynamic) 11127 return null; 11128 } 11129 11130 // 11131 // It has dynamic arguments 11132 // 11133 if (dynamic) { 11134 Arguments args = new Arguments (arguments.Count + 1); 11135 if (IsBase) { 11136 rc.Report.Error (1972, loc, 11137 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access"); 11138 } else { 11139 args.Add (new Argument (InstanceExpression)); 11140 } 11141 args.AddRange (arguments); 11142 11143 best_candidate = null; 11144 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc); 11145 } 11146 11147 // 11148 // Try to avoid resolving left expression again 11149 // 11150 if (right_side != null) 11151 ResolveInstanceExpression (rc, right_side); 11152 11153 return this; 11154 } 11155 CloneTo(CloneContext clonectx, Expression t)11156 protected override void CloneTo (CloneContext clonectx, Expression t) 11157 { 11158 IndexerExpr target = (IndexerExpr) t; 11159 11160 if (arguments != null) 11161 target.arguments = arguments.Clone (clonectx); 11162 } 11163 SetConditionalAccessReceiver()11164 public void SetConditionalAccessReceiver () 11165 { 11166 conditional_access_receiver = true; 11167 } 11168 SetTypeArguments(ResolveContext ec, TypeArguments ta)11169 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta) 11170 { 11171 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc); 11172 } 11173 11174 #region IBaseMembersProvider Members 11175 OverloadResolver.IBaseMembersProvider.GetBaseMembers(TypeSpec type)11176 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type) 11177 { 11178 var baseType = type.BaseType; 11179 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false); 11180 11181 if (members == null && !type.IsInterface) { 11182 var tps = queried_type as TypeParameterSpec; 11183 if (tps != null) 11184 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias); 11185 } 11186 11187 return members; 11188 } 11189 OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters(MemberSpec member)11190 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member) 11191 { 11192 if (queried_type == member.DeclaringType) 11193 return null; 11194 11195 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null); 11196 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember; 11197 } 11198 OverloadResolver.IBaseMembersProvider.LookupExtensionMethod(ResolveContext rc)11199 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc) 11200 { 11201 return null; 11202 } 11203 11204 #endregion 11205 } 11206 11207 // 11208 // A base access expression 11209 // 11210 public class BaseThis : This 11211 { BaseThis(Location loc)11212 public BaseThis (Location loc) 11213 : base (loc) 11214 { 11215 } 11216 BaseThis(TypeSpec type, Location loc)11217 public BaseThis (TypeSpec type, Location loc) 11218 : base (loc) 11219 { 11220 this.type = type; 11221 eclass = ExprClass.Variable; 11222 } 11223 11224 #region Properties 11225 11226 public override string Name { 11227 get { 11228 return "base"; 11229 } 11230 } 11231 11232 #endregion 11233 CreateExpressionTree(ResolveContext ec)11234 public override Expression CreateExpressionTree (ResolveContext ec) 11235 { 11236 ec.Report.Error (831, loc, "An expression tree may not contain a base access"); 11237 return base.CreateExpressionTree (ec); 11238 } 11239 Emit(EmitContext ec)11240 public override void Emit (EmitContext ec) 11241 { 11242 base.Emit (ec); 11243 11244 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) { 11245 var context_type = ec.CurrentType; 11246 ec.Emit (OpCodes.Ldobj, context_type); 11247 ec.Emit (OpCodes.Box, context_type); 11248 } 11249 } 11250 Error_ThisNotAvailable(ResolveContext ec)11251 protected override void Error_ThisNotAvailable (ResolveContext ec) 11252 { 11253 if (ec.IsStatic) { 11254 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method"); 11255 } else { 11256 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context"); 11257 } 11258 } 11259 ResolveBase(ResolveContext ec)11260 public override void ResolveBase (ResolveContext ec) 11261 { 11262 base.ResolveBase (ec); 11263 type = ec.CurrentType.BaseType; 11264 } 11265 Accept(StructuralVisitor visitor)11266 public override object Accept (StructuralVisitor visitor) 11267 { 11268 return visitor.Visit (this); 11269 } 11270 } 11271 11272 /// <summary> 11273 /// This class exists solely to pass the Type around and to be a dummy 11274 /// that can be passed to the conversion functions (this is used by 11275 /// foreach implementation to typecast the object return value from 11276 /// get_Current into the proper type. All code has been generated and 11277 /// we only care about the side effect conversions to be performed 11278 /// 11279 /// This is also now used as a placeholder where a no-action expression 11280 /// is needed (the `New' class). 11281 /// </summary> 11282 public class EmptyExpression : Expression 11283 { 11284 sealed class OutAccessExpression : EmptyExpression 11285 { OutAccessExpression(TypeSpec t)11286 public OutAccessExpression (TypeSpec t) 11287 : base (t) 11288 { 11289 } 11290 DoResolveLValue(ResolveContext rc, Expression right_side)11291 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) 11292 { 11293 rc.Report.Error (206, right_side.Location, 11294 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter"); 11295 11296 return null; 11297 } 11298 } 11299 11300 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType); 11301 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType); 11302 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType); 11303 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType); 11304 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType); 11305 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType); 11306 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType); 11307 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType); 11308 EmptyExpression(TypeSpec t)11309 public EmptyExpression (TypeSpec t) 11310 { 11311 type = t; 11312 eclass = ExprClass.Value; 11313 loc = Location.Null; 11314 } 11315 CloneTo(CloneContext clonectx, Expression target)11316 protected override void CloneTo (CloneContext clonectx, Expression target) 11317 { 11318 } 11319 ContainsEmitWithAwait()11320 public override bool ContainsEmitWithAwait () 11321 { 11322 return false; 11323 } 11324 CreateExpressionTree(ResolveContext ec)11325 public override Expression CreateExpressionTree (ResolveContext ec) 11326 { 11327 throw new NotSupportedException ("ET"); 11328 } 11329 DoResolve(ResolveContext ec)11330 protected override Expression DoResolve (ResolveContext ec) 11331 { 11332 return this; 11333 } 11334 Emit(EmitContext ec)11335 public override void Emit (EmitContext ec) 11336 { 11337 // nothing, as we only exist to not do anything. 11338 } 11339 EmitBranchable(EmitContext ec, Label target, bool on_true)11340 public override void EmitBranchable (EmitContext ec, Label target, bool on_true) 11341 { 11342 } 11343 EmitSideEffect(EmitContext ec)11344 public override void EmitSideEffect (EmitContext ec) 11345 { 11346 } 11347 Accept(StructuralVisitor visitor)11348 public override object Accept (StructuralVisitor visitor) 11349 { 11350 return visitor.Visit (this); 11351 } 11352 } 11353 11354 sealed class EmptyAwaitExpression : EmptyExpression 11355 { EmptyAwaitExpression(TypeSpec type)11356 public EmptyAwaitExpression (TypeSpec type) 11357 : base (type) 11358 { 11359 } 11360 ContainsEmitWithAwait()11361 public override bool ContainsEmitWithAwait () 11362 { 11363 return true; 11364 } 11365 } 11366 11367 // 11368 // Empty statement expression 11369 // 11370 public sealed class EmptyExpressionStatement : ExpressionStatement 11371 { 11372 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement (); 11373 EmptyExpressionStatement()11374 private EmptyExpressionStatement () 11375 { 11376 loc = Location.Null; 11377 } 11378 ContainsEmitWithAwait()11379 public override bool ContainsEmitWithAwait () 11380 { 11381 return false; 11382 } 11383 CreateExpressionTree(ResolveContext ec)11384 public override Expression CreateExpressionTree (ResolveContext ec) 11385 { 11386 return null; 11387 } 11388 EmitStatement(EmitContext ec)11389 public override void EmitStatement (EmitContext ec) 11390 { 11391 // Do nothing 11392 } 11393 DoResolve(ResolveContext ec)11394 protected override Expression DoResolve (ResolveContext ec) 11395 { 11396 eclass = ExprClass.Value; 11397 type = ec.BuiltinTypes.Object; 11398 return this; 11399 } 11400 Emit(EmitContext ec)11401 public override void Emit (EmitContext ec) 11402 { 11403 // Do nothing 11404 } 11405 Accept(StructuralVisitor visitor)11406 public override object Accept (StructuralVisitor visitor) 11407 { 11408 return visitor.Visit (this); 11409 } 11410 } 11411 11412 public class ErrorExpression : EmptyExpression 11413 { 11414 public static readonly ErrorExpression Instance = new ErrorExpression (); 11415 ErrorExpression()11416 private ErrorExpression () 11417 : base (InternalType.ErrorType) 11418 { 11419 } 11420 CreateExpressionTree(ResolveContext ec)11421 public override Expression CreateExpressionTree (ResolveContext ec) 11422 { 11423 return this; 11424 } 11425 DoResolveLValue(ResolveContext rc, Expression right_side)11426 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) 11427 { 11428 return this; 11429 } 11430 Error_ValueAssignment(ResolveContext rc, Expression rhs)11431 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs) 11432 { 11433 } 11434 Error_UnexpectedKind(ResolveContext ec, ResolveFlags flags, Location loc)11435 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc) 11436 { 11437 } 11438 Error_ValueCannotBeConverted(ResolveContext ec, TypeSpec target, bool expl)11439 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl) 11440 { 11441 } 11442 Error_OperatorCannotBeApplied(ResolveContext rc, Location loc, string oper, TypeSpec t)11443 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t) 11444 { 11445 } 11446 Accept(StructuralVisitor visitor)11447 public override object Accept (StructuralVisitor visitor) 11448 { 11449 return visitor.Visit (this); 11450 } 11451 } 11452 11453 public class UserCast : Expression { 11454 MethodSpec method; 11455 Expression source; 11456 UserCast(MethodSpec method, Expression source, Location l)11457 public UserCast (MethodSpec method, Expression source, Location l) 11458 { 11459 if (source == null) 11460 throw new ArgumentNullException ("source"); 11461 11462 this.method = method; 11463 this.source = source; 11464 type = method.ReturnType; 11465 loc = l; 11466 } 11467 11468 public Expression Source { 11469 get { 11470 return source; 11471 } 11472 set { 11473 source = value; 11474 } 11475 } 11476 ContainsEmitWithAwait()11477 public override bool ContainsEmitWithAwait () 11478 { 11479 return source.ContainsEmitWithAwait (); 11480 } 11481 CreateExpressionTree(ResolveContext ec)11482 public override Expression CreateExpressionTree (ResolveContext ec) 11483 { 11484 Arguments args = new Arguments (3); 11485 args.Add (new Argument (source.CreateExpressionTree (ec))); 11486 args.Add (new Argument (new TypeOf (type, loc))); 11487 args.Add (new Argument (new TypeOfMethod (method, loc))); 11488 return CreateExpressionFactoryCall (ec, "Convert", args); 11489 } 11490 DoResolve(ResolveContext ec)11491 protected override Expression DoResolve (ResolveContext ec) 11492 { 11493 method.CheckObsoleteness (ec, source.Location); 11494 11495 eclass = ExprClass.Value; 11496 return this; 11497 } 11498 Emit(EmitContext ec)11499 public override void Emit (EmitContext ec) 11500 { 11501 source.Emit (ec); 11502 ec.MarkCallEntry (loc); 11503 ec.Emit (OpCodes.Call, method); 11504 } 11505 FlowAnalysis(FlowAnalysisContext fc)11506 public override void FlowAnalysis (FlowAnalysisContext fc) 11507 { 11508 source.FlowAnalysis (fc); 11509 } 11510 GetSignatureForError()11511 public override string GetSignatureForError () 11512 { 11513 return TypeManager.CSharpSignature (method); 11514 } 11515 MakeExpression(BuilderContext ctx)11516 public override SLE.Expression MakeExpression (BuilderContext ctx) 11517 { 11518 #if STATIC 11519 return base.MakeExpression (ctx); 11520 #else 11521 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ()); 11522 #endif 11523 } 11524 } 11525 11526 // 11527 // Holds additional type specifiers like ?, *, [] 11528 // 11529 public class ComposedTypeSpecifier 11530 { 11531 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null); 11532 11533 public readonly int Dimension; 11534 public readonly Location Location; 11535 ComposedTypeSpecifier(int specifier, Location loc)11536 public ComposedTypeSpecifier (int specifier, Location loc) 11537 { 11538 this.Dimension = specifier; 11539 this.Location = loc; 11540 } 11541 11542 #region Properties 11543 public bool IsNullable { 11544 get { 11545 return Dimension == -1; 11546 } 11547 } 11548 11549 public bool IsPointer { 11550 get { 11551 return Dimension == -2; 11552 } 11553 } 11554 11555 public ComposedTypeSpecifier Next { get; set; } 11556 11557 #endregion 11558 CreateArrayDimension(int dimension, Location loc)11559 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc) 11560 { 11561 return new ComposedTypeSpecifier (dimension, loc); 11562 } 11563 CreateNullable(Location loc)11564 public static ComposedTypeSpecifier CreateNullable (Location loc) 11565 { 11566 return new ComposedTypeSpecifier (-1, loc); 11567 } 11568 CreatePointer(Location loc)11569 public static ComposedTypeSpecifier CreatePointer (Location loc) 11570 { 11571 return new ComposedTypeSpecifier (-2, loc); 11572 } 11573 GetSignatureForError()11574 public string GetSignatureForError () 11575 { 11576 string s = 11577 IsPointer ? "*" : 11578 IsNullable ? "?" : 11579 ArrayContainer.GetPostfixSignature (Dimension); 11580 11581 return Next != null ? s + Next.GetSignatureForError () : s; 11582 } 11583 } 11584 11585 // <summary> 11586 // This class is used to "construct" the type during a typecast 11587 // operation. Since the Type.GetType class in .NET can parse 11588 // the type specification, we just use this to construct the type 11589 // one bit at a time. 11590 // </summary> 11591 public class ComposedCast : TypeExpr { 11592 FullNamedExpression left; 11593 ComposedTypeSpecifier spec; 11594 ComposedCast(FullNamedExpression left, ComposedTypeSpecifier spec)11595 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec) 11596 { 11597 if (spec == null) 11598 throw new ArgumentNullException ("spec"); 11599 11600 this.left = left; 11601 this.spec = spec; 11602 this.loc = left.Location; 11603 } 11604 ResolveAsType(IMemberContext ec, bool allowUnboundTypeArguments)11605 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments) 11606 { 11607 type = left.ResolveAsType (ec); 11608 if (type == null) 11609 return null; 11610 11611 eclass = ExprClass.Type; 11612 11613 var single_spec = spec; 11614 11615 if (single_spec.IsNullable) { 11616 type = new Nullable.NullableType (type, loc).ResolveAsType (ec); 11617 if (type == null) 11618 return null; 11619 11620 single_spec = single_spec.Next; 11621 } else if (single_spec.IsPointer) { 11622 // 11623 // Declared fields cannot have unmanaged check done before all types are defined 11624 // 11625 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc)) 11626 return null; 11627 11628 var rc = ec as ResolveContext; 11629 if (rc?.CurrentIterator != null) { 11630 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc); 11631 } else if (!ec.IsUnsafe) { 11632 UnsafeError (ec.Module.Compiler.Report, loc); 11633 } 11634 11635 do { 11636 type = PointerContainer.MakeType (ec.Module, type); 11637 single_spec = single_spec.Next; 11638 } while (single_spec != null && single_spec.IsPointer); 11639 } 11640 11641 if (single_spec != null && single_spec.Dimension > 0) { 11642 if (type.IsSpecialRuntimeType || type.IsByRefLike) { 11643 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ()); 11644 } else if (type.IsStatic) { 11645 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type); 11646 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'", 11647 type.GetSignatureForError ()); 11648 } else { 11649 MakeArray (ec.Module, single_spec); 11650 } 11651 } 11652 11653 return type; 11654 } 11655 MakeArray(ModuleContainer module, ComposedTypeSpecifier spec)11656 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec) 11657 { 11658 if (spec.Next != null) 11659 MakeArray (module, spec.Next); 11660 11661 type = ArrayContainer.MakeType (module, type, spec.Dimension); 11662 } 11663 GetSignatureForError()11664 public override string GetSignatureForError () 11665 { 11666 return left.GetSignatureForError () + spec.GetSignatureForError (); 11667 } 11668 Accept(StructuralVisitor visitor)11669 public override object Accept (StructuralVisitor visitor) 11670 { 11671 return visitor.Visit (this); 11672 } 11673 } 11674 11675 class ReferenceTypeExpr : TypeExpr 11676 { 11677 FullNamedExpression element; 11678 readonly bool readOnly; 11679 ReferenceTypeExpr(FullNamedExpression element, bool readOnly, Location loc)11680 public ReferenceTypeExpr (FullNamedExpression element, bool readOnly, Location loc) 11681 : this (element, loc) 11682 { 11683 this.readOnly = readOnly; 11684 } 11685 ReferenceTypeExpr(FullNamedExpression element, Location loc)11686 public ReferenceTypeExpr (FullNamedExpression element, Location loc) 11687 { 11688 this.element = element; 11689 this.loc = loc; 11690 } 11691 ResolveAsType(IMemberContext mc, bool allowUnboundTypeArguments = false)11692 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false) 11693 { 11694 type = element.ResolveAsType (mc); 11695 if (type == null) 11696 return null; 11697 11698 eclass = ExprClass.Type; 11699 type = readOnly ? 11700 ReadOnlyReferenceContainer.MakeType (mc.Module, type) : 11701 ReferenceContainer.MakeType (mc.Module, type); 11702 11703 return type; 11704 } 11705 GetSignatureForError()11706 public override string GetSignatureForError () 11707 { 11708 var prefix = readOnly ? "ref " : "ref readonly "; 11709 return prefix + element.GetSignatureForError (); 11710 } 11711 Accept(StructuralVisitor visitor)11712 public override object Accept (StructuralVisitor visitor) 11713 { 11714 return visitor.Visit (this); 11715 } 11716 } 11717 11718 class FixedBufferPtr : Expression 11719 { 11720 readonly Expression array; 11721 FixedBufferPtr(Expression array, TypeSpec array_type, Location l)11722 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l) 11723 { 11724 this.type = array_type; 11725 this.array = array; 11726 this.loc = l; 11727 } 11728 ContainsEmitWithAwait()11729 public override bool ContainsEmitWithAwait () 11730 { 11731 throw new NotImplementedException (); 11732 } 11733 CreateExpressionTree(ResolveContext ec)11734 public override Expression CreateExpressionTree (ResolveContext ec) 11735 { 11736 Error_PointerInsideExpressionTree (ec); 11737 return null; 11738 } 11739 Emit(EmitContext ec)11740 public override void Emit(EmitContext ec) 11741 { 11742 array.Emit (ec); 11743 } 11744 DoResolve(ResolveContext ec)11745 protected override Expression DoResolve (ResolveContext ec) 11746 { 11747 type = PointerContainer.MakeType (ec.Module, type); 11748 eclass = ExprClass.Value; 11749 return this; 11750 } 11751 } 11752 11753 11754 // 11755 // This class is used to represent the address of an array, used 11756 // only by the Fixed statement, this generates "&a [0]" construct 11757 // for fixed (char *pa = a) 11758 // 11759 class ArrayPtr : FixedBufferPtr 11760 { ArrayPtr(Expression array, TypeSpec array_type, Location l)11761 public ArrayPtr (Expression array, TypeSpec array_type, Location l): 11762 base (array, array_type, l) 11763 { 11764 } 11765 Emit(EmitContext ec)11766 public override void Emit (EmitContext ec) 11767 { 11768 base.Emit (ec); 11769 11770 ec.EmitInt (0); 11771 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element); 11772 } 11773 } 11774 11775 // 11776 // Encapsulates a conversion rules required for array indexes 11777 // 11778 public class ArrayIndexCast : TypeCast 11779 { ArrayIndexCast(Expression expr, TypeSpec returnType)11780 public ArrayIndexCast (Expression expr, TypeSpec returnType) 11781 : base (expr, returnType) 11782 { 11783 if (expr.Type == returnType) // int -> int 11784 throw new ArgumentException ("unnecessary array index conversion"); 11785 } 11786 CreateExpressionTree(ResolveContext ec)11787 public override Expression CreateExpressionTree (ResolveContext ec) 11788 { 11789 using (ec.Set (ResolveContext.Options.CheckedScope)) { 11790 return base.CreateExpressionTree (ec); 11791 } 11792 } 11793 Emit(EmitContext ec)11794 public override void Emit (EmitContext ec) 11795 { 11796 child.Emit (ec); 11797 11798 switch (child.Type.BuiltinType) { 11799 case BuiltinTypeSpec.Type.UInt: 11800 ec.Emit (OpCodes.Conv_U); 11801 break; 11802 case BuiltinTypeSpec.Type.Long: 11803 ec.Emit (OpCodes.Conv_Ovf_I); 11804 break; 11805 case BuiltinTypeSpec.Type.ULong: 11806 ec.Emit (OpCodes.Conv_Ovf_I_Un); 11807 break; 11808 default: 11809 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type); 11810 } 11811 } 11812 } 11813 11814 // 11815 // Implements the `stackalloc' keyword 11816 // 11817 public class StackAlloc : Expression { 11818 TypeSpec otype; 11819 Expression texpr; 11820 Expression count; 11821 MethodSpec ctor; 11822 StackAlloc(Expression type, Expression count, Location l)11823 public StackAlloc (Expression type, Expression count, Location l) 11824 { 11825 texpr = type; 11826 this.count = count; 11827 loc = l; 11828 } 11829 11830 public Expression TypeExpression { 11831 get { 11832 return texpr; 11833 } 11834 } 11835 11836 public Expression CountExpression { 11837 get { 11838 return this.count; 11839 } 11840 } 11841 ContainsEmitWithAwait()11842 public override bool ContainsEmitWithAwait () 11843 { 11844 return false; 11845 } 11846 CreateExpressionTree(ResolveContext ec)11847 public override Expression CreateExpressionTree (ResolveContext ec) 11848 { 11849 throw new NotSupportedException ("ET"); 11850 } 11851 DoResolve(ResolveContext ec)11852 protected override Expression DoResolve (ResolveContext ec) 11853 { 11854 count = count.Resolve (ec); 11855 if (count == null) 11856 return null; 11857 11858 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){ 11859 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc); 11860 if (count == null) 11861 return null; 11862 } 11863 11864 Constant c = count as Constant; 11865 if (c != null && c.IsNegative) { 11866 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc"); 11867 } 11868 11869 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) { 11870 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch"); 11871 } 11872 11873 otype = texpr.ResolveAsType (ec); 11874 if (otype == null) 11875 return null; 11876 11877 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc)) 11878 return null; 11879 11880 type = PointerContainer.MakeType (ec.Module, otype); 11881 eclass = ExprClass.Value; 11882 11883 return this; 11884 } 11885 Emit(EmitContext ec)11886 public override void Emit (EmitContext ec) 11887 { 11888 int size = BuiltinTypeSpec.GetSize (otype); 11889 11890 count.Emit (ec); 11891 bool count_on_stack = false; 11892 if (ctor != null && !ExpressionAnalyzer.IsInexpensiveLoad (count)) { 11893 ec.Emit (OpCodes.Dup); 11894 count_on_stack = true; 11895 } 11896 11897 if (size == 0) 11898 ec.Emit (OpCodes.Sizeof, otype); 11899 else 11900 ec.EmitInt (size); 11901 11902 ec.Emit (OpCodes.Mul_Ovf_Un); 11903 ec.Emit (OpCodes.Localloc); 11904 11905 if (ctor != null) { 11906 if (!count_on_stack) 11907 count.Emit (ec); 11908 ec.Emit (OpCodes.Newobj, ctor); 11909 } 11910 } 11911 Error_ValueCannotBeConverted(ResolveContext rc, TypeSpec target, bool expl)11912 public override void Error_ValueCannotBeConverted (ResolveContext rc, TypeSpec target, bool expl) 11913 { 11914 var etype = ((PointerContainer)type).Element; 11915 rc.Report.Error (8346, loc, "Cannot convert a stackalloc expression of type `{0}' to type `{1}'", 11916 etype.GetSignatureForError (), target.GetSignatureForError ()); 11917 } 11918 CloneTo(CloneContext clonectx, Expression t)11919 protected override void CloneTo (CloneContext clonectx, Expression t) 11920 { 11921 StackAlloc target = (StackAlloc) t; 11922 target.count = count.Clone (clonectx); 11923 target.texpr = texpr.Clone (clonectx); 11924 } 11925 Accept(StructuralVisitor visitor)11926 public override object Accept (StructuralVisitor visitor) 11927 { 11928 return visitor.Visit (this); 11929 } 11930 ResolveSpanConversion(ResolveContext rc, TypeSpec spanType)11931 public bool ResolveSpanConversion (ResolveContext rc, TypeSpec spanType) 11932 { 11933 ctor = MemberCache.FindMember (spanType, MemberFilter.Constructor (ParametersCompiled.CreateFullyResolved (PointerContainer.MakeType (rc.Module, rc.Module.Compiler.BuiltinTypes.Void), rc.Module.Compiler.BuiltinTypes.Int)), BindingRestriction.DeclaredOnly) as MethodSpec; 11934 if (ctor == null) 11935 return false; 11936 11937 this.type = spanType; 11938 return true; 11939 } 11940 } 11941 11942 // 11943 // An object initializer expression 11944 // 11945 public class ElementInitializer : Assign 11946 { 11947 public readonly string Name; 11948 ElementInitializer(string name, Expression initializer, Location loc)11949 public ElementInitializer (string name, Expression initializer, Location loc) 11950 : base (null, initializer, loc) 11951 { 11952 this.Name = name; 11953 } 11954 11955 public bool IsDictionaryInitializer { 11956 get { 11957 return Name == null; 11958 } 11959 } 11960 CloneTo(CloneContext clonectx, Expression t)11961 protected override void CloneTo (CloneContext clonectx, Expression t) 11962 { 11963 ElementInitializer target = (ElementInitializer) t; 11964 target.source = source.Clone (clonectx); 11965 } 11966 CreateExpressionTree(ResolveContext ec)11967 public override Expression CreateExpressionTree (ResolveContext ec) 11968 { 11969 Arguments args = new Arguments (2); 11970 FieldExpr fe = target as FieldExpr; 11971 if (fe != null) 11972 args.Add (new Argument (fe.CreateTypeOfExpression ())); 11973 else 11974 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec))); 11975 11976 string mname; 11977 Expression arg_expr; 11978 var cinit = source as CollectionOrObjectInitializers; 11979 if (cinit == null) { 11980 mname = "Bind"; 11981 arg_expr = source.CreateExpressionTree (ec); 11982 } else { 11983 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind"; 11984 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty); 11985 } 11986 11987 args.Add (new Argument (arg_expr)); 11988 return CreateExpressionFactoryCall (ec, mname, args); 11989 } 11990 DoResolve(ResolveContext ec)11991 protected override Expression DoResolve (ResolveContext ec) 11992 { 11993 if (source == null) 11994 return EmptyExpressionStatement.Instance; 11995 11996 if (!ResolveElement (ec)) 11997 return null; 11998 11999 if (source is CollectionOrObjectInitializers) { 12000 target = target.Resolve (ec); 12001 if (target == null) 12002 return null; 12003 12004 Expression previous = ec.CurrentInitializerVariable; 12005 ec.CurrentInitializerVariable = target; 12006 source = source.Resolve (ec); 12007 ec.CurrentInitializerVariable = previous; 12008 if (source == null) 12009 return null; 12010 12011 eclass = source.eclass; 12012 type = source.Type; 12013 12014 return this; 12015 } 12016 12017 return base.DoResolve (ec); 12018 } 12019 EmitStatement(EmitContext ec)12020 public override void EmitStatement (EmitContext ec) 12021 { 12022 if (source is CollectionOrObjectInitializers) 12023 source.Emit (ec); 12024 else 12025 base.EmitStatement (ec); 12026 } 12027 ResolveElement(ResolveContext rc)12028 protected virtual bool ResolveElement (ResolveContext rc) 12029 { 12030 var t = rc.CurrentInitializerVariable.Type; 12031 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 12032 Arguments args = new Arguments (1); 12033 args.Add (new Argument (rc.CurrentInitializerVariable)); 12034 target = new DynamicMemberBinder (Name, args, loc); 12035 } else { 12036 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc); 12037 if (member == null) { 12038 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc); 12039 12040 if (member != null) { 12041 // TODO: ec.Report.SymbolRelatedToPreviousError (member); 12042 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc); 12043 return false; 12044 } 12045 } 12046 12047 if (member == null) { 12048 Error_TypeDoesNotContainDefinition (rc, loc, t, Name); 12049 return false; 12050 } 12051 12052 var me = member as MemberExpr; 12053 if (me is EventExpr) { 12054 me = me.ResolveMemberAccess (rc, null, null); 12055 } else if (!(member is PropertyExpr || member is FieldExpr)) { 12056 rc.Report.Error (1913, loc, 12057 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties", 12058 member.GetSignatureForError ()); 12059 12060 return false; 12061 } 12062 12063 if (me.IsStatic) { 12064 rc.Report.Error (1914, loc, 12065 "Static field or property `{0}' cannot be assigned in an object initializer", 12066 me.GetSignatureForError ()); 12067 } 12068 12069 target = me; 12070 me.InstanceExpression = rc.CurrentInitializerVariable; 12071 } 12072 12073 return true; 12074 } 12075 } 12076 12077 // 12078 // A collection initializer expression 12079 // 12080 class CollectionElementInitializer : Invocation 12081 { 12082 public class ElementInitializerArgument : Argument 12083 { ElementInitializerArgument(Expression e)12084 public ElementInitializerArgument (Expression e) 12085 : base (e) 12086 { 12087 } 12088 } 12089 12090 sealed class AddMemberAccess : MemberAccess 12091 { AddMemberAccess(Expression expr, Location loc)12092 public AddMemberAccess (Expression expr, Location loc) 12093 : base (expr, "Add", loc) 12094 { 12095 } 12096 Error_TypeDoesNotContainDefinition(ResolveContext ec, TypeSpec type, string name)12097 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name) 12098 { 12099 if (TypeManager.HasElementType (type)) 12100 return; 12101 12102 base.Error_TypeDoesNotContainDefinition (ec, type, name); 12103 } 12104 } 12105 CollectionElementInitializer(Expression argument)12106 public CollectionElementInitializer (Expression argument) 12107 : base (null, new Arguments (1)) 12108 { 12109 base.arguments.Add (new ElementInitializerArgument (argument)); 12110 this.loc = argument.Location; 12111 } 12112 CollectionElementInitializer(List<Expression> arguments, Location loc)12113 public CollectionElementInitializer (List<Expression> arguments, Location loc) 12114 : base (null, new Arguments (arguments.Count)) 12115 { 12116 foreach (Expression e in arguments) 12117 base.arguments.Add (new ElementInitializerArgument (e)); 12118 12119 this.loc = loc; 12120 } 12121 CollectionElementInitializer(Location loc)12122 public CollectionElementInitializer (Location loc) 12123 : base (null, null) 12124 { 12125 this.loc = loc; 12126 } 12127 CreateExpressionTree(ResolveContext ec)12128 public override Expression CreateExpressionTree (ResolveContext ec) 12129 { 12130 Arguments args = new Arguments (2); 12131 args.Add (new Argument (mg.CreateExpressionTree (ec))); 12132 12133 var expr_initializers = new ArrayInitializer (arguments.Count, loc); 12134 foreach (Argument a in arguments) { 12135 if (a.ArgType == Argument.AType.ExtensionType) { 12136 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method"); 12137 continue; 12138 } 12139 expr_initializers.Add (a.CreateExpressionTree (ec)); 12140 } 12141 12142 args.Add (new Argument (new ArrayCreation ( 12143 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc))); 12144 return CreateExpressionFactoryCall (ec, "ElementInit", args); 12145 } 12146 CloneTo(CloneContext clonectx, Expression t)12147 protected override void CloneTo (CloneContext clonectx, Expression t) 12148 { 12149 CollectionElementInitializer target = (CollectionElementInitializer) t; 12150 if (arguments != null) 12151 target.arguments = arguments.Clone (clonectx); 12152 } 12153 DoResolve(ResolveContext ec)12154 protected override Expression DoResolve (ResolveContext ec) 12155 { 12156 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc); 12157 12158 return base.DoResolve (ec); 12159 } 12160 } 12161 12162 class DictionaryElementInitializer : ElementInitializer 12163 { 12164 readonly Arguments args; 12165 DictionaryElementInitializer(Arguments arguments, Expression initializer, Location loc)12166 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc) 12167 : base (null, initializer, loc) 12168 { 12169 this.args = arguments; 12170 } 12171 CreateExpressionTree(ResolveContext ec)12172 public override Expression CreateExpressionTree (ResolveContext ec) 12173 { 12174 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer"); 12175 return null; 12176 } 12177 ResolveElement(ResolveContext rc)12178 protected override bool ResolveElement (ResolveContext rc) 12179 { 12180 var init = rc.CurrentInitializerVariable; 12181 var type = init.Type; 12182 12183 if (type.IsArray) { 12184 target = new ArrayAccess (new ElementAccess (init, args, loc), loc); 12185 return true; 12186 } 12187 12188 if (type.IsPointer) { 12189 target = init.MakePointerAccess (rc, type, args); 12190 return true; 12191 } 12192 12193 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false); 12194 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) { 12195 ElementAccess.Error_CannotApplyIndexing (rc, type, loc); 12196 return false; 12197 } 12198 12199 target = new IndexerExpr (indexers, type, init, args, loc); 12200 return true; 12201 } 12202 } 12203 12204 // 12205 // A block of object or collection initializers 12206 // 12207 public class CollectionOrObjectInitializers : ExpressionStatement 12208 { 12209 IList<Expression> initializers; 12210 bool is_collection_initialization; 12211 CollectionOrObjectInitializers(Location loc)12212 public CollectionOrObjectInitializers (Location loc) 12213 : this (new Expression[0], loc) 12214 { 12215 } 12216 CollectionOrObjectInitializers(IList<Expression> initializers, Location loc)12217 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc) 12218 { 12219 this.initializers = initializers; 12220 this.loc = loc; 12221 } 12222 12223 public IList<Expression> Initializers { 12224 get { 12225 return initializers; 12226 } 12227 } 12228 12229 public bool IsEmpty { 12230 get { 12231 return initializers.Count == 0; 12232 } 12233 } 12234 12235 public bool IsCollectionInitializer { 12236 get { 12237 return is_collection_initialization; 12238 } 12239 } 12240 CloneTo(CloneContext clonectx, Expression target)12241 protected override void CloneTo (CloneContext clonectx, Expression target) 12242 { 12243 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target; 12244 12245 t.initializers = new List<Expression> (initializers.Count); 12246 foreach (var e in initializers) 12247 t.initializers.Add (e.Clone (clonectx)); 12248 } 12249 ContainsEmitWithAwait()12250 public override bool ContainsEmitWithAwait () 12251 { 12252 foreach (var e in initializers) { 12253 if (e.ContainsEmitWithAwait ()) 12254 return true; 12255 } 12256 12257 return false; 12258 } 12259 CreateExpressionTree(ResolveContext ec)12260 public override Expression CreateExpressionTree (ResolveContext ec) 12261 { 12262 return CreateExpressionTree (ec, false); 12263 } 12264 CreateExpressionTree(ResolveContext ec, bool inferType)12265 public Expression CreateExpressionTree (ResolveContext ec, bool inferType) 12266 { 12267 var expr_initializers = new ArrayInitializer (initializers.Count, loc); 12268 foreach (Expression e in initializers) { 12269 Expression expr = e.CreateExpressionTree (ec); 12270 if (expr != null) 12271 expr_initializers.Add (expr); 12272 } 12273 12274 if (inferType) 12275 return new ImplicitlyTypedArrayCreation (expr_initializers, loc); 12276 12277 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc); 12278 } 12279 DoResolve(ResolveContext ec)12280 protected override Expression DoResolve (ResolveContext ec) 12281 { 12282 List<string> element_names = null; 12283 for (int i = 0; i < initializers.Count; ++i) { 12284 Expression initializer = initializers [i]; 12285 ElementInitializer element_initializer = initializer as ElementInitializer; 12286 12287 if (i == 0) { 12288 if (element_initializer != null) { 12289 element_names = new List<string> (initializers.Count); 12290 if (!element_initializer.IsDictionaryInitializer) 12291 element_names.Add (element_initializer.Name); 12292 } else if (initializer is CompletingExpression) { 12293 initializer.Resolve (ec); 12294 throw new InternalErrorException ("This line should never be reached"); 12295 } else { 12296 var t = ec.CurrentInitializerVariable.Type; 12297 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support 12298 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) { 12299 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " + 12300 "object initializer because type `{1}' does not implement `{2}' interface", 12301 ec.CurrentInitializerVariable.GetSignatureForError (), 12302 ec.CurrentInitializerVariable.Type.GetSignatureForError (), 12303 ec.BuiltinTypes.IEnumerable.GetSignatureForError ()); 12304 return null; 12305 } 12306 is_collection_initialization = true; 12307 } 12308 } else { 12309 if (is_collection_initialization != (element_initializer == null)) { 12310 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration", 12311 is_collection_initialization ? "collection initializer" : "object initializer"); 12312 continue; 12313 } 12314 12315 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) { 12316 if (element_names.Contains (element_initializer.Name)) { 12317 ec.Report.Error (1912, element_initializer.Location, 12318 "An object initializer includes more than one member `{0}' initialization", 12319 element_initializer.Name); 12320 } else { 12321 element_names.Add (element_initializer.Name); 12322 } 12323 } 12324 } 12325 12326 Expression e = initializer.Resolve (ec); 12327 if (e == EmptyExpressionStatement.Instance) 12328 initializers.RemoveAt (i--); 12329 else 12330 initializers [i] = e; 12331 } 12332 12333 type = ec.CurrentInitializerVariable.Type; 12334 if (is_collection_initialization) { 12335 if (TypeManager.HasElementType (type)) { 12336 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer", 12337 type.GetSignatureForError ()); 12338 } 12339 } 12340 12341 eclass = ExprClass.Variable; 12342 return this; 12343 } 12344 Emit(EmitContext ec)12345 public override void Emit (EmitContext ec) 12346 { 12347 EmitStatement (ec); 12348 } 12349 EmitStatement(EmitContext ec)12350 public override void EmitStatement (EmitContext ec) 12351 { 12352 foreach (ExpressionStatement e in initializers) { 12353 // TODO: need location region 12354 ec.Mark (e.Location); 12355 e.EmitStatement (ec); 12356 } 12357 } 12358 FlowAnalysis(FlowAnalysisContext fc)12359 public override void FlowAnalysis (FlowAnalysisContext fc) 12360 { 12361 foreach (var initializer in initializers) { 12362 if (initializer != null) 12363 initializer.FlowAnalysis (fc); 12364 } 12365 } 12366 } 12367 12368 // 12369 // New expression with element/object initializers 12370 // 12371 public class NewInitialize : New 12372 { 12373 // 12374 // This class serves as a proxy for variable initializer target instances. 12375 // A real variable is assigned later when we resolve left side of an 12376 // assignment 12377 // 12378 sealed class InitializerTargetExpression : Expression, IMemoryLocation 12379 { 12380 NewInitialize new_instance; 12381 InitializerTargetExpression(NewInitialize newInstance)12382 public InitializerTargetExpression (NewInitialize newInstance) 12383 { 12384 this.type = newInstance.type; 12385 this.loc = newInstance.loc; 12386 this.eclass = newInstance.eclass; 12387 this.new_instance = newInstance; 12388 } 12389 ContainsEmitWithAwait()12390 public override bool ContainsEmitWithAwait () 12391 { 12392 return false; 12393 } 12394 CreateExpressionTree(ResolveContext ec)12395 public override Expression CreateExpressionTree (ResolveContext ec) 12396 { 12397 // Should not be reached 12398 throw new NotSupportedException ("ET"); 12399 } 12400 DoResolve(ResolveContext ec)12401 protected override Expression DoResolve (ResolveContext ec) 12402 { 12403 return this; 12404 } 12405 DoResolveLValue(ResolveContext ec, Expression right_side)12406 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side) 12407 { 12408 return this; 12409 } 12410 Emit(EmitContext ec)12411 public override void Emit (EmitContext ec) 12412 { 12413 Expression e = (Expression) new_instance.instance; 12414 e.Emit (ec); 12415 } 12416 EmitToField(EmitContext ec)12417 public override Expression EmitToField (EmitContext ec) 12418 { 12419 return (Expression) new_instance.instance; 12420 } 12421 12422 #region IMemoryLocation Members 12423 AddressOf(EmitContext ec, AddressOp mode)12424 public void AddressOf (EmitContext ec, AddressOp mode) 12425 { 12426 new_instance.instance.AddressOf (ec, mode); 12427 } 12428 12429 #endregion 12430 } 12431 12432 CollectionOrObjectInitializers initializers; 12433 IMemoryLocation instance; 12434 DynamicExpressionStatement dynamic; 12435 NewInitialize(FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)12436 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l) 12437 : base (requested_type, arguments, l) 12438 { 12439 this.initializers = initializers; 12440 } 12441 12442 public CollectionOrObjectInitializers Initializers { 12443 get { 12444 return initializers; 12445 } 12446 } 12447 CloneTo(CloneContext clonectx, Expression t)12448 protected override void CloneTo (CloneContext clonectx, Expression t) 12449 { 12450 base.CloneTo (clonectx, t); 12451 12452 NewInitialize target = (NewInitialize) t; 12453 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx); 12454 } 12455 ContainsEmitWithAwait()12456 public override bool ContainsEmitWithAwait () 12457 { 12458 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait (); 12459 } 12460 CreateExpressionTree(ResolveContext ec)12461 public override Expression CreateExpressionTree (ResolveContext ec) 12462 { 12463 Arguments args = new Arguments (2); 12464 args.Add (new Argument (base.CreateExpressionTree (ec))); 12465 if (!initializers.IsEmpty) 12466 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer))); 12467 12468 return CreateExpressionFactoryCall (ec, 12469 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit", 12470 args); 12471 } 12472 DoResolve(ResolveContext rc)12473 protected override Expression DoResolve (ResolveContext rc) 12474 { 12475 Expression e = base.DoResolve (rc); 12476 if (type == null) 12477 return null; 12478 12479 if (type.IsDelegate) { 12480 rc.Report.Error (1958, Initializers.Location, 12481 "Object and collection initializers cannot be used to instantiate a delegate"); 12482 } 12483 12484 Expression previous = rc.CurrentInitializerVariable; 12485 rc.CurrentInitializerVariable = new InitializerTargetExpression (this); 12486 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) { 12487 initializers.Resolve (rc); 12488 } 12489 rc.CurrentInitializerVariable = previous; 12490 12491 dynamic = e as DynamicExpressionStatement; 12492 if (dynamic != null) 12493 return this; 12494 12495 return e; 12496 } 12497 Emit(EmitContext ec)12498 public override void Emit (EmitContext ec) 12499 { 12500 if (!CanEmitOptimizedLocalTarget (ec)) { 12501 var fe = ec.GetTemporaryField (type); 12502 12503 if (!Emit (ec, fe)) 12504 fe.Emit (ec); 12505 12506 return; 12507 } 12508 12509 base.Emit (ec); 12510 } 12511 Emit(EmitContext ec, IMemoryLocation target)12512 public override bool Emit (EmitContext ec, IMemoryLocation target) 12513 { 12514 // 12515 // Expression is initialized into temporary target then moved 12516 // to real one for atomicity 12517 // 12518 IMemoryLocation temp_target = target; 12519 12520 LocalTemporary temp = null; 12521 bool by_ref = false; 12522 if (!initializers.IsEmpty) { 12523 temp_target = target as LocalTemporary; 12524 if (temp_target == null) 12525 temp_target = target as StackFieldExpr; 12526 12527 if (temp_target == null) { 12528 var vr = target as VariableReference; 12529 if (vr != null && vr.IsRef) { 12530 vr.EmitLoad (ec); 12531 by_ref = true; 12532 } 12533 } 12534 12535 if (temp_target == null) 12536 temp_target = temp = new LocalTemporary (type); 12537 } 12538 12539 bool left_on_stack; 12540 if (dynamic != null) { 12541 dynamic.Emit (ec); 12542 left_on_stack = true; 12543 } else { 12544 left_on_stack = base.Emit (ec, temp_target); 12545 } 12546 12547 if (initializers.IsEmpty) 12548 return left_on_stack; 12549 12550 StackFieldExpr sf = null; 12551 12552 // Move a new instance (reference-type) to local temporary variable 12553 if (left_on_stack) { 12554 if (by_ref) { 12555 temp_target = temp = new LocalTemporary (type); 12556 } 12557 12558 if (temp != null) 12559 temp.Store (ec); 12560 12561 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) { 12562 if (temp == null) 12563 throw new NotImplementedException (); 12564 12565 sf = ec.GetTemporaryField (type); 12566 sf.AutomaticallyReuse = false; 12567 sf.EmitAssign (ec, temp, false, false); 12568 temp_target = sf; 12569 temp.Release (ec); 12570 left_on_stack = false; 12571 } 12572 } 12573 12574 instance = temp_target; 12575 12576 initializers.Emit (ec); 12577 12578 ((Expression)temp_target).Emit (ec); 12579 12580 if (temp != null) 12581 temp.Release (ec); 12582 12583 if (sf != null) 12584 sf.PrepareCleanup (ec); 12585 12586 return true; 12587 } 12588 CanEmitOptimizedLocalTarget(EmitContext ec)12589 public override bool CanEmitOptimizedLocalTarget (EmitContext ec) 12590 { 12591 return !(method == null && TypeSpec.IsValueType (type) && 12592 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && 12593 initializers.ContainsEmitWithAwait ()); 12594 } 12595 EmitAddressOf(EmitContext ec, AddressOp Mode)12596 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode) 12597 { 12598 instance = base.EmitAddressOf (ec, Mode); 12599 12600 if (!initializers.IsEmpty) 12601 initializers.Emit (ec); 12602 12603 return instance; 12604 } 12605 FlowAnalysis(FlowAnalysisContext fc)12606 public override void FlowAnalysis (FlowAnalysisContext fc) 12607 { 12608 base.FlowAnalysis (fc); 12609 initializers.FlowAnalysis (fc); 12610 } 12611 Accept(StructuralVisitor visitor)12612 public override object Accept (StructuralVisitor visitor) 12613 { 12614 return visitor.Visit (this); 12615 } 12616 } 12617 12618 public class NewAnonymousType : New 12619 { 12620 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0]; 12621 12622 List<AnonymousTypeParameter> parameters; 12623 readonly TypeContainer parent; 12624 AnonymousTypeClass anonymous_type; 12625 NewAnonymousType(List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)12626 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc) 12627 : base (null, null, loc) 12628 { 12629 this.parameters = parameters; 12630 this.parent = parent; 12631 } 12632 12633 public List<AnonymousTypeParameter> Parameters { 12634 get { 12635 return this.parameters; 12636 } 12637 } 12638 CloneTo(CloneContext clonectx, Expression target)12639 protected override void CloneTo (CloneContext clonectx, Expression target) 12640 { 12641 if (parameters == null) 12642 return; 12643 12644 NewAnonymousType t = (NewAnonymousType) target; 12645 t.parameters = new List<AnonymousTypeParameter> (parameters.Count); 12646 foreach (AnonymousTypeParameter atp in parameters) 12647 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx)); 12648 } 12649 CreateAnonymousType(ResolveContext ec, IList<AnonymousTypeParameter> parameters)12650 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters) 12651 { 12652 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters); 12653 if (type != null) 12654 return type; 12655 12656 type = AnonymousTypeClass.Create (parent, parameters, loc); 12657 if (type == null) 12658 return null; 12659 12660 int errors = ec.Report.Errors; 12661 type.CreateContainer (); 12662 type.DefineContainer (); 12663 type.ExpandBaseInterfaces (); 12664 type.Define (); 12665 if ((ec.Report.Errors - errors) == 0) { 12666 parent.Module.AddAnonymousType (type); 12667 type.PrepareEmit (); 12668 } 12669 12670 return type; 12671 } 12672 CreateExpressionTree(ResolveContext ec)12673 public override Expression CreateExpressionTree (ResolveContext ec) 12674 { 12675 if (parameters == null) 12676 return base.CreateExpressionTree (ec); 12677 12678 var init = new ArrayInitializer (parameters.Count, loc); 12679 foreach (var m in anonymous_type.Members) { 12680 var p = m as Property; 12681 if (p != null) 12682 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc)); 12683 } 12684 12685 var ctor_args = new ArrayInitializer (arguments.Count, loc); 12686 foreach (Argument a in arguments) 12687 ctor_args.Add (a.CreateExpressionTree (ec)); 12688 12689 Arguments args = new Arguments (3); 12690 args.Add (new Argument (new TypeOfMethod (method, loc))); 12691 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc))); 12692 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc))); 12693 12694 return CreateExpressionFactoryCall (ec, "New", args); 12695 } 12696 DoResolve(ResolveContext ec)12697 protected override Expression DoResolve (ResolveContext ec) 12698 { 12699 if (ec.HasSet (ResolveContext.Options.ConstantScope)) { 12700 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression"); 12701 return null; 12702 } 12703 12704 if (parameters == null) { 12705 anonymous_type = CreateAnonymousType (ec, EmptyParameters); 12706 RequestedType = new TypeExpression (anonymous_type.Definition, loc); 12707 return base.DoResolve (ec); 12708 } 12709 12710 bool error = false; 12711 arguments = new Arguments (parameters.Count); 12712 var t_args = new TypeSpec [parameters.Count]; 12713 for (int i = 0; i < parameters.Count; ++i) { 12714 Expression e = parameters [i].Resolve (ec); 12715 if (e == null) { 12716 error = true; 12717 continue; 12718 } 12719 12720 arguments.Add (new Argument (e)); 12721 t_args [i] = e.Type; 12722 } 12723 12724 if (error) 12725 return null; 12726 12727 anonymous_type = CreateAnonymousType (ec, parameters); 12728 if (anonymous_type == null) 12729 return null; 12730 12731 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args); 12732 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly); 12733 eclass = ExprClass.Value; 12734 return this; 12735 } 12736 Accept(StructuralVisitor visitor)12737 public override object Accept (StructuralVisitor visitor) 12738 { 12739 return visitor.Visit (this); 12740 } 12741 } 12742 12743 public class AnonymousTypeParameter : ShimExpression 12744 { 12745 public readonly string Name; 12746 AnonymousTypeParameter(Expression initializer, string name, Location loc)12747 public AnonymousTypeParameter (Expression initializer, string name, Location loc) 12748 : base (initializer) 12749 { 12750 this.Name = name; 12751 this.loc = loc; 12752 } 12753 AnonymousTypeParameter(Parameter parameter)12754 public AnonymousTypeParameter (Parameter parameter) 12755 : base (new SimpleName (parameter.Name, parameter.Location)) 12756 { 12757 this.Name = parameter.Name; 12758 this.loc = parameter.Location; 12759 } 12760 Equals(object o)12761 public override bool Equals (object o) 12762 { 12763 AnonymousTypeParameter other = o as AnonymousTypeParameter; 12764 return other != null && Name == other.Name; 12765 } 12766 GetHashCode()12767 public override int GetHashCode () 12768 { 12769 return Name.GetHashCode (); 12770 } 12771 DoResolve(ResolveContext ec)12772 protected override Expression DoResolve (ResolveContext ec) 12773 { 12774 Expression e = expr.Resolve (ec); 12775 if (e == null) 12776 return null; 12777 12778 if (e.eclass == ExprClass.MethodGroup) { 12779 Error_InvalidInitializer (ec, e.ExprClassName); 12780 return null; 12781 } 12782 12783 type = e.Type; 12784 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || type.IsPointer || (e is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) { 12785 Error_InvalidInitializer (ec, type.GetSignatureForError ()); 12786 return null; 12787 } 12788 12789 return e; 12790 } 12791 Error_InvalidInitializer(ResolveContext ec, string initializer)12792 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer) 12793 { 12794 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'", 12795 Name, initializer); 12796 } 12797 } 12798 12799 public class CatchFilterExpression : BooleanExpression 12800 { CatchFilterExpression(Expression expr, Location loc)12801 public CatchFilterExpression (Expression expr, Location loc) 12802 : base (expr) 12803 { 12804 this.loc = loc; 12805 } 12806 } 12807 12808 public class InterpolatedString : Expression 12809 { 12810 readonly StringLiteral start, end; 12811 List<Expression> interpolations; 12812 Arguments arguments; 12813 InterpolatedString(StringLiteral start, List<Expression> interpolations, StringLiteral end)12814 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end) 12815 { 12816 this.start = start; 12817 this.end = end; 12818 this.interpolations = interpolations; 12819 loc = start.Location; 12820 } 12821 CloneTo(CloneContext clonectx, Expression t)12822 protected override void CloneTo (CloneContext clonectx, Expression t) 12823 { 12824 InterpolatedString target = (InterpolatedString) t; 12825 12826 if (interpolations != null) { 12827 target.interpolations = new List<Expression> (); 12828 foreach (var interpolation in interpolations) { 12829 target.interpolations.Add (interpolation.Clone (clonectx)); 12830 } 12831 } 12832 } 12833 ConvertTo(ResolveContext rc, TypeSpec type)12834 public Expression ConvertTo (ResolveContext rc, TypeSpec type) 12835 { 12836 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve (); 12837 if (factory == null) 12838 return null; 12839 12840 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc); 12841 var res = new Invocation (ma, arguments).Resolve (rc); 12842 if (res != null && res.Type != type) 12843 res = Convert.ExplicitConversion (rc, res, type, loc); 12844 12845 return res; 12846 } 12847 ContainsEmitWithAwait()12848 public override bool ContainsEmitWithAwait () 12849 { 12850 if (interpolations == null) 12851 return false; 12852 12853 foreach (var expr in interpolations) { 12854 if (expr.ContainsEmitWithAwait ()) 12855 return true; 12856 } 12857 12858 return false; 12859 } 12860 CreateExpressionTree(ResolveContext rc)12861 public override Expression CreateExpressionTree (ResolveContext rc) 12862 { 12863 var best = ResolveBestFormatOverload (rc); 12864 if (best == null) 12865 return null; 12866 12867 Expression instance = new NullLiteral (loc); 12868 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc)); 12869 return CreateExpressionFactoryCall (rc, "Call", args); 12870 } 12871 DoResolve(ResolveContext rc)12872 protected override Expression DoResolve (ResolveContext rc) 12873 { 12874 string str; 12875 12876 if (interpolations == null) { 12877 str = start.Value; 12878 arguments = new Arguments (1); 12879 } else { 12880 arguments = new Arguments (interpolations.Count); 12881 12882 var sb = new StringBuilder (start.Value); 12883 for (int i = 0; i < interpolations.Count; ++i) { 12884 if (i % 2 == 0) { 12885 sb.Append ('{').Append (i / 2); 12886 var isi = (InterpolatedStringInsert)interpolations [i]; 12887 if (isi.Alignment != null) { 12888 sb.Append (','); 12889 var value = isi.ResolveAligment (rc); 12890 if (value != null) 12891 sb.Append (value.Value); 12892 } 12893 12894 if (isi.Format != null) { 12895 sb.Append (':'); 12896 sb.Append (isi.Format); 12897 } 12898 12899 sb.Append ('}'); 12900 arguments.Add (new Argument (isi.Resolve (rc))); 12901 } else { 12902 sb.Append (((StringLiteral)interpolations [i]).Value); 12903 } 12904 } 12905 12906 sb.Append (end.Value); 12907 str = sb.ToString (); 12908 } 12909 12910 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location))); 12911 12912 eclass = ExprClass.Value; 12913 type = rc.BuiltinTypes.String; 12914 return this; 12915 } 12916 Emit(EmitContext ec)12917 public override void Emit (EmitContext ec) 12918 { 12919 // No interpolation, convert to simple string result (needs to match string.Format unescaping) 12920 if (interpolations == null) { 12921 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}"); 12922 if (str != start.Value) 12923 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec); 12924 else 12925 start.Emit (ec); 12926 12927 return; 12928 } 12929 12930 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext)); 12931 if (best == null) 12932 return; 12933 12934 var ca = new CallEmitter (); 12935 ca.Emit (ec, best, arguments, loc); 12936 } 12937 FlowAnalysis(FlowAnalysisContext fc)12938 public override void FlowAnalysis (FlowAnalysisContext fc) 12939 { 12940 if (interpolations != null) { 12941 foreach (var expr in interpolations) { 12942 expr.FlowAnalysis (fc); 12943 } 12944 } 12945 } 12946 ResolveBestFormatOverload(ResolveContext rc)12947 MethodSpec ResolveBestFormatOverload (ResolveContext rc) 12948 { 12949 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true); 12950 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc); 12951 return res.ResolveMember<MethodSpec> (rc, ref arguments); 12952 } 12953 } 12954 12955 public class InterpolatedStringInsert : CompositeExpression 12956 { InterpolatedStringInsert(Expression expr)12957 public InterpolatedStringInsert (Expression expr) 12958 : base (expr) 12959 { 12960 } 12961 12962 public Expression Alignment { get; set; } 12963 public string Format { get; set; } 12964 CloneTo(CloneContext clonectx, Expression t)12965 protected override void CloneTo (CloneContext clonectx, Expression t) 12966 { 12967 var target = (InterpolatedStringInsert)t; 12968 target.expr = expr.Clone (clonectx); 12969 if (Alignment != null) 12970 target.Alignment = Alignment.Clone (clonectx); 12971 } 12972 DoResolve(ResolveContext rc)12973 protected override Expression DoResolve (ResolveContext rc) 12974 { 12975 var expr = base.DoResolve (rc); 12976 if (expr == null) 12977 return null; 12978 12979 // 12980 // For better error reporting, assumes the built-in implementation uses object 12981 // as argument(s) 12982 // 12983 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location); 12984 } 12985 FlowAnalysis(FlowAnalysisContext fc)12986 public override void FlowAnalysis (FlowAnalysisContext fc) 12987 { 12988 Child.FlowAnalysis (fc); 12989 } 12990 ResolveAligment(ResolveContext rc)12991 public int? ResolveAligment (ResolveContext rc) 12992 { 12993 var c = Alignment.ResolveLabelConstant (rc); 12994 if (c == null) 12995 return null; 12996 12997 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int); 12998 if (c == null) 12999 return null; 13000 13001 var value = (int) c.GetValueAsLong (); 13002 if (value > 32767 || value < -32767) { 13003 rc.Report.Warning (8094, 1, Alignment.Location, 13004 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string"); 13005 } 13006 13007 return value; 13008 } 13009 } 13010 13011 class ThrowExpression : ExpressionStatement 13012 { 13013 Expression expr; 13014 ThrowExpression(Expression expr, Location loc)13015 public ThrowExpression (Expression expr, Location loc) 13016 { 13017 this.expr = expr; 13018 this.loc = loc; 13019 } 13020 CloneTo(CloneContext clonectx, Expression t)13021 protected override void CloneTo (CloneContext clonectx, Expression t) 13022 { 13023 var target = (ThrowExpression)t; 13024 target.expr = expr.Clone (clonectx); 13025 } 13026 ContainsEmitWithAwait()13027 public override bool ContainsEmitWithAwait () 13028 { 13029 return expr.ContainsEmitWithAwait (); 13030 } 13031 CreateExpressionTree(ResolveContext rc)13032 public override Expression CreateExpressionTree (ResolveContext rc) 13033 { 13034 rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression"); 13035 return expr; 13036 } 13037 DoResolve(ResolveContext rc)13038 protected override Expression DoResolve (ResolveContext rc) 13039 { 13040 expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue); 13041 13042 if (expr == null) 13043 return null; 13044 13045 expr = Throw.ConvertType (rc, expr); 13046 13047 eclass = ExprClass.Value; 13048 type = InternalType.ThrowExpr; 13049 return this; 13050 } 13051 Emit(EmitContext ec)13052 public override void Emit (EmitContext ec) 13053 { 13054 EmitStatement (ec); 13055 } 13056 EmitStatement(EmitContext ec)13057 public override void EmitStatement (EmitContext ec) 13058 { 13059 expr.Emit (ec); 13060 13061 ec.Emit (OpCodes.Throw); 13062 } 13063 FlowAnalysis(FlowAnalysisContext fc)13064 public override void FlowAnalysis (FlowAnalysisContext fc) 13065 { 13066 expr.FlowAnalysis (fc); 13067 } 13068 MarkReachable(Reachability rc)13069 public override Reachability MarkReachable (Reachability rc) 13070 { 13071 return Reachability.CreateUnreachable (); 13072 } 13073 } 13074 13075 class ReferenceExpression : CompositeExpression 13076 { ReferenceExpression(Expression expr, Location loc)13077 public ReferenceExpression (Expression expr, Location loc) 13078 : base (expr) 13079 { 13080 this.loc = loc; 13081 } 13082 CanBeByRef(Expression expr)13083 static bool CanBeByRef (Expression expr) 13084 { 13085 if (expr is IAssignMethod) 13086 return true; 13087 13088 var invocation = expr as Invocation; 13089 if (invocation?.Type.Kind == MemberKind.ByRef) 13090 return true; 13091 13092 return false; 13093 } 13094 CreateExpressionTree(ResolveContext rc)13095 public override Expression CreateExpressionTree (ResolveContext rc) 13096 { 13097 throw new NotSupportedException ("ET"); 13098 } 13099 DoResolve(ResolveContext rc)13100 protected override Expression DoResolve (ResolveContext rc) 13101 { 13102 var res = expr.DoResolveLValue (rc, EmptyExpression.OutAccess); 13103 if (res == null || !CanBeByRef (res)) { 13104 if (res?.Type != InternalType.ErrorType) 13105 rc.Report.Error (8156, expr.Location, "An expression cannot be used in this context because it may not be returned by reference"); 13106 return ErrorExpression.Instance; 13107 } 13108 13109 type = res.Type; 13110 var type_container = type as ReferenceContainer; 13111 if (type_container != null) 13112 type = type_container.Element; 13113 13114 expr = res; 13115 eclass = ExprClass.Value; 13116 return this; 13117 } 13118 Emit(EmitContext ec)13119 public override void Emit (EmitContext ec) 13120 { 13121 var ml = expr as IMemoryLocation; 13122 if (ml != null) 13123 ml.AddressOf (ec, AddressOp.LoadStore); 13124 else 13125 expr.Emit (ec); 13126 } 13127 Error_ValueCannotBeConverted(ResolveContext rc, TypeSpec target, bool expl)13128 public override void Error_ValueCannotBeConverted (ResolveContext rc, TypeSpec target, bool expl) 13129 { 13130 rc.Report.Error (8173, loc, "The expression must be of type `{0}' because it is being assigned by reference", target.GetSignatureForError ()); 13131 } 13132 } 13133 13134 class ByRefDereference : CompositeExpression, IMemoryLocation, IAssignMethod 13135 { 13136 bool prepared; 13137 LocalTemporary temporary; 13138 ByRefDereference(Expression expr)13139 private ByRefDereference (Expression expr) 13140 : base (expr) 13141 { 13142 } 13143 Create(Expression expr)13144 public static Expression Create (Expression expr) 13145 { 13146 var rc = expr.Type as ReferenceContainer; 13147 if (rc == null) 13148 return expr; 13149 13150 return new ByRefDereference (expr) { 13151 type = rc.Element 13152 }; 13153 } 13154 AddressOf(EmitContext ec, AddressOp mode)13155 public void AddressOf (EmitContext ec, AddressOp mode) 13156 { 13157 expr.Emit (ec); 13158 } 13159 CreateExpressionTree(ResolveContext rc)13160 public override Expression CreateExpressionTree (ResolveContext rc) 13161 { 13162 rc.Report.Error (8153, Location, "An expression tree lambda cannot contain a call to a method, property, or indexer that returns by reference"); 13163 return null; 13164 } 13165 Emit(EmitContext ec, bool leave_copy)13166 public void Emit (EmitContext ec, bool leave_copy) 13167 { 13168 Emit (ec); 13169 if (leave_copy) { 13170 ec.Emit (OpCodes.Dup); 13171 temporary = new LocalTemporary (type); 13172 temporary.Store (ec); 13173 } 13174 } 13175 EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool isCompound)13176 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound) 13177 { 13178 prepared = isCompound; 13179 13180 expr.Emit (ec); 13181 13182 if (isCompound) 13183 ec.Emit (OpCodes.Dup); 13184 13185 source.Emit (ec); 13186 if (leave_copy) { 13187 throw new NotImplementedException ("leave_copy"); 13188 } 13189 13190 ec.EmitStoreFromPtr (type); 13191 13192 if (temporary != null) { 13193 temporary.Emit (ec); 13194 temporary.Release (ec); 13195 } 13196 } 13197 DoResolve(ResolveContext rc)13198 protected override Expression DoResolve (ResolveContext rc) 13199 { 13200 eclass = ExprClass.Variable; 13201 return this; 13202 } 13203 DoResolveLValue(ResolveContext rc, Expression right_side)13204 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) 13205 { 13206 if (expr.ContainsEmitWithAwait ()) { 13207 rc.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference", 13208 expr.GetSignatureForError ()); 13209 } 13210 13211 return DoResolve (rc); 13212 } 13213 Emit(EmitContext ec)13214 public override void Emit (EmitContext ec) 13215 { 13216 if (!prepared) 13217 base.Emit(ec); 13218 13219 ec.EmitLoadFromPtr (type); 13220 } 13221 Accept(StructuralVisitor visitor)13222 public override object Accept (StructuralVisitor visitor) 13223 { 13224 return visitor.Visit (this); 13225 } 13226 } 13227 13228 class DefaultLiteralExpression : Expression 13229 { DefaultLiteralExpression(Location loc)13230 public DefaultLiteralExpression (Location loc) 13231 { 13232 this.loc = loc; 13233 } 13234 CreateExpressionTree(ResolveContext ec)13235 public override Expression CreateExpressionTree (ResolveContext ec) 13236 { 13237 throw new NotImplementedException (); 13238 } 13239 DoResolve(ResolveContext rc)13240 protected override Expression DoResolve (ResolveContext rc) 13241 { 13242 type = InternalType.DefaultType; 13243 eclass = ExprClass.Value; 13244 return this; 13245 } 13246 Emit(EmitContext ec)13247 public override void Emit (EmitContext ec) 13248 { 13249 throw new NotSupportedException (); 13250 } 13251 } 13252 13253 class Discard : Expression, IAssignMethod, IMemoryLocation 13254 { Discard(Location loc)13255 public Discard (Location loc) 13256 { 13257 this.loc = loc; 13258 } 13259 CreateExpressionTree(ResolveContext rc)13260 public override Expression CreateExpressionTree (ResolveContext rc) 13261 { 13262 rc.Report.Error (8207, loc, "An expression tree cannot contain a discard"); 13263 return null; 13264 } 13265 DoResolve(ResolveContext rc)13266 protected override Expression DoResolve (ResolveContext rc) 13267 { 13268 type = InternalType.Discard; 13269 eclass = ExprClass.Variable; 13270 return this; 13271 } 13272 DoResolveLValue(ResolveContext rc, Expression right_side)13273 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side) 13274 { 13275 if (right_side.Type == InternalType.DefaultType) { 13276 rc.Report.Error (8183, loc, "Cannot infer the type of implicitly-typed discard"); 13277 type = InternalType.ErrorType; 13278 return this; 13279 } 13280 13281 if (right_side.Type.Kind == MemberKind.Void) { 13282 rc.Report.Error (8209, loc, "Cannot assign void to a discard"); 13283 type = InternalType.ErrorType; 13284 return this; 13285 } 13286 13287 if (right_side != EmptyExpression.OutAccess) { 13288 type = right_side.Type; 13289 } 13290 13291 return this; 13292 } 13293 Emit(EmitContext ec)13294 public override void Emit (EmitContext ec) 13295 { 13296 throw new NotImplementedException (); 13297 } 13298 Emit(EmitContext ec, bool leave_copy)13299 public void Emit (EmitContext ec, bool leave_copy) 13300 { 13301 throw new NotImplementedException (); 13302 } 13303 EmitAssign(EmitContext ec, Expression source, bool leave_copy, bool isCompound)13304 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound) 13305 { 13306 if (leave_copy) 13307 source.Emit (ec); 13308 else 13309 source.EmitSideEffect (ec); 13310 } 13311 AddressOf(EmitContext ec, AddressOp mode)13312 public void AddressOf (EmitContext ec, AddressOp mode) 13313 { 13314 var temp = ec.GetTemporaryLocal (type); 13315 ec.Emit (OpCodes.Ldloca, temp); 13316 13317 // TODO: Should free it on next statement but don't have mechanism for that yet 13318 // ec.FreeTemporaryLocal (temp, type); 13319 } 13320 } 13321 } 13322