2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
14 using System
.Collections
.Generic
;
16 using SLE
= System
.Linq
.Expressions
;
20 using MetaType
= IKVM
.Reflection
.Type
;
21 using IKVM
.Reflection
;
22 using IKVM
.Reflection
.Emit
;
24 using MetaType
= System
.Type
;
25 using System
.Reflection
;
26 using System
.Reflection
.Emit
;
32 // This is an user operator expression, automatically created during
35 public class UserOperatorCall
: Expression
{
36 protected readonly Arguments arguments
;
37 protected readonly MethodSpec oper
;
38 readonly Func
<ResolveContext
, Expression
, Expression
> expr_tree
;
40 public UserOperatorCall (MethodSpec oper
, Arguments args
, Func
<ResolveContext
, Expression
, Expression
> expr_tree
, Location loc
)
43 this.arguments
= args
;
44 this.expr_tree
= expr_tree
;
46 type
= oper
.ReturnType
;
47 eclass
= ExprClass
.Value
;
51 public override bool ContainsEmitWithAwait ()
53 return arguments
.ContainsEmitWithAwait ();
56 public override Expression
CreateExpressionTree (ResolveContext ec
)
58 if (expr_tree
!= null)
59 return expr_tree (ec
, new TypeOfMethod (oper
, loc
));
61 Arguments args
= Arguments
.CreateForExpressionTree (ec
, arguments
,
62 new NullLiteral (loc
),
63 new TypeOfMethod (oper
, loc
));
65 return CreateExpressionFactoryCall (ec
, "Call", args
);
68 protected override void CloneTo (CloneContext context
, Expression target
)
73 protected override Expression
DoResolve (ResolveContext ec
)
76 // We are born fully resolved
81 public override void Emit (EmitContext ec
)
83 var call
= new CallEmitter ();
84 call
.Emit (ec
, oper
, arguments
, loc
);
87 public override void FlowAnalysis (FlowAnalysisContext fc
)
89 arguments
.FlowAnalysis (fc
);
92 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
95 return base.MakeExpression (ctx
);
97 return SLE
.Expression
.Call ((MethodInfo
) oper
.GetMetaInfo (), Arguments
.MakeExpression (arguments
, ctx
));
102 public class ParenthesizedExpression
: ShimExpression
104 public ParenthesizedExpression (Expression expr
, Location loc
)
110 protected override Expression
DoResolve (ResolveContext rc
)
112 Expression res
= null;
113 using (rc
.With (ResolveContext
.Options
.DontSetConditionalAccessReceiver
, false)) {
114 res
= expr
.Resolve (rc
);
117 var constant
= res
as Constant
;
118 if (constant
!= null && constant
.IsLiteral
) {
119 if (res
is NullLiteral
)
122 return Constant
.CreateConstantFromValue (res
.Type
, constant
.GetValue (), expr
.Location
);
128 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
130 return expr
.DoResolveLValue (ec
, right_side
);
133 public override object Accept (StructuralVisitor visitor
)
135 return visitor
.Visit (this);
138 public override bool HasConditionalAccess ()
145 // Unary implements unary expressions.
147 public class Unary
: Expression
149 public enum Operator
: byte {
150 UnaryPlus
, UnaryNegation
, LogicalNot
, OnesComplement
,
154 public readonly Operator Oper
;
155 public Expression Expr
;
156 ConvCast
.Mode enum_conversion
;
158 public Unary (Operator op
, Expression expr
, Location loc
)
166 // This routine will attempt to simplify the unary expression when the
167 // argument is a constant.
169 Constant
TryReduceConstant (ResolveContext ec
, Constant constant
)
173 while (e
is EmptyConstantCast
)
174 e
= ((EmptyConstantCast
) e
).child
;
176 if (e
is SideEffectConstant
) {
177 Constant r
= TryReduceConstant (ec
, ((SideEffectConstant
) e
).value);
178 return r
== null ? null : new SideEffectConstant (r
, e
, r
.Location
);
181 TypeSpec expr_type
= e
.Type
;
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
);
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
:
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
);
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
);
235 return new IntConstant (ec
.BuiltinTypes
, -ivalue
, e
.Location
);
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
);
246 return new LongConstant (ec
.BuiltinTypes
, -lvalue
, e
.Location
);
248 case BuiltinTypeSpec
.Type
.UInt
:
249 UIntLiteral uil
= constant
as UIntLiteral
;
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
);
255 return new LongConstant (ec
.BuiltinTypes
, -((UIntConstant
) e
).Value
, e
.Location
);
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
);
264 case BuiltinTypeSpec
.Type
.Float
:
265 FloatLiteral fl
= constant
as FloatLiteral
;
266 // For better error reporting
268 return new FloatLiteral (ec
.BuiltinTypes
, -fl
.Value
, e
.Location
);
270 return new FloatConstant (ec
.BuiltinTypes
, -((FloatConstant
) e
).Value
, e
.Location
);
272 case BuiltinTypeSpec
.Type
.Double
:
273 DoubleLiteral dl
= constant
as DoubleLiteral
;
274 // For better error reporting
276 return new DoubleLiteral (ec
.BuiltinTypes
, -dl
.Value
, e
.Location
);
278 return new DoubleConstant (ec
.BuiltinTypes
, -((DoubleConstant
) e
).Value
, e
.Location
);
280 case BuiltinTypeSpec
.Type
.Decimal
:
281 return new DecimalConstant (ec
.BuiltinTypes
, -((DecimalConstant
) e
).Value
, e
.Location
);
286 case Operator
.LogicalNot
:
287 if (expr_type
.BuiltinType
!= BuiltinTypeSpec
.Type
.Bool
)
290 bool b
= (bool)e
.GetValue ();
291 return new BoolConstant (ec
.BuiltinTypes
, !b
, e
.Location
);
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
);
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
);
317 if (e
is EnumConstant
) {
318 var res
= TryReduceConstant (ec
, ((EnumConstant
)e
).Child
);
321 // Numeric promotion upgraded types to int but for enum constant
322 // original underlying constant type is needed
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
);
330 case BuiltinTypeSpec
.Type
.Short
:
331 res
= new ShortConstant (ec
.BuiltinTypes
, (short) v
, e
.Location
);
333 case BuiltinTypeSpec
.Type
.Byte
:
334 res
= new ByteConstant (ec
.BuiltinTypes
, (byte) v
, e
.Location
);
336 case BuiltinTypeSpec
.Type
.SByte
:
337 res
= new SByteConstant (ec
.BuiltinTypes
, (sbyte) v
, e
.Location
);
342 res
= new EnumConstant (res
, expr_type
);
348 throw new Exception ("Can not constant fold: " + Oper
.ToString());
351 protected virtual Expression
ResolveOperator (ResolveContext ec
, Expression expr
)
353 eclass
= ExprClass
.Value
;
355 TypeSpec expr_type
= expr
.Type
;
356 Expression best_expr
;
358 TypeSpec
[] predefined
= ec
.BuiltinTypes
.OperatorsUnary
[(int) Oper
];
361 // Primitive types first
363 if (BuiltinTypeSpec
.IsPrimitiveType (expr_type
)) {
364 best_expr
= ResolvePrimitivePredefinedType (ec
, expr
, predefined
);
365 if (best_expr
== null)
368 type
= best_expr
.Type
;
374 // E operator ~(E x);
376 if (Oper
== Operator
.OnesComplement
&& expr_type
.IsEnum
)
377 return ResolveEnumOperator (ec
, expr
, predefined
);
379 return ResolveUserType (ec
, expr
, predefined
);
382 protected virtual Expression
ResolveEnumOperator (ResolveContext ec
, Expression expr
, TypeSpec
[] predefined
)
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)
390 enum_conversion
= Binary
.GetEnumResultCast (underlying_type
);
392 return EmptyCast
.Create (this, type
);
395 public override bool ContainsEmitWithAwait ()
397 return Expr
.ContainsEmitWithAwait ();
400 public override Expression
CreateExpressionTree (ResolveContext ec
)
402 return CreateExpressionTree (ec
, null);
405 Expression
CreateExpressionTree (ResolveContext ec
, Expression user_op
)
409 case Operator
.AddressOf
:
410 Error_PointerInsideExpressionTree (ec
);
412 case Operator
.UnaryNegation
:
413 if (ec
.HasSet (ResolveContext
.Options
.CheckedScope
) && user_op
== null && !IsFloat (type
))
414 method_name
= "NegateChecked";
416 method_name
= "Negate";
418 case Operator
.OnesComplement
:
419 case Operator
.LogicalNot
:
422 case Operator
.UnaryPlus
:
423 method_name
= "UnaryPlus";
426 throw new InternalErrorException ("Unknown unary operator " + Oper
.ToString ());
429 Arguments args
= new Arguments (2);
430 args
.Add (new Argument (Expr
.CreateExpressionTree (ec
)));
432 args
.Add (new Argument (user_op
));
434 return CreateExpressionFactoryCall (ec
, method_name
, args
);
437 public static TypeSpec
[][] CreatePredefinedOperatorsTable (BuiltinTypes types
)
439 var predefined_operators
= new TypeSpec
[(int) Operator
.TOP
][];
442 // 7.6.1 Unary plus operator
444 predefined_operators
[(int) Operator
.UnaryPlus
] = new TypeSpec
[] {
445 types
.Int
, types
.UInt
,
446 types
.Long
, types
.ULong
,
447 types
.Float
, types
.Double
,
452 // 7.6.2 Unary minus operator
454 predefined_operators
[(int) Operator
.UnaryNegation
] = new TypeSpec
[] {
455 types
.Int
, types
.Long
,
456 types
.Float
, types
.Double
,
461 // 7.6.3 Logical negation operator
463 predefined_operators
[(int) Operator
.LogicalNot
] = new TypeSpec
[] {
468 // 7.6.4 Bitwise complement operator
470 predefined_operators
[(int) Operator
.OnesComplement
] = new TypeSpec
[] {
471 types
.Int
, types
.UInt
,
472 types
.Long
, types
.ULong
475 return predefined_operators
;
479 // Unary numeric promotions
481 static Expression
DoNumericPromotion (ResolveContext rc
, Operator op
, Expression expr
)
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
);
495 if (op
== Operator
.UnaryNegation
&& expr_type
.BuiltinType
== BuiltinTypeSpec
.Type
.UInt
)
496 return Convert
.ImplicitNumericConversion (expr
, rc
.BuiltinTypes
.Long
);
501 protected override Expression
DoResolve (ResolveContext ec
)
503 if (Oper
== Operator
.AddressOf
) {
504 return ResolveAddressOf (ec
);
507 Expr
= Expr
.Resolve (ec
);
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
);
517 if (Expr
.Type
.IsNullableType
)
518 return new Nullable
.LiftedUnaryOperator (Oper
, Expr
, loc
).Resolve (ec
);
521 // Attempt to use a constant folding operation.
523 Constant cexpr
= Expr
as Constant
;
525 cexpr
= TryReduceConstant (ec
, cexpr
);
530 Expression expr
= ResolveOperator (ec
, Expr
);
532 Error_OperatorCannotBeApplied (ec
, loc
, OperName (Oper
), Expr
.Type
);
535 // Reduce unary operator on predefined types
537 if (expr
== this && Oper
== Operator
.UnaryPlus
)
543 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right
)
548 public override void Emit (EmitContext ec
)
550 EmitOperator (ec
, type
);
553 protected void EmitOperator (EmitContext ec
, TypeSpec type
)
556 case Operator
.UnaryPlus
:
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
);
566 if (type
.BuiltinType
== BuiltinTypeSpec
.Type
.Long
)
567 ec
.Emit (OpCodes
.Conv_U8
);
569 ec
.Emit (OpCodes
.Sub_Ovf
);
572 ec
.Emit (OpCodes
.Neg
);
577 case Operator
.LogicalNot
:
580 ec
.Emit (OpCodes
.Ceq
);
583 case Operator
.OnesComplement
:
585 ec
.Emit (OpCodes
.Not
);
588 case Operator
.AddressOf
:
589 ((IMemoryLocation
)Expr
).AddressOf (ec
, AddressOp
.LoadStore
);
593 throw new Exception ("This should not happen: Operator = "
598 // Same trick as in Binary expression
600 if (enum_conversion
!= 0) {
601 using (ec
.With (BuilderContext
.Options
.CheckedScope
, false)) {
602 ConvCast
.Emit (ec
, enum_conversion
);
607 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
609 if (Oper
== Operator
.LogicalNot
)
610 Expr
.EmitBranchable (ec
, target
, !on_true
);
612 base.EmitBranchable (ec
, target
, on_true
);
615 public override void EmitSideEffect (EmitContext ec
)
617 Expr
.EmitSideEffect (ec
);
620 public static void Error_Ambiguous (ResolveContext rc
, string oper
, TypeSpec type
, Location loc
)
622 rc
.Report
.Error (35, loc
, "Operator `{0}' is ambiguous on an operand of type `{1}'",
623 oper
, type
.GetSignatureForError ());
626 public override void FlowAnalysis (FlowAnalysisContext fc
)
628 FlowAnalysis (fc
, false);
631 public override void FlowAnalysisConditional (FlowAnalysisContext fc
)
633 FlowAnalysis (fc
, true);
636 void FlowAnalysis (FlowAnalysisContext fc
, bool conditional
)
638 if (Oper
== Operator
.AddressOf
) {
639 var vr
= Expr
as VariableReference
;
640 if (vr
!= null && vr
.VariableInfo
!= null)
641 fc
.SetVariableAssigned (vr
.VariableInfo
);
646 if (Oper
== Operator
.LogicalNot
&& conditional
) {
647 Expr
.FlowAnalysisConditional (fc
);
649 var temp
= fc
.DefiniteAssignmentOnTrue
;
650 fc
.DefiniteAssignmentOnTrue
= fc
.DefiniteAssignmentOnFalse
;
651 fc
.DefiniteAssignmentOnFalse
= temp
;
653 Expr
.FlowAnalysis (fc
);
658 // Converts operator to System.Linq.Expressions.ExpressionType enum name
660 string GetOperatorExpressionTypeName ()
663 case Operator
.OnesComplement
:
664 return "OnesComplement";
665 case Operator
.LogicalNot
:
667 case Operator
.UnaryNegation
:
669 case Operator
.UnaryPlus
:
672 throw new NotImplementedException ("Unknown express type operator " + Oper
.ToString ());
676 static bool IsFloat (TypeSpec t
)
678 return t
.BuiltinType
== BuiltinTypeSpec
.Type
.Double
|| t
.BuiltinType
== BuiltinTypeSpec
.Type
.Float
;
682 // Returns a stringified representation of the Operator
684 public static string OperName (Operator oper
)
687 case Operator
.UnaryPlus
:
689 case Operator
.UnaryNegation
:
691 case Operator
.LogicalNot
:
693 case Operator
.OnesComplement
:
695 case Operator
.AddressOf
:
699 throw new NotImplementedException (oper
.ToString ());
702 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
704 var expr
= Expr
.MakeExpression (ctx
);
705 bool is_checked
= ctx
.HasSet (BuilderContext
.Options
.CheckedScope
);
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
);
715 throw new NotImplementedException (Oper
.ToString ());
719 Expression
ResolveAddressOf (ResolveContext ec
)
721 if (ec
.CurrentIterator
!= null) {
722 UnsafeInsideIteratorError (ec
, loc
);
723 } else if (!ec
.IsUnsafe
) {
724 UnsafeError (ec
, loc
);
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");
733 if (!TypeManager
.VerifyUnmanaged (ec
.Module
, Expr
.Type
, loc
)) {
737 IVariableReference vr
= Expr
as IVariableReference
;
740 is_fixed
= vr
.IsFixed
;
741 vr
.SetHasAddressTaken ();
743 if (vr
.IsHoisted
&& ec
.CurrentIterator
== null) {
744 AnonymousMethodExpression
.Error_AddressOfCapturedVar (ec
, vr
, loc
);
747 IFixedExpression fe
= Expr
as IFixedExpression
;
748 is_fixed
= fe
!= null && fe
.IsFixed
;
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");
755 type
= PointerContainer
.MakeType (ec
.Module
, Expr
.Type
);
756 eclass
= ExprClass
.Value
;
760 Expression
ResolvePrimitivePredefinedType (ResolveContext rc
, Expression expr
, TypeSpec
[] predefined
)
762 expr
= DoNumericPromotion (rc
, Oper
, expr
);
763 TypeSpec expr_type
= expr
.Type
;
764 foreach (TypeSpec t
in predefined
) {
772 // Perform user-operator overload resolution
774 protected virtual Expression
ResolveUserOperator (ResolveContext ec
, Expression expr
)
776 CSharp
.Operator
.OpType op_type
;
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;
787 throw new InternalErrorException (Oper
.ToString ());
790 var methods
= MemberCache
.GetUserOperator (expr
.Type
, op_type
, false);
794 Arguments args
= new Arguments (1);
795 args
.Add (new Argument (expr
));
797 var res
= new OverloadResolver (methods
, OverloadResolver
.Restrictions
.BaseMembersIncluded
| OverloadResolver
.Restrictions
.NoBaseMembers
, loc
);
798 var oper
= res
.ResolveOperator (ec
, ref args
);
803 Expr
= args
[0].Expr
;
804 return new UserOperatorCall (oper
, args
, CreateExpressionTree
, expr
.Location
);
808 // Unary user type overload resolution
810 Expression
ResolveUserType (ResolveContext ec
, Expression expr
, TypeSpec
[] predefined
)
812 Expression best_expr
= ResolveUserOperator (ec
, expr
);
813 if (best_expr
!= null)
816 foreach (TypeSpec t
in predefined
) {
817 Expression oper_expr
= Convert
.ImplicitUserConversion (ec
, expr
, t
, expr
.Location
);
818 if (oper_expr
== null)
821 if (oper_expr
== ErrorExpression
.Instance
)
825 // decimal type is predefined but has user-operators
827 if (oper_expr
.Type
.BuiltinType
== BuiltinTypeSpec
.Type
.Decimal
)
828 oper_expr
= ResolveUserType (ec
, oper_expr
, predefined
);
830 oper_expr
= ResolvePrimitivePredefinedType (ec
, oper_expr
, predefined
);
832 if (oper_expr
== null)
835 if (best_expr
== null) {
836 best_expr
= oper_expr
;
840 int result
= OverloadResolver
.BetterTypeConversion (ec
, best_expr
.Type
, t
);
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
);
845 Error_OperatorCannotBeApplied (ec
, loc
, OperName (Oper
), expr
.Type
);
852 best_expr
= oper_expr
;
855 if (best_expr
== null)
859 // HACK: Decimal user-operator is included in standard operators
861 if (best_expr
.Type
.BuiltinType
== BuiltinTypeSpec
.Type
.Decimal
)
865 type
= best_expr
.Type
;
869 protected override void CloneTo (CloneContext clonectx
, Expression t
)
871 Unary target
= (Unary
) t
;
873 target
.Expr
= Expr
.Clone (clonectx
);
876 public override object Accept (StructuralVisitor visitor
)
878 return visitor
.Visit (this);
884 // Unary operators are turned into Indirection expressions
885 // after semantic analysis (this is so we can take the address
886 // of an indirection).
888 public class Indirection
: Expression
, IMemoryLocation
, IAssignMethod
, IFixedExpression
{
890 LocalTemporary temporary
;
893 public Indirection (Expression expr
, Location l
)
899 public Expression Expr
{
905 public bool IsFixed
{
909 public override Location StartLocation
{
911 return expr
.StartLocation
;
915 protected override void CloneTo (CloneContext clonectx
, Expression t
)
917 Indirection target
= (Indirection
) t
;
918 target
.expr
= expr
.Clone (clonectx
);
921 public override bool ContainsEmitWithAwait ()
923 throw new NotImplementedException ();
926 public override Expression
CreateExpressionTree (ResolveContext ec
)
928 Error_PointerInsideExpressionTree (ec
);
932 public override void Emit (EmitContext ec
)
937 ec
.EmitLoadFromPtr (Type
);
940 public void Emit (EmitContext ec
, bool leave_copy
)
944 ec
.Emit (OpCodes
.Dup
);
945 temporary
= new LocalTemporary (expr
.Type
);
946 temporary
.Store (ec
);
950 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool isCompound
)
952 prepared
= isCompound
;
957 ec
.Emit (OpCodes
.Dup
);
961 ec
.Emit (OpCodes
.Dup
);
962 temporary
= new LocalTemporary (source
.Type
);
963 temporary
.Store (ec
);
966 ec
.EmitStoreFromPtr (type
);
968 if (temporary
!= null) {
970 temporary
.Release (ec
);
974 public void AddressOf (EmitContext ec
, AddressOp Mode
)
979 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
981 return DoResolve (ec
);
984 protected override Expression
DoResolve (ResolveContext ec
)
986 expr
= expr
.Resolve (ec
);
990 if (ec
.CurrentIterator
!= null) {
991 UnsafeInsideIteratorError (ec
, loc
);
992 } else if (!ec
.IsUnsafe
) {
993 UnsafeError (ec
, loc
);
996 var pc
= expr
.Type
as PointerContainer
;
999 ec
.Report
.Error (193, loc
, "The * or -> operator must be applied to a pointer");
1005 if (type
.Kind
== MemberKind
.Void
) {
1006 Error_VoidPointerOperation (ec
);
1010 eclass
= ExprClass
.Variable
;
1014 public override object Accept (StructuralVisitor visitor
)
1016 return visitor
.Visit (this);
1021 /// Unary Mutator expressions (pre and post ++ and --)
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.
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)
1034 public class UnaryMutator
: ExpressionStatement
1036 class DynamicPostMutator
: Expression
, IAssignMethod
1038 LocalTemporary temp
;
1041 public DynamicPostMutator (Expression expr
)
1044 this.type
= expr
.Type
;
1045 this.loc
= expr
.Location
;
1048 public override Expression
CreateExpressionTree (ResolveContext ec
)
1050 throw new NotImplementedException ("ET");
1053 protected override Expression
DoResolve (ResolveContext rc
)
1055 eclass
= expr
.eclass
;
1059 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
1061 expr
.DoResolveLValue (ec
, right_side
);
1062 return DoResolve (ec
);
1065 public override void Emit (EmitContext ec
)
1070 public void Emit (EmitContext ec
, bool leave_copy
)
1072 throw new NotImplementedException ();
1076 // Emits target assignment using unmodified source value
1078 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool isCompound
)
1081 // Allocate temporary variable to keep original value before it's modified
1083 temp
= new LocalTemporary (type
);
1087 ((IAssignMethod
) expr
).EmitAssign (ec
, source
, false, isCompound
);
1098 public enum Mode
: byte {
1105 PreDecrement
= IsDecrement
,
1106 PostIncrement
= IsPost
,
1107 PostDecrement
= IsPost
| IsDecrement
1111 bool is_expr
, recurse
;
1113 protected Expression expr
;
1115 // Holds the real operation
1116 Expression operation
;
1118 public UnaryMutator (Mode m
, Expression e
, Location loc
)
1125 public Mode UnaryMutatorMode
{
1131 public Expression Expr
{
1137 public override Location StartLocation
{
1139 return (mode
& Mode
.IsPost
) != 0 ? expr
.Location
: loc
;
1143 public override bool ContainsEmitWithAwait ()
1145 return expr
.ContainsEmitWithAwait ();
1148 public override Expression
CreateExpressionTree (ResolveContext ec
)
1150 return new SimpleAssign (this, this).CreateExpressionTree (ec
);
1153 public static TypeSpec
[] CreatePredefinedOperatorsTable (BuiltinTypes types
)
1156 // Predefined ++ and -- operators exist for the following types:
1157 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1159 return new TypeSpec
[] {
1175 protected override Expression
DoResolve (ResolveContext ec
)
1177 expr
= expr
.Resolve (ec
);
1179 if (expr
== null || expr
.Type
== InternalType
.ErrorType
)
1182 if (expr
.Type
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
) {
1184 // Handle postfix unary operators using local
1185 // temporary variable
1187 if ((mode
& Mode
.IsPost
) != 0)
1188 expr
= new DynamicPostMutator (expr
);
1190 Arguments args
= new Arguments (1);
1191 args
.Add (new Argument (expr
));
1192 return new SimpleAssign (expr
, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args
, loc
)).Resolve (ec
);
1195 if (expr
.Type
.IsNullableType
)
1196 return new Nullable
.LiftedUnaryMutator (mode
, expr
, loc
).Resolve (ec
);
1198 return DoResolveOperation (ec
);
1201 protected Expression
DoResolveOperation (ResolveContext ec
)
1203 eclass
= ExprClass
.Value
;
1206 if (expr
is RuntimeValueExpression
) {
1209 // Use itself at the top of the stack
1210 operation
= new EmptyExpression (type
);
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
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
);
1222 ec
.Report
.Error (1059, loc
, "The operand of an increment or decrement operator must be a variable, property or indexer");
1227 // Step 1: Try to find a user operator, it has priority over predefined ones
1229 var user_op
= IsDecrement
? Operator
.OpType
.Decrement
: Operator
.OpType
.Increment
;
1230 var methods
= MemberCache
.GetUserOperator (type
, user_op
, false);
1232 if (methods
!= null) {
1233 Arguments args
= new Arguments (1);
1234 args
.Add (new Argument (expr
));
1236 var res
= new OverloadResolver (methods
, OverloadResolver
.Restrictions
.BaseMembersIncluded
| OverloadResolver
.Restrictions
.NoBaseMembers
, loc
);
1237 var method
= res
.ResolveOperator (ec
, ref args
);
1241 args
[0].Expr
= operation
;
1242 operation
= new UserOperatorCall (method
, args
, null, loc
);
1243 operation
= Convert
.ImplicitConversionRequired (ec
, operation
, type
, loc
);
1248 // Step 2: Try predefined types
1251 Expression source
= null;
1252 bool primitive_type
;
1255 // Predefined without user conversion first for speed-up
1257 // Predefined ++ and -- operators exist for the following types:
1258 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
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
:
1274 primitive_type
= true;
1277 primitive_type
= false;
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
);
1288 Expression best_source
= null;
1289 foreach (var t
in ec
.BuiltinTypes
.OperatorsUnaryMutator
) {
1290 source
= Convert
.ImplicitUserConversion (ec
, operation
, t
, loc
);
1292 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1296 if (best_source
== null) {
1297 best_source
= source
;
1301 var better
= OverloadResolver
.BetterTypeConversion (ec
, best_source
.Type
, source
.Type
);
1306 best_source
= source
;
1310 Unary
.Error_Ambiguous (ec
, OperName (mode
), type
, loc
);
1314 source
= best_source
;
1317 // ++/-- on enum types
1318 if (source
== null && type
.IsEnum
)
1321 if (source
== null) {
1322 expr
.Error_OperatorCannotBeApplied (ec
, loc
, Operator
.GetName (user_op
), type
);
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");
1336 if (operation
.Type
!= type
) {
1338 operation
= Convert
.ExplicitNumericConversion (ec
, operation
, type
);
1340 operation
= Convert
.ImplicitConversionRequired (ec
, operation
, type
, loc
);
1346 void EmitCode (EmitContext ec
, bool is_expr
)
1349 this.is_expr
= is_expr
;
1350 ((IAssignMethod
) expr
).EmitAssign (ec
, this, is_expr
&& (mode
== Mode
.PreIncrement
|| mode
== Mode
.PreDecrement
), true);
1353 public override void Emit (EmitContext ec
)
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
1361 ((IAssignMethod
) expr
).Emit (ec
, is_expr
&& (mode
== Mode
.PostIncrement
|| mode
== Mode
.PostDecrement
));
1369 EmitCode (ec
, true);
1372 protected virtual void EmitOperation (EmitContext ec
)
1374 operation
.Emit (ec
);
1377 public override void EmitStatement (EmitContext ec
)
1379 EmitCode (ec
, false);
1382 public override void FlowAnalysis (FlowAnalysisContext fc
)
1384 expr
.FlowAnalysis (fc
);
1388 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1390 string GetOperatorExpressionTypeName ()
1392 return IsDecrement
? "Decrement" : "Increment";
1396 get { return (mode & Mode.IsDecrement) != 0; }
1400 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
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
);
1407 public static string OperName (Mode oper
)
1409 return (oper
& Mode
.IsDecrement
) != 0 ? "--" : "++";
1412 protected override void CloneTo (CloneContext clonectx
, Expression t
)
1414 UnaryMutator target
= (UnaryMutator
) t
;
1416 target
.expr
= expr
.Clone (clonectx
);
1419 public override object Accept (StructuralVisitor visitor
)
1421 return visitor
.Visit (this);
1427 // Base class for the `is' and `as' operators
1429 public abstract class Probe
: Expression
1431 public Expression ProbeType
;
1432 protected Expression expr
;
1433 protected TypeSpec probe_type_expr
;
1435 protected Probe (Expression expr
, Expression probe_type
, Location l
)
1437 ProbeType
= probe_type
;
1442 public Expression Expr
{
1448 public override bool ContainsEmitWithAwait ()
1450 return expr
.ContainsEmitWithAwait ();
1453 protected Expression
ResolveCommon (ResolveContext rc
)
1455 expr
= expr
.Resolve (rc
);
1459 ResolveProbeType (rc
);
1460 if (probe_type_expr
== null)
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 ());
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",
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",
1481 if (expr
.Type
== InternalType
.DefaultType
) {
1482 Error_OperatorCannotBeApplied (rc
, loc
, OperatorName
, expr
.Type
);
1489 protected virtual void ResolveProbeType (ResolveContext rc
)
1491 probe_type_expr
= ProbeType
.ResolveAsType (rc
);
1494 public override void EmitSideEffect (EmitContext ec
)
1496 expr
.EmitSideEffect (ec
);
1499 public override void EmitPrepare (EmitContext ec
)
1501 expr
.EmitPrepare (ec
);
1504 public override void FlowAnalysis (FlowAnalysisContext fc
)
1506 expr
.FlowAnalysis (fc
);
1509 public override bool HasConditionalAccess ()
1511 return expr
.HasConditionalAccess ();
1514 protected abstract string OperatorName { get; }
1516 protected override void CloneTo (CloneContext clonectx
, Expression t
)
1518 Probe target
= (Probe
) t
;
1520 target
.expr
= expr
.Clone (clonectx
);
1521 target
.ProbeType
= ProbeType
.Clone (clonectx
);
1527 /// Implementation of the `is' operator.
1529 public class Is
: Probe
1531 Nullable
.Unwrap expr_unwrap
;
1532 MethodSpec number_mg
;
1533 Arguments number_args
;
1535 public Is (Expression expr
, Expression probe_type
, Location l
)
1536 : base (expr
, probe_type
, l
)
1540 protected override string OperatorName
{
1541 get { return "is"; }
1544 public LocalVariable Variable { get; set; }
1546 public override Expression
CreateExpressionTree (ResolveContext ec
)
1548 if (Variable
!= null)
1549 ec
.Report
.Error (8122, loc
, "An expression tree cannot contain a pattern matching operator");
1551 Arguments args
= Arguments
.CreateForExpressionTree (ec
, null,
1552 expr
.CreateExpressionTree (ec
),
1553 new TypeOf (probe_type_expr
, loc
));
1555 return CreateExpressionFactoryCall (ec
, "TypeIs", args
);
1558 Expression
CreateConstantResult (ResolveContext rc
, bool result
)
1561 rc
.Report
.Warning (183, 1, loc
, "The given expression is always of the provided (`{0}') type",
1562 probe_type_expr
.GetSignatureForError ());
1564 rc
.Report
.Warning (184, 1, loc
, "The given expression is never of the provided (`{0}') type",
1565 probe_type_expr
.GetSignatureForError ());
1567 var c
= new BoolConstant (rc
.BuiltinTypes
, result
, loc
);
1568 return expr
.IsSideEffectFree
?
1569 ReducedExpression
.Create (c
, this) :
1570 new SideEffectConstant (c
, this, loc
);
1573 public override void Emit (EmitContext ec
)
1575 if (probe_type_expr
== null) {
1576 if (ProbeType
is WildcardPattern
) {
1577 expr
.EmitSideEffect (ec
);
1578 ProbeType
.Emit (ec
);
1580 EmitPatternMatch (ec
);
1587 if (expr_unwrap
== null) {
1589 ec
.Emit (OpCodes
.Cgt_Un
);
1593 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
1595 if (probe_type_expr
== null) {
1596 EmitPatternMatch (ec
);
1601 ec
.Emit (on_true
? OpCodes
.Brtrue
: OpCodes
.Brfalse
, target
);
1604 public override void EmitPrepare (EmitContext ec
)
1606 base.EmitPrepare (ec
);
1608 if (Variable
!= null)
1609 Variable
.CreateBuilder (ec
);
1612 void EmitPatternMatch (EmitContext ec
)
1614 var no_match
= ec
.DefineLabel ();
1615 var end
= ec
.DefineLabel ();
1617 if (expr_unwrap
!= null) {
1618 expr_unwrap
.EmitCheck (ec
);
1620 if (ProbeType
.IsNull
) {
1622 ec
.Emit (OpCodes
.Ceq
);
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
);
1637 if (number_args
!= null && number_args
.Count
== 3) {
1638 var ce
= new CallEmitter ();
1639 ce
.Emit (ec
, number_mg
, number_args
, loc
);
1643 var probe_type
= ProbeType
.Type
;
1646 ec
.Emit (OpCodes
.Isinst
, probe_type
);
1647 ec
.Emit (OpCodes
.Dup
);
1648 ec
.Emit (OpCodes
.Brfalse
, no_match
);
1650 bool complex_pattern
= ProbeType
is ComplexPatternExpression
;
1651 Label prev
= ec
.RecursivePatternLabel
;
1652 if (complex_pattern
)
1653 ec
.RecursivePatternLabel
= ec
.DefineLabel ();
1655 if (number_mg
!= null) {
1656 var ce
= new CallEmitter ();
1657 ce
.Emit (ec
, number_mg
, number_args
, loc
);
1659 if (TypeSpec
.IsValueType (probe_type
))
1660 ec
.Emit (OpCodes
.Unbox_Any
, probe_type
);
1662 ProbeType
.Emit (ec
);
1663 if (complex_pattern
) {
1666 ec
.Emit (OpCodes
.Ceq
);
1669 ec
.Emit (OpCodes
.Br_S
, end
);
1670 ec
.MarkLabel (no_match
);
1672 ec
.Emit (OpCodes
.Pop
);
1674 if (complex_pattern
)
1675 ec
.MarkLabel (ec
.RecursivePatternLabel
);
1677 ec
.RecursivePatternLabel
= prev
;
1683 void EmitLoad (EmitContext ec
)
1685 if (expr_unwrap
!= null) {
1686 expr_unwrap
.EmitCheck (ec
);
1688 if (Variable
== null)
1691 ec
.Emit (OpCodes
.Dup
);
1692 var no_value_label
= ec
.DefineLabel ();
1693 ec
.Emit (OpCodes
.Brfalse_S
, no_value_label
);
1695 if (Variable
.HoistedVariant
!= null)
1698 expr_unwrap
.Emit (ec
);
1700 if (Variable
.HoistedVariant
!= null) {
1701 Variable
.HoistedVariant
.EmitAssignFromStack (ec
);
1704 // It's ok to have variable builder created out of order. It simplifies emit
1705 // of statements like while (condition) { }
1707 if (!Variable
.Created
)
1708 Variable
.CreateBuilder (ec
);
1710 Variable
.EmitAssign (ec
);
1713 ec
.MarkLabel (no_value_label
);
1719 bool vtype_variable
= Variable
!= null && (probe_type_expr
.IsGenericParameter
|| TypeSpec
.IsValueType (ProbeType
.Type
));
1720 LocalBuilder expr_copy
= null;
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
)) {
1728 // Only to make verifier happy
1730 ec
.Emit (OpCodes
.Box
, expr
.Type
);
1733 ec
.Emit (OpCodes
.Isinst
, probe_type_expr
);
1735 if (Variable
!= null) {
1736 ec
.Emit (OpCodes
.Dup
);
1738 var nonmatching_label
= ec
.DefineLabel ();
1739 ec
.Emit (OpCodes
.Brfalse_S
, nonmatching_label
);
1741 if (vtype_variable
) {
1742 if (expr_copy
!= null) {
1743 ec
.Emit (OpCodes
.Ldloc
, expr_copy
);
1744 ec
.FreeTemporaryLocal (expr_copy
, expr
.Type
);
1749 ec
.Emit (OpCodes
.Unbox_Any
, probe_type_expr
);
1751 // Already on the stack
1754 if (Variable
.HoistedVariant
!= null) {
1755 var temp
= new LocalTemporary (ProbeType
.Type
);
1757 Variable
.HoistedVariant
.EmitAssign (ec
, temp
, false, false);
1760 if (!vtype_variable
)
1761 Variable
.HoistedVariant
.Emit (ec
);
1764 // It's ok to have variable builder created out of order. It simplifies emit
1765 // of statements like while (condition) { }
1767 if (!Variable
.Created
)
1768 Variable
.CreateBuilder (ec
);
1770 Variable
.EmitAssign (ec
);
1772 if (!vtype_variable
)
1776 ec
.MarkLabel (nonmatching_label
);
1780 protected override Expression
DoResolve (ResolveContext rc
)
1782 if (ResolveCommon (rc
) == null)
1785 type
= rc
.BuiltinTypes
.Bool
;
1786 eclass
= ExprClass
.Value
;
1788 if (probe_type_expr
== null)
1789 return ResolveMatchingExpression (rc
);
1791 var res
= ResolveResultExpression (rc
);
1792 if (Variable
!= null) {
1793 if (res
is Constant
)
1794 throw new NotImplementedException ("constant in type pattern matching");
1796 Variable
.Type
= probe_type_expr
;
1797 var bc
= rc
as BlockContext
;
1799 Variable
.PrepareAssignmentAnalysis (bc
);
1805 public override void FlowAnalysis (FlowAnalysisContext fc
)
1807 base.FlowAnalysis (fc
);
1809 if (Variable
!= null)
1810 fc
.SetVariableAssigned (Variable
.VariableInfo
, true);
1813 public override void FlowAnalysisConditional (FlowAnalysisContext fc
)
1815 if (Variable
== null) {
1816 base.FlowAnalysisConditional (fc
);
1820 expr
.FlowAnalysis (fc
);
1822 fc
.DefiniteAssignmentOnTrue
= fc
.BranchDefiniteAssignment ();
1823 fc
.DefiniteAssignmentOnFalse
= fc
.DefiniteAssignment
;
1825 fc
.SetVariableAssigned (Variable
.VariableInfo
, fc
.DefiniteAssignmentOnTrue
);
1828 protected override void ResolveProbeType (ResolveContext rc
)
1830 if (!(ProbeType
is TypeExpr
) && rc
.Module
.Compiler
.Settings
.Version
== LanguageVersion
.Experimental
) {
1831 if (ProbeType
is PatternExpression
) {
1832 ProbeType
.Resolve (rc
);
1837 // Have to use session recording because we don't have reliable type probing
1838 // mechanism (similar issue as in attributes resolving)
1840 // TODO: This is still wrong because ResolveAsType can be destructive
1842 var type_printer
= new SessionReportPrinter ();
1843 var prev_recorder
= rc
.Report
.SetPrinter (type_printer
);
1845 probe_type_expr
= ProbeType
.ResolveAsType (rc
);
1846 type_printer
.EndSession ();
1848 if (probe_type_expr
!= null) {
1849 type_printer
.Merge (rc
.Report
.Printer
);
1850 rc
.Report
.SetPrinter (prev_recorder
);
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
);
1861 var expr_printer
= new SessionReportPrinter ();
1862 rc
.Report
.SetPrinter (expr_printer
);
1863 ProbeType
= ProbeType
.Resolve (rc
);
1864 expr_printer
.EndSession ();
1866 if (ProbeType
!= null) {
1867 expr_printer
.Merge (rc
.Report
.Printer
);
1869 type_printer
.Merge (rc
.Report
.Printer
);
1872 rc
.Report
.SetPrinter (prev_recorder
);
1876 base.ResolveProbeType (rc
);
1879 Expression
ResolveMatchingExpression (ResolveContext rc
)
1881 var mc
= ProbeType
as Constant
;
1883 if (!Convert
.ImplicitConversionExists (rc
, ProbeType
, Expr
.Type
)) {
1884 ProbeType
.Error_ValueCannotBeConverted (rc
, Expr
.Type
, false);
1889 return new Binary (Binary
.Operator
.Equality
, Expr
, mc
).Resolve (rc
);
1891 var c
= Expr
as Constant
;
1893 c
= ConstantFold
.BinaryFold (rc
, Binary
.Operator
.Equality
, c
, mc
, loc
);
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
;
1910 // There are actually 3 arguments but the first one is already on the stack
1912 number_args
= new Arguments (3);
1913 if (!ProbeType
.Type
.IsEnum
)
1914 number_args
.Add (new Argument (Expr
));
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
)));
1923 if (ProbeType
is PatternExpression
) {
1924 if (!(ProbeType
is WildcardPattern
) && !Convert
.ImplicitConversionExists (rc
, ProbeType
, Expr
.Type
)) {
1925 ProbeType
.Error_ValueCannotBeConverted (rc
, Expr
.Type
, false);
1931 // TODO: Better error message
1932 rc
.Report
.Error (150, ProbeType
.Location
, "A constant value is expected");
1936 Expression
ResolveResultExpression (ResolveContext ec
)
1938 if (Variable
!= null) {
1939 if (expr
is NullLiteral
) {
1940 ec
.Report
.Error (8117, loc
, "Cannot use null as pattern matching operand");
1944 CheckExpressionVariable (ec
);
1947 TypeSpec d
= expr
.Type
;
1948 bool d_is_nullable
= false;
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
1955 return CreateConstantResult (ec
, false);
1957 if (d
.IsNullableType
) {
1958 var ut
= Nullable
.NullableInfo
.GetUnderlyingType (d
);
1959 if (!ut
.IsGenericParameter
) {
1961 d_is_nullable
= true;
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 ());
1973 var ut
= Nullable
.NullableInfo
.GetUnderlyingType (t
);
1974 if (!ut
.IsGenericParameter
) {
1976 t_is_nullable
= true;
1983 // D and T are the same value types but D can be null
1985 if (d_is_nullable
&& !t_is_nullable
) {
1986 expr_unwrap
= Nullable
.Unwrap
.Create (expr
, true);
1991 // The result is true if D and T are the same value types
1993 return CreateConstantResult (ec
, true);
1996 var tp
= d
as TypeParameterSpec
;
1998 return ResolveGenericParameter (ec
, t
, tp
);
2001 // An unboxing conversion exists
2003 if (Convert
.ExplicitReferenceConversionExists (d
, t
))
2007 // open generic type
2009 if (d
is InflatedTypeSpec
&& InflatedTypeSpec
.ContainsTypeParameter (d
))
2012 var tps
= t
as TypeParameterSpec
;
2014 return ResolveGenericParameter (ec
, d
, tps
);
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 ());
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 ());
2026 if (TypeManager
.IsGenericParameter (d
))
2027 return ResolveGenericParameter (ec
, t
, (TypeParameterSpec
) d
);
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);
2036 return CreateConstantResult (ec
, true);
2039 if (Convert
.ImplicitReferenceConversionExists (d
, t
)) {
2040 var c
= expr
as Constant
;
2042 return CreateConstantResult (ec
, !c
.IsNull
);
2045 // Do not optimize for imported type or dynamic type
2047 if (d
.MemberDefinition
.IsImported
&& d
.BuiltinType
!= BuiltinTypeSpec
.Type
.None
&&
2048 d
.MemberDefinition
.DeclaringAssembly
!= t
.MemberDefinition
.DeclaringAssembly
) {
2052 if (d
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
)
2056 // Turn is check into simple null check for implicitly convertible reference types
2058 return ReducedExpression
.Create (
2059 new Binary (Binary
.Operator
.Inequality
, expr
, new NullLiteral (loc
), Binary
.State
.UserOperatorsExcluded
).Resolve (ec
),
2063 if (Convert
.ExplicitReferenceConversionExists (d
, t
))
2067 // open generic type
2069 if ((d
is InflatedTypeSpec
|| d
.IsArray
) && InflatedTypeSpec
.ContainsTypeParameter (d
))
2074 return CreateConstantResult (ec
, false);
2077 Expression
ResolveGenericParameter (ResolveContext ec
, TypeSpec d
, TypeParameterSpec t
)
2079 if (t
.IsReferenceType
) {
2081 return CreateConstantResult (ec
, false);
2084 if (expr
.Type
.IsGenericParameter
) {
2085 if (expr
.Type
== d
&& TypeSpec
.IsValueType (t
) && TypeSpec
.IsValueType (d
))
2086 return CreateConstantResult (ec
, true);
2088 expr
= new BoxedCast (expr
, d
);
2094 public override object Accept (StructuralVisitor visitor
)
2096 return visitor
.Visit (this);
2100 class WildcardPattern
: PatternExpression
2102 public WildcardPattern (Location loc
)
2107 protected override Expression
DoResolve (ResolveContext rc
)
2109 eclass
= ExprClass
.Value
;
2110 type
= rc
.BuiltinTypes
.Object
;
2114 public override void Emit (EmitContext ec
)
2120 class RecursivePattern
: ComplexPatternExpression
2122 MethodGroupExpr operator_mg
;
2123 Arguments operator_args
;
2125 public RecursivePattern (ATypeNameExpression typeExpresion
, Arguments arguments
, Location loc
)
2126 : base (typeExpresion
, loc
)
2128 Arguments
= arguments
;
2131 public Arguments Arguments { get; private set; }
2133 protected override Expression
DoResolve (ResolveContext rc
)
2135 type
= TypeExpression
.ResolveAsType (rc
);
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");
2145 var ops
= FindMatchingOverloads (operators
);
2147 // TODO: better error message
2148 Error_TypeDoesNotContainDefinition (rc
, type
, Operator
.GetName (Operator
.OpType
.Is
) + " operator");
2153 Arguments
.Resolve (rc
, out dynamic_args
);
2155 throw new NotImplementedException ("dynamic argument");
2157 var op
= FindBestOverload (rc
, ops
);
2159 // TODO: better error message
2160 Error_TypeDoesNotContainDefinition (rc
, type
, Operator
.GetName (Operator
.OpType
.Is
) + " operator");
2164 var op_types
= op
.Parameters
.Types
;
2165 operator_args
= new Arguments (op_types
.Length
);
2166 operator_args
.Add (new Argument (new EmptyExpression (type
)));
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
));
2173 if (comparisons
== null)
2174 comparisons
= new Expression
[Arguments
.Count
];
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
;
2189 comparisons
[arg_comp_index
] = ResolveComparison (rc
, expr
, lt
);
2192 operator_mg
= MethodGroupExpr
.CreatePredefined (op
, type
, loc
);
2194 eclass
= ExprClass
.Value
;
2198 List
<MethodSpec
> FindMatchingOverloads (IList
<MemberSpec
> members
)
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
)
2207 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2209 for (int ii
= 1; ii
< pm
.Count
; ++ii
) {
2210 if ((pm
.FixedParameters
[ii
].ModFlags
& Parameter
.Modifier
.OUT
) == 0) {
2220 best
= new List
<MethodSpec
> ();
2228 MethodSpec
FindBestOverload (ResolveContext rc
, List
<MethodSpec
> methods
)
2230 for (int ii
= 0; ii
< Arguments
.Count
; ++ii
) {
2231 var arg
= Arguments
[ii
];
2232 var expr
= arg
.Expr
;
2233 if (expr
is WildcardPattern
)
2236 var na
= arg
as NamedArgument
;
2237 for (int i
= 0; i
< methods
.Count
; ++i
) {
2238 var pd
= methods
[i
].Parameters
;
2242 index
= pd
.GetParameterIndexByName (na
.Name
);
2244 methods
.RemoveAt (i
--);
2251 var m
= pd
.Types
[index
];
2252 if (!Convert
.ImplicitConversionExists (rc
, expr
, m
))
2253 methods
.RemoveAt (i
--);
2257 if (methods
.Count
!= 1)
2263 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
2265 operator_mg
.EmitCall (ec
, operator_args
, false);
2266 ec
.Emit (OpCodes
.Brfalse
, target
);
2268 base.EmitBranchable (ec
, target
, on_true
);
2271 static Expression
ResolveComparison (ResolveContext rc
, Expression expr
, LocalTemporary lt
)
2273 if (expr
is WildcardPattern
)
2274 return new EmptyExpression (expr
.Type
);
2276 var recursive
= expr
as RecursivePattern
;
2277 expr
= Convert
.ImplicitConversionRequired (rc
, expr
, lt
.Type
, expr
.Location
);
2281 if (recursive
!= null) {
2282 recursive
.SetParentInstance (lt
);
2286 // TODO: Better error handling
2287 return new Binary (Binary
.Operator
.Equality
, lt
, expr
, expr
.Location
).Resolve (rc
);
2290 public void SetParentInstance (Expression instance
)
2292 operator_args
[0] = new Argument (instance
);
2296 class PropertyPattern
: ComplexPatternExpression
2298 LocalTemporary instance
;
2300 public PropertyPattern (ATypeNameExpression typeExpresion
, List
<PropertyPatternMember
> members
, Location loc
)
2301 : base (typeExpresion
, loc
)
2306 public List
<PropertyPatternMember
> Members { get; private set; }
2308 protected override Expression
DoResolve (ResolveContext rc
)
2310 type
= TypeExpression
.ResolveAsType (rc
);
2314 comparisons
= new Expression
[Members
.Count
];
2316 // TODO: optimize when source is VariableReference, it'd save dup+pop
2317 instance
= new LocalTemporary (type
);
2319 for (int i
= 0; i
< Members
.Count
; i
++) {
2320 var lookup
= Members
[i
];
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
);
2331 if (member
== null) {
2332 Expression
.Error_TypeDoesNotContainDefinition (rc
, Location
, Type
, lookup
.Name
);
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
);
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 ());
2349 var expr
= lookup
.Expr
.Resolve (rc
);
2353 var me
= (MemberExpr
)member
;
2354 me
.InstanceExpression
= instance
;
2356 comparisons
[i
] = ResolveComparison (rc
, expr
, me
);
2359 eclass
= ExprClass
.Value
;
2363 static Expression
ResolveComparison (ResolveContext rc
, Expression expr
, Expression instance
)
2365 if (expr
is WildcardPattern
)
2366 return new EmptyExpression (expr
.Type
);
2368 return new Is (instance
, expr
, expr
.Location
).Resolve (rc
);
2371 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
2373 instance
.Store (ec
);
2375 base.EmitBranchable (ec
, target
, on_true
);
2379 class PropertyPatternMember
2381 public PropertyPatternMember (string name
, Expression expr
, Location loc
)
2388 public string Name { get; private set; }
2389 public Expression Expr { get; private set; }
2390 public Location Location { get; private set; }
2393 abstract class PatternExpression
: Expression
2395 protected PatternExpression (Location loc
)
2400 public override Expression
CreateExpressionTree (ResolveContext ec
)
2402 throw new NotImplementedException ();
2406 abstract class ComplexPatternExpression
: PatternExpression
2408 protected Expression
[] comparisons
;
2410 protected ComplexPatternExpression (ATypeNameExpression typeExpresion
, Location loc
)
2413 TypeExpression
= typeExpresion
;
2416 public ATypeNameExpression TypeExpression { get; private set; }
2418 public override void Emit (EmitContext ec
)
2420 EmitBranchable (ec
, ec
.RecursivePatternLabel
, false);
2423 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
2425 if (comparisons
!= null) {
2426 foreach (var comp
in comparisons
) {
2427 comp
.EmitBranchable (ec
, target
, false);
2434 /// Implementation of the `as' operator.
2436 public class As
: Probe
{
2438 public As (Expression expr
, Expression probe_type
, Location l
)
2439 : base (expr
, probe_type
, l
)
2443 protected override string OperatorName
{
2444 get { return "as"; }
2447 public override Expression
CreateExpressionTree (ResolveContext ec
)
2449 Arguments args
= Arguments
.CreateForExpressionTree (ec
, null,
2450 expr
.CreateExpressionTree (ec
),
2451 new TypeOf (probe_type_expr
, loc
));
2453 return CreateExpressionFactoryCall (ec
, "TypeAs", args
);
2456 public override void Emit (EmitContext ec
)
2460 ec
.Emit (OpCodes
.Isinst
, type
);
2462 if (TypeManager
.IsGenericParameter (type
) || type
.IsNullableType
)
2463 ec
.Emit (OpCodes
.Unbox_Any
, type
);
2466 protected override Expression
DoResolve (ResolveContext ec
)
2468 if (ResolveCommon (ec
) == null)
2471 type
= probe_type_expr
;
2472 eclass
= ExprClass
.Value
;
2473 TypeSpec etype
= expr
.Type
;
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
;
2482 type
= InternalType
.ErrorType
;
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 ());
2492 ec
.Report
.Error (77, loc
,
2493 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2494 type
.GetSignatureForError ());
2499 if (expr
.IsNull
&& type
.IsNullableType
) {
2500 return Nullable
.LiftedNull
.CreateFromExpression (ec
, this);
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
) {
2508 Expression e
= Convert
.ImplicitConversionStandard (ec
, expr
, type
, loc
);
2510 e
= EmptyCast
.Create (e
, type
);
2511 return ReducedExpression
.Create (e
, this).Resolve (ec
);
2514 if (Convert
.ExplicitReferenceConversionExists (etype
, type
)){
2515 if (TypeManager
.IsGenericParameter (etype
))
2516 expr
= new BoxedCast (expr
, etype
);
2521 if (InflatedTypeSpec
.ContainsTypeParameter (etype
) || InflatedTypeSpec
.ContainsTypeParameter (type
)) {
2522 expr
= new BoxedCast (expr
, etype
);
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 ());
2534 public override object Accept (StructuralVisitor visitor
)
2536 return visitor
.Visit (this);
2541 // This represents a typecast in the source language.
2543 public class Cast
: ShimExpression
{
2544 Expression target_type
;
2546 public Cast (Expression cast_type
, Expression expr
, Location loc
)
2549 this.target_type
= cast_type
;
2553 public Expression TargetType
{
2554 get { return target_type; }
2557 protected override Expression
DoResolve (ResolveContext ec
)
2559 expr
= expr
.Resolve (ec
);
2563 type
= target_type
.ResolveAsType (ec
);
2567 if (type
.IsStatic
) {
2568 ec
.Report
.Error (716, loc
, "Cannot convert to static type `{0}'", type
.GetSignatureForError ());
2572 if (type
.IsPointer
) {
2573 if (ec
.CurrentIterator
!= null) {
2574 UnsafeInsideIteratorError (ec
, loc
);
2575 } else if (!ec
.IsUnsafe
) {
2576 UnsafeError (ec
, loc
);
2580 eclass
= ExprClass
.Value
;
2582 Constant c
= expr
as Constant
;
2584 c
= c
.Reduce (ec
, type
);
2589 var res
= Convert
.ExplicitConversion (ec
, expr
, type
, loc
);
2591 return EmptyCast
.Create (res
, type
);
2596 protected override void CloneTo (CloneContext clonectx
, Expression t
)
2598 Cast target
= (Cast
) t
;
2600 target
.target_type
= target_type
.Clone (clonectx
);
2601 target
.expr
= expr
.Clone (clonectx
);
2604 public override object Accept (StructuralVisitor visitor
)
2606 return visitor
.Visit (this);
2610 public class ImplicitCast
: ShimExpression
2614 public ImplicitCast (Expression expr
, TypeSpec target
, bool arrayAccess
)
2617 this.loc
= expr
.Location
;
2619 this.arrayAccess
= arrayAccess
;
2622 protected override Expression
DoResolve (ResolveContext ec
)
2624 expr
= expr
.Resolve (ec
);
2629 expr
= ConvertExpressionToArrayIndex (ec
, expr
);
2631 expr
= Convert
.ImplicitConversionRequired (ec
, expr
, type
, loc
);
2637 public class DeclarationExpression
: Expression
, IMemoryLocation
2639 LocalVariableReference lvr
;
2641 public DeclarationExpression (FullNamedExpression variableType
, LocalVariable variable
)
2643 VariableType
= variableType
;
2644 Variable
= variable
;
2645 this.loc
= variable
.Location
;
2648 public LocalVariable Variable { get; set; }
2649 public Expression Initializer { get; set; }
2650 public FullNamedExpression VariableType { get; set; }
2652 public void AddressOf (EmitContext ec
, AddressOp mode
)
2654 if (!Variable
.Created
)
2655 Variable
.CreateBuilder (ec
);
2657 if (Initializer
!= null) {
2658 lvr
.EmitAssign (ec
, Initializer
, false, false);
2661 lvr
.AddressOf (ec
, mode
);
2664 protected override void CloneTo (CloneContext clonectx
, Expression t
)
2666 var target
= (DeclarationExpression
) t
;
2668 target
.VariableType
= (FullNamedExpression
) VariableType
.Clone (clonectx
);
2670 if (Initializer
!= null)
2671 target
.Initializer
= Initializer
.Clone (clonectx
);
2674 public override Expression
CreateExpressionTree (ResolveContext rc
)
2676 rc
.Report
.Error (8198, loc
, "An expression tree cannot contain out variable declaration");
2680 bool DoResolveCommon (ResolveContext rc
)
2682 CheckExpressionVariable (rc
);
2684 var var_expr
= VariableType
as VarExpr
;
2685 if (var_expr
!= null) {
2686 type
= InternalType
.VarOutType
;
2688 type
= VariableType
.ResolveAsType (rc
);
2693 if (Initializer
!= null) {
2694 Initializer
= Initializer
.Resolve (rc
);
2696 if (var_expr
!= null && Initializer
!= null && var_expr
.InferType (rc
, Initializer
)) {
2697 type
= var_expr
.Type
;
2701 Variable
.Type
= type
;
2702 lvr
= new LocalVariableReference (Variable
, loc
);
2704 eclass
= ExprClass
.Variable
;
2708 protected override Expression
DoResolve (ResolveContext rc
)
2710 if (DoResolveCommon (rc
))
2716 public override Expression
DoResolveLValue (ResolveContext rc
, Expression right_side
)
2718 if (lvr
== null && DoResolveCommon (rc
))
2719 lvr
.ResolveLValue (rc
, right_side
);
2724 public override void Emit (EmitContext ec
)
2726 throw new NotImplementedException ();
2729 public override void EmitPrepare (EmitContext ec
)
2731 Variable
.CreateBuilder (ec
);
2736 // C# 2.0 Default value expression
2738 public class DefaultValueExpression
: Expression
2742 public DefaultValueExpression (Expression expr
, Location loc
)
2748 public Expression Expr
{
2754 public override bool IsSideEffectFree
{
2760 public override bool ContainsEmitWithAwait ()
2765 public override Expression
CreateExpressionTree (ResolveContext ec
)
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
);
2773 protected override Expression
DoResolve (ResolveContext ec
)
2775 type
= expr
.ResolveAsType (ec
);
2779 if (type
.IsStatic
) {
2780 ec
.Report
.Error (-244, loc
, "The `default value' operator cannot be applied to an operand of a static type");
2784 return new NullLiteral (Location
).ConvertImplicitly (type
);
2786 if (TypeSpec
.IsReferenceType (type
))
2787 return new NullConstant (type
, loc
);
2789 Constant c
= New
.Constantify (type
, expr
.Location
);
2793 eclass
= ExprClass
.Variable
;
2797 public override void Emit (EmitContext ec
)
2799 LocalTemporary temp_storage
= new LocalTemporary(type
);
2801 temp_storage
.AddressOf(ec
, AddressOp
.LoadStore
);
2802 ec
.Emit(OpCodes
.Initobj
, type
);
2803 temp_storage
.Emit(ec
);
2804 temp_storage
.Release (ec
);
2808 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
2810 return SLE
.Expression
.Default (type
.GetMetaInfo ());
2814 protected override void CloneTo (CloneContext clonectx
, Expression t
)
2816 DefaultValueExpression target
= (DefaultValueExpression
) t
;
2818 target
.expr
= expr
.Clone (clonectx
);
2821 public override object Accept (StructuralVisitor visitor
)
2823 return visitor
.Visit (this);
2828 /// Binary operators
2830 public class Binary
: Expression
, IDynamicBinder
2832 public class PredefinedOperator
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
;
2841 public PredefinedOperator (TypeSpec ltype
, TypeSpec rtype
, Operator op_mask
)
2842 : this (ltype
, rtype
, op_mask
, ltype
)
2846 public PredefinedOperator (TypeSpec type
, Operator op_mask
, TypeSpec return_type
)
2847 : this (type
, type
, op_mask
, return_type
)
2851 public PredefinedOperator (TypeSpec type
, Operator op_mask
)
2852 : this (type
, type
, op_mask
, type
)
2856 public PredefinedOperator (TypeSpec ltype
, TypeSpec rtype
, Operator op_mask
, TypeSpec return_type
)
2858 if ((op_mask
& Operator
.ValuesOnlyMask
) != 0)
2859 throw new InternalErrorException ("Only masked values can be used");
2861 if ((op_mask
& Operator
.NullableMask
) != 0) {
2862 left_unwrap
= Nullable
.NullableInfo
.GetUnderlyingType (ltype
);
2863 right_unwrap
= Nullable
.NullableInfo
.GetUnderlyingType (rtype
);
2865 left_unwrap
= ltype
;
2866 right_unwrap
= rtype
;
2871 this.OperatorsMask
= op_mask
;
2872 this.ReturnType
= return_type
;
2875 public bool IsLifted
{
2877 return (OperatorsMask
& Operator
.NullableMask
) != 0;
2881 public virtual Expression
ConvertResult (ResolveContext rc
, Binary b
)
2885 var left_expr
= b
.left
;
2886 var right_expr
= b
.right
;
2888 b
.type
= ReturnType
;
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
);
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
);
2904 b
.left
= Convert
.ImplicitConversion (rc
, b
.left
, left
, b
.left
.Location
);
2905 b
.right
= Convert
.ImplicitConversion (rc
, b
.right
, right
, b
.right
.Location
);
2907 if ((b
.Oper
& (Operator
.ArithmeticMask
| Operator
.ShiftMask
)) != 0)
2908 return Nullable
.LiftedNull
.CreateFromExpression (rc
, b
);
2910 return b
.CreateLiftedValueTypeResult (rc
, left
);
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
);
2920 b
.left
= Convert
.ImplicitConversion (rc
, b
.left
, left
, b
.left
.Location
);
2921 b
.right
= Convert
.ImplicitConversion (rc
, b
.right
, right
, b
.right
.Location
);
2923 if ((b
.Oper
& (Operator
.ArithmeticMask
| Operator
.ShiftMask
)) != 0)
2924 return Nullable
.LiftedNull
.CreateFromExpression (rc
, b
);
2926 return b
.CreateLiftedValueTypeResult (rc
, right
);
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
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
);
2940 return b
.ResolveUserOperator (rc
, b
.left
, b
.right
);
2943 c
= right_expr
as Constant
;
2945 if (c
.IsDefaultValue
) {
2949 // (expr + 0) to expr
2950 // (expr - 0) to expr
2951 // (bool? | false) to bool?
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
);
2960 // Optimizes (value &/&& 0) to 0
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
);
2968 // Optimizes (bool? & true) to bool?
2970 if (IsLifted
&& left_unwrap
.BuiltinType
== BuiltinTypeSpec
.Type
.Bool
&& b
.oper
== Operator
.BitwiseAnd
) {
2971 return ReducedExpression
.Create (b
.left
, b
).Resolve (rc
);
2975 if ((b
.oper
== Operator
.Multiply
|| b
.oper
== Operator
.Division
) && c
.IsOneInteger
)
2976 return ReducedExpression
.Create (b
.left
, b
).Resolve (rc
);
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
);
2983 c
= b
.left
as Constant
;
2985 if (c
.IsDefaultValue
) {
2989 // (0 + expr) to expr
2990 // (false | bool?) to bool?
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
);
2999 // Optimizes (false && expr) to false
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
);
3008 // Optimizes (0 & value) to 0
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
);
3016 // Optimizes (true & bool?) to bool?
3018 if (IsLifted
&& left_unwrap
.BuiltinType
== BuiltinTypeSpec
.Type
.Bool
&& b
.oper
== Operator
.BitwiseAnd
) {
3019 return ReducedExpression
.Create (b
.right
, b
).Resolve (rc
);
3023 // Optimizes (true || expr) to true
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
);
3032 if (b
.oper
== Operator
.Multiply
&& c
.IsOneInteger
)
3033 return ReducedExpression
.Create (b
.right
, b
).Resolve (rc
);
3037 var lifted
= new Nullable
.LiftedBinaryOperator (b
);
3039 TypeSpec ltype
, rtype
;
3040 if (b
.left
.Type
.IsNullableType
) {
3041 lifted
.UnwrapLeft
= new Nullable
.Unwrap (b
.left
);
3042 ltype
= left_unwrap
;
3047 if (b
.right
.Type
.IsNullableType
) {
3048 lifted
.UnwrapRight
= new Nullable
.Unwrap (b
.right
);
3049 rtype
= right_unwrap
;
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
);
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
);
3062 return lifted
.Resolve (rc
);
3065 b
.left
= Convert
.ImplicitConversion (rc
, b
.left
, left
, b
.left
.Location
);
3066 b
.right
= Convert
.ImplicitConversion (rc
, b
.right
, right
, b
.right
.Location
);
3071 public bool IsPrimitiveApplicable (TypeSpec ltype
, TypeSpec rtype
)
3074 // We are dealing with primitive types only
3076 return left
== ltype
&& ltype
== rtype
;
3079 public virtual bool IsApplicable (ResolveContext ec
, Expression lexpr
, Expression rexpr
)
3082 if (left
== lexpr
.Type
&& right
== rexpr
.Type
)
3085 return Convert
.ImplicitConversionExists (ec
, lexpr
, left
) &&
3086 Convert
.ImplicitConversionExists (ec
, rexpr
, right
);
3089 public PredefinedOperator
ResolveBetterOperator (ResolveContext ec
, PredefinedOperator best_operator
)
3091 if ((OperatorsMask
& Operator
.DecomposedMask
) != 0)
3092 return best_operator
;
3094 if ((best_operator
.OperatorsMask
& Operator
.DecomposedMask
) != 0)
3098 if (left
!= null && best_operator
.left
!= null) {
3099 result
= OverloadResolver
.BetterTypeConversion (ec
, best_operator
.left_unwrap
, left_unwrap
);
3103 // When second argument is same as the first one, the result is same
3105 if (right
!= null && (left
!= right
|| best_operator
.left
!= best_operator
.right
)) {
3106 result
|= OverloadResolver
.BetterTypeConversion (ec
, best_operator
.right_unwrap
, right_unwrap
);
3109 if (result
== 0 || result
> 2)
3112 return result
== 1 ? best_operator
: this;
3116 sealed class PredefinedStringOperator
: PredefinedOperator
3118 public PredefinedStringOperator (TypeSpec type
, Operator op_mask
, TypeSpec retType
)
3119 : base (type
, type
, op_mask
, retType
)
3123 public PredefinedStringOperator (TypeSpec ltype
, TypeSpec rtype
, Operator op_mask
, TypeSpec retType
)
3124 : base (ltype
, rtype
, op_mask
, retType
)
3128 public override Expression
ConvertResult (ResolveContext ec
, Binary b
)
3131 // Use original expression for nullable arguments
3133 Nullable
.Unwrap unwrap
= b
.left
as Nullable
.Unwrap
;
3135 b
.left
= unwrap
.Original
;
3137 unwrap
= b
.right
as Nullable
.Unwrap
;
3139 b
.right
= unwrap
.Original
;
3141 b
.left
= Convert
.ImplicitConversion (ec
, b
.left
, left
, b
.left
.Location
);
3142 b
.right
= Convert
.ImplicitConversion (ec
, b
.right
, right
, b
.right
.Location
);
3145 // Start a new concat expression using converted expression
3147 return StringConcat
.Create (ec
, b
.left
, b
.right
, b
.loc
);
3151 sealed class PredefinedEqualityOperator
: PredefinedOperator
3153 MethodSpec equal_method
, inequal_method
;
3155 public PredefinedEqualityOperator (TypeSpec arg
, TypeSpec retType
)
3156 : base (arg
, arg
, Operator
.EqualityMask
, retType
)
3160 public override Expression
ConvertResult (ResolveContext ec
, Binary b
)
3162 b
.type
= ReturnType
;
3164 b
.left
= Convert
.ImplicitConversion (ec
, b
.left
, left
, b
.left
.Location
);
3165 b
.right
= Convert
.ImplicitConversion (ec
, b
.right
, right
, b
.right
.Location
);
3167 Arguments args
= new Arguments (2);
3168 args
.Add (new Argument (b
.left
));
3169 args
.Add (new Argument (b
.right
));
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
);
3179 throw new NotImplementedException (left
.GetSignatureForError ());
3182 method
= equal_method
;
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
);
3190 throw new NotImplementedException (left
.GetSignatureForError ());
3193 method
= inequal_method
;
3196 return new UserOperatorCall (method
, args
, b
.CreateExpressionTree
, b
.loc
);
3200 class PredefinedPointerOperator
: PredefinedOperator
3202 public PredefinedPointerOperator (TypeSpec ltype
, TypeSpec rtype
, Operator op_mask
)
3203 : base (ltype
, rtype
, op_mask
)
3207 public PredefinedPointerOperator (TypeSpec ltype
, TypeSpec rtype
, Operator op_mask
, TypeSpec retType
)
3208 : base (ltype
, rtype
, op_mask
, retType
)
3212 public PredefinedPointerOperator (TypeSpec type
, Operator op_mask
, TypeSpec return_type
)
3213 : base (type
, op_mask
, return_type
)
3217 public override bool IsApplicable (ResolveContext ec
, Expression lexpr
, Expression rexpr
)
3220 if (!lexpr
.Type
.IsPointer
)
3223 if (!Convert
.ImplicitConversionExists (ec
, lexpr
, left
))
3227 if (right
== null) {
3228 if (!rexpr
.Type
.IsPointer
)
3231 if (!Convert
.ImplicitConversionExists (ec
, rexpr
, right
))
3238 public override Expression
ConvertResult (ResolveContext ec
, Binary b
)
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
);
3246 TypeSpec r_type
= ReturnType
;
3247 Expression left_arg
, right_arg
;
3248 if (r_type
== null) {
3251 right_arg
= b
.right
;
3252 r_type
= b
.left
.Type
;
3256 r_type
= b
.right
.Type
;
3260 right_arg
= b
.right
;
3263 return new PointerArithmetic (b
.oper
, left_arg
, right_arg
, r_type
, b
.loc
).Resolve (ec
);
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
,
3275 LeftShift
= 5 | ShiftMask
,
3276 RightShift
= 6 | ShiftMask
,
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
,
3285 BitwiseAnd
= 13 | BitwiseMask
,
3286 ExclusiveOr
= 14 | BitwiseMask
,
3287 BitwiseOr
= 15 | BitwiseMask
,
3289 LogicalAnd
= 16 | LogicalMask
,
3290 LogicalOr
= 17 | LogicalMask
,
3295 ValuesOnlyMask
= ArithmeticMask
- 1,
3296 ArithmeticMask
= 1 << 5,
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,
3306 DecomposedMask
= 1 << 19,
3307 NullableMask
= 1 << 20
3311 public enum State
: byte
3315 UserOperatorsExcluded
= 1 << 2
3318 readonly Operator oper
;
3319 Expression left
, right
;
3321 ConvCast
.Mode enum_conversion
;
3323 public Binary (Operator oper
, Expression left
, Expression right
, bool isCompound
)
3324 : this (oper
, left
, right
, State
.Compound
)
3328 public Binary (Operator oper
, Expression left
, Expression right
, State state
)
3329 : this (oper
, left
, right
)
3334 public Binary (Operator oper
, Expression left
, Expression right
)
3335 : this (oper
, left
, right
, left
.Location
)
3339 public Binary (Operator oper
, Expression left
, Expression right
, Location loc
)
3349 public bool IsCompound
{
3351 return (state
& State
.Compound
) != 0;
3355 public Operator Oper
{
3361 public Expression Left
{
3367 public Expression Right
{
3373 public override Location StartLocation
{
3375 return left
.StartLocation
;
3382 /// Returns a stringified representation of the Operator
3384 string OperName (Operator oper
)
3388 case Operator
.Multiply
:
3391 case Operator
.Division
:
3394 case Operator
.Modulus
:
3397 case Operator
.Addition
:
3400 case Operator
.Subtraction
:
3403 case Operator
.LeftShift
:
3406 case Operator
.RightShift
:
3409 case Operator
.LessThan
:
3412 case Operator
.GreaterThan
:
3415 case Operator
.LessThanOrEqual
:
3418 case Operator
.GreaterThanOrEqual
:
3421 case Operator
.Equality
:
3424 case Operator
.Inequality
:
3427 case Operator
.BitwiseAnd
:
3430 case Operator
.BitwiseOr
:
3433 case Operator
.ExclusiveOr
:
3436 case Operator
.LogicalOr
:
3439 case Operator
.LogicalAnd
:
3443 s
= oper
.ToString ();
3453 public static void Error_OperatorCannotBeApplied (ResolveContext ec
, Expression left
, Expression right
, Operator oper
, Location loc
)
3455 new Binary (oper
, left
, right
).Error_OperatorCannotBeApplied (ec
, left
, right
);
3458 public static void Error_OperatorCannotBeApplied (ResolveContext ec
, Expression left
, Expression right
, string oper
, Location loc
)
3460 if (left
.Type
== InternalType
.ErrorType
|| right
.Type
== InternalType
.ErrorType
)
3464 l
= left
.Type
.GetSignatureForError ();
3465 r
= right
.Type
.GetSignatureForError ();
3467 ec
.Report
.Error (19, loc
, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3471 void Error_OperatorCannotBeApplied (ResolveContext ec
, Expression left
, Expression right
)
3473 Error_OperatorCannotBeApplied (ec
, left
, right
, OperName (oper
), loc
);
3476 public override void FlowAnalysis (FlowAnalysisContext fc
)
3479 // Optimized version when on-true/on-false data are not needed
3481 if ((oper
& Operator
.LogicalMask
) == 0) {
3482 left
.FlowAnalysis (fc
);
3483 right
.FlowAnalysis (fc
);
3487 left
.FlowAnalysisConditional (fc
);
3488 var left_fc_ontrue
= fc
.DefiniteAssignmentOnTrue
;
3489 var left_fc_onfalse
= fc
.DefiniteAssignmentOnFalse
;
3491 fc
.DefiniteAssignmentOnTrue
= fc
.DefiniteAssignmentOnFalse
= fc
.DefiniteAssignment
= new DefiniteAssignmentBitSet (
3492 oper
== Operator
.LogicalOr
? left_fc_onfalse
: left_fc_ontrue
);
3493 right
.FlowAnalysisConditional (fc
);
3495 if (oper
== Operator
.LogicalOr
)
3496 fc
.DefiniteAssignment
= (left_fc_onfalse
| (fc
.DefiniteAssignmentOnFalse
& fc
.DefiniteAssignmentOnTrue
)) & left_fc_ontrue
;
3498 fc
.DefiniteAssignment
= (left_fc_ontrue
| (fc
.DefiniteAssignmentOnFalse
& fc
.DefiniteAssignmentOnTrue
)) & left_fc_onfalse
;
3501 public override void FlowAnalysisConditional (FlowAnalysisContext fc
)
3503 if ((oper
& Operator
.LogicalMask
) == 0) {
3504 base.FlowAnalysisConditional (fc
);
3508 left
.FlowAnalysisConditional (fc
);
3509 var left_fc_ontrue
= fc
.DefiniteAssignmentOnTrue
;
3510 var left_fc_onfalse
= fc
.DefiniteAssignmentOnFalse
;
3512 fc
.DefiniteAssignmentOnTrue
= fc
.DefiniteAssignmentOnFalse
= fc
.DefiniteAssignment
= new DefiniteAssignmentBitSet (
3513 oper
== Operator
.LogicalOr
? left_fc_onfalse
: left_fc_ontrue
);
3514 right
.FlowAnalysisConditional (fc
);
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
;
3522 fc
.DefiniteAssignmentOnTrue
= new DefiniteAssignmentBitSet (left_fc_ontrue
& (left_fc_onfalse
| fc
.DefiniteAssignmentOnTrue
));
3524 fc
.DefiniteAssignmentOnTrue
= left_fc_ontrue
| fc
.DefiniteAssignmentOnTrue
;
3525 if (lc
!= null && !lc
.IsDefaultValue
)
3526 fc
.DefiniteAssignmentOnFalse
= fc
.DefiniteAssignmentOnTrue
;
3528 fc
.DefiniteAssignmentOnFalse
= new DefiniteAssignmentBitSet ((left_fc_ontrue
| fc
.DefiniteAssignmentOnFalse
) & left_fc_onfalse
);
3533 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3535 string GetOperatorExpressionTypeName ()
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
:
3550 case Operator
.GreaterThan
:
3551 return "GreaterThan";
3552 case Operator
.GreaterThanOrEqual
:
3553 return "GreaterThanOrEqual";
3554 case Operator
.Inequality
:
3556 case Operator
.LeftShift
:
3557 return IsCompound
? "LeftShiftAssign" : "LeftShift";
3558 case Operator
.LessThan
:
3560 case Operator
.LessThanOrEqual
:
3561 return "LessThanOrEqual";
3562 case Operator
.LogicalAnd
:
3564 case Operator
.LogicalOr
:
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";
3575 throw new NotImplementedException ("Unknown expression type operator " + oper
.ToString ());
3579 public static CSharp
.Operator
.OpType
ConvertBinaryToUserOperator (Operator 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
;
3617 throw new InternalErrorException (op
.ToString ());
3621 public override bool ContainsEmitWithAwait ()
3623 return left
.ContainsEmitWithAwait () || right
.ContainsEmitWithAwait ();
3626 public static void EmitOperatorOpcode (EmitContext ec
, Operator oper
, TypeSpec l
, Expression right
)
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
;
3638 opcode
= OpCodes
.Mul
;
3640 opcode
= OpCodes
.Mul
;
3644 case Operator
.Division
:
3646 opcode
= OpCodes
.Div_Un
;
3648 opcode
= OpCodes
.Div
;
3651 case Operator
.Modulus
:
3653 opcode
= OpCodes
.Rem_Un
;
3655 opcode
= OpCodes
.Rem
;
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
;
3665 opcode
= OpCodes
.Add
;
3667 opcode
= OpCodes
.Add
;
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
;
3677 opcode
= OpCodes
.Sub
;
3679 opcode
= OpCodes
.Sub
;
3682 case Operator
.RightShift
:
3683 if (!(right
is IntConstant
)) {
3684 ec
.EmitInt (GetShiftMask (l
));
3685 ec
.Emit (OpCodes
.And
);
3689 opcode
= OpCodes
.Shr_Un
;
3691 opcode
= OpCodes
.Shr
;
3694 case Operator
.LeftShift
:
3695 if (!(right
is IntConstant
)) {
3696 ec
.EmitInt (GetShiftMask (l
));
3697 ec
.Emit (OpCodes
.And
);
3700 opcode
= OpCodes
.Shl
;
3703 case Operator
.Equality
:
3704 opcode
= OpCodes
.Ceq
;
3707 case Operator
.Inequality
:
3708 ec
.Emit (OpCodes
.Ceq
);
3711 opcode
= OpCodes
.Ceq
;
3714 case Operator
.LessThan
:
3716 opcode
= OpCodes
.Clt_Un
;
3718 opcode
= OpCodes
.Clt
;
3721 case Operator
.GreaterThan
:
3723 opcode
= OpCodes
.Cgt_Un
;
3725 opcode
= OpCodes
.Cgt
;
3728 case Operator
.LessThanOrEqual
:
3729 if (IsUnsigned (l
) || IsFloat (l
))
3730 ec
.Emit (OpCodes
.Cgt_Un
);
3732 ec
.Emit (OpCodes
.Cgt
);
3735 opcode
= OpCodes
.Ceq
;
3738 case Operator
.GreaterThanOrEqual
:
3739 if (IsUnsigned (l
) || IsFloat (l
))
3740 ec
.Emit (OpCodes
.Clt_Un
);
3742 ec
.Emit (OpCodes
.Clt
);
3746 opcode
= OpCodes
.Ceq
;
3749 case Operator
.BitwiseOr
:
3750 opcode
= OpCodes
.Or
;
3753 case Operator
.BitwiseAnd
:
3754 opcode
= OpCodes
.And
;
3757 case Operator
.ExclusiveOr
:
3758 opcode
= OpCodes
.Xor
;
3762 throw new InternalErrorException (oper
.ToString ());
3768 static int GetShiftMask (TypeSpec type
)
3770 return type
.BuiltinType
== BuiltinTypeSpec
.Type
.Int
|| type
.BuiltinType
== BuiltinTypeSpec
.Type
.UInt
? 0x1f : 0x3f;
3773 static bool IsUnsigned (TypeSpec t
)
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
:
3787 static bool IsFloat (TypeSpec t
)
3789 return t
.BuiltinType
== BuiltinTypeSpec
.Type
.Float
|| t
.BuiltinType
== BuiltinTypeSpec
.Type
.Double
;
3792 public Expression
ResolveOperator (ResolveContext rc
)
3794 eclass
= ExprClass
.Value
;
3796 TypeSpec l
= left
.Type
;
3797 TypeSpec r
= right
.Type
;
3799 bool primitives_only
= false;
3802 // Handles predefined primitive types
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
))
3810 primitives_only
= BuiltinTypeSpec
.IsPrimitiveType (l
) && BuiltinTypeSpec
.IsPrimitiveType (r
);
3814 if (l
.IsPointer
|| r
.IsPointer
)
3815 return ResolveOperatorPointer (rc
, l
, r
);
3818 if ((state
& State
.UserOperatorsExcluded
) == 0) {
3819 expr
= ResolveUserOperator (rc
, left
, right
);
3824 bool lenum
= l
.IsEnum
;
3825 bool renum
= r
.IsEnum
;
3826 if ((oper
& (Operator
.ComparisonMask
| Operator
.BitwiseMask
)) != 0) {
3830 if (IsEnumOrNullableEnum (l
) || IsEnumOrNullableEnum (r
)) {
3831 expr
= ResolveSingleEnumOperators (rc
, lenum
, renum
, l
, r
);
3836 if ((oper
& Operator
.BitwiseMask
) != 0) {
3837 expr
= EmptyCast
.Create (expr
, type
);
3838 enum_conversion
= GetEnumResultCast (type
);
3840 if (oper
== Operator
.BitwiseAnd
&& left
.Type
.IsEnum
&& right
.Type
.IsEnum
) {
3841 expr
= OptimizeAndOperation (expr
);
3845 left
= ConvertEnumOperandToUnderlyingType (rc
, left
, r
.IsNullableType
);
3846 right
= ConvertEnumOperandToUnderlyingType (rc
, right
, l
.IsNullableType
);
3849 } else if ((oper
== Operator
.Addition
|| oper
== Operator
.Subtraction
)) {
3850 if (IsEnumOrNullableEnum (l
) || IsEnumOrNullableEnum (r
)) {
3854 expr
= ResolveEnumOperators (rc
, lenum
, renum
, l
, r
);
3857 // We cannot break here there is also Enum + String possible match
3858 // which is not ambiguous with predefined enum operators
3861 left
= ConvertEnumOperandToUnderlyingType (rc
, left
, false);
3862 right
= ConvertEnumOperandToUnderlyingType (rc
, right
, false);
3866 } else if (l
.IsDelegate
|| r
.IsDelegate
) {
3870 expr
= ResolveOperatorDelegate (rc
, l
, r
);
3872 // TODO: Can this be ambiguous
3880 // Equality operators are more complicated
3882 if ((oper
& Operator
.EqualityMask
) != 0) {
3883 return ResolveEquality (rc
, l
, r
, primitives_only
);
3886 expr
= ResolveOperatorPredefined (rc
, rc
.BuiltinTypes
.OperatorsBinaryStandard
, primitives_only
);
3890 if (primitives_only
)
3894 // Lifted operators have lower priority
3896 return ResolveOperatorPredefined (rc
, rc
.Module
.OperatorsBinaryLifted
, false);
3899 static bool IsEnumOrNullableEnum (TypeSpec type
)
3901 return type
.IsEnum
|| (type
.IsNullableType
&& Nullable
.NullableInfo
.GetUnderlyingType (type
).IsEnum
);
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'
3907 Constant
EnumLiftUp (ResolveContext ec
, Constant left
, Constant right
)
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
)
3922 if (left
.IsZeroInteger
)
3923 return left
.Reduce (ec
, right
.Type
);
3927 case Operator
.Addition
:
3928 case Operator
.Subtraction
:
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
)
3945 // The `|' operator used on types which were extended is dangerous
3947 void CheckBitwiseOrOnSignExtended (ResolveContext ec
)
3949 OpcodeCast lcast
= left
as OpcodeCast
;
3950 if (lcast
!= null) {
3951 if (IsUnsigned (lcast
.UnderlyingType
))
3955 OpcodeCast rcast
= right
as OpcodeCast
;
3956 if (rcast
!= null) {
3957 if (IsUnsigned (rcast
.UnderlyingType
))
3961 if (lcast
== null && rcast
== null)
3964 // FIXME: consider constants
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 ());
3972 public static PredefinedOperator
[] CreatePointerOperatorsTable (BuiltinTypes types
)
3974 return new PredefinedOperator
[] {
3976 // Pointer arithmetic:
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);
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
),
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);
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),
4000 // long operator - (T* x, T *y)
4002 new PredefinedPointerOperator (null, Operator
.SubtractionMask
, types
.Long
)
4006 public static PredefinedOperator
[] CreateStandardOperatorsTable (BuiltinTypes types
)
4008 TypeSpec bool_type
= types
.Bool
;
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
),
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
),
4027 new PredefinedStringOperator (types
.String
, Operator
.AdditionMask
, types
.String
),
4028 // Remaining string operators are in lifted tables
4030 new PredefinedOperator (bool_type
, Operator
.BitwiseMask
| Operator
.LogicalMask
| Operator
.EqualityMask
, bool_type
),
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
)
4038 public static PredefinedOperator
[] CreateStandardLiftedOperatorsTable (ModuleContainer module
)
4040 var types
= module
.Compiler
.BuiltinTypes
;
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?)
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
),
4051 var nullable
= module
.PredefinedTypes
.Nullable
.TypeSpec
;
4052 if (nullable
== null)
4053 return string_operators
;
4055 var bool_type
= types
.Bool
;
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 }
);
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
),
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
),
4083 new PredefinedOperator (nullable_bool
, Operator
.NullableMask
| Operator
.BitwiseMask
, nullable_bool
),
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
),
4089 string_operators
[0],
4090 string_operators
[1]
4094 public static PredefinedOperator
[] CreateEqualityOperatorsTable (BuiltinTypes types
)
4096 TypeSpec bool_type
= types
.Bool
;
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
),
4112 public static PredefinedOperator
[] CreateEqualityLiftedOperatorsTable (ModuleContainer module
)
4114 var nullable
= module
.PredefinedTypes
.Nullable
.TypeSpec
;
4116 if (nullable
== null)
4117 return new PredefinedOperator
[0];
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 }
);
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
)
4143 // 7.2.6.2 Binary numeric promotions
4145 bool DoBinaryOperatorPromotion (ResolveContext rc
)
4147 TypeSpec ltype
= left
.Type
;
4148 if (ltype
.IsNullableType
) {
4149 ltype
= Nullable
.NullableInfo
.GetUnderlyingType (ltype
);
4153 // This is numeric promotion code only
4155 if (ltype
.BuiltinType
== BuiltinTypeSpec
.Type
.Bool
)
4158 TypeSpec rtype
= right
.Type
;
4159 if (rtype
.IsNullableType
) {
4160 rtype
= Nullable
.NullableInfo
.GetUnderlyingType (rtype
);
4163 var lb
= ltype
.BuiltinType
;
4164 var rb
= rtype
.BuiltinType
;
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
;
4177 if (IsSignedType (lb
)) {
4178 expr
= ConvertSignedConstant (left
, type
);
4182 } else if (IsSignedType (rb
)) {
4183 expr
= ConvertSignedConstant (right
, type
);
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
;
4194 if (IsSignedType (lb
)) {
4195 expr
= ConvertSignedConstant (left
, type
);
4197 type
= rc
.BuiltinTypes
.Long
;
4198 } else if (IsSignedType (rb
)) {
4199 expr
= ConvertSignedConstant (right
, type
);
4201 type
= rc
.BuiltinTypes
.Long
;
4204 type
= rc
.BuiltinTypes
.Int
;
4207 if (ltype
!= type
) {
4208 expr
= PromoteExpression (rc
, left
, type
);
4215 if (rtype
!= type
) {
4216 expr
= PromoteExpression (rc
, right
, type
);
4226 static bool IsSignedType (BuiltinTypeSpec
.Type type
)
4229 case BuiltinTypeSpec
.Type
.Int
:
4230 case BuiltinTypeSpec
.Type
.Short
:
4231 case BuiltinTypeSpec
.Type
.SByte
:
4232 case BuiltinTypeSpec
.Type
.Long
:
4239 static Expression
ConvertSignedConstant (Expression expr
, TypeSpec type
)
4241 var c
= expr
as Constant
;
4245 return c
.ConvertImplicitly (type
);
4248 static Expression
PromoteExpression (ResolveContext rc
, Expression expr
, TypeSpec type
)
4250 if (expr
.Type
.IsNullableType
) {
4251 return Convert
.ImplicitConversionStandard (rc
, expr
,
4252 rc
.Module
.PredefinedTypes
.Nullable
.TypeSpec
.MakeGenericType (rc
, new[] { type }
), expr
.Location
);
4255 var c
= expr
as Constant
;
4257 return c
.ConvertImplicitly (type
);
4259 return Convert
.ImplicitNumericConversion (expr
, type
);
4262 protected override Expression
DoResolve (ResolveContext ec
)
4267 if ((oper
== Operator
.Subtraction
) && (left
is ParenthesizedExpression
)) {
4268 left
= ((ParenthesizedExpression
) left
).Expr
;
4269 left
= left
.Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.Type
);
4273 if (left
.eclass
== ExprClass
.Type
) {
4274 ec
.Report
.Error (75, loc
, "To cast a negative value, you must enclose the value in parentheses");
4278 left
= left
.Resolve (ec
);
4283 right
= right
.Resolve (ec
);
4287 Constant lc
= left
as Constant
;
4288 Constant rc
= right
as Constant
;
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
);
4294 rc
= EnumLiftUp (ec
, rc
, lc
);
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
)
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?");
4309 CheckOutOfRangeComparison (ec
, lc
, right
.Type
);
4310 CheckOutOfRangeComparison (ec
, rc
, left
.Type
);
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
);
4319 // Only default with == and != is explicitly allowed
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
));
4327 if (ltype
== rtype
) {
4328 ec
.Report
.Error (8315, loc
, "Operator `{0}' is ambiguous on operands `default' and `default'", OperName (Oper
));
4332 if (rtype
== InternalType
.DefaultType
) {
4333 right
= new DefaultValueExpression (new TypeExpression (ltype
, right
.Location
), right
.Location
).Resolve (ec
);
4335 left
= new DefaultValueExpression (new TypeExpression (rtype
, left
.Location
), left
.Location
).Resolve (ec
);
4339 return DoResolveCore (ec
, left
, right
);
4342 Expression
DoResolveDynamic (ResolveContext rc
)
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
);
4355 // Special handling for logical boolean operators which require rhs not to be
4356 // evaluated based on lhs value
4358 if ((oper
& Operator
.LogicalMask
) != 0) {
4359 Expression cond_left
, cond_right
, expr
;
4361 args
= new Arguments (2);
4363 if (lt
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
) {
4364 LocalVariable temp
= LocalVariable
.CreateCompilerGenerated (lt
, rc
.CurrentBlock
, loc
);
4366 var cond_args
= new Arguments (1);
4367 cond_args
.Add (new Argument (new SimpleAssign (temp
.CreateReferenceExpression (rc
, loc
), left
).Resolve (rc
)));
4370 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4371 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4373 left
= temp
.CreateReferenceExpression (rc
, loc
);
4374 if (oper
== Operator
.LogicalAnd
) {
4375 expr
= DynamicUnaryConversion
.CreateIsFalse (rc
, cond_args
, loc
);
4378 expr
= DynamicUnaryConversion
.CreateIsTrue (rc
, cond_args
, loc
);
4382 args
.Add (new Argument (left
));
4383 args
.Add (new Argument (right
));
4384 cond_right
= new DynamicExpressionStatement (this, args
, loc
);
4386 LocalVariable temp
= LocalVariable
.CreateCompilerGenerated (rc
.BuiltinTypes
.Bool
, rc
.CurrentBlock
, loc
);
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");
4395 args
.Add (new Argument (temp
.CreateReferenceExpression (rc
, loc
).Resolve (rc
)));
4396 args
.Add (new Argument (right
));
4397 right
= new DynamicExpressionStatement (this, args
, loc
);
4400 // bool && dynamic => (temp = left) ? temp && right : temp;
4401 // bool || dynamic => (temp = left) ? temp : temp || right;
4403 if (oper
== Operator
.LogicalAnd
) {
4405 cond_right
= temp
.CreateReferenceExpression (rc
, loc
);
4407 cond_left
= temp
.CreateReferenceExpression (rc
, loc
);
4411 expr
= new BooleanExpression (new SimpleAssign (temp
.CreateReferenceExpression (rc
, loc
), left
));
4414 return new Conditional (expr
, cond_left
, cond_right
, loc
).Resolve (rc
);
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
);
4423 Expression
DoResolveCore (ResolveContext ec
, Expression left_orig
, Expression right_orig
)
4425 Expression expr
= ResolveOperator (ec
);
4427 Error_OperatorCannotBeApplied (ec
, left_orig
, right_orig
);
4429 if (left
== null || right
== null)
4430 throw new InternalErrorException ("Invalid conversion");
4432 if (oper
== Operator
.BitwiseOr
)
4433 CheckBitwiseOrOnSignExtended (ec
);
4438 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
4440 return MakeExpression (ctx
, left
, right
);
4443 public SLE
.Expression
MakeExpression (BuilderContext ctx
, Expression left
, Expression right
)
4445 var le
= left
.MakeExpression (ctx
);
4446 var re
= right
.MakeExpression (ctx
);
4447 bool is_checked
= ctx
.HasSet (BuilderContext
.Options
.CheckedScope
);
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
);
4487 throw new NotImplementedException (oper
.ToString ());
4492 // D operator + (D x, D y)
4493 // D operator - (D x, D y)
4495 Expression
ResolveOperatorDelegate (ResolveContext ec
, TypeSpec l
, TypeSpec r
)
4497 if (l
!= r
&& !TypeSpecComparer
.Variant
.IsEqual (r
, l
)) {
4499 if (right
.eclass
== ExprClass
.MethodGroup
|| r
== InternalType
.AnonymousMethod
|| r
== InternalType
.NullLiteral
) {
4500 tmp
= Convert
.ImplicitConversionRequired (ec
, right
, l
, loc
);
4505 } else if (left
.eclass
== ExprClass
.MethodGroup
|| (l
== InternalType
.AnonymousMethod
|| l
== InternalType
.NullLiteral
)) {
4506 tmp
= Convert
.ImplicitConversionRequired (ec
, left
, r
, loc
);
4516 MethodSpec method
= null;
4517 Arguments args
= new Arguments (2);
4518 args
.Add (new Argument (left
));
4519 args
.Add (new Argument (right
));
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
);
4528 return new EmptyExpression (ec
.BuiltinTypes
.Decimal
);
4530 Expression expr
= new UserOperatorCall (method
, args
, CreateExpressionTree
, loc
);
4531 return new ClassCast (expr
, l
);
4535 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4537 Expression
ResolveSingleEnumOperators (ResolveContext rc
, bool lenum
, bool renum
, TypeSpec ltype
, TypeSpec rtype
)
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);
4547 // E operator & (E x, E y);
4548 // E operator | (E x, E y);
4549 // E operator ^ (E x, E y);
4552 if ((oper
& Operator
.ComparisonMask
) != 0) {
4553 type
= rc
.BuiltinTypes
.Bool
;
4559 else if (ltype
.IsNullableType
&& Nullable
.NullableInfo
.GetUnderlyingType (ltype
).IsEnum
)
4565 if (ltype
== rtype
) {
4569 var lifted
= new Nullable
.LiftedBinaryOperator (this);
4571 lifted
.Right
= right
;
4572 return lifted
.Resolve (rc
);
4575 if (renum
&& !ltype
.IsNullableType
) {
4576 expr
= Convert
.ImplicitConversion (rc
, left
, rtype
, loc
);
4581 } else if (lenum
&& !rtype
.IsNullableType
) {
4582 expr
= Convert
.ImplicitConversion (rc
, right
, ltype
, loc
);
4590 // Now try lifted version of predefined operator
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 }
);
4597 expr
= Convert
.ImplicitConversion (rc
, left
, lifted_type
, loc
);
4600 right
= Convert
.ImplicitConversion (rc
, right
, lifted_type
, loc
);
4603 if ((oper
& Operator
.BitwiseMask
) != 0)
4607 if ((oper
& Operator
.BitwiseMask
) != 0)
4608 return Nullable
.LiftedNull
.CreateFromExpression (rc
, this);
4610 return CreateLiftedValueTypeResult (rc
, rtype
);
4614 var lifted
= new Nullable
.LiftedBinaryOperator (this);
4616 lifted
.Right
= right
;
4617 return lifted
.Resolve (rc
);
4619 } else if (lenum
&& !rtype
.IsNullableType
) {
4620 var lifted_type
= nullable_type
.MakeGenericType (rc
.Module
, new[] { ltype }
);
4622 expr
= Convert
.ImplicitConversion (rc
, right
, lifted_type
, loc
);
4625 left
= Convert
.ImplicitConversion (rc
, left
, lifted_type
, loc
);
4628 if ((oper
& Operator
.BitwiseMask
) != 0)
4632 if ((oper
& Operator
.BitwiseMask
) != 0)
4633 return Nullable
.LiftedNull
.CreateFromExpression (rc
, this);
4635 return CreateLiftedValueTypeResult (rc
, ltype
);
4639 var lifted
= new Nullable
.LiftedBinaryOperator (this);
4641 lifted
.Right
= expr
;
4642 return lifted
.Resolve (rc
);
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
);
4650 if ((oper
& Operator
.RelationalMask
) != 0)
4651 return CreateLiftedValueTypeResult (rc
, rtype
);
4653 if ((oper
& Operator
.BitwiseMask
) != 0)
4654 return Nullable
.LiftedNull
.CreateFromExpression (rc
, this);
4657 return CreateLiftedValueTypeResult (rc
, left
.Type
);
4659 // Equality operators are valid between E? and null
4661 unwrap
= new Nullable
.Unwrap (right
);
4663 expr
= Convert
.ImplicitConversion (rc
, left
, Nullable
.NullableInfo
.GetUnderlyingType (rtype
), loc
);
4667 if ((oper
& Operator
.BitwiseMask
) != 0)
4672 var lifted
= new Nullable
.LiftedBinaryOperator (this);
4674 lifted
.Right
= right
;
4675 lifted
.UnwrapRight
= unwrap
;
4676 return lifted
.Resolve (rc
);
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
);
4684 if ((oper
& Operator
.RelationalMask
) != 0)
4685 return CreateLiftedValueTypeResult (rc
, ltype
);
4687 if ((oper
& Operator
.BitwiseMask
) != 0)
4688 return Nullable
.LiftedNull
.CreateFromExpression (rc
, this);
4691 return CreateLiftedValueTypeResult (rc
, right
.Type
);
4693 // Equality operators are valid between E? and null
4695 unwrap
= new Nullable
.Unwrap (left
);
4697 expr
= Convert
.ImplicitConversion (rc
, right
, Nullable
.NullableInfo
.GetUnderlyingType (ltype
), loc
);
4701 if ((oper
& Operator
.BitwiseMask
) != 0)
4706 var lifted
= new Nullable
.LiftedBinaryOperator (this);
4708 lifted
.UnwrapLeft
= unwrap
;
4709 lifted
.Right
= expr
;
4710 return lifted
.Resolve (rc
);
4718 static Expression
ConvertEnumOperandToUnderlyingType (ResolveContext rc
, Expression expr
, bool liftType
)
4720 TypeSpec underlying_type
;
4721 if (expr
.Type
.IsNullableType
) {
4722 var nt
= Nullable
.NullableInfo
.GetUnderlyingType (expr
.Type
);
4724 underlying_type
= EnumSpec
.GetUnderlyingType (nt
);
4726 underlying_type
= nt
;
4727 } else if (expr
.Type
.IsEnum
) {
4728 underlying_type
= EnumSpec
.GetUnderlyingType (expr
.Type
);
4730 underlying_type
= expr
.Type
;
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
;
4742 if (expr
.Type
.IsNullableType
|| liftType
)
4743 underlying_type
= rc
.Module
.PredefinedTypes
.Nullable
.TypeSpec
.MakeGenericType (rc
.Module
, new[] { underlying_type }
);
4745 if (expr
.Type
== underlying_type
)
4748 return EmptyCast
.Create (expr
, underlying_type
);
4751 Expression
ResolveEnumOperators (ResolveContext rc
, bool lenum
, bool renum
, TypeSpec ltype
, TypeSpec rtype
)
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
4758 // E operator + (E e, U x)
4759 // E operator + (U x, E e)
4768 else if (ltype
.IsNullableType
&& Nullable
.NullableInfo
.GetUnderlyingType (ltype
).IsEnum
)
4774 if (!enum_type
.IsNullableType
) {
4775 expr
= ResolveOperatorPredefined (rc
, rc
.Module
.GetPredefinedEnumAritmeticOperators (enum_type
, false), false);
4777 if (oper
== Operator
.Subtraction
)
4778 expr
= ConvertEnumSubtractionResult (rc
, expr
);
4780 expr
= ConvertEnumAdditionalResult (expr
, enum_type
);
4782 enum_conversion
= GetEnumResultCast (expr
.Type
);
4787 var nullable
= rc
.Module
.PredefinedTypes
.Nullable
;
4790 // Don't try nullable version when nullable type is undefined
4792 if (!nullable
.IsDefined
)
4795 enum_type
= nullable
.TypeSpec
.MakeGenericType (rc
.Module
, new[] { enum_type }
);
4798 expr
= ResolveOperatorPredefined (rc
, rc
.Module
.GetPredefinedEnumAritmeticOperators (enum_type
, true), false);
4800 if (oper
== Operator
.Subtraction
)
4801 expr
= ConvertEnumSubtractionResult (rc
, expr
);
4803 expr
= ConvertEnumAdditionalResult (expr
, enum_type
);
4805 enum_conversion
= GetEnumResultCast (expr
.Type
);
4811 static Expression
ConvertEnumAdditionalResult (Expression expr
, TypeSpec enumType
)
4813 return EmptyCast
.Create (expr
, enumType
);
4816 Expression
ConvertEnumSubtractionResult (ResolveContext rc
, Expression expr
)
4819 // Enumeration subtraction has different result type based on
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
) {
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
4830 result_type
= left
.Type
;
4832 result_type
= left
.Type
.IsNullableType
?
4833 Nullable
.NullableInfo
.GetEnumUnderlyingType (rc
.Module
, left
.Type
) :
4834 EnumSpec
.GetUnderlyingType (left
.Type
);
4837 if (IsEnumOrNullableEnum (left
.Type
)) {
4838 result_type
= left
.Type
;
4840 result_type
= right
.Type
;
4843 if (expr
is Nullable
.LiftedBinaryOperator
&& !result_type
.IsNullableType
)
4844 result_type
= rc
.Module
.PredefinedTypes
.Nullable
.TypeSpec
.MakeGenericType (rc
.Module
, new[] { result_type }
);
4847 return EmptyCast
.Create (expr
, result_type
);
4850 public static ConvCast
.Mode
GetEnumResultCast (TypeSpec type
)
4852 if (type
.IsNullableType
)
4853 type
= Nullable
.NullableInfo
.GetUnderlyingType (type
);
4856 type
= EnumSpec
.GetUnderlyingType (type
);
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
;
4873 // Equality operators rules
4875 Expression
ResolveEquality (ResolveContext ec
, TypeSpec l
, TypeSpec r
, bool primitives_only
)
4878 type
= ec
.BuiltinTypes
.Bool
;
4879 bool no_arg_conv
= false;
4881 if (!primitives_only
) {
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
4889 // LAMESPEC: Very confusing details in the specification, basically any
4890 // reference like type-parameter is allowed
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
)
4899 left
= new BoxedCast (left
, ec
.BuiltinTypes
.Object
);
4903 if (!tparam_l
.IsReferenceType
)
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
))
4912 if (r
.Kind
== MemberKind
.InternalCompilerType
)
4916 if (tparam_r
!= null) {
4917 if (left
is NullLiteral
) {
4918 if (tparam_r
.GetEffectiveBase ().BuiltinType
== BuiltinTypeSpec
.Type
.ValueType
)
4921 right
= new BoxedCast (right
, ec
.BuiltinTypes
.Object
);
4925 if (!tparam_r
.IsReferenceType
)
4928 r
= tparam_r
.GetEffectiveBase ();
4929 right
= new BoxedCast (right
, r
);
4930 } else if (right
is NullLiteral
) {
4931 if (TypeSpec
.IsReferenceType (l
))
4934 if (l
.Kind
== MemberKind
.InternalCompilerType
)
4939 // LAMESPEC: method groups can be compared when they convert to other side delegate
4942 if (right
.eclass
== ExprClass
.MethodGroup
) {
4943 result
= Convert
.ImplicitConversion (ec
, right
, l
, loc
);
4949 } else if (r
.IsDelegate
&& l
!= r
) {
4952 } else if (left
.eclass
== ExprClass
.MethodGroup
&& r
.IsDelegate
) {
4953 result
= Convert
.ImplicitConversionRequired (ec
, left
, r
, loc
);
4960 no_arg_conv
= l
== r
&& !l
.IsStruct
;
4965 // bool operator != (string a, string b)
4966 // bool operator == (string a, string b)
4968 // bool operator != (Delegate a, Delegate b)
4969 // bool operator == (Delegate a, Delegate b)
4971 // bool operator != (bool a, bool b)
4972 // bool operator == (bool a, bool b)
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
4978 if (r
.BuiltinType
!= BuiltinTypeSpec
.Type
.Object
&& l
.BuiltinType
!= BuiltinTypeSpec
.Type
.Object
) {
4979 result
= ResolveOperatorPredefined (ec
, ec
.BuiltinTypes
.OperatorsBinaryEquality
, no_arg_conv
);
4984 // Now try lifted version of predefined operators
4986 if (no_arg_conv
&& !l
.IsNullableType
) {
4988 // Optimizes cases which won't match
4991 result
= ResolveOperatorPredefined (ec
, ec
.Module
.OperatorsBinaryEqualityLifted
, no_arg_conv
);
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.
5001 if ((l
.IsNullableType
&& right
.IsNull
) || (r
.IsNullableType
&& left
.IsNull
)) {
5002 var lifted
= new Nullable
.LiftedBinaryOperator (this);
5004 lifted
.Right
= right
;
5005 return lifted
.Resolve (ec
);
5010 // bool operator != (object a, object b)
5011 // bool operator == (object a, object b)
5013 // An explicit reference conversion exists from the
5014 // type of either operand to the type of the other operand.
5017 // Optimize common path
5019 return l
.Kind
== MemberKind
.InternalCompilerType
|| l
.Kind
== MemberKind
.Struct
? null : this;
5022 if (!Convert
.ExplicitReferenceConversionExists (l
, r
) &&
5023 !Convert
.ExplicitReferenceConversionExists (r
, l
))
5026 // Reject allowed explicit conversions like int->object
5027 if (!TypeSpec
.IsReferenceType (l
) || !TypeSpec
.IsReferenceType (r
))
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 ());
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 ());
5044 Expression
ResolveOperatorPointer (ResolveContext ec
, TypeSpec l
, TypeSpec r
)
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);
5054 if ((oper
& Operator
.ComparisonMask
) != 0) {
5057 temp
= Convert
.ImplicitConversion (ec
, left
, r
, left
.Location
);
5064 temp
= Convert
.ImplicitConversion (ec
, right
, l
, right
.Location
);
5070 type
= ec
.BuiltinTypes
.Bool
;
5074 return ResolveOperatorPredefined (ec
, ec
.BuiltinTypes
.OperatorsBinaryUnsafe
, false);
5078 // Build-in operators method overloading
5080 Expression
ResolveOperatorPredefined (ResolveContext ec
, PredefinedOperator
[] operators
, bool primitives_only
)
5082 PredefinedOperator best_operator
= null;
5083 TypeSpec l
= left
.Type
;
5084 TypeSpec r
= right
.Type
;
5085 Operator oper_mask
= oper
& ~Operator
.ValuesOnlyMask
;
5087 foreach (PredefinedOperator po
in operators
) {
5088 if ((po
.OperatorsMask
& oper_mask
) == 0)
5091 if (primitives_only
) {
5092 if (!po
.IsPrimitiveApplicable (l
, r
))
5095 if (!po
.IsApplicable (ec
, left
, right
))
5099 if (best_operator
== null) {
5101 if (primitives_only
)
5107 best_operator
= po
.ResolveBetterOperator (ec
, best_operator
);
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 ());
5118 if (best_operator
== null)
5121 return best_operator
.ConvertResult (ec
, this);
5125 // Optimize & constant expressions with 0 value
5127 Expression
OptimizeAndOperation (Expression expr
)
5129 Constant rc
= right
as Constant
;
5130 Constant lc
= left
as Constant
;
5131 if ((lc
!= null && lc
.IsDefaultValue
) || (rc
!= null && rc
.IsDefaultValue
)) {
5133 // The result is a constant with side-effect
5135 Constant side_effect
= rc
== null ?
5136 new SideEffectConstant (lc
, right
, loc
) :
5137 new SideEffectConstant (rc
, left
, loc
);
5139 return ReducedExpression
.Create (side_effect
, expr
);
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.
5149 public Expression
CreateLiftedValueTypeResult (ResolveContext rc
, TypeSpec valueType
)
5151 if (rc
.HasSet (ResolveContext
.Options
.ExpressionTreeConversion
)) {
5152 type
= rc
.BuiltinTypes
.Bool
;
5156 // FIXME: Handle side effect constants
5157 Constant c
= new BoolConstant (rc
.BuiltinTypes
, Oper
== Operator
.Inequality
, loc
);
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 ());
5163 rc
.Report
.Warning (464, 2, loc
, "The result of comparing type `{0}' with null is always `{1}'",
5164 valueType
.GetSignatureForError (), c
.GetValueAsLiteral ());
5171 // Performs user-operator overloading
5173 Expression
ResolveUserOperator (ResolveContext rc
, Expression left
, Expression right
)
5175 Expression oper_expr
;
5177 var op
= ConvertBinaryToUserOperator (oper
);
5179 if (l
.IsNullableType
)
5180 l
= Nullable
.NullableInfo
.GetUnderlyingType (l
);
5182 if (r
.IsNullableType
)
5183 r
= Nullable
.NullableInfo
.GetUnderlyingType (r
);
5185 IList
<MemberSpec
> left_operators
= MemberCache
.GetUserOperator (l
, op
, false);
5186 IList
<MemberSpec
> right_operators
= null;
5189 right_operators
= MemberCache
.GetUserOperator (r
, op
, false);
5190 if (right_operators
== null && left_operators
== null)
5192 } else if (left_operators
== null) {
5196 Arguments args
= new Arguments (2);
5197 Argument larg
= new Argument (left
);
5199 Argument rarg
= new Argument (right
);
5203 // User-defined operator implementations always take precedence
5204 // over predefined operator implementations
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
;
5212 const OverloadResolver
.Restrictions restr
= OverloadResolver
.Restrictions
.ProbingOnly
|
5213 OverloadResolver
.Restrictions
.NoBaseMembers
| OverloadResolver
.Restrictions
.BaseMembersIncluded
;
5215 var res
= new OverloadResolver (left_operators
, restr
, loc
);
5217 var oper_method
= res
.ResolveOperator (rc
, ref args
);
5218 if (oper_method
== null) {
5220 // Logical && and || cannot be lifted
5222 if ((oper
& Operator
.LogicalMask
) != 0)
5226 // Apply lifted user operators only for liftable types. Implicit conversion
5227 // to nullable types is not allowed
5229 if (!IsLiftedOperatorApplicable ())
5232 // TODO: Cache the result in module container
5233 var lifted_methods
= CreateLiftedOperators (rc
, left_operators
);
5234 if (lifted_methods
== null)
5237 res
= new OverloadResolver (lifted_methods
, restr
| OverloadResolver
.Restrictions
.ProbingOnly
, loc
);
5239 oper_method
= res
.ResolveOperator (rc
, ref args
);
5240 if (oper_method
== null)
5243 MethodSpec best_original
= null;
5244 foreach (MethodSpec ms
in left_operators
) {
5245 if (ms
.MemberDefinition
== oper_method
.MemberDefinition
) {
5251 if (rc
.HasSet (ResolveContext
.Options
.ExpressionTreeConversion
)) {
5253 // Expression trees use lifted notation in this case
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
);
5259 var ptypes
= best_original
.Parameters
.Types
;
5261 if (left
.IsNull
|| right
.IsNull
) {
5263 // The lifted operator produces a null value if one or both operands are null
5265 if ((oper
& (Operator
.ArithmeticMask
| Operator
.ShiftMask
| Operator
.BitwiseMask
)) != 0) {
5266 type
= oper_method
.ReturnType
;
5267 return Nullable
.LiftedNull
.CreateFromExpression (rc
, this);
5271 // The lifted operator produces the value false if one or both operands are null for
5272 // relational operators.
5274 if ((oper
& Operator
.RelationalMask
) != 0) {
5276 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5277 // because return type is actually bool
5279 return CreateLiftedValueTypeResult (rc
, left
.IsNull
? ptypes
[1] : ptypes
[0]);
5282 if ((oper
& Operator
.EqualityMask
) != 0 && ((left
.IsNull
&& !right
.Type
.IsNullableType
) || !left
.Type
.IsNullableType
)) {
5283 return CreateLiftedValueTypeResult (rc
, left
.IsNull
? ptypes
[1] : ptypes
[0]);
5287 type
= oper_method
.ReturnType
;
5288 var lifted
= new Nullable
.LiftedBinaryOperator (this);
5289 lifted
.UserOperator
= best_original
;
5291 if (left
.Type
.IsNullableType
&& !ptypes
[0].IsNullableType
) {
5292 lifted
.UnwrapLeft
= new Nullable
.Unwrap (left
);
5295 if (right
.Type
.IsNullableType
&& !ptypes
[1].IsNullableType
) {
5296 lifted
.UnwrapRight
= new Nullable
.Unwrap (right
);
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
);
5302 return lifted
.Resolve (rc
);
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
);
5310 oper_expr
= new UserOperatorCall (oper_method
, args
, CreateExpressionTree
, loc
);
5313 this.left
= larg
.Expr
;
5314 this.right
= rarg
.Expr
;
5319 bool IsLiftedOperatorApplicable ()
5321 if (left
.Type
.IsNullableType
) {
5322 if ((oper
& Operator
.EqualityMask
) != 0)
5323 return !right
.IsNull
;
5328 if (right
.Type
.IsNullableType
) {
5329 if ((oper
& Operator
.EqualityMask
) != 0)
5330 return !left
.IsNull
;
5335 if (TypeSpec
.IsValueType (left
.Type
))
5336 return right
.IsNull
;
5338 if (TypeSpec
.IsValueType (right
.Type
))
5344 List
<MemberSpec
> CreateLiftedOperators (ResolveContext rc
, IList
<MemberSpec
> operators
)
5346 var nullable_type
= rc
.Module
.PredefinedTypes
.Nullable
.TypeSpec
;
5347 if (nullable_type
== null)
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
5356 List
<MemberSpec
> lifted
= null;
5357 foreach (MethodSpec oper
in operators
) {
5359 if ((Oper
& Operator
.ComparisonMask
) != 0) {
5361 // Result type must be of type bool for lifted comparison operators
5363 rt
= oper
.ReturnType
;
5364 if (rt
.BuiltinType
!= BuiltinTypeSpec
.Type
.Bool
)
5367 if (!TypeSpec
.IsNonNullableValueType (oper
.ReturnType
))
5373 var ptypes
= oper
.Parameters
.Types
;
5374 if (!TypeSpec
.IsNonNullableValueType (ptypes
[0]) || !TypeSpec
.IsNonNullableValueType (ptypes
[1]))
5378 // LAMESPEC: I am not sure why but for equality operators to be lifted
5379 // both types have to match
5381 if ((Oper
& Operator
.EqualityMask
) != 0 && ptypes
[0] != ptypes
[1])
5385 lifted
= new List
<MemberSpec
> ();
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
5392 rt
= nullable_type
.MakeGenericType (rc
.Module
, new[] { oper.ReturnType }
);
5394 var parameters
= ParametersCompiled
.CreateFullyResolved (
5395 nullable_type
.MakeGenericType (rc
.Module
, new [] { ptypes[0] }
),
5396 nullable_type
.MakeGenericType (rc
.Module
, new [] { ptypes[1] }
));
5398 var lifted_op
= new MethodSpec (oper
.Kind
, oper
.DeclaringType
, oper
.MemberDefinition
,
5399 rt
, parameters
, oper
.Modifiers
);
5401 lifted
.Add (lifted_op
);
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
5411 static IList
<MemberSpec
> CombineUserOperators (IList
<MemberSpec
> left
, IList
<MemberSpec
> right
)
5413 var combined
= new List
<MemberSpec
> (left
.Count
+ right
.Count
);
5414 combined
.AddRange (left
);
5415 foreach (var r
in right
) {
5417 foreach (var l
in left
) {
5418 if (l
.DeclaringType
== r
.DeclaringType
) {
5431 void CheckOutOfRangeComparison (ResolveContext ec
, Constant c
, TypeSpec type
)
5433 if (c
is IntegralConstant
|| c
is CharConstant
) {
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 ());
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.
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
5452 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
5454 if (ec
.HasSet (BuilderContext
.Options
.AsyncBody
) && right
.ContainsEmitWithAwait ()) {
5455 left
= left
.EmitToField (ec
);
5457 if ((oper
& Operator
.LogicalMask
) == 0) {
5458 right
= right
.EmitToField (ec
);
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
5468 if ((oper
& Operator
.EqualityMask
) != 0 && (left
is Constant
|| right
is Constant
)) {
5469 bool my_on_true
= oper
== Operator
.Inequality
? on_true
: !on_true
;
5472 // put the constant on the rhs, for simplicity
5474 if (left
is Constant
) {
5475 Expression swap
= right
;
5481 // brtrue/brfalse works with native int only
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
);
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
);
5493 } else if (oper
== Operator
.LogicalAnd
) {
5496 Label tests_end
= ec
.DefineLabel ();
5498 left
.EmitBranchable (ec
, tests_end
, false);
5499 right
.EmitBranchable (ec
, target
, true);
5500 ec
.MarkLabel (tests_end
);
5503 // This optimizes code like this
5504 // if (true && i > 4)
5506 if (!(left
is Constant
))
5507 left
.EmitBranchable (ec
, target
, false);
5509 if (!(right
is Constant
))
5510 right
.EmitBranchable (ec
, target
, false);
5515 } else if (oper
== Operator
.LogicalOr
){
5517 left
.EmitBranchable (ec
, target
, true);
5518 right
.EmitBranchable (ec
, target
, true);
5521 Label tests_end
= ec
.DefineLabel ();
5522 left
.EmitBranchable (ec
, tests_end
, true);
5523 right
.EmitBranchable (ec
, target
, false);
5524 ec
.MarkLabel (tests_end
);
5529 } else if ((oper
& Operator
.ComparisonMask
) == 0) {
5530 base.EmitBranchable (ec
, target
, on_true
);
5537 TypeSpec t
= left
.Type
;
5538 bool is_float
= IsFloat (t
);
5539 bool is_unsigned
= is_float
|| IsUnsigned (t
);
5542 case Operator
.Equality
:
5544 ec
.Emit (OpCodes
.Beq
, target
);
5546 ec
.Emit (OpCodes
.Bne_Un
, target
);
5549 case Operator
.Inequality
:
5551 ec
.Emit (OpCodes
.Bne_Un
, target
);
5553 ec
.Emit (OpCodes
.Beq
, target
);
5556 case Operator
.LessThan
:
5558 if (is_unsigned
&& !is_float
)
5559 ec
.Emit (OpCodes
.Blt_Un
, target
);
5561 ec
.Emit (OpCodes
.Blt
, target
);
5564 ec
.Emit (OpCodes
.Bge_Un
, target
);
5566 ec
.Emit (OpCodes
.Bge
, target
);
5569 case Operator
.GreaterThan
:
5571 if (is_unsigned
&& !is_float
)
5572 ec
.Emit (OpCodes
.Bgt_Un
, target
);
5574 ec
.Emit (OpCodes
.Bgt
, target
);
5577 ec
.Emit (OpCodes
.Ble_Un
, target
);
5579 ec
.Emit (OpCodes
.Ble
, target
);
5582 case Operator
.LessThanOrEqual
:
5584 if (is_unsigned
&& !is_float
)
5585 ec
.Emit (OpCodes
.Ble_Un
, target
);
5587 ec
.Emit (OpCodes
.Ble
, target
);
5590 ec
.Emit (OpCodes
.Bgt_Un
, target
);
5592 ec
.Emit (OpCodes
.Bgt
, target
);
5596 case Operator
.GreaterThanOrEqual
:
5598 if (is_unsigned
&& !is_float
)
5599 ec
.Emit (OpCodes
.Bge_Un
, target
);
5601 ec
.Emit (OpCodes
.Bge
, target
);
5604 ec
.Emit (OpCodes
.Blt_Un
, target
);
5606 ec
.Emit (OpCodes
.Blt
, target
);
5609 throw new InternalErrorException (oper
.ToString ());
5613 public override void Emit (EmitContext ec
)
5615 if (ec
.HasSet (BuilderContext
.Options
.AsyncBody
) && right
.ContainsEmitWithAwait ()) {
5616 left
= left
.EmitToField (ec
);
5618 if ((oper
& Operator
.LogicalMask
) == 0) {
5619 right
= right
.EmitToField (ec
);
5624 // Handle short-circuit operators differently
5627 if ((oper
& Operator
.LogicalMask
) != 0) {
5628 Label load_result
= ec
.DefineLabel ();
5629 Label end
= ec
.DefineLabel ();
5631 bool is_or
= oper
== Operator
.LogicalOr
;
5632 left
.EmitBranchable (ec
, load_result
, is_or
);
5634 ec
.Emit (OpCodes
.Br_S
, end
);
5636 ec
.MarkLabel (load_result
);
5637 ec
.EmitInt (is_or
? 1 : 0);
5643 // Optimize zero-based operations which cannot be optimized at expression level
5645 if (oper
== Operator
.Subtraction
) {
5646 var lc
= left
as IntegralConstant
;
5647 if (lc
!= null && lc
.IsDefaultValue
) {
5649 ec
.Emit (OpCodes
.Neg
);
5654 EmitOperator (ec
, left
, right
);
5657 public void EmitOperator (EmitContext ec
, Expression left
, Expression right
)
5662 EmitOperatorOpcode (ec
, oper
, left
.Type
, right
);
5665 // Emit result enumerable conversion this way because it's quite complicated get it
5666 // to resolved tree because expression tree cannot see it.
5668 if (enum_conversion
!= 0)
5669 ConvCast
.Emit (ec
, enum_conversion
);
5672 public override void EmitSideEffect (EmitContext ec
)
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
);
5678 left
.EmitSideEffect (ec
);
5679 right
.EmitSideEffect (ec
);
5683 public override Expression
EmitToField (EmitContext ec
)
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
);
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
);
5701 return base.EmitToField (ec
);
5704 protected override void CloneTo (CloneContext clonectx
, Expression t
)
5706 Binary target
= (Binary
) t
;
5708 target
.left
= left
.Clone (clonectx
);
5709 target
.right
= right
.Clone (clonectx
);
5712 public Expression
CreateCallSiteBinder (ResolveContext ec
, Arguments args
)
5714 Arguments binder_args
= new Arguments (4);
5716 MemberAccess sle
= new MemberAccess (new MemberAccess (
5717 new QualifiedAliasMember (QualifiedAliasMember
.GlobalAlias
, "System", loc
), "Linq", loc
), "Expressions", loc
);
5719 CSharpBinderFlags flags
= 0;
5720 if (ec
.HasSet (ResolveContext
.Options
.CheckedScope
))
5721 flags
= CSharpBinderFlags
.CheckedContext
;
5723 if ((oper
& Operator
.LogicalMask
) != 0)
5724 flags
|= CSharpBinderFlags
.BinaryOperationLogical
;
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
)));
5731 return new Invocation (new MemberAccess (new TypeExpression (ec
.Module
.PredefinedTypes
.Binder
.TypeSpec
, loc
), "BinaryOperation", loc
), binder_args
);
5734 public override Expression
CreateExpressionTree (ResolveContext ec
)
5736 return CreateExpressionTree (ec
, null);
5739 public Expression
CreateExpressionTree (ResolveContext ec
, Expression method
)
5742 bool lift_arg
= false;
5745 case Operator
.Addition
:
5746 if (method
== null && ec
.HasSet (ResolveContext
.Options
.CheckedScope
) && !IsFloat (type
))
5747 method_name
= "AddChecked";
5749 method_name
= "Add";
5751 case Operator
.BitwiseAnd
:
5752 method_name
= "And";
5754 case Operator
.BitwiseOr
:
5757 case Operator
.Division
:
5758 method_name
= "Divide";
5760 case Operator
.Equality
:
5761 method_name
= "Equal";
5764 case Operator
.ExclusiveOr
:
5765 method_name
= "ExclusiveOr";
5767 case Operator
.GreaterThan
:
5768 method_name
= "GreaterThan";
5771 case Operator
.GreaterThanOrEqual
:
5772 method_name
= "GreaterThanOrEqual";
5775 case Operator
.Inequality
:
5776 method_name
= "NotEqual";
5779 case Operator
.LeftShift
:
5780 method_name
= "LeftShift";
5782 case Operator
.LessThan
:
5783 method_name
= "LessThan";
5786 case Operator
.LessThanOrEqual
:
5787 method_name
= "LessThanOrEqual";
5790 case Operator
.LogicalAnd
:
5791 method_name
= "AndAlso";
5793 case Operator
.LogicalOr
:
5794 method_name
= "OrElse";
5796 case Operator
.Modulus
:
5797 method_name
= "Modulo";
5799 case Operator
.Multiply
:
5800 if (method
== null && ec
.HasSet (ResolveContext
.Options
.CheckedScope
) && !IsFloat (type
))
5801 method_name
= "MultiplyChecked";
5803 method_name
= "Multiply";
5805 case Operator
.RightShift
:
5806 method_name
= "RightShift";
5808 case Operator
.Subtraction
:
5809 if (method
== null && ec
.HasSet (ResolveContext
.Options
.CheckedScope
) && !IsFloat (type
))
5810 method_name
= "SubtractChecked";
5812 method_name
= "Subtract";
5816 throw new InternalErrorException ("Unknown expression tree binary operator " + oper
);
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) {
5824 args
.Add (new Argument (new BoolLiteral (ec
.BuiltinTypes
, false, loc
)));
5826 args
.Add (new Argument (method
));
5829 return CreateExpressionFactoryCall (ec
, method_name
, args
);
5832 public override object Accept (StructuralVisitor visitor
)
5834 return visitor
.Visit (this);
5840 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5841 // b, c, d... may be strings or objects.
5843 public class StringConcat
: Expression
5845 Arguments arguments
;
5847 StringConcat (Location loc
)
5850 arguments
= new Arguments (2);
5853 public override bool ContainsEmitWithAwait ()
5855 return arguments
.ContainsEmitWithAwait ();
5858 public static StringConcat
Create (ResolveContext rc
, Expression left
, Expression right
, Location loc
)
5860 if (left
.eclass
== ExprClass
.Unresolved
|| right
.eclass
== ExprClass
.Unresolved
)
5861 throw new ArgumentException ();
5863 var s
= new StringConcat (loc
);
5864 s
.type
= rc
.BuiltinTypes
.String
;
5865 s
.eclass
= ExprClass
.Value
;
5867 s
.Append (rc
, left
);
5868 s
.Append (rc
, right
);
5872 public override Expression
CreateExpressionTree (ResolveContext ec
)
5874 Argument arg
= arguments
[0];
5875 return CreateExpressionAddCall (ec
, arg
, arg
.CreateExpressionTree (ec
), 1);
5879 // Creates nested calls tree from an array of arguments used for IL emit
5881 Expression
CreateExpressionAddCall (ResolveContext ec
, Argument left
, Expression left_etree
, int pos
)
5883 Arguments concat_args
= new Arguments (2);
5884 Arguments add_args
= new Arguments (3);
5886 concat_args
.Add (left
);
5887 add_args
.Add (new Argument (left_etree
));
5889 concat_args
.Add (arguments
[pos
]);
5890 add_args
.Add (new Argument (arguments
[pos
].CreateExpressionTree (ec
)));
5892 var methods
= GetConcatMethodCandidates ();
5893 if (methods
== null)
5896 var res
= new OverloadResolver (methods
, OverloadResolver
.Restrictions
.NoBaseMembers
, loc
);
5897 var method
= res
.ResolveMember
<MethodSpec
> (ec
, ref concat_args
);
5901 add_args
.Add (new Argument (new TypeOfMethod (method
, loc
)));
5903 Expression expr
= CreateExpressionFactoryCall (ec
, "Add", add_args
);
5904 if (++pos
== arguments
.Count
)
5907 left
= new Argument (new EmptyExpression (method
.ReturnType
));
5908 return CreateExpressionAddCall (ec
, left
, expr
, pos
);
5911 protected override Expression
DoResolve (ResolveContext ec
)
5916 void Append (ResolveContext rc
, Expression operand
)
5921 StringConstant sc
= operand
as StringConstant
;
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
);
5933 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5935 StringConcat concat_oper
= operand
as StringConcat
;
5936 if (concat_oper
!= null) {
5937 arguments
.AddRange (concat_oper
.arguments
);
5942 arguments
.Add (new Argument (operand
));
5945 IList
<MemberSpec
> GetConcatMethodCandidates ()
5947 return MemberCache
.FindMembers (type
, "Concat", true);
5950 public override void Emit (EmitContext ec
)
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
--);
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);
5967 public override void FlowAnalysis (FlowAnalysisContext fc
)
5969 arguments
.FlowAnalysis (fc
);
5972 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
5974 if (arguments
.Count
!= 2)
5975 throw new NotImplementedException ("arguments.Count != 2");
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
);
5983 // User-defined conditional logical operator
5985 public class ConditionalLogicalOperator
: UserOperatorCall
5987 readonly bool is_and
;
5988 Expression oper_expr
;
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
)
5993 this.is_and
= is_and
;
5994 eclass
= ExprClass
.Unresolved
;
5997 protected override Expression
DoResolve (ResolveContext ec
)
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 ());
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 ());
6017 oper_expr
= is_and
? op_false
: op_true
;
6018 eclass
= ExprClass
.Value
;
6022 public override void Emit (EmitContext ec
)
6024 Label end_target
= ec
.DefineLabel ();
6027 // Emit and duplicate left argument
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
);
6034 arguments
[0].Expr
.Emit (ec
);
6035 ec
.Emit (OpCodes
.Dup
);
6036 arguments
.RemoveAt (0);
6039 oper_expr
.EmitBranchable (ec
, end_target
, true);
6043 if (right_contains_await
) {
6045 // Special handling when right expression contains await and left argument
6046 // could not be left on stack before logical branch
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
);
6054 ec
.MarkLabel (end_target
);
6059 public class PointerArithmetic
: Expression
{
6060 Expression left
, right
;
6061 readonly Binary
.Operator op
;
6064 // We assume that `l' is always a pointer
6066 public PointerArithmetic (Binary
.Operator op
, Expression l
, Expression r
, TypeSpec t
, Location loc
)
6075 public override bool ContainsEmitWithAwait ()
6077 throw new NotImplementedException ();
6080 public override Expression
CreateExpressionTree (ResolveContext ec
)
6082 Error_PointerInsideExpressionTree (ec
);
6086 protected override Expression
DoResolve (ResolveContext ec
)
6088 eclass
= ExprClass
.Variable
;
6090 var pc
= left
.Type
as PointerContainer
;
6091 if (pc
!= null && pc
.Element
.Kind
== MemberKind
.Void
) {
6092 Error_VoidPointerOperation (ec
);
6099 public override void Emit (EmitContext ec
)
6101 TypeSpec op_type
= left
.Type
;
6103 // It must be either array or fixed buffer
6105 if (TypeManager
.HasElementType (op_type
)) {
6106 element
= TypeManager
.GetElementType (op_type
);
6108 FieldExpr fe
= left
as FieldExpr
;
6110 element
= ((FixedFieldSpec
) (fe
.Spec
)).ElementType
;
6115 int size
= BuiltinTypeSpec
.GetSize(element
);
6116 TypeSpec rtype
= right
.Type
;
6118 if ((op
& Binary
.Operator
.SubtractionMask
) != 0 && rtype
.IsPointer
){
6120 // handle (pointer - pointer)
6124 ec
.Emit (OpCodes
.Sub
);
6128 ec
.Emit (OpCodes
.Sizeof
, element
);
6131 ec
.Emit (OpCodes
.Div
);
6133 ec
.Emit (OpCodes
.Conv_I8
);
6136 // handle + and - on (pointer op int)
6138 Constant left_const
= left
as Constant
;
6139 if (left_const
!= null) {
6141 // Optimize ((T*)null) pointer operations
6143 if (left_const
.IsDefaultValue
) {
6144 left
= EmptyExpression
.Null
;
6152 var right_const
= right
as Constant
;
6153 if (right_const
!= null) {
6155 // Optimize 0-based arithmetic
6157 if (right_const
.IsDefaultValue
)
6161 right
= new IntConstant (ec
.BuiltinTypes
, size
, right
.Location
);
6163 right
= new SizeOf (new TypeExpression (element
, right
.Location
), right
.Location
);
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
);
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
);
6182 case BuiltinTypeSpec
.Type
.UInt
:
6183 ec
.Emit (OpCodes
.Conv_U
);
6188 if (right_const
== null && size
!= 1){
6190 ec
.Emit (OpCodes
.Sizeof
, element
);
6193 if (rtype
.BuiltinType
== BuiltinTypeSpec
.Type
.Long
|| rtype
.BuiltinType
== BuiltinTypeSpec
.Type
.ULong
)
6194 ec
.Emit (OpCodes
.Conv_I8
);
6196 Binary
.EmitOperatorOpcode (ec
, Binary
.Operator
.Multiply
, rtype
, right
);
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
);
6205 Binary
.EmitOperatorOpcode (ec
, op
, op_type
, right
);
6212 // A boolean-expression is an expression that yields a result
6215 public class BooleanExpression
: ShimExpression
6217 public BooleanExpression (Expression expr
)
6220 this.loc
= expr
.Location
;
6223 public override Expression
CreateExpressionTree (ResolveContext ec
)
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
);
6230 protected override Expression
DoResolve (ResolveContext ec
)
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
6236 expr
= expr
.Resolve (ec
);
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 ?");
6246 if (expr
.Type
.BuiltinType
== BuiltinTypeSpec
.Type
.Bool
)
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
);
6255 type
= ec
.BuiltinTypes
.Bool
;
6256 Expression converted
= Convert
.ImplicitConversion (ec
, expr
, type
, loc
);
6257 if (converted
!= null)
6261 // If no implicit conversion to bool exists, try using `operator true'
6263 converted
= GetOperatorTrue (ec
, expr
, loc
);
6264 if (converted
== null) {
6265 expr
.Error_ValueCannotBeConverted (ec
, type
, false);
6272 public override object Accept (StructuralVisitor visitor
)
6274 return visitor
.Visit (this);
6278 public class BooleanExpressionFalse
: Unary
6280 public BooleanExpressionFalse (Expression expr
)
6281 : base (Operator
.LogicalNot
, expr
, expr
.Location
)
6285 protected override Expression
ResolveOperator (ResolveContext ec
, Expression expr
)
6287 return GetOperatorFalse (ec
, expr
, loc
) ?? base.ResolveOperator (ec
, expr
);
6292 /// Implements the ternary conditional operator (?:)
6294 public class Conditional
: Expression
{
6295 Expression expr
, true_expr
, false_expr
;
6297 public Conditional (Expression expr
, Expression true_expr
, Expression false_expr
, Location loc
)
6300 this.true_expr
= true_expr
;
6301 this.false_expr
= false_expr
;
6307 public Expression Expr
{
6313 public Expression TrueExpr
{
6319 public Expression FalseExpr
{
6327 public override bool ContainsEmitWithAwait ()
6329 return Expr
.ContainsEmitWithAwait () || true_expr
.ContainsEmitWithAwait () || false_expr
.ContainsEmitWithAwait ();
6332 public override Expression
CreateExpressionTree (ResolveContext ec
)
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
);
6341 protected override Expression
DoResolve (ResolveContext ec
)
6343 expr
= expr
.Resolve (ec
);
6344 true_expr
= true_expr
.Resolve (ec
);
6345 false_expr
= false_expr
.Resolve (ec
);
6347 if (true_expr
== null || false_expr
== null || expr
== null)
6350 eclass
= ExprClass
.Value
;
6351 TypeSpec true_type
= true_expr
.Type
;
6352 TypeSpec false_type
= false_expr
.Type
;
6356 // First, if an implicit conversion exists from true_expr
6357 // to false_expr, then the result type is of type false_expr.Type
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
) {
6363 // Check if both can convert implicitly to each other's type
6367 if (false_type
.BuiltinType
!= BuiltinTypeSpec
.Type
.Dynamic
) {
6368 var conv_false_expr
= Convert
.ImplicitConversion (ec
, false_expr
, true_type
, loc
);
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.
6374 // var res = condition ? (short)1 : 1;
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.
6379 if (conv_false_expr
!= null) {
6380 if (conv_false_expr
.Type
.BuiltinType
== BuiltinTypeSpec
.Type
.Int
&& conv
is Constant
) {
6382 conv_false_expr
= null;
6383 } else if (type
.BuiltinType
== BuiltinTypeSpec
.Type
.Int
&& conv_false_expr
is Constant
) {
6384 conv_false_expr
= null;
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 ());
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) {
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 ());
6410 Constant c
= expr
as Constant
;
6412 bool is_false
= c
.IsDefaultValue
;
6415 // Don't issue the warning for constant expressions
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
);
6422 return ReducedExpression
.Create (
6423 is_false
? false_expr
: true_expr
, this,
6424 false_expr
is Constant
&& true_expr
is Constant
).Resolve (ec
);
6430 public override void Emit (EmitContext ec
)
6432 Label false_target
= ec
.DefineLabel ();
6433 Label end_target
= ec
.DefineLabel ();
6435 expr
.EmitBranchable (ec
, false_target
, false);
6436 true_expr
.Emit (ec
);
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
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
);
6450 ec
.Emit (OpCodes
.Br
, end_target
);
6451 ec
.MarkLabel (false_target
);
6452 false_expr
.Emit (ec
);
6453 ec
.MarkLabel (end_target
);
6456 public override void FlowAnalysis (FlowAnalysisContext fc
)
6458 expr
.FlowAnalysisConditional (fc
);
6459 var expr_true
= fc
.DefiniteAssignmentOnTrue
;
6460 var expr_false
= fc
.DefiniteAssignmentOnFalse
;
6462 fc
.BranchDefiniteAssignment (expr_true
);
6463 true_expr
.FlowAnalysis (fc
);
6464 var true_fc
= fc
.DefiniteAssignment
;
6466 fc
.BranchDefiniteAssignment (expr_false
);
6467 false_expr
.FlowAnalysis (fc
);
6469 fc
.DefiniteAssignment
&= true_fc
;
6472 public override void FlowAnalysisConditional (FlowAnalysisContext fc
)
6474 expr
.FlowAnalysisConditional (fc
);
6475 var expr_true
= fc
.DefiniteAssignmentOnTrue
;
6476 var expr_false
= fc
.DefiniteAssignmentOnFalse
;
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
;
6484 fc
.DefiniteAssignmentOnTrue
= fc
.DefiniteAssignmentOnFalse
= fc
.DefiniteAssignment
= new DefiniteAssignmentBitSet (expr_false
);
6485 false_expr
.FlowAnalysisConditional (fc
);
6487 fc
.DefiniteAssignment
&= true_fc
;
6488 fc
.DefiniteAssignmentOnTrue
= true_da_true
& fc
.DefiniteAssignmentOnTrue
;
6489 fc
.DefiniteAssignmentOnFalse
= true_da_false
& fc
.DefiniteAssignmentOnFalse
;
6492 protected override void CloneTo (CloneContext clonectx
, Expression t
)
6494 Conditional target
= (Conditional
) t
;
6496 target
.expr
= expr
.Clone (clonectx
);
6497 target
.true_expr
= true_expr
.Clone (clonectx
);
6498 target
.false_expr
= false_expr
.Clone (clonectx
);
6502 public abstract class VariableReference
: Expression
, IAssignMethod
, IMemoryLocation
, IVariableReference
6504 LocalTemporary temp
;
6507 public abstract HoistedVariable
GetHoistedVariable (AnonymousExpression ae
);
6508 public abstract void SetHasAddressTaken ();
6510 public abstract bool IsLockedByStatement { get; set; }
6512 public abstract bool IsFixed { get; }
6513 public abstract bool IsRef { get; }
6514 public abstract string Name { get; }
6517 // Variable IL data, it has to be protected to encapsulate hoisted variables
6519 protected abstract ILocalVariable Variable { get; }
6522 // Variable flow-analysis data
6524 public abstract VariableInfo VariableInfo { get; }
6527 public virtual void AddressOf (EmitContext ec
, AddressOp mode
)
6529 HoistedVariable hv
= GetHoistedVariable (ec
);
6531 hv
.AddressOf (ec
, mode
);
6535 Variable
.EmitAddressOf (ec
);
6538 public override bool ContainsEmitWithAwait ()
6543 public override Expression
CreateExpressionTree (ResolveContext ec
)
6545 HoistedVariable hv
= GetHoistedVariable (ec
);
6547 return hv
.CreateExpressionTree ();
6549 Arguments arg
= new Arguments (1);
6550 arg
.Add (new Argument (this));
6551 return CreateExpressionFactoryCall (ec
, "Constant", arg
);
6554 public override Expression
DoResolveLValue (ResolveContext rc
, Expression right_side
)
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",
6565 public override void Emit (EmitContext ec
)
6570 public override void EmitSideEffect (EmitContext ec
)
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).
6581 public void EmitLoad (EmitContext ec
)
6586 public void Emit (EmitContext ec
, bool leave_copy
)
6588 HoistedVariable hv
= GetHoistedVariable (ec
);
6590 hv
.Emit (ec
, leave_copy
);
6598 // If we are a reference, we loaded on the stack a pointer
6599 // Now lets load the real value
6601 ec
.EmitLoadFromPtr (type
);
6605 ec
.Emit (OpCodes
.Dup
);
6608 temp
= new LocalTemporary (Type
);
6614 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
,
6615 bool prepare_for_load
)
6617 HoistedVariable hv
= GetHoistedVariable (ec
);
6619 hv
.EmitAssign (ec
, source
, leave_copy
, prepare_for_load
);
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)) {
6630 ec
.EmitLoadFromPtr (type
);
6642 ec
.Emit (OpCodes
.Dup
);
6644 temp
= new LocalTemporary (Type
);
6650 ec
.EmitStoreFromPtr (type
);
6652 Variable
.EmitAssign (ec
);
6660 public override Expression
EmitToField (EmitContext ec
)
6662 HoistedVariable hv
= GetHoistedVariable (ec
);
6664 return hv
.EmitToField (ec
);
6667 return base.EmitToField (ec
);
6670 public HoistedVariable
GetHoistedVariable (ResolveContext rc
)
6672 return GetHoistedVariable (rc
.CurrentAnonymousMethod
);
6675 public HoistedVariable
GetHoistedVariable (EmitContext ec
)
6677 return GetHoistedVariable (ec
.CurrentAnonymousMethod
);
6680 public override string GetSignatureForError ()
6685 public bool IsHoisted
{
6686 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6691 // Resolved reference to a local variable
6693 public class LocalVariableReference
: VariableReference
6695 public LocalVariable local_info
;
6697 public LocalVariableReference (LocalVariable li
, Location l
)
6699 this.local_info
= li
;
6703 public override VariableInfo VariableInfo
{
6704 get { return local_info.VariableInfo; }
6707 public override HoistedVariable
GetHoistedVariable (AnonymousExpression ae
)
6709 return local_info
.HoistedVariant
;
6715 // A local variable is always fixed
6717 public override bool IsFixed
{
6723 public override bool IsLockedByStatement
{
6725 return local_info
.IsLocked
;
6728 local_info
.IsLocked
= value;
6732 public override bool IsRef
{
6733 get { return local_info.IsByRef; }
6736 public override string Name
{
6737 get { return local_info.Name; }
6742 public override void FlowAnalysis (FlowAnalysisContext fc
)
6744 VariableInfo variable_info
= VariableInfo
;
6745 if (variable_info
== null)
6748 if (fc
.IsDefinitelyAssigned (variable_info
))
6751 fc
.Report
.Error (165, loc
, "Use of unassigned local variable `{0}'", Name
);
6752 variable_info
.SetAssigned (fc
.DefiniteAssignment
, true);
6755 public override void SetHasAddressTaken ()
6757 local_info
.SetHasAddressTaken ();
6760 void DoResolveBase (ResolveContext ec
)
6762 eclass
= ExprClass
.Variable
;
6763 type
= local_info
.Type
;
6766 // If we are referencing a variable from the external block
6767 // flag it for capturing
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
6780 ec
.Report
.Error (8175, loc
,
6781 "Cannot use by-reference variable `{0}' inside an anonymous method, lambda expression, or query expression",
6782 GetSignatureForError ());
6786 if (ec
.IsVariableCapturingRequired
) {
6787 AnonymousMethodStorey storey
= local_info
.Block
.Explicit
.CreateAnonymousMethodStorey (ec
);
6788 storey
.CaptureLocalVariable (ec
, local_info
);
6793 protected override Expression
DoResolve (ResolveContext ec
)
6795 local_info
.SetIsUsed ();
6799 if (local_info
.Type
== InternalType
.VarOutType
) {
6800 ec
.Report
.Error (8048, loc
, "Cannot use uninitialized variable `{0}'",
6801 GetSignatureForError ());
6803 type
= InternalType
.ErrorType
;
6809 public override Expression
DoResolveLValue (ResolveContext ec
, Expression rhs
)
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
6815 if (rhs
== EmptyExpression
.OutAccess
|| rhs
.eclass
== ExprClass
.PropertyAccess
|| rhs
.eclass
== ExprClass
.IndexerAccess
)
6816 local_info
.SetIsUsed ();
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
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}'";
6833 code
= 1656; msg
= "Cannot assign to `{0}' because it is a `{1}'";
6835 ec
.Report
.Error (code
, loc
, msg
, Name
, local_info
.GetReadOnlyContext ());
6839 if (eclass
== ExprClass
.Unresolved
)
6842 return base.DoResolveLValue (ec
, rhs
);
6845 public override int GetHashCode ()
6847 return local_info
.GetHashCode ();
6850 public override bool Equals (object obj
)
6852 LocalVariableReference lvr
= obj
as LocalVariableReference
;
6856 return local_info
== lvr
.local_info
;
6859 protected override ILocalVariable Variable
{
6860 get { return local_info; }
6863 public override string ToString ()
6865 return String
.Format ("{0} ({1}:{2})", GetType (), Name
, loc
);
6868 protected override void CloneTo (CloneContext clonectx
, Expression t
)
6875 /// This represents a reference to a parameter in the intermediate
6878 public class ParameterReference
: VariableReference
6880 protected ParametersBlock
.ParameterInfo pi
;
6882 public ParameterReference (ParametersBlock
.ParameterInfo pi
, Location loc
)
6890 public override bool IsLockedByStatement
{
6895 pi
.IsLocked
= value;
6899 public override bool IsRef
{
6900 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6903 bool HasOutModifier
{
6904 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6907 public override HoistedVariable
GetHoistedVariable (AnonymousExpression ae
)
6909 return pi
.Parameter
.HoistedVariant
;
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
6916 public override bool IsFixed
{
6917 get { return !IsRef; }
6920 public override string Name
{
6921 get { return Parameter.Name; }
6924 public Parameter Parameter
{
6925 get { return pi.Parameter; }
6928 public override VariableInfo VariableInfo
{
6929 get { return pi.VariableInfo; }
6932 protected override ILocalVariable Variable
{
6933 get { return Parameter; }
6938 public override void AddressOf (EmitContext ec
, AddressOp mode
)
6941 // ParameterReferences might already be a reference
6948 base.AddressOf (ec
, mode
);
6951 public override void SetHasAddressTaken ()
6953 Parameter
.HasAddressTaken
= true;
6956 bool DoResolveBase (ResolveContext ec
)
6958 if (eclass
!= ExprClass
.Unresolved
)
6961 type
= pi
.ParameterType
;
6962 eclass
= ExprClass
.Variable
;
6965 // If we are referencing a parameter from the external block
6966 // flag it for capturing
6968 if (ec
.MustCaptureVariable (pi
)) {
6969 if (Parameter
.HasAddressTaken
)
6970 AnonymousMethodExpression
.Error_AddressOfCapturedVar (ec
, this, loc
);
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
);
6978 if (ec
.IsVariableCapturingRequired
&& !pi
.Block
.ParametersBlock
.IsExpressionTree
) {
6979 AnonymousMethodStorey storey
= pi
.Block
.Explicit
.CreateAnonymousMethodStorey (ec
);
6980 storey
.CaptureParameter (ec
, pi
, this);
6987 public override int GetHashCode ()
6989 return Name
.GetHashCode ();
6992 public override bool Equals (object obj
)
6994 ParameterReference pr
= obj
as ParameterReference
;
6998 return Name
== pr
.Name
;
7001 protected override void CloneTo (CloneContext clonectx
, Expression target
)
7007 public override Expression
CreateExpressionTree (ResolveContext ec
)
7009 HoistedVariable hv
= GetHoistedVariable (ec
);
7011 return hv
.CreateExpressionTree ();
7013 return Parameter
.ExpressionTreeVariableReference ();
7016 protected override Expression
DoResolve (ResolveContext ec
)
7018 if (!DoResolveBase (ec
))
7024 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
7026 if (!DoResolveBase (ec
))
7029 if (Parameter
.HoistedVariant
!= null)
7030 Parameter
.HoistedVariant
.IsAssigned
= true;
7032 return base.DoResolveLValue (ec
, right_side
);
7035 public override void FlowAnalysis (FlowAnalysisContext fc
)
7037 VariableInfo variable_info
= VariableInfo
;
7038 if (variable_info
== null)
7041 if (fc
.IsDefinitelyAssigned (variable_info
))
7044 fc
.Report
.Error (269, loc
, "Use of unassigned out parameter `{0}'", Name
);
7045 fc
.SetVariableAssigned (variable_info
);
7050 /// Invocation of methods or delegates.
7052 public class Invocation
: ExpressionStatement
7054 public class Predefined
: Invocation
7056 public Predefined (MethodGroupExpr expr
, Arguments arguments
)
7057 : base (expr
, arguments
)
7062 protected override MethodGroupExpr
DoResolveOverload (ResolveContext rc
)
7064 mg
.BestCandidate
.CheckObsoleteness (rc
, loc
);
7070 protected Arguments arguments
;
7071 protected Expression expr
;
7072 protected MethodGroupExpr mg
;
7073 bool conditional_access_receiver
;
7075 public Invocation (Expression expr
, Arguments arguments
)
7078 this.arguments
= arguments
;
7080 loc
= expr
.Location
;
7085 public Arguments Arguments
{
7091 public Expression Exp
{
7097 public MethodGroupExpr MethodGroup
{
7103 public override Location StartLocation
{
7105 return expr
.StartLocation
;
7111 public override MethodGroupExpr
CanReduceLambda (AnonymousMethodBody body
)
7113 if (MethodGroup
== null)
7116 var candidate
= MethodGroup
.BestCandidate
;
7117 if (candidate
== null || !(candidate
.IsStatic
|| Exp
is This
))
7120 var args_count
= arguments
== null ? 0 : arguments
.Count
;
7121 if (args_count
!= body
.Parameters
.Count
)
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
;
7130 if (lambda_parameters
[i
] != pr
.Parameter
)
7133 if ((lambda_parameters
[i
].ModFlags
& Parameter
.Modifier
.RefOutMask
) != (pr
.Parameter
.ModFlags
& Parameter
.Modifier
.RefOutMask
))
7137 var emg
= MethodGroup
as ExtensionMethodGroupExpr
;
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
);
7146 mg
.SetTypeArguments (null, new TypeArguments (targs
));
7155 protected override void CloneTo (CloneContext clonectx
, Expression t
)
7157 Invocation target
= (Invocation
) t
;
7159 if (arguments
!= null)
7160 target
.arguments
= arguments
.Clone (clonectx
);
7162 target
.expr
= expr
.Clone (clonectx
);
7165 public override bool ContainsEmitWithAwait ()
7167 if (arguments
!= null && arguments
.ContainsEmitWithAwait ())
7170 return mg
.ContainsEmitWithAwait ();
7173 public override Expression
CreateExpressionTree (ResolveContext ec
)
7175 Expression instance
= mg
.IsInstance
?
7176 mg
.InstanceExpression
.CreateExpressionTree (ec
) :
7177 new NullLiteral (loc
);
7179 var args
= Arguments
.CreateForExpressionTree (ec
, arguments
,
7181 mg
.CreateExpressionTree (ec
));
7183 return CreateExpressionFactoryCall (ec
, "Call", args
);
7186 void ResolveConditionalAccessReceiver (ResolveContext rc
)
7188 if (!rc
.HasSet (ResolveContext
.Options
.DontSetConditionalAccessReceiver
) && expr
.HasConditionalAccess ()) {
7189 conditional_access_receiver
= true;
7193 bool statement_resolve
;
7194 public override ExpressionStatement
ResolveStatement (BlockContext bc
)
7196 statement_resolve
= true;
7197 var es
= base.ResolveStatement (bc
);
7198 statement_resolve
= false;
7203 protected override Expression
DoResolve (ResolveContext rc
)
7205 ResolveConditionalAccessReceiver (rc
);
7206 return DoResolveInvocation (rc
, null);
7209 public override Expression
DoResolveLValue (ResolveContext rc
, Expression right_side
)
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
;
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
));
7226 var res
= new TupleDeconstruct (variables
, right_side
, loc
);
7227 return res
.Resolve (rc
);
7230 if (right_side
!= null) {
7231 if (eclass
!= ExprClass
.Unresolved
)
7234 var res
= DoResolveInvocation (rc
, right_side
);
7241 return base.DoResolveLValue (rc
, right_side
);
7244 Expression
DoResolveInvocation (ResolveContext ec
, Expression rhs
)
7246 Expression member_expr
;
7247 var atn
= expr
as ATypeNameExpression
;
7249 var flags
= default (ResolveContext
.FlagsHandle
);
7250 if (conditional_access_receiver
)
7251 flags
= ec
.Set (ResolveContext
.Options
.DontSetConditionalAccessReceiver
);
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
);
7261 member_expr
= member_expr
.Resolve (ec
);
7264 member_expr
= expr
.Resolve (ec
);
7267 if (conditional_access_receiver
)
7270 if (member_expr
== null)
7274 // Next, evaluate all the expressions in the argument list
7276 bool dynamic_arg
= false;
7277 if (arguments
!= null) {
7278 using (ec
.With (ResolveContext
.Options
.DontSetConditionalAccessReceiver
, false)) {
7279 arguments
.Resolve (ec
, out dynamic_arg
);
7283 TypeSpec expr_type
= member_expr
.Type
;
7284 if (expr_type
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
)
7285 return DoResolveDynamic (ec
, member_expr
);
7287 mg
= member_expr
as MethodGroupExpr
;
7288 Expression invoke
= 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
)
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 ());
7303 MemberExpr me
= member_expr
as MemberExpr
;
7305 member_expr
.Error_UnexpectedKind (ec
, ResolveFlags
.MethodGroup
, loc
);
7309 ec
.Report
.Error (1955, loc
, "The member `{0}' cannot be used as method or delegate",
7310 member_expr
.GetSignatureForError ());
7315 if (invoke
== null) {
7316 mg
= DoResolveOverload (ec
);
7322 return DoResolveDynamic (ec
, member_expr
);
7324 var method
= mg
.BestCandidate
;
7325 type
= mg
.BestCandidateReturnType
;
7326 if (conditional_access_receiver
&& !statement_resolve
)
7327 type
= LiftMemberType (ec
, type
);
7329 if (arguments
== null && method
.DeclaringType
.BuiltinType
== BuiltinTypeSpec
.Type
.Object
&& method
.Name
== Destructor
.MetadataName
) {
7331 ec
.Report
.Error (250, loc
, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7333 ec
.Report
.Error (245, loc
, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7337 IsSpecialMethodInvocation (ec
, method
, loc
);
7339 eclass
= ExprClass
.Value
;
7341 if (type
.Kind
== MemberKind
.ByRef
&& rhs
!= EmptyExpression
.OutAccess
)
7342 return ByRefDereference
.Create (this).Resolve (ec
);
7347 protected virtual Expression
DoResolveDynamic (ResolveContext ec
, Expression memberExpr
)
7350 DynamicMemberBinder dmb
= memberExpr
as DynamicMemberBinder
;
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);
7361 args
.Insert (0, new Argument (memberExpr
));
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",
7371 if (arguments
== null)
7372 args
= new Arguments (1);
7376 MemberAccess ma
= expr
as MemberAccess
;
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) {
7384 // Any value type has to be pass as by-ref to get back the same
7385 // instance on which the member was called
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
));
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
));
7395 args
.Insert (0, new Argument (new This (loc
).Resolve (ec
)));
7400 return new DynamicInvocation (expr
as ATypeNameExpression
, args
, conditional_access_receiver
, loc
).Resolve (ec
);
7403 protected virtual MethodGroupExpr
DoResolveOverload (ResolveContext ec
)
7405 return mg
.OverloadResolve (ec
, ref arguments
, null, OverloadResolver
.Restrictions
.None
);
7408 public override void FlowAnalysis (FlowAnalysisContext fc
)
7410 if (mg
.IsConditionallyExcluded
)
7413 var da
= conditional_access_receiver
? fc
.BranchDefiniteAssignment () : null;
7415 mg
.FlowAnalysis (fc
);
7417 if (arguments
!= null)
7418 arguments
.FlowAnalysis (fc
);
7420 if (conditional_access_receiver
)
7421 fc
.DefiniteAssignment
= da
;
7424 public override string GetSignatureForError ()
7426 return mg
.GetSignatureForError ();
7429 public override bool HasConditionalAccess ()
7431 return expr
.HasConditionalAccess ();
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
7438 public static bool IsMemberInvocable (MemberSpec member
)
7440 switch (member
.Kind
) {
7441 case MemberKind
.Event
:
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
;
7452 public static bool IsSpecialMethodInvocation (ResolveContext ec
, MethodSpec method
, Location loc
)
7454 if (!method
.IsReservedMethod
)
7457 if (ec
.HasSet (ResolveContext
.Options
.InvokeSpecialName
) || ec
.CurrentMemberDefinition
.IsCompilerGenerated
)
7460 ec
.Report
.SymbolRelatedToPreviousError (method
);
7461 ec
.Report
.Error (571, loc
, "`{0}': cannot explicitly call operator or accessor",
7462 method
.GetSignatureForError ());
7467 public override void Emit (EmitContext ec
)
7469 if (mg
.IsConditionallyExcluded
)
7472 if (conditional_access_receiver
)
7473 mg
.EmitCall (ec
, arguments
, type
, false);
7475 mg
.EmitCall (ec
, arguments
, false);
7478 public override void EmitPrepare (EmitContext ec
)
7480 mg
.EmitPrepare (ec
);
7482 arguments
?.EmitPrepare (ec
);
7485 public override void EmitStatement (EmitContext ec
)
7487 if (mg
.IsConditionallyExcluded
)
7490 if (conditional_access_receiver
)
7491 mg
.EmitCall (ec
, arguments
, type
, true);
7493 mg
.EmitCall (ec
, arguments
, true);
7496 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
7498 return MakeExpression (ctx
, mg
.InstanceExpression
, mg
.BestCandidate
, arguments
);
7501 public static SLE
.Expression
MakeExpression (BuilderContext ctx
, Expression instance
, MethodSpec mi
, Arguments args
)
7504 throw new NotSupportedException ();
7506 var instance_expr
= instance
== null ? null : instance
.MakeExpression (ctx
);
7507 return SLE
.Expression
.Call (instance_expr
, (MethodInfo
) mi
.GetMetaInfo (), Arguments
.MakeExpression (args
, ctx
));
7511 public override object Accept (StructuralVisitor visitor
)
7513 return visitor
.Visit (this);
7518 // Implements simple new expression
7520 public class New
: ExpressionStatement
, IMemoryLocation
7522 protected Arguments arguments
;
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)
7529 protected Expression RequestedType
;
7531 protected MethodSpec method
;
7533 public New (Expression requested_type
, Arguments arguments
, Location l
)
7535 RequestedType
= requested_type
;
7536 this.arguments
= arguments
;
7541 public Arguments Arguments
{
7548 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7550 public bool IsGeneratedStructConstructor
{
7552 return arguments
== null && method
== null && type
.IsStruct
&& GetType () == typeof (New
);
7556 public Expression TypeExpression
{
7558 return RequestedType
;
7565 /// Converts complex core type syntax like 'new int ()' to simple constant
7567 public static Constant
Constantify (TypeSpec t
, Location loc
)
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
);
7599 return new EnumConstant (Constantify (EnumSpec
.GetUnderlyingType (t
), loc
), t
);
7601 if (t
.IsNullableType
)
7602 return Nullable
.LiftedNull
.Create (t
, loc
);
7607 public override bool ContainsEmitWithAwait ()
7609 return arguments
!= null && arguments
.ContainsEmitWithAwait ();
7613 // Checks whether the type is an interface that has the
7614 // [ComImport, CoClass] attributes and must be treated
7617 public Expression
CheckComImport (ResolveContext ec
)
7619 if (!type
.IsInterface
)
7623 // Turn the call into:
7624 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7626 var real_class
= type
.MemberDefinition
.GetAttributeCoClass ();
7627 if (real_class
== null)
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
);
7635 public override Expression
CreateExpressionTree (ResolveContext ec
)
7638 if (method
== null) {
7639 args
= new Arguments (1);
7640 args
.Add (new Argument (new TypeOf (type
, loc
)));
7642 args
= Arguments
.CreateForExpressionTree (ec
,
7643 arguments
, new TypeOfMethod (method
, loc
));
7646 return CreateExpressionFactoryCall (ec
, "New", args
);
7649 protected override Expression
DoResolve (ResolveContext ec
)
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.");
7655 type
= RequestedType
.ResolveAsType (ec
);
7659 eclass
= ExprClass
.Value
;
7661 if (type
.IsPointer
) {
7662 ec
.Report
.Error (1919, loc
, "Unsafe type `{0}' cannot be used in an object creation expression",
7663 type
.GetSignatureForError ());
7667 if (arguments
== null) {
7668 Constant c
= Constantify (type
, RequestedType
.Location
);
7670 return ReducedExpression
.Create (c
, this);
7673 if (type
.IsDelegate
) {
7674 return (new NewDelegate (type
, arguments
, loc
)).Resolve (ec
);
7677 var tparam
= type
as TypeParameterSpec
;
7678 if (tparam
!= null) {
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
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 ());
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 ());
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 ());
7704 if (type
.IsInterface
|| type
.IsAbstract
){
7705 if (!TypeManager
.IsGenericType (type
)) {
7706 RequestedType
= CheckComImport (ec
);
7707 if (RequestedType
!= null)
7708 return RequestedType
;
7711 ec
.Report
.SymbolRelatedToPreviousError (type
);
7712 ec
.Report
.Error (144, loc
, "Cannot create an instance of the abstract class or interface `{0}'", type
.GetSignatureForError ());
7717 if (arguments
!= null) {
7718 arguments
.Resolve (ec
, out dynamic);
7723 method
= ConstructorLookup (ec
, type
, ref arguments
, loc
);
7726 arguments
.Insert (0, new Argument (new TypeOf (type
, loc
).Resolve (ec
), Argument
.AType
.DynamicTypeName
));
7727 return new DynamicConstructorBinder (type
, arguments
, loc
).Resolve (ec
);
7733 void DoEmitTypeParameter (EmitContext ec
)
7735 var m
= ec
.Module
.PredefinedMembers
.ActivatorCreateInstance
.Resolve (loc
);
7739 var ctor_factory
= m
.MakeGenericMethod (ec
.MemberContext
, type
);
7740 ec
.Emit (OpCodes
.Call
, ctor_factory
);
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)
7748 // If we are dealing with a ValueType, we have a few
7749 // situations to deal with:
7751 // * The target is a ValueType, and we have been provided
7752 // the instance (this is easy, we are being assigned).
7754 // * The target of New is being passed as an argument,
7755 // to a boxing operation or a function that takes a
7758 // In this case, we need to create a temporary variable
7759 // that is the argument of New.
7761 // Returns whether a value is left on the stack
7763 // *** Implementation note ***
7765 // To benefit from this optimization, each assignable expression
7766 // has to manually cast to New and call this Emit.
7768 // TODO: It's worth to implement it for arrays and fields
7770 public virtual bool Emit (EmitContext ec
, IMemoryLocation target
)
7772 bool is_value_type
= type
.IsStructOrEnum
;
7773 VariableReference vr
= target
as VariableReference
;
7775 bool prepare_await
= ec
.HasSet (BuilderContext
.Options
.AsyncBody
) && arguments
?.ContainsEmitWithAwait () == true;
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;
7783 target
.AddressOf (ec
, AddressOp
.Store
);
7784 } else if (vr
!= null && vr
.IsRef
) {
7788 if (arguments
!= null) {
7790 arguments
= arguments
.Emit (ec
, false, true);
7792 arguments
.Emit (ec
);
7795 if (is_value_type
) {
7796 if (method
== null) {
7797 ec
.Emit (OpCodes
.Initobj
, type
);
7802 ec
.MarkCallEntry (loc
);
7803 ec
.Emit (OpCodes
.Call
, method
);
7808 if (type
is TypeParameterSpec
) {
7809 DoEmitTypeParameter (ec
);
7813 ec
.MarkCallEntry (loc
);
7814 ec
.Emit (OpCodes
.Newobj
, method
);
7818 public override void Emit (EmitContext ec
)
7820 LocalTemporary v
= null;
7821 if (method
== null && type
.IsStructOrEnum
) {
7822 // TODO: Use temporary variable from pool
7823 v
= new LocalTemporary (type
);
7830 public override void EmitStatement (EmitContext ec
)
7832 LocalTemporary v
= null;
7833 if (method
== null && TypeSpec
.IsValueType (type
)) {
7834 // TODO: Use temporary variable from pool
7835 v
= new LocalTemporary (type
);
7839 ec
.Emit (OpCodes
.Pop
);
7842 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec
)
7847 public override void FlowAnalysis (FlowAnalysisContext fc
)
7849 if (arguments
!= null)
7850 arguments
.FlowAnalysis (fc
);
7853 public void AddressOf (EmitContext ec
, AddressOp mode
)
7855 EmitAddressOf (ec
, mode
);
7858 protected virtual IMemoryLocation
EmitAddressOf (EmitContext ec
, AddressOp mode
)
7860 LocalTemporary value_target
= new LocalTemporary (type
);
7862 if (type
is TypeParameterSpec
) {
7863 DoEmitTypeParameter (ec
);
7864 value_target
.Store (ec
);
7865 value_target
.AddressOf (ec
, mode
);
7866 return value_target
;
7869 value_target
.AddressOf (ec
, AddressOp
.Store
);
7871 if (method
== null) {
7872 ec
.Emit (OpCodes
.Initobj
, type
);
7874 if (arguments
!= null)
7875 arguments
.Emit (ec
);
7877 ec
.Emit (OpCodes
.Call
, method
);
7880 value_target
.AddressOf (ec
, mode
);
7881 return value_target
;
7884 protected override void CloneTo (CloneContext clonectx
, Expression t
)
7886 New target
= (New
) t
;
7888 target
.RequestedType
= RequestedType
.Clone (clonectx
);
7889 if (arguments
!= null){
7890 target
.arguments
= arguments
.Clone (clonectx
);
7894 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
7897 return base.MakeExpression (ctx
);
7899 return SLE
.Expression
.New ((ConstructorInfo
) method
.GetMetaInfo (), Arguments
.MakeExpression (arguments
, ctx
));
7903 public override object Accept (StructuralVisitor visitor
)
7905 return visitor
.Visit (this);
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)
7915 public class ArrayInitializer
: Expression
7917 List
<Expression
> elements
;
7918 BlockVariable variable
;
7920 public ArrayInitializer (List
<Expression
> init
, Location loc
)
7926 public ArrayInitializer (int count
, Location loc
)
7927 : this (new List
<Expression
> (count
), loc
)
7931 public ArrayInitializer (Location loc
)
7939 get { return elements.Count; }
7942 public List
<Expression
> Elements
{
7948 public Expression
this [int index
] {
7950 return elements
[index
];
7954 public BlockVariable VariableDeclaration
{
7965 public void Add (Expression expr
)
7967 elements
.Add (expr
);
7970 public override bool ContainsEmitWithAwait ()
7972 throw new NotSupportedException ();
7975 public override Expression
CreateExpressionTree (ResolveContext ec
)
7977 throw new NotSupportedException ("ET");
7980 protected override void CloneTo (CloneContext clonectx
, Expression t
)
7982 var target
= (ArrayInitializer
) t
;
7984 target
.elements
= new List
<Expression
> (elements
.Count
);
7985 foreach (var element
in elements
)
7986 target
.elements
.Add (element
.Clone (clonectx
));
7989 protected override Expression
DoResolve (ResolveContext rc
)
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
;
8001 type
= new TypeExpression (variable
.Variable
.Type
, variable
.Variable
.Location
);
8003 throw new NotImplementedException ("Unexpected array initializer context");
8006 return new ArrayCreation (type
, this).Resolve (rc
);
8009 public override void Emit (EmitContext ec
)
8011 throw new InternalErrorException ("Missing Resolve call");
8014 public override void FlowAnalysis (FlowAnalysisContext fc
)
8016 throw new InternalErrorException ("Missing Resolve call");
8019 public override object Accept (StructuralVisitor visitor
)
8021 return visitor
.Visit (this);
8026 /// 14.5.10.2: Represents an array creation expression.
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.
8035 public class ArrayCreation
: Expression
8037 FullNamedExpression requested_base_type
;
8038 ArrayInitializer initializers
;
8041 // The list of Argument types.
8042 // This is used to construct the `newarray' or constructor signature
8044 protected List
<Expression
> arguments
;
8046 protected TypeSpec array_element_type
;
8048 protected int dimensions
;
8049 protected readonly ComposedTypeSpecifier rank
;
8050 Expression first_emit
;
8051 LocalTemporary first_emit_temp
;
8053 protected List
<Expression
> array_data
;
8055 Dictionary
<int, int> bounds
;
8058 // The number of constants in array initializers
8059 int const_initializers_count
;
8060 bool only_constant_initializers
;
8062 public ArrayCreation (FullNamedExpression requested_base_type
, List
<Expression
> exprs
, ComposedTypeSpecifier rank
, ArrayInitializer initializers
, Location l
)
8063 : this (requested_base_type
, rank
, initializers
, l
)
8065 arguments
= new List
<Expression
> (exprs
);
8066 num_arguments
= arguments
.Count
;
8070 // For expressions like int[] foo = new int[] { 1, 2, 3 };
8072 public ArrayCreation (FullNamedExpression requested_base_type
, ComposedTypeSpecifier rank
, ArrayInitializer initializers
, Location loc
)
8074 this.requested_base_type
= requested_base_type
;
8076 this.initializers
= initializers
;
8080 num_arguments
= rank
.Dimension
;
8084 // For compiler generated single dimensional arrays only
8086 public ArrayCreation (FullNamedExpression requested_base_type
, ArrayInitializer initializers
, Location loc
)
8087 : this (requested_base_type
, ComposedTypeSpecifier
.SingleDimension
, initializers
, loc
)
8092 // For expressions like int[] foo = { 1, 2, 3 };
8094 public ArrayCreation (FullNamedExpression requested_base_type
, ArrayInitializer initializers
)
8095 : this (requested_base_type
, null, initializers
, initializers
.Location
)
8099 public bool NoEmptyInterpolation { get; set; }
8101 public ComposedTypeSpecifier Rank
{
8107 public FullNamedExpression TypeExpression
{
8109 return this.requested_base_type
;
8113 public ArrayInitializer Initializers
{
8115 return this.initializers
;
8119 bool CheckIndices (ResolveContext ec
, ArrayInitializer probe
, int idx
, bool specified_dims
, int child_bounds
)
8121 if (initializers
!= null && bounds
== null) {
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
8126 array_data
= new List
<Expression
> (probe
.Count
);
8127 bounds
= new Dictionary
<int, int> ();
8130 if (specified_dims
) {
8131 Expression a
= arguments
[idx
];
8136 a
= ConvertExpressionToArrayIndex (ec
, a
);
8142 if (initializers
!= null) {
8143 Constant c
= a
as Constant
;
8144 if (c
== null && a
is ArrayIndexCast
)
8145 c
= ((ArrayIndexCast
) a
).Child
as Constant
;
8148 ec
.Report
.Error (150, a
.Location
, "A constant value is expected");
8154 value = System
.Convert
.ToInt32 (c
.GetValue ());
8156 ec
.Report
.Error (150, a
.Location
, "A constant value is expected");
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 ());
8166 bounds
[idx
] = value;
8170 if (initializers
== null)
8173 for (int i
= 0; i
< probe
.Count
; ++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");
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
;
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());
8191 bool ret
= CheckIndices (ec
, sub_probe
, idx
+ 1, specified_dims
, child_bounds
- 1);
8194 } else if (child_bounds
> 1) {
8195 ec
.Report
.Error (846, o
.Location
, "A nested array initializer was expected");
8197 Expression element
= ResolveArrayElement (ec
, o
);
8198 if (element
== null)
8201 // Initializers with the default values can be ignored
8202 Constant c
= element
as Constant
;
8204 if (!c
.IsDefaultInitializer (array_element_type
)) {
8205 ++const_initializers_count
;
8208 only_constant_initializers
= false;
8211 array_data
.Add (element
);
8218 public override bool ContainsEmitWithAwait ()
8220 foreach (var arg
in arguments
) {
8221 if (arg
.ContainsEmitWithAwait ())
8225 return InitializersContainAwait ();
8228 public override Expression
CreateExpressionTree (ResolveContext ec
)
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
)));
8238 return CreateExpressionFactoryCall (ec
, "NewArrayBounds", args
);
8241 if (dimensions
> 1) {
8242 ec
.Report
.Error (838, loc
, "An expression tree cannot contain a multidimensional array initializer");
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
)));
8255 return CreateExpressionFactoryCall (ec
, "NewArrayInit", args
);
8258 void UpdateIndices (ResolveContext rc
)
8261 for (var probe
= initializers
; probe
!= null;) {
8262 Expression e
= new IntConstant (rc
.BuiltinTypes
, probe
.Count
, Location
.Null
);
8264 bounds
[i
++] = probe
.Count
;
8266 if (probe
.Count
> 0 && probe
[0] is ArrayInitializer
) {
8267 probe
= (ArrayInitializer
) probe
[0];
8268 } else if (dimensions
> i
) {
8276 protected override void Error_NegativeArrayIndex (ResolveContext ec
, Location loc
)
8278 ec
.Report
.Error (248, loc
, "Cannot create an array with a negative size");
8281 public override void FlowAnalysis (FlowAnalysisContext fc
)
8283 foreach (var arg
in arguments
)
8284 arg
.FlowAnalysis (fc
);
8286 if (array_data
!= null) {
8287 foreach (var ad
in array_data
)
8288 ad
.FlowAnalysis (fc
);
8292 bool InitializersContainAwait ()
8294 if (array_data
== null)
8297 foreach (var expr
in array_data
) {
8298 if (expr
.ContainsEmitWithAwait ())
8305 protected virtual Expression
ResolveArrayElement (ResolveContext ec
, Expression element
)
8307 element
= element
.Resolve (ec
);
8308 if (element
== null)
8311 var te
= element
as CompoundAssign
.TargetExpression
;
8313 for (int i
= 1; i
< initializers
.Count
; ++i
) {
8314 if (initializers
[i
].ContainsEmitWithAwait ()) {
8315 te
.RequiresEmitWithAwait
= true;
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
);
8328 return Convert
.ImplicitConversionRequired (
8329 ec
, element
, array_element_type
, loc
);
8332 protected bool ResolveInitializers (ResolveContext ec
)
8335 only_constant_initializers
= true;
8338 if (arguments
!= null) {
8340 for (int i
= 0; i
< arguments
.Count
; ++i
) {
8341 res
&= CheckIndices (ec
, initializers
, i
, true, dimensions
);
8342 if (initializers
!= null)
8349 arguments
= new List
<Expression
> ();
8351 if (!CheckIndices (ec
, initializers
, 0, false, dimensions
))
8360 // Resolved the type of the array
8362 bool ResolveArrayType (ResolveContext ec
)
8367 FullNamedExpression array_type_expr
;
8368 if (num_arguments
> 0) {
8369 array_type_expr
= new ComposedCast (requested_base_type
, rank
);
8371 array_type_expr
= requested_base_type
;
8374 type
= array_type_expr
.ResolveAsType (ec
);
8375 if (array_type_expr
== null)
8378 var ac
= type
as ArrayContainer
;
8380 ec
.Report
.Error (622, loc
, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8384 array_element_type
= ac
.Element
;
8385 dimensions
= ac
.Rank
;
8390 protected override Expression
DoResolve (ResolveContext ec
)
8395 if (!ResolveArrayType (ec
))
8399 // validate the initializers and fill in any missing bits
8401 if (!ResolveInitializers (ec
))
8404 eclass
= ExprClass
.Value
;
8408 byte [] MakeByteBlob ()
8413 int count
= array_data
.Count
;
8415 TypeSpec element_type
= array_element_type
;
8416 if (element_type
.IsEnum
)
8417 element_type
= EnumSpec
.GetUnderlyingType (element_type
);
8419 factor
= BuiltinTypeSpec
.GetSize (element_type
);
8421 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type
);
8423 data
= new byte [(count
* factor
+ 3) & ~
3];
8426 for (int i
= 0; i
< count
; ++i
) {
8427 var c
= array_data
[i
] as Constant
;
8433 object v
= c
.GetValue ();
8435 switch (element_type
.BuiltinType
) {
8436 case BuiltinTypeSpec
.Type
.Long
:
8437 long lval
= (long) v
;
8439 for (int j
= 0; j
< factor
; ++j
) {
8440 data
[idx
+ j
] = (byte) (lval
& 0xFF);
8444 case BuiltinTypeSpec
.Type
.ULong
:
8445 ulong ulval
= (ulong) v
;
8447 for (int j
= 0; j
< factor
; ++j
) {
8448 data
[idx
+ j
] = (byte) (ulval
& 0xFF);
8449 ulval
= (ulval
>> 8);
8452 case BuiltinTypeSpec
.Type
.Float
:
8453 var fval
= SingleConverter
.SingleToInt32Bits((float) v
);
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);
8460 case BuiltinTypeSpec
.Type
.Double
:
8461 element
= BitConverter
.GetBytes ((double) v
);
8463 for (int j
= 0; j
< factor
; ++j
)
8464 data
[idx
+ j
] = element
[j
];
8466 // FIXME: Handle the ARM float format.
8467 if (!BitConverter
.IsLittleEndian
)
8468 System
.Array
.Reverse (data
, idx
, 8);
8470 case BuiltinTypeSpec
.Type
.Char
:
8471 int chval
= (int) ((char) v
);
8473 data
[idx
] = (byte) (chval
& 0xff);
8474 data
[idx
+ 1] = (byte) (chval
>> 8);
8476 case BuiltinTypeSpec
.Type
.Short
:
8477 int sval
= (int) ((short) v
);
8479 data
[idx
] = (byte) (sval
& 0xff);
8480 data
[idx
+ 1] = (byte) (sval
>> 8);
8482 case BuiltinTypeSpec
.Type
.UShort
:
8483 int usval
= (int) ((ushort) v
);
8485 data
[idx
] = (byte) (usval
& 0xff);
8486 data
[idx
+ 1] = (byte) (usval
>> 8);
8488 case BuiltinTypeSpec
.Type
.Int
:
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);
8496 case BuiltinTypeSpec
.Type
.UInt
:
8497 uint uval
= (uint) v
;
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);
8504 case BuiltinTypeSpec
.Type
.SByte
:
8505 data
[idx
] = (byte) (sbyte) v
;
8507 case BuiltinTypeSpec
.Type
.Byte
:
8508 data
[idx
] = (byte) v
;
8510 case BuiltinTypeSpec
.Type
.Bool
:
8511 data
[idx
] = (byte) ((bool) v
? 1 : 0);
8513 case BuiltinTypeSpec
.Type
.Decimal
:
8514 int[] bits
= Decimal
.GetBits ((decimal) v
);
8517 // FIXME: For some reason, this doesn't work on the MS runtime.
8518 int[] nbits
= new int[4];
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);
8532 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type
);
8541 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
8544 return base.MakeExpression (ctx
);
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 ());
8551 initializers
[i
] = array_data
[i
].MakeExpression (ctx
);
8554 return SLE
.Expression
.NewArrayInit (array_element_type
.GetMetaInfo (), initializers
);
8559 // Emits the initializers for the array
8561 void EmitStaticInitializers (EmitContext ec
, FieldExpr stackArray
)
8563 var m
= ec
.Module
.PredefinedMembers
.RuntimeHelpersInitializeArray
.Resolve (loc
);
8568 // First, the static data
8570 byte [] data
= MakeByteBlob ();
8571 var fb
= ec
.CurrentTypeDefinition
.Module
.MakeStaticData (data
, loc
);
8573 if (stackArray
== null) {
8574 ec
.Emit (OpCodes
.Dup
);
8576 stackArray
.Emit (ec
);
8579 ec
.Emit (OpCodes
.Ldtoken
, fb
);
8580 ec
.Emit (OpCodes
.Call
, m
);
8585 // Emits pieces of the array that can not be computed at compile
8586 // time (variables and string locations).
8588 // This always expect the top value on the stack to be the array
8590 void EmitDynamicInitializers (EmitContext ec
, bool emitConstants
, StackFieldExpr stackArray
)
8592 int dims
= bounds
.Count
;
8593 var current_pos
= new int [dims
];
8595 for (int i
= 0; i
< array_data
.Count
; i
++){
8597 Expression e
= array_data
[i
];
8598 var c
= e
as Constant
;
8600 // Constant can be initialized via StaticInitializer
8601 if (c
== null || (c
!= null && emitConstants
&& !c
.IsDefaultInitializer (array_element_type
))) {
8605 if (stackArray
!= null) {
8606 if (e
.ContainsEmitWithAwait ()) {
8607 e
= e
.EmitToField (ec
);
8610 stackArray
.EmitLoad (ec
);
8612 ec
.Emit (OpCodes
.Dup
);
8615 for (int idx
= 0; idx
< dims
; idx
++)
8616 ec
.EmitInt (current_pos
[idx
]);
8619 // If we are dealing with a struct, get the
8620 // address of it, so we can store it.
8622 if (dims
== 1 && etype
.IsStruct
&& !BuiltinTypeSpec
.IsPrimitiveType (etype
))
8623 ec
.Emit (OpCodes
.Ldelema
, etype
);
8627 ec
.EmitArrayStore ((ArrayContainer
) type
);
8633 for (int j
= dims
- 1; j
>= 0; j
--){
8635 if (current_pos
[j
] < bounds
[j
])
8637 current_pos
[j
] = 0;
8641 if (stackArray
!= null)
8642 stackArray
.PrepareCleanup (ec
);
8645 public override void Emit (EmitContext ec
)
8647 if (!NoEmptyInterpolation
&& EmitOptimizedEmpty (ec
))
8650 var await_field
= EmitToFieldSource (ec
);
8651 if (await_field
!= null)
8652 await_field
.Emit (ec
);
8655 bool EmitOptimizedEmpty (EmitContext ec
)
8657 if (arguments
.Count
!= 1 || dimensions
!= 1)
8660 var c
= arguments
[0] as Constant
;
8661 if (c
== null || !c
.IsZeroInteger
)
8664 var m
= ec
.Module
.PredefinedMembers
.ArrayEmpty
.Get ();
8665 if (m
== null || ec
.CurrentType
.MemberDefinition
.DeclaringAssembly
== m
.DeclaringType
.MemberDefinition
.DeclaringAssembly
)
8668 m
= m
.MakeGenericMethod (ec
.MemberContext
, array_element_type
);
8669 ec
.Emit (OpCodes
.Call
, m
);
8673 protected sealed override FieldExpr
EmitToFieldSource (EmitContext ec
)
8675 if (first_emit
!= null) {
8676 first_emit
.Emit (ec
);
8677 first_emit_temp
.Store (ec
);
8680 StackFieldExpr await_stack_field
;
8681 if (ec
.HasSet (BuilderContext
.Options
.AsyncBody
) && InitializersContainAwait ()) {
8682 await_stack_field
= ec
.GetTemporaryField (type
);
8685 await_stack_field
= null;
8688 EmitExpressionsList (ec
, arguments
);
8690 ec
.EmitArrayNew ((ArrayContainer
) type
);
8692 if (initializers
== null)
8693 return await_stack_field
;
8695 if (await_stack_field
!= null)
8696 await_stack_field
.EmitAssignFromStack (ec
);
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
8704 // NOTE: const_initializers_count does not contain default constant values.
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
);
8710 if (!only_constant_initializers
)
8711 EmitDynamicInitializers (ec
, false, await_stack_field
);
8715 EmitDynamicInitializers (ec
, true, await_stack_field
);
8718 if (first_emit_temp
!= null)
8719 first_emit_temp
.Release (ec
);
8721 return await_stack_field
;
8724 public override void EncodeAttributeValue (IMemberContext rc
, AttributeEncoder enc
, TypeSpec targetType
, TypeSpec parameterType
)
8726 // no multi dimensional or jagged arrays
8727 if (arguments
.Count
!= 1 || array_element_type
.IsArray
) {
8728 base.EncodeAttributeValue (rc
, enc
, targetType
, parameterType
);
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
);
8739 if (enc
.Encode (type
) == AttributeEncoder
.EncodedTypeProperties
.DynamicType
) {
8740 Attribute
.Error_AttributeArgumentIsDynamic (rc
, loc
);
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
);
8757 enc
.Encode (array_data
.Count
);
8758 foreach (var element
in array_data
) {
8759 element
.EncodeAttributeValue (rc
, enc
, array_element_type
, parameterType
);
8763 protected override void CloneTo (CloneContext clonectx
, Expression t
)
8765 ArrayCreation target
= (ArrayCreation
) t
;
8767 if (requested_base_type
!= null)
8768 target
.requested_base_type
= (FullNamedExpression
)requested_base_type
.Clone (clonectx
);
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
));
8776 if (initializers
!= null)
8777 target
.initializers
= (ArrayInitializer
) initializers
.Clone (clonectx
);
8780 public override object Accept (StructuralVisitor visitor
)
8782 return visitor
.Visit (this);
8787 // Represents an implicitly typed array epxression
8789 class ImplicitlyTypedArrayCreation
: ArrayCreation
8791 TypeInferenceContext best_type_inference
;
8793 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank
, ArrayInitializer initializers
, Location loc
)
8794 : base (null, rank
, initializers
, loc
)
8798 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers
, Location loc
)
8799 : base (null, initializers
, loc
)
8803 protected override Expression
DoResolve (ResolveContext ec
)
8808 dimensions
= rank
.Dimension
;
8810 best_type_inference
= new TypeInferenceContext ();
8812 if (!ResolveInitializers (ec
))
8815 best_type_inference
.FixAllTypes (ec
);
8816 array_element_type
= best_type_inference
.InferredTypeArguments
[0];
8817 best_type_inference
= null;
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");
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
8830 UnifyInitializerElement (ec
);
8832 type
= ArrayContainer
.MakeType (ec
.Module
, array_element_type
, dimensions
);
8833 eclass
= ExprClass
.Value
;
8838 // Converts static initializer only
8840 void UnifyInitializerElement (ResolveContext ec
)
8842 for (int i
= 0; i
< array_data
.Count
; ++i
) {
8843 Expression e
= array_data
[i
];
8845 array_data
[i
] = Convert
.ImplicitConversion (ec
, e
, array_element_type
, Location
.Null
);
8849 protected override Expression
ResolveArrayElement (ResolveContext ec
, Expression element
)
8851 element
= element
.Resolve (ec
);
8852 if (element
!= null)
8853 best_type_inference
.AddCommonTypeBound (element
.Type
);
8859 sealed class CompilerGeneratedThis
: This
8861 public CompilerGeneratedThis (TypeSpec type
, Location loc
)
8867 protected override Expression
DoResolve (ResolveContext rc
)
8869 eclass
= ExprClass
.Variable
;
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
;
8882 public override Expression
DoResolveLValue (ResolveContext rc
, Expression right_side
)
8884 return DoResolve (rc
);
8887 public override HoistedVariable
GetHoistedVariable (AnonymousExpression ae
)
8894 /// Represents the `this' construct
8897 public class This
: VariableReference
8899 sealed class ThisVariable
: ILocalVariable
8901 public static readonly ILocalVariable Instance
= new ThisVariable ();
8903 public void Emit (EmitContext ec
)
8908 public void EmitAssign (EmitContext ec
)
8910 throw new InvalidOperationException ();
8913 public void EmitAddressOf (EmitContext ec
)
8919 protected VariableInfo variable_info
;
8921 public This (Location loc
)
8928 public override string Name
{
8929 get { return "this"; }
8932 public override bool IsLockedByStatement
{
8940 public override bool IsRef
{
8941 get { return type.IsStruct; }
8944 public override bool IsSideEffectFree
{
8950 protected override ILocalVariable Variable
{
8951 get { return ThisVariable.Instance; }
8954 public override VariableInfo VariableInfo
{
8955 get { return variable_info; }
8958 public override bool IsFixed
{
8959 get { return false; }
8964 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc
)
8967 // It's null for all cases when we don't need to check `this'
8968 // definitive assignment
8970 if (variable_info
== null)
8973 if (fc
.IsDefinitelyAssigned (variable_info
))
8976 fc
.Report
.Error (188, loc
, "The `this' object cannot be used before all of its fields are assigned to");
8979 protected virtual void Error_ThisNotAvailable (ResolveContext ec
)
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");
8988 ec
.Report
.Error (27, loc
, "Keyword `this' is not available in the current context");
8992 public override void FlowAnalysis (FlowAnalysisContext fc
)
8994 CheckStructThisDefiniteAssignment (fc
);
8997 public override HoistedVariable
GetHoistedVariable (AnonymousExpression ae
)
9002 AnonymousMethodStorey storey
= ae
.Storey
;
9003 return storey
!= null ? storey
.HoistedThis
: null;
9006 public static bool IsThisAvailable (ResolveContext ec
, bool ignoreAnonymous
)
9008 if (ec
.IsStatic
|| ec
.HasAny (ResolveContext
.Options
.FieldInitializerScope
| ResolveContext
.Options
.BaseInitializer
| ResolveContext
.Options
.ConstantScope
))
9011 if (ignoreAnonymous
|| ec
.CurrentAnonymousMethod
== null)
9014 if (ec
.CurrentType
.IsStruct
&& !(ec
.CurrentAnonymousMethod
is StateMachineInitializer
))
9020 public virtual void ResolveBase (ResolveContext ec
)
9022 eclass
= ExprClass
.Variable
;
9023 type
= ec
.CurrentType
;
9025 if (!IsThisAvailable (ec
, false)) {
9026 Error_ThisNotAvailable (ec
);
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
;
9036 AnonymousExpression am
= ec
.CurrentAnonymousMethod
;
9037 if (am
!= null && ec
.IsVariableCapturingRequired
&& !block
.Explicit
.HasCapturedThis
) {
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
9045 top
.AddThisReferenceFromChildrenBlock (block
.Explicit
);
9046 am
.SetHasThisAccess ();
9051 protected override Expression
DoResolve (ResolveContext ec
)
9057 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
9059 if (eclass
== ExprClass
.Unresolved
)
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");
9068 ec
.Report
.Error (1604, loc
, "Cannot assign to `this' because it is read-only");
9074 public override int GetHashCode()
9076 throw new NotImplementedException ();
9079 public override bool Equals (object obj
)
9081 This t
= obj
as This
;
9088 protected override void CloneTo (CloneContext clonectx
, Expression t
)
9093 public override void SetHasAddressTaken ()
9098 public override object Accept (StructuralVisitor visitor
)
9100 return visitor
.Visit (this);
9105 /// Represents the `__arglist' construct
9107 public class ArglistAccess
: Expression
9109 public ArglistAccess (Location loc
)
9114 protected override void CloneTo (CloneContext clonectx
, Expression target
)
9119 public override bool ContainsEmitWithAwait ()
9124 public override Expression
CreateExpressionTree (ResolveContext ec
)
9126 throw new NotSupportedException ("ET");
9129 protected override Expression
DoResolve (ResolveContext ec
)
9131 eclass
= ExprClass
.Variable
;
9132 type
= ec
.Module
.PredefinedTypes
.RuntimeArgumentHandle
.Resolve ();
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");
9142 public override void Emit (EmitContext ec
)
9144 ec
.Emit (OpCodes
.Arglist
);
9147 public override object Accept (StructuralVisitor visitor
)
9149 return visitor
.Visit (this);
9154 /// Represents the `__arglist (....)' construct
9156 public class Arglist
: Expression
9158 Arguments arguments
;
9160 public Arglist (Location loc
)
9165 public Arglist (Arguments args
, Location l
)
9171 public Arguments Arguments
{
9177 public MetaType
[] ArgumentTypes
{
9179 if (arguments
== null)
9180 return MetaType
.EmptyTypes
;
9182 var retval
= new MetaType
[arguments
.Count
];
9183 for (int i
= 0; i
< retval
.Length
; i
++)
9184 retval
[i
] = arguments
[i
].Expr
.Type
.GetMetaInfo ();
9190 public override bool ContainsEmitWithAwait ()
9192 throw new NotImplementedException ();
9195 public override Expression
CreateExpressionTree (ResolveContext ec
)
9197 ec
.Report
.Error (1952, loc
, "An expression tree cannot contain a method with variable arguments");
9201 protected override Expression
DoResolve (ResolveContext ec
)
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);
9213 public override void Emit (EmitContext ec
)
9215 if (arguments
!= null)
9216 arguments
.Emit (ec
);
9219 protected override void CloneTo (CloneContext clonectx
, Expression t
)
9221 Arglist target
= (Arglist
) t
;
9223 if (arguments
!= null)
9224 target
.arguments
= arguments
.Clone (clonectx
);
9227 public override object Accept (StructuralVisitor visitor
)
9229 return visitor
.Visit (this);
9233 public class RefValueExpr
: ShimExpression
, IAssignMethod
, IMemoryLocation
9235 FullNamedExpression texpr
;
9237 public RefValueExpr (Expression expr
, FullNamedExpression texpr
, Location loc
)
9244 public FullNamedExpression TypeExpression
{
9250 public override bool ContainsEmitWithAwait ()
9255 public void AddressOf (EmitContext ec
, AddressOp mode
)
9258 ec
.Emit (OpCodes
.Refanyval
, type
);
9261 protected override Expression
DoResolve (ResolveContext rc
)
9263 expr
= expr
.Resolve (rc
);
9264 type
= texpr
.ResolveAsType (rc
);
9265 if (expr
== null || type
== null)
9268 expr
= Convert
.ImplicitConversionRequired (rc
, expr
, rc
.Module
.PredefinedTypes
.TypedReference
.Resolve (), loc
);
9269 eclass
= ExprClass
.Variable
;
9273 public override Expression
DoResolveLValue (ResolveContext rc
, Expression right_side
)
9275 return DoResolve (rc
);
9278 public override void Emit (EmitContext ec
)
9281 ec
.Emit (OpCodes
.Refanyval
, type
);
9282 ec
.EmitLoadFromPtr (type
);
9285 public void Emit (EmitContext ec
, bool leave_copy
)
9287 throw new NotImplementedException ();
9290 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool isCompound
)
9293 ec
.Emit (OpCodes
.Refanyval
, type
);
9296 LocalTemporary temporary
= null;
9298 ec
.Emit (OpCodes
.Dup
);
9299 temporary
= new LocalTemporary (source
.Type
);
9300 temporary
.Store (ec
);
9303 ec
.EmitStoreFromPtr (type
);
9305 if (temporary
!= null) {
9306 temporary
.Emit (ec
);
9307 temporary
.Release (ec
);
9311 public override object Accept (StructuralVisitor visitor
)
9313 return visitor
.Visit (this);
9317 public class RefTypeExpr
: ShimExpression
9319 public RefTypeExpr (Expression expr
, Location loc
)
9325 protected override Expression
DoResolve (ResolveContext rc
)
9327 expr
= expr
.Resolve (rc
);
9331 expr
= Convert
.ImplicitConversionRequired (rc
, expr
, rc
.Module
.PredefinedTypes
.TypedReference
.Resolve (), loc
);
9335 type
= rc
.BuiltinTypes
.Type
;
9336 eclass
= ExprClass
.Value
;
9340 public override void Emit (EmitContext ec
)
9343 ec
.Emit (OpCodes
.Refanytype
);
9344 var m
= ec
.Module
.PredefinedMembers
.TypeGetTypeFromHandle
.Resolve (loc
);
9346 ec
.Emit (OpCodes
.Call
, m
);
9349 public override object Accept (StructuralVisitor visitor
)
9351 return visitor
.Visit (this);
9355 public class MakeRefExpr
: ShimExpression
9357 public MakeRefExpr (Expression expr
, Location loc
)
9363 public override bool ContainsEmitWithAwait ()
9365 throw new NotImplementedException ();
9368 protected override Expression
DoResolve (ResolveContext rc
)
9370 expr
= expr
.ResolveLValue (rc
, EmptyExpression
.LValueMemberAccess
);
9371 type
= rc
.Module
.PredefinedTypes
.TypedReference
.Resolve ();
9372 eclass
= ExprClass
.Value
;
9376 public override void Emit (EmitContext ec
)
9378 ((IMemoryLocation
) expr
).AddressOf (ec
, AddressOp
.Load
);
9379 ec
.Emit (OpCodes
.Mkrefany
, expr
.Type
);
9382 public override object Accept (StructuralVisitor visitor
)
9384 return visitor
.Visit (this);
9389 /// Implements the typeof operator
9391 public class TypeOf
: Expression
{
9392 FullNamedExpression QueriedType
;
9395 public TypeOf (FullNamedExpression queried_type
, Location l
)
9397 QueriedType
= queried_type
;
9402 // Use this constructor for any compiler generated typeof expression
9404 public TypeOf (TypeSpec type
, Location loc
)
9406 this.typearg
= type
;
9412 public override bool IsSideEffectFree
{
9418 public TypeSpec TypeArgument
{
9424 public FullNamedExpression TypeExpression
{
9433 protected override void CloneTo (CloneContext clonectx
, Expression t
)
9435 TypeOf target
= (TypeOf
) t
;
9436 if (QueriedType
!= null)
9437 target
.QueriedType
= (FullNamedExpression
) QueriedType
.Clone (clonectx
);
9440 public override bool ContainsEmitWithAwait ()
9445 public override Expression
CreateExpressionTree (ResolveContext ec
)
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
);
9453 protected override Expression
DoResolve (ResolveContext ec
)
9455 if (eclass
!= ExprClass
.Unresolved
)
9458 if (typearg
== null) {
9460 // Pointer types are allowed without explicit unsafe, they are just tokens
9462 using (ec
.Set (ResolveContext
.Options
.UnsafeScope
)) {
9463 typearg
= QueriedType
.ResolveAsType (ec
, true);
9466 if (typearg
== null)
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");
9475 type
= ec
.BuiltinTypes
.Type
;
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
;
9483 static bool ContainsDynamicType (TypeSpec type
)
9485 if (type
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
)
9488 var element_container
= type
as ElementTypeSpec
;
9489 if (element_container
!= null)
9490 return ContainsDynamicType (element_container
.Element
);
9492 foreach (var t
in type
.TypeArguments
) {
9493 if (ContainsDynamicType (t
)) {
9501 public override void EncodeAttributeValue (IMemberContext rc
, AttributeEncoder enc
, TypeSpec targetType
, TypeSpec parameterType
)
9503 // Target type is not System.Type therefore must be object
9504 // and we need to use different encoding sequence
9505 if (targetType
!= type
)
9508 if (typearg
is InflatedTypeSpec
) {
9511 if (InflatedTypeSpec
.ContainsTypeParameter (gt
)) {
9512 rc
.Module
.Compiler
.Report
.Error (416, loc
, "`{0}': an attribute argument cannot use type parameters",
9513 typearg
.GetSignatureForError ());
9517 gt
= gt
.DeclaringType
;
9518 } while (gt
!= null);
9521 if (ContainsDynamicType (typearg
)) {
9522 Attribute
.Error_AttributeArgumentIsDynamic (rc
, loc
);
9526 enc
.EncodeTypeName (typearg
);
9529 public override void Emit (EmitContext ec
)
9531 ec
.Emit (OpCodes
.Ldtoken
, typearg
);
9532 var m
= ec
.Module
.PredefinedMembers
.TypeGetTypeFromHandle
.Resolve (loc
);
9534 ec
.Emit (OpCodes
.Call
, m
);
9537 public override object Accept (StructuralVisitor visitor
)
9539 return visitor
.Visit (this);
9543 sealed class TypeOfMethod
: TypeOfMember
<MethodSpec
>
9545 public TypeOfMethod (MethodSpec method
, Location loc
)
9546 : base (method
, loc
)
9550 protected override Expression
DoResolve (ResolveContext ec
)
9552 if (member
.IsConstructor
) {
9553 type
= ec
.Module
.PredefinedTypes
.ConstructorInfo
.Resolve ();
9555 type
= ec
.Module
.PredefinedTypes
.MethodInfo
.Resolve ();
9561 return base.DoResolve (ec
);
9564 public override void Emit (EmitContext ec
)
9566 ec
.Emit (OpCodes
.Ldtoken
, member
);
9569 ec
.Emit (OpCodes
.Castclass
, type
);
9572 protected override PredefinedMember
<MethodSpec
> GetTypeFromHandle (EmitContext ec
)
9574 return ec
.Module
.PredefinedMembers
.MethodInfoGetMethodFromHandle
;
9577 protected override PredefinedMember
<MethodSpec
> GetTypeFromHandleGeneric (EmitContext ec
)
9579 return ec
.Module
.PredefinedMembers
.MethodInfoGetMethodFromHandle2
;
9583 abstract class TypeOfMember
<T
> : Expression where T
: MemberSpec
9585 protected readonly T member
;
9587 protected TypeOfMember (T member
, Location loc
)
9589 this.member
= member
;
9593 public override bool IsSideEffectFree
{
9599 public override bool ContainsEmitWithAwait ()
9604 public override Expression
CreateExpressionTree (ResolveContext ec
)
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
);
9612 protected override Expression
DoResolve (ResolveContext ec
)
9614 eclass
= ExprClass
.Value
;
9618 public override void Emit (EmitContext ec
)
9620 bool is_generic
= member
.DeclaringType
.IsGenericOrParentIsGeneric
;
9621 PredefinedMember
<MethodSpec
> p
;
9623 p
= GetTypeFromHandleGeneric (ec
);
9624 ec
.Emit (OpCodes
.Ldtoken
, member
.DeclaringType
);
9626 p
= GetTypeFromHandle (ec
);
9629 var mi
= p
.Resolve (loc
);
9631 ec
.Emit (OpCodes
.Call
, mi
);
9634 protected abstract PredefinedMember
<MethodSpec
> GetTypeFromHandle (EmitContext ec
);
9635 protected abstract PredefinedMember
<MethodSpec
> GetTypeFromHandleGeneric (EmitContext ec
);
9638 sealed class TypeOfField
: TypeOfMember
<FieldSpec
>
9640 public TypeOfField (FieldSpec field
, Location loc
)
9645 protected override Expression
DoResolve (ResolveContext ec
)
9647 type
= ec
.Module
.PredefinedTypes
.FieldInfo
.Resolve ();
9651 return base.DoResolve (ec
);
9654 public override void Emit (EmitContext ec
)
9656 ec
.Emit (OpCodes
.Ldtoken
, member
);
9660 protected override PredefinedMember
<MethodSpec
> GetTypeFromHandle (EmitContext ec
)
9662 return ec
.Module
.PredefinedMembers
.FieldInfoGetFieldFromHandle
;
9665 protected override PredefinedMember
<MethodSpec
> GetTypeFromHandleGeneric (EmitContext ec
)
9667 return ec
.Module
.PredefinedMembers
.FieldInfoGetFieldFromHandle2
;
9672 /// Implements the sizeof expression
9674 public class SizeOf
: Expression
{
9675 readonly Expression texpr
;
9676 TypeSpec type_queried
;
9678 public SizeOf (Expression queried_type
, Location l
)
9680 this.texpr
= queried_type
;
9684 public override bool IsSideEffectFree
{
9690 public Expression TypeExpression
{
9696 public override bool ContainsEmitWithAwait ()
9701 public override Expression
CreateExpressionTree (ResolveContext ec
)
9703 Error_PointerInsideExpressionTree (ec
);
9707 protected override Expression
DoResolve (ResolveContext ec
)
9709 type_queried
= texpr
.ResolveAsType (ec
);
9710 if (type_queried
== null)
9713 if (type_queried
.IsEnum
)
9714 type_queried
= EnumSpec
.GetUnderlyingType (type_queried
);
9716 int size_of
= BuiltinTypeSpec
.GetSize (type_queried
);
9718 return new IntConstant (ec
.BuiltinTypes
, size_of
, loc
);
9721 if (!TypeManager
.VerifyUnmanaged (ec
.Module
, type_queried
, loc
)){
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 ());
9731 type
= ec
.BuiltinTypes
.Int
;
9732 eclass
= ExprClass
.Value
;
9736 public override void Emit (EmitContext ec
)
9738 ec
.Emit (OpCodes
.Sizeof
, type_queried
);
9741 protected override void CloneTo (CloneContext clonectx
, Expression t
)
9745 public override object Accept (StructuralVisitor visitor
)
9747 return visitor
.Visit (this);
9752 /// Implements the qualified-alias-member (::) expression.
9754 public class QualifiedAliasMember
: MemberAccess
9756 readonly string alias;
9757 public static readonly string GlobalAlias
= "global";
9759 public QualifiedAliasMember (string alias, string identifier
, Location l
)
9760 : base (null, identifier
, l
)
9765 public QualifiedAliasMember (string alias, string identifier
, TypeArguments targs
, Location l
)
9766 : base (null, identifier
, targs
, l
)
9771 public QualifiedAliasMember (string alias, string identifier
, int arity
, Location l
)
9772 : base (null, identifier
, arity
, l
)
9777 public string Alias
{
9783 public FullNamedExpression
CreateExpressionFromAlias (IMemberContext mc
)
9785 if (alias == GlobalAlias
)
9786 return new NamespaceExpression (mc
.Module
.GlobalRootNamespace
, loc
);
9788 int errors
= mc
.Module
.Compiler
.Report
.Errors
;
9789 var expr
= mc
.LookupNamespaceAlias (alias);
9791 if (errors
== mc
.Module
.Compiler
.Report
.Errors
)
9792 mc
.Module
.Compiler
.Report
.Error (432, loc
, "Alias `{0}' not found", alias);
9800 public override FullNamedExpression
ResolveAsTypeOrNamespace (IMemberContext mc
, bool allowUnboundTypeArguments
)
9802 expr
= CreateExpressionFromAlias (mc
);
9806 return base.ResolveAsTypeOrNamespace (mc
, allowUnboundTypeArguments
);
9809 protected override Expression
DoResolve (ResolveContext rc
)
9811 return ResolveAsTypeOrNamespace (rc
, false);
9814 public override string GetSignatureForError ()
9817 if (targs
!= null) {
9818 name
= Name
+ "<" + targs
.GetSignatureForError () + ">";
9821 return alias + "::" + name
;
9824 public override bool HasConditionalAccess ()
9829 public override Expression
LookupNameExpression (ResolveContext rc
, MemberLookupRestrictions restrictions
)
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 ());
9839 return DoResolve (rc
);
9842 protected override void CloneTo (CloneContext clonectx
, Expression t
)
9847 public override object Accept (StructuralVisitor visitor
)
9849 return visitor
.Visit (this);
9854 /// Implements the member access expression
9856 public class MemberAccess
: ATypeNameExpression
9858 protected Expression expr
;
9860 public MemberAccess (Expression expr
, string id
)
9861 : base (id
, expr
.Location
)
9866 public MemberAccess (Expression expr
, string identifier
, Location loc
)
9867 : base (identifier
, loc
)
9872 public MemberAccess (Expression expr
, string identifier
, TypeArguments args
, Location loc
)
9873 : base (identifier
, args
, loc
)
9878 public MemberAccess (Expression expr
, string identifier
, int arity
, Location loc
)
9879 : base (identifier
, arity
, loc
)
9884 public Expression LeftExpression
{
9890 public override Location StartLocation
{
9892 return expr
== null ? loc
: expr
.StartLocation
;
9896 protected override Expression
DoResolve (ResolveContext rc
)
9898 var e
= LookupNameExpression (rc
, MemberLookupRestrictions
.ReadAccess
| MemberLookupRestrictions
.DontSetConditionalAccess
);
9900 e
= e
.Resolve (rc
, ResolveFlags
.VariableOrValue
| ResolveFlags
.Type
| ResolveFlags
.MethodGroup
);
9905 public override Expression
DoResolveLValue (ResolveContext rc
, Expression rhs
)
9907 var e
= LookupNameExpression (rc
, MemberLookupRestrictions
.None
);
9909 if (e
is TypeExpr
) {
9910 e
.Error_UnexpectedKind (rc
, ResolveFlags
.VariableOrValue
, loc
);
9915 e
= e
.ResolveLValue (rc
, rhs
);
9920 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc
, TypeSpec type
)
9922 if (type
== InternalType
.NullLiteral
&& rc
.IsRuntimeBinder
)
9923 rc
.Report
.Error (Report
.RuntimeErrorId
, loc
, "Cannot perform member binding on `null' value");
9925 expr
.Error_OperatorCannotBeApplied (rc
, loc
, ".", type
);
9928 public override bool HasConditionalAccess ()
9930 return LeftExpression
.HasConditionalAccess ();
9933 public static bool IsValidDotExpression (TypeSpec type
)
9935 const MemberKind dot_kinds
= MemberKind
.Class
| MemberKind
.Struct
| MemberKind
.Delegate
| MemberKind
.Enum
|
9936 MemberKind
.Interface
| MemberKind
.TypeParameter
| MemberKind
.ArrayType
| MemberKind
.ByRef
;
9938 return (type
.Kind
& dot_kinds
) != 0 || type
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
;
9941 public override Expression
LookupNameExpression (ResolveContext rc
, MemberLookupRestrictions restrictions
)
9943 var sn
= expr
as SimpleName
;
9944 const ResolveFlags flags
= ResolveFlags
.VariableOrValue
| ResolveFlags
.Type
;
9947 expr
= sn
.LookupNameExpression (rc
, MemberLookupRestrictions
.ReadAccess
| MemberLookupRestrictions
.ExactArity
);
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
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
);
9961 if ((restrictions
& MemberLookupRestrictions
.DontSetConditionalAccess
) != 0) {
9962 using (rc
.Set (ResolveContext
.Options
.DontSetConditionalAccessReceiver
)) {
9963 expr
= expr
.Resolve (rc
, flags
);
9966 expr
= expr
.Resolve (rc
, flags
);
9973 var ns
= expr
as NamespaceExpression
;
9975 var retval
= ns
.LookupTypeOrNamespace (rc
, Name
, Arity
, LookupMode
.Normal
, loc
);
9977 if (retval
== null) {
9978 ns
.Error_NamespaceDoesNotExist (rc
, Name
, Arity
, loc
);
9983 if (HasTypeArguments
)
9984 return new GenericTypeExpr (retval
.Type
, targs
, loc
);
9986 targs
.Resolve (rc
, false);
9992 var cma
= this as ConditionalMemberAccess
;
9995 TypeSpec expr_type
= expr
.Type
;
9996 if (expr_type
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
) {
9997 me
= expr
as MemberExpr
;
9999 me
.ResolveInstanceExpression (rc
, null);
10001 Arguments args
= new Arguments (1);
10002 args
.Add (new Argument (expr
));
10005 return new DynamicConditionalMemberBinder (Name
, args
, loc
);
10007 return new DynamicMemberBinder (Name
, args
, loc
);
10011 if (!IsNullPropagatingValid (expr
.Type
)) {
10012 expr
.Error_OperatorCannotBeApplied (rc
, loc
, "?", expr
.Type
);
10016 if (expr_type
.IsNullableType
) {
10017 expr
= Nullable
.Unwrap
.Create (expr
.Resolve (rc
), true);
10018 expr_type
= expr
.Type
;
10022 if (!IsValidDotExpression (expr_type
)) {
10023 Error_OperatorCannotBeApplied (rc
, expr_type
);
10027 var lookup_arity
= Arity
;
10028 bool errorMode
= false;
10029 Expression member_lookup
;
10031 member_lookup
= MemberLookup (rc
, errorMode
, expr_type
, Name
, lookup_arity
, restrictions
, loc
);
10032 if (member_lookup
== null) {
10034 // Try to look for extension method when member lookup failed
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))
10044 emg
.SetTypeArguments (rc
, targs
);
10048 emg
.ConditionalAccess
= true;
10050 // TODO: it should really skip the checks bellow
10051 return emg
.Resolve (rc
);
10057 if (member_lookup
== null) {
10058 var dep
= expr_type
.GetMissingDependencies ();
10060 ImportedTypeDefinition
.Error_MissingDependency (rc
, dep
, loc
);
10061 } else if (expr
is TypeExpr
) {
10062 base.Error_TypeDoesNotContainDefinition (rc
, expr_type
, Name
);
10064 Error_TypeDoesNotContainDefinition (rc
, expr_type
, Name
);
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
);
10079 if (member_lookup
!= null)
10083 restrictions
&= ~MemberLookupRestrictions
.InvocableOnly
;
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 ());
10094 if (!texpr
.Type
.IsAccessible (rc
)) {
10095 rc
.Report
.SymbolRelatedToPreviousError (member_lookup
.Type
);
10096 ErrorIsInaccesible (rc
, member_lookup
.Type
.GetSignatureForError (), loc
);
10100 if (HasTypeArguments
) {
10101 return new GenericTypeExpr (member_lookup
.Type
, targs
, loc
);
10104 return member_lookup
;
10107 me
= member_lookup
as MemberExpr
;
10109 if (sn
!= null && me
.IsStatic
&& (expr
= me
.ProbeIdenticalTypeName (rc
, expr
, sn
)) != expr
) {
10114 me
.ConditionalAccess
= true;
10117 me
= me
.ResolveMemberAccess (rc
, expr
, sn
);
10120 if (!targs
.Resolve (rc
, false))
10123 me
.SetTypeArguments (rc
, targs
);
10129 public override FullNamedExpression
ResolveAsTypeOrNamespace (IMemberContext rc
, bool allowUnboundTypeArguments
)
10131 FullNamedExpression fexpr
= expr
as FullNamedExpression
;
10132 if (fexpr
== null) {
10133 expr
.ResolveAsType (rc
);
10137 FullNamedExpression expr_resolved
= fexpr
.ResolveAsTypeOrNamespace (rc
, allowUnboundTypeArguments
);
10139 if (expr_resolved
== null)
10142 var ns
= expr_resolved
as NamespaceExpression
;
10144 FullNamedExpression retval
= ns
.LookupTypeOrNamespace (rc
, Name
, Arity
, LookupMode
.Normal
, loc
);
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)
10154 targs
.Resolve (rc
, allowUnboundTypeArguments
);
10156 retval
= new GenericOpenTypeExpr (retval
.Type
, loc
);
10163 var tnew_expr
= expr_resolved
.ResolveAsType (rc
);
10164 if (tnew_expr
== null)
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 ());
10174 var qam
= this as QualifiedAliasMember
;
10176 rc
.Module
.Compiler
.Report
.Error (431, loc
,
10177 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
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
);
10191 expr_type
= tnew_expr
;
10192 nested
= MemberCache
.FindNestedType (expr_type
, Name
, Arity
, false);
10193 ErrorIsInaccesible (rc
, nested
.GetSignatureForError (), loc
);
10197 if (nested
.IsAccessible (rc
))
10201 // Keep looking after inaccessible candidate but only if
10202 // we are not in same context as the definition itself
10204 if (expr_type
.MemberDefinition
== rc
.CurrentMemberDefinition
)
10207 expr_type
= expr_type
.BaseType
;
10212 if (HasTypeArguments
) {
10213 texpr
= new GenericTypeExpr (nested
, targs
, loc
);
10215 targs
.Resolve (rc
, allowUnboundTypeArguments
&& !(expr_resolved
is GenericTypeExpr
));
10217 texpr
= new GenericOpenTypeExpr (nested
, loc
);
10219 } else if (expr_resolved
is GenericOpenTypeExpr
) {
10220 texpr
= new GenericOpenTypeExpr (nested
, loc
);
10222 texpr
= new TypeExpression (nested
, loc
);
10225 if (texpr
.ResolveAsType (rc
) == null)
10231 public void Error_IdentifierNotFound (IMemberContext rc
, TypeSpec expr_type
)
10233 var nested
= MemberCache
.FindNestedType (expr_type
, Name
, -System
.Math
.Max (1, Arity
), false);
10235 if (nested
!= null) {
10236 Error_TypeArgumentsCannotBeUsed (rc
, nested
, expr
.Location
);
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
);
10246 rc
.Module
.Compiler
.Report
.Error (426, loc
, "The nested type `{0}' does not exist in the type `{1}'",
10247 Name
, expr_type
.GetSignatureForError ());
10250 protected override void Error_InvalidExpressionStatement (Report report
, Location loc
)
10252 base.Error_InvalidExpressionStatement (report
, LeftExpression
.Location
);
10255 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec
, TypeSpec type
, string name
)
10257 if (ec
.Module
.Compiler
.Settings
.Version
> LanguageVersion
.ISO_2
&& !ec
.IsRuntimeBinder
&& MethodGroupExpr
.IsExtensionMethodArgument (expr
)) {
10258 ec
.Report
.SymbolRelatedToPreviousError (type
);
10260 var cand
= ec
.Module
.GlobalRootNamespace
.FindExtensionMethodNamespaces (ec
, name
, Arity
);
10262 // a using directive or an assembly reference
10263 if (cand
!= null) {
10264 missing
= "`" + string.Join ("' or `", cand
.ToArray ()) + "' using directive";
10266 missing
= "an assembly reference";
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
);
10275 base.Error_TypeDoesNotContainDefinition (ec
, type
, name
);
10278 public override string GetSignatureForError ()
10280 return expr
.GetSignatureForError () + "." + base.GetSignatureForError ();
10283 protected override void CloneTo (CloneContext clonectx
, Expression t
)
10285 MemberAccess target
= (MemberAccess
) t
;
10287 target
.expr
= expr
.Clone (clonectx
);
10290 public override object Accept (StructuralVisitor visitor
)
10292 return visitor
.Visit (this);
10296 public class ConditionalMemberAccess
: MemberAccess
10298 public ConditionalMemberAccess (Expression expr
, string identifier
, TypeArguments args
, Location loc
)
10299 : base (expr
, identifier
, args
, loc
)
10303 public override bool HasConditionalAccess ()
10310 /// Implements checked expressions
10312 public class CheckedExpr
: Expression
{
10314 public Expression Expr
;
10316 public CheckedExpr (Expression e
, Location l
)
10322 public override bool ContainsEmitWithAwait ()
10324 return Expr
.ContainsEmitWithAwait ();
10327 public override Expression
CreateExpressionTree (ResolveContext ec
)
10329 using (ec
.With (ResolveContext
.Options
.AllCheckStateFlags
, true))
10330 return Expr
.CreateExpressionTree (ec
);
10333 protected override Expression
DoResolve (ResolveContext ec
)
10335 using (ec
.With (ResolveContext
.Options
.AllCheckStateFlags
, true))
10336 Expr
= Expr
.Resolve (ec
);
10341 if (Expr
is Constant
|| Expr
is MethodGroupExpr
|| Expr
is AnonymousMethodExpression
|| Expr
is DefaultValueExpression
)
10344 eclass
= Expr
.eclass
;
10349 public override void Emit (EmitContext ec
)
10351 using (ec
.With (EmitContext
.Options
.CheckedScope
, true))
10355 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
10357 using (ec
.With (EmitContext
.Options
.CheckedScope
, true))
10358 Expr
.EmitBranchable (ec
, target
, on_true
);
10361 public override void FlowAnalysis (FlowAnalysisContext fc
)
10363 Expr
.FlowAnalysis (fc
);
10366 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
10368 using (ctx
.With (BuilderContext
.Options
.CheckedScope
, true)) {
10369 return Expr
.MakeExpression (ctx
);
10373 protected override void CloneTo (CloneContext clonectx
, Expression t
)
10375 CheckedExpr target
= (CheckedExpr
) t
;
10377 target
.Expr
= Expr
.Clone (clonectx
);
10380 public override object Accept (StructuralVisitor visitor
)
10382 return visitor
.Visit (this);
10387 /// Implements the unchecked expression
10389 public class UnCheckedExpr
: Expression
{
10391 public Expression Expr
;
10393 public UnCheckedExpr (Expression e
, Location l
)
10399 public override bool ContainsEmitWithAwait ()
10401 return Expr
.ContainsEmitWithAwait ();
10404 public override Expression
CreateExpressionTree (ResolveContext ec
)
10406 using (ec
.With (ResolveContext
.Options
.AllCheckStateFlags
, false))
10407 return Expr
.CreateExpressionTree (ec
);
10410 protected override Expression
DoResolve (ResolveContext ec
)
10412 using (ec
.With (ResolveContext
.Options
.AllCheckStateFlags
, false))
10413 Expr
= Expr
.Resolve (ec
);
10418 if (Expr
is Constant
|| Expr
is MethodGroupExpr
|| Expr
is AnonymousMethodExpression
|| Expr
is DefaultValueExpression
)
10421 eclass
= Expr
.eclass
;
10426 public override void Emit (EmitContext ec
)
10428 using (ec
.With (EmitContext
.Options
.CheckedScope
, false))
10432 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
10434 using (ec
.With (EmitContext
.Options
.CheckedScope
, false))
10435 Expr
.EmitBranchable (ec
, target
, on_true
);
10438 public override void FlowAnalysis (FlowAnalysisContext fc
)
10440 Expr
.FlowAnalysis (fc
);
10443 protected override void CloneTo (CloneContext clonectx
, Expression t
)
10445 UnCheckedExpr target
= (UnCheckedExpr
) t
;
10447 target
.Expr
= Expr
.Clone (clonectx
);
10450 public override object Accept (StructuralVisitor visitor
)
10452 return visitor
.Visit (this);
10457 /// An Element Access expression.
10459 /// During semantic analysis these are transformed into
10460 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10462 public class ElementAccess
: Expression
10464 public Arguments Arguments
;
10465 public Expression Expr
;
10466 bool conditional_access_receiver
;
10468 public ElementAccess (Expression e
, Arguments args
, Location loc
)
10472 this.Arguments
= args
;
10475 public bool ConditionalAccess { get; set; }
10477 public override Location StartLocation
{
10479 return Expr
.StartLocation
;
10483 public override bool ContainsEmitWithAwait ()
10485 return Expr
.ContainsEmitWithAwait () || Arguments
.ContainsEmitWithAwait ();
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.
10492 Expression
CreateAccessExpression (ResolveContext ec
, bool conditionalAccessReceiver
)
10494 if (conditionalAccessReceiver
)
10495 ec
.Set (ResolveContext
.Options
.DontSetConditionalAccessReceiver
);
10497 Expr
= Expr
.Resolve (ec
);
10499 if (conditionalAccessReceiver
)
10500 ec
.With (ResolveContext
.Options
.DontSetConditionalAccessReceiver
, false);
10507 if (ConditionalAccess
&& !IsNullPropagatingValid (type
)) {
10508 Error_OperatorCannotBeApplied (ec
, loc
, "?", type
);
10512 if (type
.IsArray
) {
10513 var aa
= new ArrayAccess (this, loc
) {
10514 ConditionalAccess
= ConditionalAccess
,
10517 if (conditionalAccessReceiver
)
10518 aa
.SetConditionalAccessReceiver ();
10523 if (type
.IsPointer
)
10524 return Expr
.MakePointerAccess (ec
, type
, Arguments
);
10526 FieldExpr fe
= Expr
as FieldExpr
;
10528 var ff
= fe
.Spec
as FixedFieldSpec
;
10530 return Expr
.MakePointerAccess (ec
, ff
.ElementType
, Arguments
);
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
10540 if (conditionalAccessReceiver
)
10541 indexer
.SetConditionalAccessReceiver ();
10546 Error_CannotApplyIndexing (ec
, type
, loc
);
10551 public override Expression
CreateExpressionTree (ResolveContext ec
)
10553 Arguments args
= Arguments
.CreateForExpressionTree (ec
, Arguments
,
10554 Expr
.CreateExpressionTree (ec
));
10556 return CreateExpressionFactoryCall (ec
, "ArrayIndex", args
);
10559 public static void Error_CannotApplyIndexing (ResolveContext rc
, TypeSpec type
, Location loc
)
10561 if (type
!= InternalType
.ErrorType
) {
10562 rc
.Report
.Error (21, loc
, "Cannot apply indexing with [] to an expression of type `{0}'",
10563 type
.GetSignatureForError ());
10567 public override bool HasConditionalAccess ()
10569 return ConditionalAccess
|| Expr
.HasConditionalAccess ();
10572 void ResolveConditionalAccessReceiver (ResolveContext rc
)
10574 if (!rc
.HasSet (ResolveContext
.Options
.DontSetConditionalAccessReceiver
) && HasConditionalAccess ()) {
10575 conditional_access_receiver
= true;
10579 protected override Expression
DoResolve (ResolveContext rc
)
10581 ResolveConditionalAccessReceiver (rc
);
10583 var expr
= CreateAccessExpression (rc
, conditional_access_receiver
);
10587 return expr
.Resolve (rc
);
10590 public override Expression
DoResolveLValue (ResolveContext ec
, Expression rhs
)
10592 var res
= CreateAccessExpression (ec
, false);
10596 return res
.ResolveLValue (ec
, rhs
);
10599 public override void Emit (EmitContext ec
)
10601 throw new Exception ("Should never be reached");
10604 public override void FlowAnalysis (FlowAnalysisContext fc
)
10606 Expr
.FlowAnalysis (fc
);
10608 Arguments
.FlowAnalysis (fc
);
10611 public override string GetSignatureForError ()
10613 return Expr
.GetSignatureForError ();
10616 protected override void CloneTo (CloneContext clonectx
, Expression t
)
10618 ElementAccess target
= (ElementAccess
) t
;
10620 target
.Expr
= Expr
.Clone (clonectx
);
10621 if (Arguments
!= null)
10622 target
.Arguments
= Arguments
.Clone (clonectx
);
10625 public override object Accept (StructuralVisitor visitor
)
10627 return visitor
.Visit (this);
10632 /// Implements array access
10634 public class ArrayAccess
: Expression
, IDynamicAssign
, IMemoryLocation
{
10636 // Points to our "data" repository
10640 LocalTemporary temp
;
10642 bool? has_await_args
;
10643 bool conditional_access_receiver
;
10645 public ArrayAccess (ElementAccess ea_data
, Location l
)
10651 public bool ConditionalAccess { get; set; }
10653 public void AddressOf (EmitContext ec
, AddressOp mode
)
10655 var ac
= (ArrayContainer
) ea
.Expr
.Type
;
10657 if (!has_await_args
.HasValue
&& ec
.HasSet (BuilderContext
.Options
.AsyncBody
) && ea
.Arguments
.ContainsEmitWithAwait ()) {
10658 LoadInstanceAndArguments (ec
, false, true);
10661 LoadInstanceAndArguments (ec
, false, false);
10663 if (ac
.Element
.IsGenericParameter
&& mode
== AddressOp
.Load
)
10664 ec
.Emit (OpCodes
.Readonly
);
10666 ec
.EmitArrayAddress (ac
);
10669 public override Expression
CreateExpressionTree (ResolveContext ec
)
10671 if (ConditionalAccess
)
10672 Error_NullShortCircuitInsideExpressionTree (ec
);
10674 return ea
.CreateExpressionTree (ec
);
10677 public override bool ContainsEmitWithAwait ()
10679 return ea
.ContainsEmitWithAwait ();
10682 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
10684 if (HasConditionalAccess ())
10685 Error_NullPropagatingLValue (ec
);
10687 return DoResolve (ec
);
10690 protected override Expression
DoResolve (ResolveContext ec
)
10692 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10694 ea
.Arguments
.Resolve (ec
, out dynamic);
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 ());
10705 if (type
.IsPointer
) {
10706 if (ec
.CurrentIterator
!= null) {
10707 UnsafeInsideIteratorError (ec
, ea
.Location
);
10708 } else if (!ec
.IsUnsafe
) {
10709 UnsafeError (ec
, ea
.Location
);
10713 if (conditional_access_receiver
)
10714 type
= LiftMemberType (ec
, type
);
10716 foreach (Argument a
in ea
.Arguments
) {
10717 var na
= a
as NamedArgument
;
10719 ElementAccess
.Error_NamedArgument (na
, ec
.Report
);
10721 a
.Expr
= ConvertExpressionToArrayIndex (ec
, a
.Expr
);
10724 eclass
= ExprClass
.Variable
;
10729 protected override void Error_NegativeArrayIndex (ResolveContext ec
, Location loc
)
10731 ec
.Report
.Warning (251, 2, loc
, "Indexing an array with a negative index (array indices always start at zero)");
10734 public override void FlowAnalysis (FlowAnalysisContext fc
)
10736 var da
= conditional_access_receiver
? fc
.BranchDefiniteAssignment () : null;
10738 ea
.FlowAnalysis (fc
);
10740 if (conditional_access_receiver
)
10741 fc
.DefiniteAssignment
= da
;
10744 public override bool HasConditionalAccess ()
10746 return ConditionalAccess
|| ea
.Expr
.HasConditionalAccess ();
10750 // Load the array arguments into the stack.
10752 void LoadInstanceAndArguments (EmitContext ec
, bool duplicateArguments
, bool prepareAwait
)
10754 if (prepareAwait
) {
10755 ea
.Expr
= ea
.Expr
.EmitToField (ec
);
10757 var ie
= new InstanceEmitter (ea
.Expr
, false);
10758 ie
.Emit (ec
, ConditionalAccess
);
10760 if (duplicateArguments
) {
10761 ec
.Emit (OpCodes
.Dup
);
10763 var copy
= new LocalTemporary (ea
.Expr
.Type
);
10769 var dup_args
= ea
.Arguments
.Emit (ec
, duplicateArguments
, prepareAwait
);
10770 if (dup_args
!= null)
10771 ea
.Arguments
= dup_args
;
10774 public void Emit (EmitContext ec
, bool leave_copy
)
10777 ec
.EmitLoadFromPtr (type
);
10779 if (!has_await_args
.HasValue
&& ec
.HasSet (BuilderContext
.Options
.AsyncBody
) && ea
.Arguments
.ContainsEmitWithAwait ()) {
10780 LoadInstanceAndArguments (ec
, false, true);
10783 if (conditional_access_receiver
)
10784 ec
.ConditionalAccess
= new ConditionalAccessContext (type
, ec
.DefineLabel ());
10786 var ac
= (ArrayContainer
) ea
.Expr
.Type
;
10787 LoadInstanceAndArguments (ec
, false, false);
10788 ec
.EmitArrayLoad (ac
);
10790 if (conditional_access_receiver
)
10791 ec
.CloseConditionalAccess (type
.IsNullableType
&& type
!= ac
.Element
? type
: null);
10795 ec
.Emit (OpCodes
.Dup
);
10796 temp
= new LocalTemporary (this.type
);
10801 public override void Emit (EmitContext ec
)
10806 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool isCompound
)
10808 var ac
= (ArrayContainer
) ea
.Expr
.Type
;
10809 TypeSpec t
= source
.Type
;
10811 has_await_args
= ec
.HasSet (BuilderContext
.Options
.AsyncBody
) && (ea
.Arguments
.ContainsEmitWithAwait () || source
.ContainsEmitWithAwait ());
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
10818 if (t
.IsStruct
&& ((isCompound
&& !(source
is DynamicExpressionStatement
)) || !BuiltinTypeSpec
.IsPrimitiveType (t
))) {
10819 LoadInstanceAndArguments (ec
, false, has_await_args
.Value
);
10821 if (has_await_args
.Value
) {
10822 if (source
.ContainsEmitWithAwait ()) {
10823 source
= source
.EmitToField (ec
);
10824 isCompound
= false;
10828 LoadInstanceAndArguments (ec
, isCompound
, false);
10833 ec
.EmitArrayAddress (ac
);
10836 ec
.Emit (OpCodes
.Dup
);
10840 LoadInstanceAndArguments (ec
, isCompound
, has_await_args
.Value
);
10842 if (has_await_args
.Value
) {
10843 if (source
.ContainsEmitWithAwait ())
10844 source
= source
.EmitToField (ec
);
10846 LoadInstanceAndArguments (ec
, false, false);
10853 var lt
= ea
.Expr
as LocalTemporary
;
10859 ec
.Emit (OpCodes
.Dup
);
10860 temp
= new LocalTemporary (this.type
);
10865 ec
.EmitStoreFromPtr (t
);
10867 ec
.EmitArrayStore (ac
);
10870 if (temp
!= null) {
10876 public override Expression
EmitToField (EmitContext ec
)
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
10885 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10887 ea
.Expr
= ea
.Expr
.EmitToField (ec
);
10888 ea
.Arguments
= ea
.Arguments
.Emit (ec
, false, true);
10892 public SLE
.Expression
MakeAssignExpression (BuilderContext ctx
, Expression source
)
10894 return SLE
.Expression
.ArrayAccess (ea
.Expr
.MakeExpression (ctx
), MakeExpressionArguments (ctx
));
10897 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
10899 return SLE
.Expression
.ArrayIndex (ea
.Expr
.MakeExpression (ctx
), MakeExpressionArguments (ctx
));
10902 SLE
.Expression
[] MakeExpressionArguments (BuilderContext ctx
)
10904 using (ctx
.With (BuilderContext
.Options
.CheckedScope
, true)) {
10905 return Arguments
.MakeExpression (ea
.Arguments
, ctx
);
10909 public void SetConditionalAccessReceiver ()
10911 conditional_access_receiver
= true;
10916 // Indexer access expression
10918 class IndexerExpr
: PropertyOrIndexerExpr
<IndexerSpec
>, OverloadResolver
.IBaseMembersProvider
10920 IList
<MemberSpec
> indexers
;
10921 Arguments arguments
;
10922 TypeSpec queried_type
;
10924 public IndexerExpr (IList
<MemberSpec
> indexers
, TypeSpec queriedType
, ElementAccess ea
)
10925 : this (indexers
, queriedType
, ea
.Expr
, ea
.Arguments
, ea
.Location
)
10929 public IndexerExpr (IList
<MemberSpec
> indexers
, TypeSpec queriedType
, Expression instance
, Arguments args
, Location loc
)
10932 this.indexers
= indexers
;
10933 this.queried_type
= queriedType
;
10934 this.InstanceExpression
= instance
;
10935 this.arguments
= args
;
10940 protected override Arguments Arguments
{
10949 protected override TypeSpec DeclaringType
{
10951 return best_candidate
.DeclaringType
;
10955 public override bool IsInstance
{
10961 public override bool IsStatic
{
10967 public override string KindName
{
10968 get { return "indexer"; }
10971 public override string Name
{
10979 public override bool ContainsEmitWithAwait ()
10981 return base.ContainsEmitWithAwait () || arguments
.ContainsEmitWithAwait ();
10984 public override Expression
CreateExpressionTree (ResolveContext ec
)
10986 if (ConditionalAccess
) {
10987 Error_NullShortCircuitInsideExpressionTree (ec
);
10990 Arguments args
= Arguments
.CreateForExpressionTree (ec
, arguments
,
10991 InstanceExpression
.CreateExpressionTree (ec
),
10992 new TypeOfMethod (Getter
, loc
));
10994 return CreateExpressionFactoryCall (ec
, "Call", args
);
10997 public override void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool isCompound
)
10999 LocalTemporary await_source_arg
= null;
11002 emitting_compound_assignment
= true;
11003 if (source
is DynamicExpressionStatement
) {
11008 emitting_compound_assignment
= false;
11010 if (has_await_arguments
) {
11011 await_source_arg
= new LocalTemporary (Type
);
11012 await_source_arg
.Store (ec
);
11014 arguments
.Add (new Argument (await_source_arg
));
11017 temp
= await_source_arg
;
11020 has_await_arguments
= false;
11025 ec
.Emit (OpCodes
.Dup
);
11026 temp
= new LocalTemporary (Type
);
11032 if (ec
.HasSet (BuilderContext
.Options
.AsyncBody
) && (arguments
.ContainsEmitWithAwait () || source
.ContainsEmitWithAwait ())) {
11033 source
= source
.EmitToField (ec
);
11035 temp
= new LocalTemporary (Type
);
11042 arguments
.Add (new Argument (source
));
11045 var call
= new CallEmitter ();
11046 call
.InstanceExpression
= InstanceExpression
;
11047 if (arguments
== null)
11048 call
.InstanceExpressionOnStack
= true;
11050 call
.Emit (ec
, Setter
, arguments
, loc
);
11052 if (temp
!= null) {
11055 } else if (leave_copy
) {
11059 if (await_source_arg
!= null) {
11060 await_source_arg
.Release (ec
);
11064 public override void FlowAnalysis (FlowAnalysisContext fc
)
11066 var da
= conditional_access_receiver
? fc
.BranchDefiniteAssignment () : null;
11068 base.FlowAnalysis (fc
);
11069 arguments
.FlowAnalysis (fc
);
11071 if (conditional_access_receiver
)
11072 fc
.DefiniteAssignment
= da
;
11075 public override string GetSignatureForError ()
11077 return best_candidate
.GetSignatureForError ();
11080 public override SLE
.Expression
MakeAssignExpression (BuilderContext ctx
, Expression source
)
11083 throw new NotSupportedException ();
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
),
11093 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
11096 return base.MakeExpression (ctx
);
11098 var args
= Arguments
.MakeExpression (arguments
, ctx
);
11099 return SLE
.Expression
.Call (InstanceExpression
.MakeExpression (ctx
), (MethodInfo
) Getter
.GetMetaInfo (), args
);
11103 protected override Expression
OverloadResolve (ResolveContext rc
, Expression right_side
)
11105 if (best_candidate
!= null)
11108 eclass
= ExprClass
.IndexerAccess
;
11111 using (rc
.With (ResolveContext
.Options
.DontSetConditionalAccessReceiver
, false)) {
11112 arguments
.Resolve (rc
, out dynamic);
11115 if (indexers
== null && InstanceExpression
.Type
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
) {
11118 var res
= new OverloadResolver (indexers
, OverloadResolver
.Restrictions
.None
, loc
);
11119 res
.BaseMembersProvider
= this;
11120 res
.InstanceQualifier
= this;
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
)
11131 // It has dynamic arguments
11134 Arguments args
= new Arguments (arguments
.Count
+ 1);
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");
11139 args
.Add (new Argument (InstanceExpression
));
11141 args
.AddRange (arguments
);
11143 best_candidate
= null;
11144 return new DynamicIndexBinder (args
, conditional_access_receiver
, ConditionalAccess
, loc
);
11148 // Try to avoid resolving left expression again
11150 if (right_side
!= null)
11151 ResolveInstanceExpression (rc
, right_side
);
11156 protected override void CloneTo (CloneContext clonectx
, Expression t
)
11158 IndexerExpr target
= (IndexerExpr
) t
;
11160 if (arguments
!= null)
11161 target
.arguments
= arguments
.Clone (clonectx
);
11164 public void SetConditionalAccessReceiver ()
11166 conditional_access_receiver
= true;
11169 public override void SetTypeArguments (ResolveContext ec
, TypeArguments ta
)
11171 Error_TypeArgumentsCannotBeUsed (ec
, "indexer", GetSignatureForError (), loc
);
11174 #region IBaseMembersProvider Members
11176 IList
<MemberSpec
> OverloadResolver
.IBaseMembersProvider
.GetBaseMembers (TypeSpec type
)
11178 var baseType
= type
.BaseType
;
11179 var members
= baseType
== null ? null : MemberCache
.FindMembers (baseType
, MemberCache
.IndexerNameAlias
, false);
11181 if (members
== null && !type
.IsInterface
) {
11182 var tps
= queried_type
as TypeParameterSpec
;
11184 members
= MemberCache
.FindInterfaceMembers (tps
, MemberCache
.IndexerNameAlias
);
11190 IParametersMember OverloadResolver
.IBaseMembersProvider
.GetOverrideMemberParameters (MemberSpec member
)
11192 if (queried_type
== member
.DeclaringType
)
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
;
11199 MethodGroupExpr OverloadResolver
.IBaseMembersProvider
.LookupExtensionMethod (ResolveContext rc
)
11208 // A base access expression
11210 public class BaseThis
: This
11212 public BaseThis (Location loc
)
11217 public BaseThis (TypeSpec type
, Location loc
)
11221 eclass
= ExprClass
.Variable
;
11226 public override string Name
{
11234 public override Expression
CreateExpressionTree (ResolveContext ec
)
11236 ec
.Report
.Error (831, loc
, "An expression tree may not contain a base access");
11237 return base.CreateExpressionTree (ec
);
11240 public override void Emit (EmitContext ec
)
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
);
11251 protected override void Error_ThisNotAvailable (ResolveContext ec
)
11254 ec
.Report
.Error (1511, loc
, "Keyword `base' is not available in a static method");
11256 ec
.Report
.Error (1512, loc
, "Keyword `base' is not available in the current context");
11260 public override void ResolveBase (ResolveContext ec
)
11262 base.ResolveBase (ec
);
11263 type
= ec
.CurrentType
.BaseType
;
11266 public override object Accept (StructuralVisitor visitor
)
11268 return visitor
.Visit (this);
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
11279 /// This is also now used as a placeholder where a no-action expression
11280 /// is needed (the `New' class).
11282 public class EmptyExpression
: Expression
11284 sealed class OutAccessExpression
: EmptyExpression
11286 public OutAccessExpression (TypeSpec t
)
11291 public override Expression
DoResolveLValue (ResolveContext rc
, Expression right_side
)
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");
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
);
11309 public EmptyExpression (TypeSpec t
)
11312 eclass
= ExprClass
.Value
;
11313 loc
= Location
.Null
;
11316 protected override void CloneTo (CloneContext clonectx
, Expression target
)
11320 public override bool ContainsEmitWithAwait ()
11325 public override Expression
CreateExpressionTree (ResolveContext ec
)
11327 throw new NotSupportedException ("ET");
11330 protected override Expression
DoResolve (ResolveContext ec
)
11335 public override void Emit (EmitContext ec
)
11337 // nothing, as we only exist to not do anything.
11340 public override void EmitBranchable (EmitContext ec
, Label target
, bool on_true
)
11344 public override void EmitSideEffect (EmitContext ec
)
11348 public override object Accept (StructuralVisitor visitor
)
11350 return visitor
.Visit (this);
11354 sealed class EmptyAwaitExpression
: EmptyExpression
11356 public EmptyAwaitExpression (TypeSpec type
)
11361 public override bool ContainsEmitWithAwait ()
11368 // Empty statement expression
11370 public sealed class EmptyExpressionStatement
: ExpressionStatement
11372 public static readonly EmptyExpressionStatement Instance
= new EmptyExpressionStatement ();
11374 private EmptyExpressionStatement ()
11376 loc
= Location
.Null
;
11379 public override bool ContainsEmitWithAwait ()
11384 public override Expression
CreateExpressionTree (ResolveContext ec
)
11389 public override void EmitStatement (EmitContext ec
)
11394 protected override Expression
DoResolve (ResolveContext ec
)
11396 eclass
= ExprClass
.Value
;
11397 type
= ec
.BuiltinTypes
.Object
;
11401 public override void Emit (EmitContext ec
)
11406 public override object Accept (StructuralVisitor visitor
)
11408 return visitor
.Visit (this);
11412 public class ErrorExpression
: EmptyExpression
11414 public static readonly ErrorExpression Instance
= new ErrorExpression ();
11416 private ErrorExpression ()
11417 : base (InternalType
.ErrorType
)
11421 public override Expression
CreateExpressionTree (ResolveContext ec
)
11426 public override Expression
DoResolveLValue (ResolveContext rc
, Expression right_side
)
11431 public override void Error_ValueAssignment (ResolveContext rc
, Expression rhs
)
11435 public override void Error_UnexpectedKind (ResolveContext ec
, ResolveFlags flags
, Location loc
)
11439 public override void Error_ValueCannotBeConverted (ResolveContext ec
, TypeSpec target
, bool expl
)
11443 public override void Error_OperatorCannotBeApplied (ResolveContext rc
, Location loc
, string oper
, TypeSpec t
)
11447 public override object Accept (StructuralVisitor visitor
)
11449 return visitor
.Visit (this);
11453 public class UserCast
: Expression
{
11457 public UserCast (MethodSpec method
, Expression source
, Location l
)
11459 if (source
== null)
11460 throw new ArgumentNullException ("source");
11462 this.method
= method
;
11463 this.source
= source
;
11464 type
= method
.ReturnType
;
11468 public Expression Source
{
11477 public override bool ContainsEmitWithAwait ()
11479 return source
.ContainsEmitWithAwait ();
11482 public override Expression
CreateExpressionTree (ResolveContext ec
)
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
);
11491 protected override Expression
DoResolve (ResolveContext ec
)
11493 method
.CheckObsoleteness (ec
, source
.Location
);
11495 eclass
= ExprClass
.Value
;
11499 public override void Emit (EmitContext ec
)
11502 ec
.MarkCallEntry (loc
);
11503 ec
.Emit (OpCodes
.Call
, method
);
11506 public override void FlowAnalysis (FlowAnalysisContext fc
)
11508 source
.FlowAnalysis (fc
);
11511 public override string GetSignatureForError ()
11513 return TypeManager
.CSharpSignature (method
);
11516 public override SLE
.Expression
MakeExpression (BuilderContext ctx
)
11519 return base.MakeExpression (ctx
);
11521 return SLE
.Expression
.Convert (source
.MakeExpression (ctx
), type
.GetMetaInfo (), (MethodInfo
) method
.GetMetaInfo ());
11527 // Holds additional type specifiers like ?, *, []
11529 public class ComposedTypeSpecifier
11531 public static readonly ComposedTypeSpecifier SingleDimension
= new ComposedTypeSpecifier (1, Location
.Null
);
11533 public readonly int Dimension
;
11534 public readonly Location Location
;
11536 public ComposedTypeSpecifier (int specifier
, Location loc
)
11538 this.Dimension
= specifier
;
11539 this.Location
= loc
;
11543 public bool IsNullable
{
11545 return Dimension
== -1;
11549 public bool IsPointer
{
11551 return Dimension
== -2;
11555 public ComposedTypeSpecifier Next { get; set; }
11559 public static ComposedTypeSpecifier
CreateArrayDimension (int dimension
, Location loc
)
11561 return new ComposedTypeSpecifier (dimension
, loc
);
11564 public static ComposedTypeSpecifier
CreateNullable (Location loc
)
11566 return new ComposedTypeSpecifier (-1, loc
);
11569 public static ComposedTypeSpecifier
CreatePointer (Location loc
)
11571 return new ComposedTypeSpecifier (-2, loc
);
11574 public string GetSignatureForError ()
11579 ArrayContainer
.GetPostfixSignature (Dimension
);
11581 return Next
!= null ? s
+ Next
.GetSignatureForError () : s
;
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.
11591 public class ComposedCast
: TypeExpr
{
11592 FullNamedExpression left
;
11593 ComposedTypeSpecifier spec
;
11595 public ComposedCast (FullNamedExpression left
, ComposedTypeSpecifier spec
)
11598 throw new ArgumentNullException ("spec");
11602 this.loc
= left
.Location
;
11605 public override TypeSpec
ResolveAsType (IMemberContext ec
, bool allowUnboundTypeArguments
)
11607 type
= left
.ResolveAsType (ec
);
11611 eclass
= ExprClass
.Type
;
11613 var single_spec
= spec
;
11615 if (single_spec
.IsNullable
) {
11616 type
= new Nullable
.NullableType (type
, loc
).ResolveAsType (ec
);
11620 single_spec
= single_spec
.Next
;
11621 } else if (single_spec
.IsPointer
) {
11623 // Declared fields cannot have unmanaged check done before all types are defined
11625 if (!(ec
.CurrentMemberDefinition
is Field
) && !TypeManager
.VerifyUnmanaged (ec
.Module
, type
, loc
))
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
);
11636 type
= PointerContainer
.MakeType (ec
.Module
, type
);
11637 single_spec
= single_spec
.Next
;
11638 } while (single_spec
!= null && single_spec
.IsPointer
);
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 ());
11649 MakeArray (ec
.Module
, single_spec
);
11656 void MakeArray (ModuleContainer module
, ComposedTypeSpecifier spec
)
11658 if (spec
.Next
!= null)
11659 MakeArray (module
, spec
.Next
);
11661 type
= ArrayContainer
.MakeType (module
, type
, spec
.Dimension
);
11664 public override string GetSignatureForError ()
11666 return left
.GetSignatureForError () + spec
.GetSignatureForError ();
11669 public override object Accept (StructuralVisitor visitor
)
11671 return visitor
.Visit (this);
11675 class ReferenceTypeExpr
: TypeExpr
11677 FullNamedExpression element
;
11678 readonly bool readOnly
;
11680 public ReferenceTypeExpr (FullNamedExpression element
, bool readOnly
, Location loc
)
11681 : this (element
, loc
)
11683 this.readOnly
= readOnly
;
11686 public ReferenceTypeExpr (FullNamedExpression element
, Location loc
)
11688 this.element
= element
;
11692 public override TypeSpec
ResolveAsType (IMemberContext mc
, bool allowUnboundTypeArguments
= false)
11694 type
= element
.ResolveAsType (mc
);
11698 eclass
= ExprClass
.Type
;
11700 ReadOnlyReferenceContainer
.MakeType (mc
.Module
, type
) :
11701 ReferenceContainer
.MakeType (mc
.Module
, type
);
11706 public override string GetSignatureForError ()
11708 var prefix
= readOnly
? "ref " : "ref readonly ";
11709 return prefix
+ element
.GetSignatureForError ();
11712 public override object Accept (StructuralVisitor visitor
)
11714 return visitor
.Visit (this);
11718 class FixedBufferPtr
: Expression
11720 readonly Expression array
;
11722 public FixedBufferPtr (Expression array
, TypeSpec array_type
, Location l
)
11724 this.type
= array_type
;
11725 this.array
= array
;
11729 public override bool ContainsEmitWithAwait ()
11731 throw new NotImplementedException ();
11734 public override Expression
CreateExpressionTree (ResolveContext ec
)
11736 Error_PointerInsideExpressionTree (ec
);
11740 public override void Emit(EmitContext ec
)
11745 protected override Expression
DoResolve (ResolveContext ec
)
11747 type
= PointerContainer
.MakeType (ec
.Module
, type
);
11748 eclass
= ExprClass
.Value
;
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)
11759 class ArrayPtr
: FixedBufferPtr
11761 public ArrayPtr (Expression array
, TypeSpec array_type
, Location l
):
11762 base (array
, array_type
, l
)
11766 public override void Emit (EmitContext ec
)
11771 ec
.Emit (OpCodes
.Ldelema
, ((PointerContainer
) type
).Element
);
11776 // Encapsulates a conversion rules required for array indexes
11778 public class ArrayIndexCast
: TypeCast
11780 public ArrayIndexCast (Expression expr
, TypeSpec returnType
)
11781 : base (expr
, returnType
)
11783 if (expr
.Type
== returnType
) // int -> int
11784 throw new ArgumentException ("unnecessary array index conversion");
11787 public override Expression
CreateExpressionTree (ResolveContext ec
)
11789 using (ec
.Set (ResolveContext
.Options
.CheckedScope
)) {
11790 return base.CreateExpressionTree (ec
);
11794 public override void Emit (EmitContext ec
)
11798 switch (child
.Type
.BuiltinType
) {
11799 case BuiltinTypeSpec
.Type
.UInt
:
11800 ec
.Emit (OpCodes
.Conv_U
);
11802 case BuiltinTypeSpec
.Type
.Long
:
11803 ec
.Emit (OpCodes
.Conv_Ovf_I
);
11805 case BuiltinTypeSpec
.Type
.ULong
:
11806 ec
.Emit (OpCodes
.Conv_Ovf_I_Un
);
11809 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type
);
11815 // Implements the `stackalloc' keyword
11817 public class StackAlloc
: Expression
{
11822 public StackAlloc (Expression type
, Expression count
, Location l
)
11825 this.count
= count
;
11829 public Expression TypeExpression
{
11835 public Expression CountExpression
{
11841 public override bool ContainsEmitWithAwait ()
11846 public override Expression
CreateExpressionTree (ResolveContext ec
)
11848 throw new NotSupportedException ("ET");
11851 protected override Expression
DoResolve (ResolveContext ec
)
11853 count
= count
.Resolve (ec
);
11857 if (count
.Type
.BuiltinType
!= BuiltinTypeSpec
.Type
.UInt
){
11858 count
= Convert
.ImplicitConversionRequired (ec
, count
, ec
.BuiltinTypes
.Int
, loc
);
11863 Constant c
= count
as Constant
;
11864 if (c
!= null && c
.IsNegative
) {
11865 ec
.Report
.Error (247, loc
, "Cannot use a negative size with stackalloc");
11868 if (ec
.HasAny (ResolveContext
.Options
.CatchScope
| ResolveContext
.Options
.FinallyScope
)) {
11869 ec
.Report
.Error (255, loc
, "Cannot use stackalloc in finally or catch");
11872 otype
= texpr
.ResolveAsType (ec
);
11876 if (!TypeManager
.VerifyUnmanaged (ec
.Module
, otype
, loc
))
11879 type
= PointerContainer
.MakeType (ec
.Module
, otype
);
11880 eclass
= ExprClass
.Value
;
11885 public override void Emit (EmitContext ec
)
11887 int size
= BuiltinTypeSpec
.GetSize (otype
);
11892 ec
.Emit (OpCodes
.Sizeof
, otype
);
11896 ec
.Emit (OpCodes
.Mul_Ovf_Un
);
11897 ec
.Emit (OpCodes
.Localloc
);
11900 protected override void CloneTo (CloneContext clonectx
, Expression t
)
11902 StackAlloc target
= (StackAlloc
) t
;
11903 target
.count
= count
.Clone (clonectx
);
11904 target
.texpr
= texpr
.Clone (clonectx
);
11907 public override object Accept (StructuralVisitor visitor
)
11909 return visitor
.Visit (this);
11914 // An object initializer expression
11916 public class ElementInitializer
: Assign
11918 public readonly string Name
;
11920 public ElementInitializer (string name
, Expression initializer
, Location loc
)
11921 : base (null, initializer
, loc
)
11926 public bool IsDictionaryInitializer
{
11928 return Name
== null;
11932 protected override void CloneTo (CloneContext clonectx
, Expression t
)
11934 ElementInitializer target
= (ElementInitializer
) t
;
11935 target
.source
= source
.Clone (clonectx
);
11938 public override Expression
CreateExpressionTree (ResolveContext ec
)
11940 Arguments args
= new Arguments (2);
11941 FieldExpr fe
= target
as FieldExpr
;
11943 args
.Add (new Argument (fe
.CreateTypeOfExpression ()));
11945 args
.Add (new Argument (((PropertyExpr
) target
).CreateSetterTypeOfExpression (ec
)));
11948 Expression arg_expr
;
11949 var cinit
= source
as CollectionOrObjectInitializers
;
11950 if (cinit
== null) {
11952 arg_expr
= source
.CreateExpressionTree (ec
);
11954 mname
= cinit
.IsEmpty
|| cinit
.Initializers
[0] is ElementInitializer
? "MemberBind" : "ListBind";
11955 arg_expr
= cinit
.CreateExpressionTree (ec
, !cinit
.IsEmpty
);
11958 args
.Add (new Argument (arg_expr
));
11959 return CreateExpressionFactoryCall (ec
, mname
, args
);
11962 protected override Expression
DoResolve (ResolveContext ec
)
11964 if (source
== null)
11965 return EmptyExpressionStatement
.Instance
;
11967 if (!ResolveElement (ec
))
11970 if (source
is CollectionOrObjectInitializers
) {
11971 target
= target
.Resolve (ec
);
11972 if (target
== null)
11975 Expression previous
= ec
.CurrentInitializerVariable
;
11976 ec
.CurrentInitializerVariable
= target
;
11977 source
= source
.Resolve (ec
);
11978 ec
.CurrentInitializerVariable
= previous
;
11979 if (source
== null)
11982 eclass
= source
.eclass
;
11983 type
= source
.Type
;
11988 return base.DoResolve (ec
);
11991 public override void EmitStatement (EmitContext ec
)
11993 if (source
is CollectionOrObjectInitializers
)
11996 base.EmitStatement (ec
);
11999 protected virtual bool ResolveElement (ResolveContext rc
)
12001 var t
= rc
.CurrentInitializerVariable
.Type
;
12002 if (t
.BuiltinType
== BuiltinTypeSpec
.Type
.Dynamic
) {
12003 Arguments args
= new Arguments (1);
12004 args
.Add (new Argument (rc
.CurrentInitializerVariable
));
12005 target
= new DynamicMemberBinder (Name
, args
, loc
);
12007 var member
= MemberLookup (rc
, false, t
, Name
, 0, MemberLookupRestrictions
.ExactArity
, loc
);
12008 if (member
== null) {
12009 member
= Expression
.MemberLookup (rc
, true, t
, Name
, 0, MemberLookupRestrictions
.ExactArity
, loc
);
12011 if (member
!= null) {
12012 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
12013 ErrorIsInaccesible (rc
, member
.GetSignatureForError (), loc
);
12018 if (member
== null) {
12019 Error_TypeDoesNotContainDefinition (rc
, loc
, t
, Name
);
12023 var me
= member
as MemberExpr
;
12024 if (me
is EventExpr
) {
12025 me
= me
.ResolveMemberAccess (rc
, null, null);
12026 } else if (!(member
is PropertyExpr
|| member
is FieldExpr
)) {
12027 rc
.Report
.Error (1913, loc
,
12028 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
12029 member
.GetSignatureForError ());
12035 rc
.Report
.Error (1914, loc
,
12036 "Static field or property `{0}' cannot be assigned in an object initializer",
12037 me
.GetSignatureForError ());
12041 me
.InstanceExpression
= rc
.CurrentInitializerVariable
;
12049 // A collection initializer expression
12051 class CollectionElementInitializer
: Invocation
12053 public class ElementInitializerArgument
: Argument
12055 public ElementInitializerArgument (Expression e
)
12061 sealed class AddMemberAccess
: MemberAccess
12063 public AddMemberAccess (Expression expr
, Location loc
)
12064 : base (expr
, "Add", loc
)
12068 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec
, TypeSpec type
, string name
)
12070 if (TypeManager
.HasElementType (type
))
12073 base.Error_TypeDoesNotContainDefinition (ec
, type
, name
);
12077 public CollectionElementInitializer (Expression argument
)
12078 : base (null, new Arguments (1))
12080 base.arguments
.Add (new ElementInitializerArgument (argument
));
12081 this.loc
= argument
.Location
;
12084 public CollectionElementInitializer (List
<Expression
> arguments
, Location loc
)
12085 : base (null, new Arguments (arguments
.Count
))
12087 foreach (Expression e
in arguments
)
12088 base.arguments
.Add (new ElementInitializerArgument (e
));
12093 public CollectionElementInitializer (Location loc
)
12094 : base (null, null)
12099 public override Expression
CreateExpressionTree (ResolveContext ec
)
12101 Arguments args
= new Arguments (2);
12102 args
.Add (new Argument (mg
.CreateExpressionTree (ec
)));
12104 var expr_initializers
= new ArrayInitializer (arguments
.Count
, loc
);
12105 foreach (Argument a
in arguments
) {
12106 if (a
.ArgType
== Argument
.AType
.ExtensionType
) {
12107 ec
.Report
.Error (8075, a
.Expr
.Location
, "An expression tree cannot contain a collection initializer with extension method");
12110 expr_initializers
.Add (a
.CreateExpressionTree (ec
));
12113 args
.Add (new Argument (new ArrayCreation (
12114 CreateExpressionTypeExpression (ec
, loc
), expr_initializers
, loc
)));
12115 return CreateExpressionFactoryCall (ec
, "ElementInit", args
);
12118 protected override void CloneTo (CloneContext clonectx
, Expression t
)
12120 CollectionElementInitializer target
= (CollectionElementInitializer
) t
;
12121 if (arguments
!= null)
12122 target
.arguments
= arguments
.Clone (clonectx
);
12125 protected override Expression
DoResolve (ResolveContext ec
)
12127 base.expr
= new AddMemberAccess (ec
.CurrentInitializerVariable
, loc
);
12129 return base.DoResolve (ec
);
12133 class DictionaryElementInitializer
: ElementInitializer
12135 readonly Arguments args
;
12137 public DictionaryElementInitializer (Arguments arguments
, Expression initializer
, Location loc
)
12138 : base (null, initializer
, loc
)
12140 this.args
= arguments
;
12143 public override Expression
CreateExpressionTree (ResolveContext ec
)
12145 ec
.Report
.Error (8074, loc
, "Expression tree cannot contain a dictionary initializer");
12149 protected override bool ResolveElement (ResolveContext rc
)
12151 var init
= rc
.CurrentInitializerVariable
;
12152 var type
= init
.Type
;
12154 if (type
.IsArray
) {
12155 target
= new ArrayAccess (new ElementAccess (init
, args
, loc
), loc
);
12159 if (type
.IsPointer
) {
12160 target
= init
.MakePointerAccess (rc
, type
, args
);
12164 var indexers
= MemberCache
.FindMembers (type
, MemberCache
.IndexerNameAlias
, false);
12165 if (indexers
== null && type
.BuiltinType
!= BuiltinTypeSpec
.Type
.Dynamic
) {
12166 ElementAccess
.Error_CannotApplyIndexing (rc
, type
, loc
);
12170 target
= new IndexerExpr (indexers
, type
, init
, args
, loc
);
12176 // A block of object or collection initializers
12178 public class CollectionOrObjectInitializers
: ExpressionStatement
12180 IList
<Expression
> initializers
;
12181 bool is_collection_initialization
;
12183 public CollectionOrObjectInitializers (Location loc
)
12184 : this (new Expression
[0], loc
)
12188 public CollectionOrObjectInitializers (IList
<Expression
> initializers
, Location loc
)
12190 this.initializers
= initializers
;
12194 public IList
<Expression
> Initializers
{
12196 return initializers
;
12200 public bool IsEmpty
{
12202 return initializers
.Count
== 0;
12206 public bool IsCollectionInitializer
{
12208 return is_collection_initialization
;
12212 protected override void CloneTo (CloneContext clonectx
, Expression target
)
12214 CollectionOrObjectInitializers t
= (CollectionOrObjectInitializers
) target
;
12216 t
.initializers
= new List
<Expression
> (initializers
.Count
);
12217 foreach (var e
in initializers
)
12218 t
.initializers
.Add (e
.Clone (clonectx
));
12221 public override bool ContainsEmitWithAwait ()
12223 foreach (var e
in initializers
) {
12224 if (e
.ContainsEmitWithAwait ())
12231 public override Expression
CreateExpressionTree (ResolveContext ec
)
12233 return CreateExpressionTree (ec
, false);
12236 public Expression
CreateExpressionTree (ResolveContext ec
, bool inferType
)
12238 var expr_initializers
= new ArrayInitializer (initializers
.Count
, loc
);
12239 foreach (Expression e
in initializers
) {
12240 Expression expr
= e
.CreateExpressionTree (ec
);
12242 expr_initializers
.Add (expr
);
12246 return new ImplicitlyTypedArrayCreation (expr_initializers
, loc
);
12248 return new ArrayCreation (new TypeExpression (ec
.Module
.PredefinedTypes
.MemberBinding
.Resolve (), loc
), expr_initializers
, loc
);
12251 protected override Expression
DoResolve (ResolveContext ec
)
12253 List
<string> element_names
= null;
12254 for (int i
= 0; i
< initializers
.Count
; ++i
) {
12255 Expression initializer
= initializers
[i
];
12256 ElementInitializer element_initializer
= initializer
as ElementInitializer
;
12259 if (element_initializer
!= null) {
12260 element_names
= new List
<string> (initializers
.Count
);
12261 if (!element_initializer
.IsDictionaryInitializer
)
12262 element_names
.Add (element_initializer
.Name
);
12263 } else if (initializer
is CompletingExpression
) {
12264 initializer
.Resolve (ec
);
12265 throw new InternalErrorException ("This line should never be reached");
12267 var t
= ec
.CurrentInitializerVariable
.Type
;
12268 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12269 if (!t
.ImplementsInterface (ec
.BuiltinTypes
.IEnumerable
, false) && t
.BuiltinType
!= BuiltinTypeSpec
.Type
.Dynamic
) {
12270 ec
.Report
.Error (1922, loc
, "A field or property `{0}' cannot be initialized with a collection " +
12271 "object initializer because type `{1}' does not implement `{2}' interface",
12272 ec
.CurrentInitializerVariable
.GetSignatureForError (),
12273 ec
.CurrentInitializerVariable
.Type
.GetSignatureForError (),
12274 ec
.BuiltinTypes
.IEnumerable
.GetSignatureForError ());
12277 is_collection_initialization
= true;
12280 if (is_collection_initialization
!= (element_initializer
== null)) {
12281 ec
.Report
.Error (747, initializer
.Location
, "Inconsistent `{0}' member declaration",
12282 is_collection_initialization
? "collection initializer" : "object initializer");
12286 if (!is_collection_initialization
&& !element_initializer
.IsDictionaryInitializer
) {
12287 if (element_names
.Contains (element_initializer
.Name
)) {
12288 ec
.Report
.Error (1912, element_initializer
.Location
,
12289 "An object initializer includes more than one member `{0}' initialization",
12290 element_initializer
.Name
);
12292 element_names
.Add (element_initializer
.Name
);
12297 Expression e
= initializer
.Resolve (ec
);
12298 if (e
== EmptyExpressionStatement
.Instance
)
12299 initializers
.RemoveAt (i
--);
12301 initializers
[i
] = e
;
12304 type
= ec
.CurrentInitializerVariable
.Type
;
12305 if (is_collection_initialization
) {
12306 if (TypeManager
.HasElementType (type
)) {
12307 ec
.Report
.Error (1925, loc
, "Cannot initialize object of type `{0}' with a collection initializer",
12308 type
.GetSignatureForError ());
12312 eclass
= ExprClass
.Variable
;
12316 public override void Emit (EmitContext ec
)
12318 EmitStatement (ec
);
12321 public override void EmitStatement (EmitContext ec
)
12323 foreach (ExpressionStatement e
in initializers
) {
12324 // TODO: need location region
12325 ec
.Mark (e
.Location
);
12326 e
.EmitStatement (ec
);
12330 public override void FlowAnalysis (FlowAnalysisContext fc
)
12332 foreach (var initializer
in initializers
) {
12333 if (initializer
!= null)
12334 initializer
.FlowAnalysis (fc
);
12340 // New expression with element/object initializers
12342 public class NewInitialize
: New
12345 // This class serves as a proxy for variable initializer target instances.
12346 // A real variable is assigned later when we resolve left side of an
12349 sealed class InitializerTargetExpression
: Expression
, IMemoryLocation
12351 NewInitialize new_instance
;
12353 public InitializerTargetExpression (NewInitialize newInstance
)
12355 this.type
= newInstance
.type
;
12356 this.loc
= newInstance
.loc
;
12357 this.eclass
= newInstance
.eclass
;
12358 this.new_instance
= newInstance
;
12361 public override bool ContainsEmitWithAwait ()
12366 public override Expression
CreateExpressionTree (ResolveContext ec
)
12368 // Should not be reached
12369 throw new NotSupportedException ("ET");
12372 protected override Expression
DoResolve (ResolveContext ec
)
12377 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
12382 public override void Emit (EmitContext ec
)
12384 Expression e
= (Expression
) new_instance
.instance
;
12388 public override Expression
EmitToField (EmitContext ec
)
12390 return (Expression
) new_instance
.instance
;
12393 #region IMemoryLocation Members
12395 public void AddressOf (EmitContext ec
, AddressOp mode
)
12397 new_instance
.instance
.AddressOf (ec
, mode
);
12403 CollectionOrObjectInitializers initializers
;
12404 IMemoryLocation instance
;
12405 DynamicExpressionStatement
dynamic;
12407 public NewInitialize (FullNamedExpression requested_type
, Arguments arguments
, CollectionOrObjectInitializers initializers
, Location l
)
12408 : base (requested_type
, arguments
, l
)
12410 this.initializers
= initializers
;
12413 public CollectionOrObjectInitializers Initializers
{
12415 return initializers
;
12419 protected override void CloneTo (CloneContext clonectx
, Expression t
)
12421 base.CloneTo (clonectx
, t
);
12423 NewInitialize target
= (NewInitialize
) t
;
12424 target
.initializers
= (CollectionOrObjectInitializers
) initializers
.Clone (clonectx
);
12427 public override bool ContainsEmitWithAwait ()
12429 return base.ContainsEmitWithAwait () || initializers
.ContainsEmitWithAwait ();
12432 public override Expression
CreateExpressionTree (ResolveContext ec
)
12434 Arguments args
= new Arguments (2);
12435 args
.Add (new Argument (base.CreateExpressionTree (ec
)));
12436 if (!initializers
.IsEmpty
)
12437 args
.Add (new Argument (initializers
.CreateExpressionTree (ec
, initializers
.IsCollectionInitializer
)));
12439 return CreateExpressionFactoryCall (ec
,
12440 initializers
.IsCollectionInitializer
? "ListInit" : "MemberInit",
12444 protected override Expression
DoResolve (ResolveContext rc
)
12446 Expression e
= base.DoResolve (rc
);
12450 if (type
.IsDelegate
) {
12451 rc
.Report
.Error (1958, Initializers
.Location
,
12452 "Object and collection initializers cannot be used to instantiate a delegate");
12455 Expression previous
= rc
.CurrentInitializerVariable
;
12456 rc
.CurrentInitializerVariable
= new InitializerTargetExpression (this);
12457 using (rc
.With (ResolveContext
.Options
.DontSetConditionalAccessReceiver
, false)) {
12458 initializers
.Resolve (rc
);
12460 rc
.CurrentInitializerVariable
= previous
;
12462 dynamic = e
as DynamicExpressionStatement
;
12463 if (dynamic != null)
12469 public override void Emit (EmitContext ec
)
12471 if (!CanEmitOptimizedLocalTarget (ec
)) {
12472 var fe
= ec
.GetTemporaryField (type
);
12474 if (!Emit (ec
, fe
))
12483 public override bool Emit (EmitContext ec
, IMemoryLocation target
)
12486 // Expression is initialized into temporary target then moved
12487 // to real one for atomicity
12489 IMemoryLocation temp_target
= target
;
12491 LocalTemporary temp
= null;
12492 bool by_ref
= false;
12493 if (!initializers
.IsEmpty
) {
12494 temp_target
= target
as LocalTemporary
;
12495 if (temp_target
== null)
12496 temp_target
= target
as StackFieldExpr
;
12498 if (temp_target
== null) {
12499 var vr
= target
as VariableReference
;
12500 if (vr
!= null && vr
.IsRef
) {
12506 if (temp_target
== null)
12507 temp_target
= temp
= new LocalTemporary (type
);
12510 bool left_on_stack
;
12511 if (dynamic != null) {
12513 left_on_stack
= true;
12515 left_on_stack
= base.Emit (ec
, temp_target
);
12518 if (initializers
.IsEmpty
)
12519 return left_on_stack
;
12521 StackFieldExpr sf
= null;
12523 // Move a new instance (reference-type) to local temporary variable
12524 if (left_on_stack
) {
12526 temp_target
= temp
= new LocalTemporary (type
);
12532 if (ec
.HasSet (BuilderContext
.Options
.AsyncBody
) && initializers
.ContainsEmitWithAwait ()) {
12534 throw new NotImplementedException ();
12536 sf
= ec
.GetTemporaryField (type
);
12537 sf
.AutomaticallyReuse
= false;
12538 sf
.EmitAssign (ec
, temp
, false, false);
12541 left_on_stack
= false;
12545 instance
= temp_target
;
12547 initializers
.Emit (ec
);
12549 ((Expression
)temp_target
).Emit (ec
);
12555 sf
.PrepareCleanup (ec
);
12560 public override bool CanEmitOptimizedLocalTarget (EmitContext ec
)
12562 return !(method
== null && TypeSpec
.IsValueType (type
) &&
12563 initializers
.Initializers
.Count
> 1 && ec
.HasSet (BuilderContext
.Options
.AsyncBody
) &&
12564 initializers
.ContainsEmitWithAwait ());
12567 protected override IMemoryLocation
EmitAddressOf (EmitContext ec
, AddressOp Mode
)
12569 instance
= base.EmitAddressOf (ec
, Mode
);
12571 if (!initializers
.IsEmpty
)
12572 initializers
.Emit (ec
);
12577 public override void FlowAnalysis (FlowAnalysisContext fc
)
12579 base.FlowAnalysis (fc
);
12580 initializers
.FlowAnalysis (fc
);
12583 public override object Accept (StructuralVisitor visitor
)
12585 return visitor
.Visit (this);
12589 public class NewAnonymousType
: New
12591 static readonly AnonymousTypeParameter
[] EmptyParameters
= new AnonymousTypeParameter
[0];
12593 List
<AnonymousTypeParameter
> parameters
;
12594 readonly TypeContainer parent
;
12595 AnonymousTypeClass anonymous_type
;
12597 public NewAnonymousType (List
<AnonymousTypeParameter
> parameters
, TypeContainer parent
, Location loc
)
12598 : base (null, null, loc
)
12600 this.parameters
= parameters
;
12601 this.parent
= parent
;
12604 public List
<AnonymousTypeParameter
> Parameters
{
12606 return this.parameters
;
12610 protected override void CloneTo (CloneContext clonectx
, Expression target
)
12612 if (parameters
== null)
12615 NewAnonymousType t
= (NewAnonymousType
) target
;
12616 t
.parameters
= new List
<AnonymousTypeParameter
> (parameters
.Count
);
12617 foreach (AnonymousTypeParameter atp
in parameters
)
12618 t
.parameters
.Add ((AnonymousTypeParameter
) atp
.Clone (clonectx
));
12621 AnonymousTypeClass
CreateAnonymousType (ResolveContext ec
, IList
<AnonymousTypeParameter
> parameters
)
12623 AnonymousTypeClass type
= parent
.Module
.GetAnonymousType (parameters
);
12627 type
= AnonymousTypeClass
.Create (parent
, parameters
, loc
);
12631 int errors
= ec
.Report
.Errors
;
12632 type
.CreateContainer ();
12633 type
.DefineContainer ();
12634 type
.ExpandBaseInterfaces ();
12636 if ((ec
.Report
.Errors
- errors
) == 0) {
12637 parent
.Module
.AddAnonymousType (type
);
12638 type
.PrepareEmit ();
12644 public override Expression
CreateExpressionTree (ResolveContext ec
)
12646 if (parameters
== null)
12647 return base.CreateExpressionTree (ec
);
12649 var init
= new ArrayInitializer (parameters
.Count
, loc
);
12650 foreach (var m
in anonymous_type
.Members
) {
12651 var p
= m
as Property
;
12653 init
.Add (new TypeOfMethod (MemberCache
.GetMember (type
, p
.Get
.Spec
), loc
));
12656 var ctor_args
= new ArrayInitializer (arguments
.Count
, loc
);
12657 foreach (Argument a
in arguments
)
12658 ctor_args
.Add (a
.CreateExpressionTree (ec
));
12660 Arguments args
= new Arguments (3);
12661 args
.Add (new Argument (new TypeOfMethod (method
, loc
)));
12662 args
.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec
, loc
), ctor_args
, loc
)));
12663 args
.Add (new Argument (new ImplicitlyTypedArrayCreation (init
, loc
)));
12665 return CreateExpressionFactoryCall (ec
, "New", args
);
12668 protected override Expression
DoResolve (ResolveContext ec
)
12670 if (ec
.HasSet (ResolveContext
.Options
.ConstantScope
)) {
12671 ec
.Report
.Error (836, loc
, "Anonymous types cannot be used in this expression");
12675 if (parameters
== null) {
12676 anonymous_type
= CreateAnonymousType (ec
, EmptyParameters
);
12677 RequestedType
= new TypeExpression (anonymous_type
.Definition
, loc
);
12678 return base.DoResolve (ec
);
12681 bool error
= false;
12682 arguments
= new Arguments (parameters
.Count
);
12683 var t_args
= new TypeSpec
[parameters
.Count
];
12684 for (int i
= 0; i
< parameters
.Count
; ++i
) {
12685 Expression e
= parameters
[i
].Resolve (ec
);
12691 arguments
.Add (new Argument (e
));
12692 t_args
[i
] = e
.Type
;
12698 anonymous_type
= CreateAnonymousType (ec
, parameters
);
12699 if (anonymous_type
== null)
12702 type
= anonymous_type
.Definition
.MakeGenericType (ec
.Module
, t_args
);
12703 method
= (MethodSpec
) MemberCache
.FindMember (type
, MemberFilter
.Constructor (null), BindingRestriction
.DeclaredOnly
);
12704 eclass
= ExprClass
.Value
;
12708 public override object Accept (StructuralVisitor visitor
)
12710 return visitor
.Visit (this);
12714 public class AnonymousTypeParameter
: ShimExpression
12716 public readonly string Name
;
12718 public AnonymousTypeParameter (Expression initializer
, string name
, Location loc
)
12719 : base (initializer
)
12725 public AnonymousTypeParameter (Parameter parameter
)
12726 : base (new SimpleName (parameter
.Name
, parameter
.Location
))
12728 this.Name
= parameter
.Name
;
12729 this.loc
= parameter
.Location
;
12732 public override bool Equals (object o
)
12734 AnonymousTypeParameter other
= o
as AnonymousTypeParameter
;
12735 return other
!= null && Name
== other
.Name
;
12738 public override int GetHashCode ()
12740 return Name
.GetHashCode ();
12743 protected override Expression
DoResolve (ResolveContext ec
)
12745 Expression e
= expr
.Resolve (ec
);
12749 if (e
.eclass
== ExprClass
.MethodGroup
) {
12750 Error_InvalidInitializer (ec
, e
.ExprClassName
);
12755 if (type
.Kind
== MemberKind
.Void
|| InternalType
.HasNoType (type
) || type
.IsPointer
|| (e
is TupleLiteral
&& TupleLiteral
.ContainsNoTypeElement (type
))) {
12756 Error_InvalidInitializer (ec
, type
.GetSignatureForError ());
12763 protected virtual void Error_InvalidInitializer (ResolveContext ec
, string initializer
)
12765 ec
.Report
.Error (828, loc
, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12766 Name
, initializer
);
12770 public class CatchFilterExpression
: BooleanExpression
12772 public CatchFilterExpression (Expression expr
, Location loc
)
12779 public class InterpolatedString
: Expression
12781 readonly StringLiteral start
, end
;
12782 List
<Expression
> interpolations
;
12783 Arguments arguments
;
12785 public InterpolatedString (StringLiteral start
, List
<Expression
> interpolations
, StringLiteral end
)
12787 this.start
= start
;
12789 this.interpolations
= interpolations
;
12790 loc
= start
.Location
;
12793 protected override void CloneTo (CloneContext clonectx
, Expression t
)
12795 InterpolatedString target
= (InterpolatedString
) t
;
12797 if (interpolations
!= null) {
12798 target
.interpolations
= new List
<Expression
> ();
12799 foreach (var interpolation
in interpolations
) {
12800 target
.interpolations
.Add (interpolation
.Clone (clonectx
));
12805 public Expression
ConvertTo (ResolveContext rc
, TypeSpec type
)
12807 var factory
= rc
.Module
.PredefinedTypes
.FormattableStringFactory
.Resolve ();
12808 if (factory
== null)
12811 var ma
= new MemberAccess (new TypeExpression (factory
, loc
), "Create", loc
);
12812 var res
= new Invocation (ma
, arguments
).Resolve (rc
);
12813 if (res
!= null && res
.Type
!= type
)
12814 res
= Convert
.ExplicitConversion (rc
, res
, type
, loc
);
12819 public override bool ContainsEmitWithAwait ()
12821 if (interpolations
== null)
12824 foreach (var expr
in interpolations
) {
12825 if (expr
.ContainsEmitWithAwait ())
12832 public override Expression
CreateExpressionTree (ResolveContext rc
)
12834 var best
= ResolveBestFormatOverload (rc
);
12838 Expression instance
= new NullLiteral (loc
);
12839 var args
= Arguments
.CreateForExpressionTree (rc
, arguments
, instance
, new TypeOfMethod (best
, loc
));
12840 return CreateExpressionFactoryCall (rc
, "Call", args
);
12843 protected override Expression
DoResolve (ResolveContext rc
)
12847 if (interpolations
== null) {
12849 arguments
= new Arguments (1);
12851 arguments
= new Arguments (interpolations
.Count
);
12853 var sb
= new StringBuilder (start
.Value
);
12854 for (int i
= 0; i
< interpolations
.Count
; ++i
) {
12856 sb
.Append ('{').Append (i
/ 2);
12857 var isi
= (InterpolatedStringInsert
)interpolations
[i
];
12858 if (isi
.Alignment
!= null) {
12860 var value = isi
.ResolveAligment (rc
);
12862 sb
.Append (value.Value
);
12865 if (isi
.Format
!= null) {
12867 sb
.Append (isi
.Format
);
12871 arguments
.Add (new Argument (isi
.Resolve (rc
)));
12873 sb
.Append (((StringLiteral
)interpolations
[i
]).Value
);
12877 sb
.Append (end
.Value
);
12878 str
= sb
.ToString ();
12881 arguments
.Insert (0, new Argument (new StringLiteral (rc
.BuiltinTypes
, str
, start
.Location
)));
12883 eclass
= ExprClass
.Value
;
12884 type
= rc
.BuiltinTypes
.String
;
12888 public override void Emit (EmitContext ec
)
12890 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12891 if (interpolations
== null) {
12892 var str
= start
.Value
.Replace ("{{", "{").Replace ("}}", "}");
12893 if (str
!= start
.Value
)
12894 new StringConstant (ec
.BuiltinTypes
, str
, loc
).Emit (ec
);
12901 var best
= ResolveBestFormatOverload (new ResolveContext (ec
.MemberContext
));
12905 var ca
= new CallEmitter ();
12906 ca
.Emit (ec
, best
, arguments
, loc
);
12909 public override void FlowAnalysis (FlowAnalysisContext fc
)
12911 if (interpolations
!= null) {
12912 foreach (var expr
in interpolations
) {
12913 expr
.FlowAnalysis (fc
);
12918 MethodSpec
ResolveBestFormatOverload (ResolveContext rc
)
12920 var members
= MemberCache
.FindMembers (rc
.BuiltinTypes
.String
, "Format", true);
12921 var res
= new OverloadResolver (members
, OverloadResolver
.Restrictions
.NoBaseMembers
, loc
);
12922 return res
.ResolveMember
<MethodSpec
> (rc
, ref arguments
);
12926 public class InterpolatedStringInsert
: CompositeExpression
12928 public InterpolatedStringInsert (Expression expr
)
12933 public Expression Alignment { get; set; }
12934 public string Format { get; set; }
12936 protected override void CloneTo (CloneContext clonectx
, Expression t
)
12938 var target
= (InterpolatedStringInsert
)t
;
12939 target
.expr
= expr
.Clone (clonectx
);
12940 if (Alignment
!= null)
12941 target
.Alignment
= Alignment
.Clone (clonectx
);
12944 protected override Expression
DoResolve (ResolveContext rc
)
12946 var expr
= base.DoResolve (rc
);
12951 // For better error reporting, assumes the built-in implementation uses object
12954 return Convert
.ImplicitConversionRequired (rc
, expr
, rc
.BuiltinTypes
.Object
, expr
.Location
);
12957 public override void FlowAnalysis (FlowAnalysisContext fc
)
12959 Child
.FlowAnalysis (fc
);
12962 public int? ResolveAligment (ResolveContext rc
)
12964 var c
= Alignment
.ResolveLabelConstant (rc
);
12968 c
= c
.ImplicitConversionRequired (rc
, rc
.BuiltinTypes
.Int
);
12972 var value = (int) c
.GetValueAsLong ();
12973 if (value > 32767 || value < -32767) {
12974 rc
.Report
.Warning (8094, 1, Alignment
.Location
,
12975 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");
12982 class ThrowExpression
: ExpressionStatement
12986 public ThrowExpression (Expression expr
, Location loc
)
12992 protected override void CloneTo (CloneContext clonectx
, Expression t
)
12994 var target
= (ThrowExpression
)t
;
12995 target
.expr
= expr
.Clone (clonectx
);
12998 public override bool ContainsEmitWithAwait ()
13000 return expr
.ContainsEmitWithAwait ();
13003 public override Expression
CreateExpressionTree (ResolveContext rc
)
13005 rc
.Report
.Error (8188, loc
, "An expression tree cannot not contain a throw expression");
13009 protected override Expression
DoResolve (ResolveContext rc
)
13011 expr
= expr
.Resolve (rc
, ResolveFlags
.Type
| ResolveFlags
.VariableOrValue
);
13016 expr
= Throw
.ConvertType (rc
, expr
);
13018 eclass
= ExprClass
.Value
;
13019 type
= InternalType
.ThrowExpr
;
13023 public override void Emit (EmitContext ec
)
13025 EmitStatement (ec
);
13028 public override void EmitStatement (EmitContext ec
)
13032 ec
.Emit (OpCodes
.Throw
);
13035 public override void FlowAnalysis (FlowAnalysisContext fc
)
13037 expr
.FlowAnalysis (fc
);
13040 public override Reachability
MarkReachable (Reachability rc
)
13042 return Reachability
.CreateUnreachable ();
13046 class ReferenceExpression
: CompositeExpression
13048 public ReferenceExpression (Expression expr
, Location loc
)
13054 static bool CanBeByRef (Expression expr
)
13056 if (expr
is IAssignMethod
)
13059 var invocation
= expr
as Invocation
;
13060 if (invocation
?.Type
.Kind
== MemberKind
.ByRef
)
13066 public override Expression
CreateExpressionTree (ResolveContext rc
)
13068 throw new NotSupportedException ("ET");
13071 protected override Expression
DoResolve (ResolveContext rc
)
13073 var res
= expr
.DoResolveLValue (rc
, EmptyExpression
.OutAccess
);
13074 if (res
== null || !CanBeByRef (res
)) {
13075 if (res
?.Type
!= InternalType
.ErrorType
)
13076 rc
.Report
.Error (8156, expr
.Location
, "An expression cannot be used in this context because it may not be returned by reference");
13077 return ErrorExpression
.Instance
;
13081 var type_container
= type
as ReferenceContainer
;
13082 if (type_container
!= null)
13083 type
= type_container
.Element
;
13086 eclass
= ExprClass
.Value
;
13090 public override void Emit (EmitContext ec
)
13092 var ml
= expr
as IMemoryLocation
;
13094 ml
.AddressOf (ec
, AddressOp
.LoadStore
);
13099 public override void Error_ValueCannotBeConverted (ResolveContext rc
, TypeSpec target
, bool expl
)
13101 rc
.Report
.Error (8173, loc
, "The expression must be of type `{0}' because it is being assigned by reference", target
.GetSignatureForError ());
13105 class ByRefDereference
: CompositeExpression
, IMemoryLocation
, IAssignMethod
13108 LocalTemporary temporary
;
13110 private ByRefDereference (Expression expr
)
13115 public static Expression
Create (Expression expr
)
13117 var rc
= expr
.Type
as ReferenceContainer
;
13121 return new ByRefDereference (expr
) {
13126 public void AddressOf (EmitContext ec
, AddressOp mode
)
13131 public override Expression
CreateExpressionTree (ResolveContext rc
)
13133 rc
.Report
.Error (8153, Location
, "An expression tree lambda cannot contain a call to a method, property, or indexer that returns by reference");
13137 public void Emit (EmitContext ec
, bool leave_copy
)
13141 ec
.Emit (OpCodes
.Dup
);
13142 temporary
= new LocalTemporary (type
);
13143 temporary
.Store (ec
);
13147 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool isCompound
)
13149 prepared
= isCompound
;
13154 ec
.Emit (OpCodes
.Dup
);
13158 throw new NotImplementedException ("leave_copy");
13161 ec
.EmitStoreFromPtr (type
);
13163 if (temporary
!= null) {
13164 temporary
.Emit (ec
);
13165 temporary
.Release (ec
);
13169 protected override Expression
DoResolve (ResolveContext rc
)
13171 eclass
= ExprClass
.Variable
;
13175 public override Expression
DoResolveLValue (ResolveContext rc
, Expression right_side
)
13177 if (expr
.ContainsEmitWithAwait ()) {
13178 rc
.Report
.Error (8178, loc
, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
13179 expr
.GetSignatureForError ());
13182 return DoResolve (rc
);
13185 public override void Emit (EmitContext ec
)
13190 ec
.EmitLoadFromPtr (type
);
13193 public override object Accept (StructuralVisitor visitor
)
13195 return visitor
.Visit (this);
13199 class DefaultLiteralExpression
: Expression
13201 public DefaultLiteralExpression (Location loc
)
13206 public override Expression
CreateExpressionTree (ResolveContext ec
)
13208 throw new NotImplementedException ();
13211 protected override Expression
DoResolve (ResolveContext rc
)
13213 type
= InternalType
.DefaultType
;
13214 eclass
= ExprClass
.Value
;
13218 public override void Emit (EmitContext ec
)
13220 throw new NotSupportedException ();
13224 class Discard
: Expression
, IAssignMethod
, IMemoryLocation
13226 public Discard (Location loc
)
13231 public override Expression
CreateExpressionTree (ResolveContext rc
)
13233 rc
.Report
.Error (8207, loc
, "An expression tree cannot contain a discard");
13237 protected override Expression
DoResolve (ResolveContext rc
)
13239 type
= InternalType
.Discard
;
13240 eclass
= ExprClass
.Variable
;
13244 public override Expression
DoResolveLValue (ResolveContext rc
, Expression right_side
)
13246 if (right_side
.Type
== InternalType
.DefaultType
) {
13247 rc
.Report
.Error (8183, loc
, "Cannot infer the type of implicitly-typed discard");
13248 type
= InternalType
.ErrorType
;
13252 if (right_side
.Type
.Kind
== MemberKind
.Void
) {
13253 rc
.Report
.Error (8209, loc
, "Cannot assign void to a discard");
13254 type
= InternalType
.ErrorType
;
13258 if (right_side
!= EmptyExpression
.OutAccess
) {
13259 type
= right_side
.Type
;
13265 public override void Emit (EmitContext ec
)
13267 throw new NotImplementedException ();
13270 public void Emit (EmitContext ec
, bool leave_copy
)
13272 throw new NotImplementedException ();
13275 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool isCompound
)
13280 source
.EmitSideEffect (ec
);
13283 public void AddressOf (EmitContext ec
, AddressOp mode
)
13285 var temp
= ec
.GetTemporaryLocal (type
);
13286 ec
.Emit (OpCodes
.Ldloca
, temp
);
13288 // TODO: Should free it on next statement but don't have mechanism for that yet
13289 // ec.FreeTemporaryLocal (temp, type);