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.
13
using System.Collections.Generic;
15
using SLE = System.Linq.Expressions;
18
using MetaType = IKVM.Reflection.Type;
19
using IKVM.Reflection;
20
using IKVM.Reflection.Emit;
22
using MetaType = System.Type;
23
using System.Reflection;
24
using System.Reflection.Emit;
30
// This is an user operator expression, automatically created during
33
public class UserOperatorCall : Expression {
34
protected readonly Arguments arguments;
35
protected readonly MethodSpec oper;
36
readonly Func<ResolveContext, Expression, Expression> expr_tree;
38
public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
41
this.arguments = args;
42
this.expr_tree = expr_tree;
44
type = oper.ReturnType;
45
eclass = ExprClass.Value;
49
public override Expression CreateExpressionTree (ResolveContext ec)
51
if (expr_tree != null)
52
return expr_tree (ec, new TypeOfMethod (oper, loc));
54
Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
55
new NullLiteral (loc),
56
new TypeOfMethod (oper, loc));
58
return CreateExpressionFactoryCall (ec, "Call", args);
61
protected override void CloneTo (CloneContext context, Expression target)
66
protected override Expression DoResolve (ResolveContext ec)
69
// We are born fully resolved
74
public override void Emit (EmitContext ec)
76
Invocation.EmitCall (ec, null, oper, arguments, loc);
79
public override SLE.Expression MakeExpression (BuilderContext ctx)
82
return base.MakeExpression (ctx);
84
return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
89
public class ParenthesizedExpression : ShimExpression
91
public ParenthesizedExpression (Expression expr)
97
protected override Expression DoResolve (ResolveContext ec)
99
return expr.Resolve (ec);
102
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
104
return expr.DoResolveLValue (ec, right_side);
107
public override object Accept (StructuralVisitor visitor)
109
return visitor.Visit (this);
114
// Unary implements unary expressions.
116
public class Unary : Expression
118
public enum Operator : byte {
119
UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
123
public readonly Operator Oper;
124
public Expression Expr;
125
Expression enum_conversion;
127
public Unary (Operator op, Expression expr, Location loc)
135
// This routine will attempt to simplify the unary expression when the
136
// argument is a constant.
138
Constant TryReduceConstant (ResolveContext ec, Constant e)
140
if (e is EmptyConstantCast)
141
return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
143
if (e is SideEffectConstant) {
144
Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
145
return r == null ? null : new SideEffectConstant (r, e, r.Location);
148
TypeSpec expr_type = e.Type;
151
case Operator.UnaryPlus:
152
// Unary numeric promotions
153
switch (expr_type.BuiltinType) {
154
case BuiltinTypeSpec.Type.Byte:
155
return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
156
case BuiltinTypeSpec.Type.SByte:
157
return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
158
case BuiltinTypeSpec.Type.Short:
159
return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
160
case BuiltinTypeSpec.Type.UShort:
161
return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
162
case BuiltinTypeSpec.Type.Char:
163
return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
165
// Predefined operators
166
case BuiltinTypeSpec.Type.Int:
167
case BuiltinTypeSpec.Type.UInt:
168
case BuiltinTypeSpec.Type.Long:
169
case BuiltinTypeSpec.Type.ULong:
170
case BuiltinTypeSpec.Type.Float:
171
case BuiltinTypeSpec.Type.Double:
172
case BuiltinTypeSpec.Type.Decimal:
178
case Operator.UnaryNegation:
179
// Unary numeric promotions
180
switch (expr_type.BuiltinType) {
181
case BuiltinTypeSpec.Type.Byte:
182
return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
183
case BuiltinTypeSpec.Type.SByte:
184
return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
185
case BuiltinTypeSpec.Type.Short:
186
return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
187
case BuiltinTypeSpec.Type.UShort:
188
return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
189
case BuiltinTypeSpec.Type.Char:
190
return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
192
// Predefined operators
193
case BuiltinTypeSpec.Type.Int:
194
int ivalue = ((IntConstant) e).Value;
195
if (ivalue == int.MinValue) {
196
if (ec.ConstantCheckState) {
197
ConstantFold.Error_CompileTimeOverflow (ec, loc);
202
return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
204
case BuiltinTypeSpec.Type.Long:
205
long lvalue = ((LongConstant) e).Value;
206
if (lvalue == long.MinValue) {
207
if (ec.ConstantCheckState) {
208
ConstantFold.Error_CompileTimeOverflow (ec, loc);
213
return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
215
case BuiltinTypeSpec.Type.UInt:
216
UIntLiteral uil = e as UIntLiteral;
218
if (uil.Value == int.MaxValue + (uint) 1)
219
return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
220
return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
222
return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
225
case BuiltinTypeSpec.Type.ULong:
226
ULongLiteral ull = e as ULongLiteral;
227
if (ull != null && ull.Value == 9223372036854775808)
228
return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
231
case BuiltinTypeSpec.Type.Float:
232
FloatLiteral fl = e as FloatLiteral;
233
// For better error reporting
235
return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
237
return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
239
case BuiltinTypeSpec.Type.Double:
240
DoubleLiteral dl = e as DoubleLiteral;
241
// For better error reporting
243
return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
245
return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
247
case BuiltinTypeSpec.Type.Decimal:
248
return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
253
case Operator.LogicalNot:
254
if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
257
bool b = (bool)e.GetValue ();
258
return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
260
case Operator.OnesComplement:
261
// Unary numeric promotions
262
switch (expr_type.BuiltinType) {
263
case BuiltinTypeSpec.Type.Byte:
264
return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
265
case BuiltinTypeSpec.Type.SByte:
266
return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
267
case BuiltinTypeSpec.Type.Short:
268
return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
269
case BuiltinTypeSpec.Type.UShort:
270
return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
271
case BuiltinTypeSpec.Type.Char:
272
return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
274
// Predefined operators
275
case BuiltinTypeSpec.Type.Int:
276
return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
277
case BuiltinTypeSpec.Type.UInt:
278
return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
279
case BuiltinTypeSpec.Type.Long:
280
return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
281
case BuiltinTypeSpec.Type.ULong:
282
return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
284
if (e is EnumConstant) {
285
e = TryReduceConstant (ec, ((EnumConstant)e).Child);
287
e = new EnumConstant (e, expr_type);
292
throw new Exception ("Can not constant fold: " + Oper.ToString());
295
protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
297
eclass = ExprClass.Value;
299
TypeSpec expr_type = expr.Type;
300
Expression best_expr;
302
TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
305
// Primitive types first
307
if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
308
best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
309
if (best_expr == null)
312
type = best_expr.Type;
318
// E operator ~(E x);
320
if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
321
return ResolveEnumOperator (ec, expr, predefined);
323
return ResolveUserType (ec, expr, predefined);
326
protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
328
TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
329
Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
330
if (best_expr == null)
334
enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (best_expr.Type), underlying_type);
336
return EmptyCast.Create (this, type);
339
public override Expression CreateExpressionTree (ResolveContext ec)
341
return CreateExpressionTree (ec, null);
344
Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
348
case Operator.AddressOf:
349
Error_PointerInsideExpressionTree (ec);
351
case Operator.UnaryNegation:
352
if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
353
method_name = "NegateChecked";
355
method_name = "Negate";
357
case Operator.OnesComplement:
358
case Operator.LogicalNot:
361
case Operator.UnaryPlus:
362
method_name = "UnaryPlus";
365
throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
368
Arguments args = new Arguments (2);
369
args.Add (new Argument (Expr.CreateExpressionTree (ec)));
371
args.Add (new Argument (user_op));
373
return CreateExpressionFactoryCall (ec, method_name, args);
376
public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
378
var predefined_operators = new TypeSpec[(int) Operator.TOP][];
381
// 7.6.1 Unary plus operator
383
predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
384
types.Int, types.UInt,
385
types.Long, types.ULong,
386
types.Float, types.Double,
391
// 7.6.2 Unary minus operator
393
predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
394
types.Int, types.Long,
395
types.Float, types.Double,
400
// 7.6.3 Logical negation operator
402
predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
407
// 7.6.4 Bitwise complement operator
409
predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
410
types.Int, types.UInt,
411
types.Long, types.ULong
414
return predefined_operators;
418
// Unary numeric promotions
420
static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
422
TypeSpec expr_type = expr.Type;
423
if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
424
switch (expr_type.BuiltinType) {
425
case BuiltinTypeSpec.Type.Byte:
426
case BuiltinTypeSpec.Type.SByte:
427
case BuiltinTypeSpec.Type.Short:
428
case BuiltinTypeSpec.Type.UShort:
429
case BuiltinTypeSpec.Type.Char:
430
return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
434
if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
435
return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
440
protected override Expression DoResolve (ResolveContext ec)
442
if (Oper == Operator.AddressOf) {
443
return ResolveAddressOf (ec);
446
Expr = Expr.Resolve (ec);
450
if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
451
Arguments args = new Arguments (1);
452
args.Add (new Argument (Expr));
453
return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
456
if (Expr.Type.IsNullableType)
457
return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
460
// Attempt to use a constant folding operation.
462
Constant cexpr = Expr as Constant;
464
cexpr = TryReduceConstant (ec, cexpr);
469
Expression expr = ResolveOperator (ec, Expr);
471
Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
474
// Reduce unary operator on predefined types
476
if (expr == this && Oper == Operator.UnaryPlus)
482
public override Expression DoResolveLValue (ResolveContext ec, Expression right)
487
public override void Emit (EmitContext ec)
489
EmitOperator (ec, type);
492
protected void EmitOperator (EmitContext ec, TypeSpec type)
495
case Operator.UnaryPlus:
499
case Operator.UnaryNegation:
500
if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
501
ec.Emit (OpCodes.Ldc_I4_0);
502
if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
503
ec.Emit (OpCodes.Conv_U8);
505
ec.Emit (OpCodes.Sub_Ovf);
508
ec.Emit (OpCodes.Neg);
513
case Operator.LogicalNot:
515
ec.Emit (OpCodes.Ldc_I4_0);
516
ec.Emit (OpCodes.Ceq);
519
case Operator.OnesComplement:
521
ec.Emit (OpCodes.Not);
524
case Operator.AddressOf:
525
((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
529
throw new Exception ("This should not happen: Operator = "
534
// Same trick as in Binary expression
536
if (enum_conversion != null)
537
enum_conversion.Emit (ec);
540
public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
542
if (Oper == Operator.LogicalNot)
543
Expr.EmitBranchable (ec, target, !on_true);
545
base.EmitBranchable (ec, target, on_true);
548
public override void EmitSideEffect (EmitContext ec)
550
Expr.EmitSideEffect (ec);
553
public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, TypeSpec t)
555
ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
556
oper, TypeManager.CSharpName (t));
560
// Converts operator to System.Linq.Expressions.ExpressionType enum name
562
string GetOperatorExpressionTypeName ()
565
case Operator.OnesComplement:
566
return "OnesComplement";
567
case Operator.LogicalNot:
569
case Operator.UnaryNegation:
571
case Operator.UnaryPlus:
574
throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
578
static bool IsFloat (TypeSpec t)
580
return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
584
// Returns a stringified representation of the Operator
586
public static string OperName (Operator oper)
589
case Operator.UnaryPlus:
591
case Operator.UnaryNegation:
593
case Operator.LogicalNot:
595
case Operator.OnesComplement:
597
case Operator.AddressOf:
601
throw new NotImplementedException (oper.ToString ());
604
public override SLE.Expression MakeExpression (BuilderContext ctx)
606
var expr = Expr.MakeExpression (ctx);
607
bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
610
case Operator.UnaryNegation:
611
return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
612
case Operator.LogicalNot:
613
return SLE.Expression.Not (expr);
615
case Operator.OnesComplement:
616
return SLE.Expression.OnesComplement (expr);
619
throw new NotImplementedException (Oper.ToString ());
623
Expression ResolveAddressOf (ResolveContext ec)
626
UnsafeError (ec, loc);
628
Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
629
if (Expr == null || Expr.eclass != ExprClass.Variable) {
630
ec.Report.Error (211, loc, "Cannot take the address of the given expression");
634
if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
638
IVariableReference vr = Expr as IVariableReference;
641
VariableInfo vi = vr.VariableInfo;
643
if (vi.LocalInfo != null)
644
vi.LocalInfo.SetIsUsed ();
647
// A variable is considered definitely assigned if you take its address.
652
is_fixed = vr.IsFixed;
653
vr.SetHasAddressTaken ();
656
AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
659
IFixedExpression fe = Expr as IFixedExpression;
660
is_fixed = fe != null && fe.IsFixed;
663
if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
664
ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
667
type = PointerContainer.MakeType (ec.Module, Expr.Type);
668
eclass = ExprClass.Value;
672
Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
674
expr = DoNumericPromotion (rc, Oper, expr);
675
TypeSpec expr_type = expr.Type;
676
foreach (TypeSpec t in predefined) {
684
// Perform user-operator overload resolution
686
protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
688
CSharp.Operator.OpType op_type;
690
case Operator.LogicalNot:
691
op_type = CSharp.Operator.OpType.LogicalNot; break;
692
case Operator.OnesComplement:
693
op_type = CSharp.Operator.OpType.OnesComplement; break;
694
case Operator.UnaryNegation:
695
op_type = CSharp.Operator.OpType.UnaryNegation; break;
696
case Operator.UnaryPlus:
697
op_type = CSharp.Operator.OpType.UnaryPlus; break;
699
throw new InternalErrorException (Oper.ToString ());
702
var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
706
Arguments args = new Arguments (1);
707
args.Add (new Argument (expr));
709
var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
710
var oper = res.ResolveOperator (ec, ref args);
715
Expr = args [0].Expr;
716
return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
720
// Unary user type overload resolution
722
Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
724
Expression best_expr = ResolveUserOperator (ec, expr);
725
if (best_expr != null)
728
foreach (TypeSpec t in predefined) {
729
Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
730
if (oper_expr == null)
733
if (oper_expr == ErrorExpression.Instance)
737
// decimal type is predefined but has user-operators
739
if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
740
oper_expr = ResolveUserType (ec, oper_expr, predefined);
742
oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
744
if (oper_expr == null)
747
if (best_expr == null) {
748
best_expr = oper_expr;
752
int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
754
if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
755
ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
756
OperName (Oper), expr.Type.GetSignatureForError ());
758
Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
765
best_expr = oper_expr;
768
if (best_expr == null)
772
// HACK: Decimal user-operator is included in standard operators
774
if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
778
type = best_expr.Type;
782
protected override void CloneTo (CloneContext clonectx, Expression t)
784
Unary target = (Unary) t;
786
target.Expr = Expr.Clone (clonectx);
789
public override object Accept (StructuralVisitor visitor)
791
return visitor.Visit (this);
797
// Unary operators are turned into Indirection expressions
798
// after semantic analysis (this is so we can take the address
799
// of an indirection).
801
public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
803
LocalTemporary temporary;
806
public Expression Expr {
812
public Indirection (Expression expr, Location l)
818
public override Expression CreateExpressionTree (ResolveContext ec)
820
Error_PointerInsideExpressionTree (ec);
824
protected override void CloneTo (CloneContext clonectx, Expression t)
826
Indirection target = (Indirection) t;
827
target.expr = expr.Clone (clonectx);
830
public override void Emit (EmitContext ec)
835
ec.EmitLoadFromPtr (Type);
838
public void Emit (EmitContext ec, bool leave_copy)
842
ec.Emit (OpCodes.Dup);
843
temporary = new LocalTemporary (expr.Type);
844
temporary.Store (ec);
848
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
850
prepared = prepare_for_load;
854
if (prepare_for_load)
855
ec.Emit (OpCodes.Dup);
859
ec.Emit (OpCodes.Dup);
860
temporary = new LocalTemporary (source.Type);
861
temporary.Store (ec);
864
ec.EmitStoreFromPtr (type);
866
if (temporary != null) {
868
temporary.Release (ec);
872
public void AddressOf (EmitContext ec, AddressOp Mode)
877
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
879
return DoResolve (ec);
882
protected override Expression DoResolve (ResolveContext ec)
884
expr = expr.Resolve (ec);
889
UnsafeError (ec, loc);
891
var pc = expr.Type as PointerContainer;
894
ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
900
if (type.Kind == MemberKind.Void) {
901
Error_VoidPointerOperation (ec);
905
eclass = ExprClass.Variable;
909
public bool IsFixed {
913
public override string ToString ()
915
return "*(" + expr + ")";
918
public override object Accept (StructuralVisitor visitor)
920
return visitor.Visit (this);
925
/// Unary Mutator expressions (pre and post ++ and --)
929
/// UnaryMutator implements ++ and -- expressions. It derives from
930
/// ExpressionStatement becuase the pre/post increment/decrement
931
/// operators can be used in a statement context.
933
/// FIXME: Idea, we could split this up in two classes, one simpler
934
/// for the common case, and one with the extra fields for more complex
935
/// classes (indexers require temporary access; overloaded require method)
938
public class UnaryMutator : ExpressionStatement
940
class DynamicPostMutator : Expression, IAssignMethod
945
public DynamicPostMutator (Expression expr)
948
this.type = expr.Type;
949
this.loc = expr.Location;
952
public override Expression CreateExpressionTree (ResolveContext ec)
954
throw new NotImplementedException ("ET");
957
protected override Expression DoResolve (ResolveContext rc)
959
eclass = expr.eclass;
963
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
965
expr.DoResolveLValue (ec, right_side);
966
return DoResolve (ec);
969
public override void Emit (EmitContext ec)
974
public void Emit (EmitContext ec, bool leave_copy)
976
throw new NotImplementedException ();
980
// Emits target assignment using unmodified source value
982
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
985
// Allocate temporary variable to keep original value before it's modified
987
temp = new LocalTemporary (type);
991
((IAssignMethod) expr).EmitAssign (ec, source, false, prepare_for_load);
1002
public enum Mode : byte {
1009
PreDecrement = IsDecrement,
1010
PostIncrement = IsPost,
1011
PostDecrement = IsPost | IsDecrement
1015
bool is_expr, recurse;
1019
// Holds the real operation
1020
Expression operation;
1022
public Mode UnaryMutatorMode {
1028
public Expression Expr {
1034
public UnaryMutator (Mode m, Expression e, Location loc)
1041
public override Expression CreateExpressionTree (ResolveContext ec)
1043
return new SimpleAssign (this, this).CreateExpressionTree (ec);
1046
public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1049
// Predefined ++ and -- operators exist for the following types:
1050
// sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1052
return new TypeSpec[] {
1068
protected override Expression DoResolve (ResolveContext ec)
1070
expr = expr.Resolve (ec);
1075
if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1077
// Handle postfix unary operators using local
1078
// temporary variable
1080
if ((mode & Mode.IsPost) != 0)
1081
expr = new DynamicPostMutator (expr);
1083
Arguments args = new Arguments (1);
1084
args.Add (new Argument (expr));
1085
return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1088
if (expr.Type.IsNullableType)
1089
return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1091
eclass = ExprClass.Value;
1094
if (expr is RuntimeValueExpression) {
1097
// Use itself at the top of the stack
1098
operation = new EmptyExpression (type);
1102
// The operand of the prefix/postfix increment decrement operators
1103
// should be an expression that is classified as a variable,
1104
// a property access or an indexer access
1106
// TODO: Move to parser, expr is ATypeNameExpression
1107
if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1108
expr = expr.ResolveLValue (ec, expr);
1110
ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1114
// Step 1: Try to find a user operator, it has priority over predefined ones
1116
var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1117
var methods = MemberCache.GetUserOperator (type, user_op, false);
1119
if (methods != null) {
1120
Arguments args = new Arguments (1);
1121
args.Add (new Argument (expr));
1123
var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1124
var method = res.ResolveOperator (ec, ref args);
1128
args[0].Expr = operation;
1129
operation = new UserOperatorCall (method, args, null, loc);
1130
operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1135
// Step 2: Try predefined types
1138
Expression source = null;
1139
bool primitive_type;
1142
// Predefined without user conversion first for speed-up
1144
// Predefined ++ and -- operators exist for the following types:
1145
// sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1147
switch (type.BuiltinType) {
1148
case BuiltinTypeSpec.Type.Byte:
1149
case BuiltinTypeSpec.Type.SByte:
1150
case BuiltinTypeSpec.Type.Short:
1151
case BuiltinTypeSpec.Type.UShort:
1152
case BuiltinTypeSpec.Type.Int:
1153
case BuiltinTypeSpec.Type.UInt:
1154
case BuiltinTypeSpec.Type.Long:
1155
case BuiltinTypeSpec.Type.ULong:
1156
case BuiltinTypeSpec.Type.Char:
1157
case BuiltinTypeSpec.Type.Float:
1158
case BuiltinTypeSpec.Type.Double:
1159
case BuiltinTypeSpec.Type.Decimal:
1161
primitive_type = true;
1164
primitive_type = false;
1166
// ++/-- on pointer variables of all types except void*
1167
if (type.IsPointer) {
1168
if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1169
Error_VoidPointerOperation (ec);
1175
foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1176
source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1178
// LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1179
if (source != null) {
1185
// ++/-- on enum types
1186
if (source == null && type.IsEnum)
1189
if (source == null) {
1190
Unary.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1197
var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1198
var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1199
operation = new Binary (op, source, one, loc);
1200
operation = operation.Resolve (ec);
1201
if (operation == null)
1202
throw new NotImplementedException ("should not be reached");
1204
if (operation.Type != type) {
1206
operation = Convert.ExplicitNumericConversion (ec, operation, type);
1208
operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1214
void EmitCode (EmitContext ec, bool is_expr)
1217
this.is_expr = is_expr;
1218
((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1221
public override void Emit (EmitContext ec)
1224
// We use recurse to allow ourselfs to be the source
1225
// of an assignment. This little hack prevents us from
1226
// having to allocate another expression
1229
((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1231
operation.Emit (ec);
1237
EmitCode (ec, true);
1240
public override void EmitStatement (EmitContext ec)
1242
EmitCode (ec, false);
1246
// Converts operator to System.Linq.Expressions.ExpressionType enum name
1248
string GetOperatorExpressionTypeName ()
1250
return IsDecrement ? "Decrement" : "Increment";
1254
get { return (mode & Mode.IsDecrement) != 0; }
1259
public override SLE.Expression MakeExpression (BuilderContext ctx)
1261
var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1262
var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1263
return SLE.Expression.Assign (target, source);
1267
protected override void CloneTo (CloneContext clonectx, Expression t)
1269
UnaryMutator target = (UnaryMutator) t;
1271
target.expr = expr.Clone (clonectx);
1273
public override object Accept (StructuralVisitor visitor)
1275
return visitor.Visit (this);
1281
/// Base class for the `Is' and `As' classes.
1285
/// FIXME: Split this in two, and we get to save the `Operator' Oper
1288
public abstract class Probe : Expression {
1289
public Expression ProbeType;
1290
protected Expression expr;
1291
protected TypeSpec probe_type_expr;
1293
public Probe (Expression expr, Expression probe_type, Location l)
1295
ProbeType = probe_type;
1300
public Expression Expr {
1306
protected override Expression DoResolve (ResolveContext ec)
1308
probe_type_expr = ProbeType.ResolveAsType (ec);
1309
if (probe_type_expr == null)
1312
expr = expr.Resolve (ec);
1316
if (probe_type_expr.IsStatic) {
1317
ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1321
if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1322
ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1327
if (expr.Type == InternalType.AnonymousMethod) {
1328
ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1336
protected abstract string OperatorName { get; }
1338
protected override void CloneTo (CloneContext clonectx, Expression t)
1340
Probe target = (Probe) t;
1342
target.expr = expr.Clone (clonectx);
1343
target.ProbeType = ProbeType.Clone (clonectx);
1349
/// Implementation of the `is' operator.
1351
public class Is : Probe {
1352
Nullable.Unwrap expr_unwrap;
1354
public Is (Expression expr, Expression probe_type, Location l)
1355
: base (expr, probe_type, l)
1359
public override Expression CreateExpressionTree (ResolveContext ec)
1361
Arguments args = Arguments.CreateForExpressionTree (ec, null,
1362
expr.CreateExpressionTree (ec),
1363
new TypeOf (probe_type_expr, loc));
1365
return CreateExpressionFactoryCall (ec, "TypeIs", args);
1368
public override void Emit (EmitContext ec)
1370
if (expr_unwrap != null) {
1371
expr_unwrap.EmitCheck (ec);
1377
// Only to make verifier happy
1378
if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1379
ec.Emit (OpCodes.Box, expr.Type);
1381
ec.Emit (OpCodes.Isinst, probe_type_expr);
1382
ec.Emit (OpCodes.Ldnull);
1383
ec.Emit (OpCodes.Cgt_Un);
1386
public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1388
if (expr_unwrap != null) {
1389
expr_unwrap.EmitCheck (ec);
1392
ec.Emit (OpCodes.Isinst, probe_type_expr);
1394
ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1397
Expression CreateConstantResult (ResolveContext ec, bool result)
1400
ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1401
TypeManager.CSharpName (probe_type_expr));
1403
ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1404
TypeManager.CSharpName (probe_type_expr));
1406
return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, result, loc), this);
1409
protected override Expression DoResolve (ResolveContext ec)
1411
if (base.DoResolve (ec) == null)
1414
TypeSpec d = expr.Type;
1415
bool d_is_nullable = false;
1418
// If E is a method group or the null literal, or if the type of E is a reference
1419
// type or a nullable type and the value of E is null, the result is false
1421
if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1422
return CreateConstantResult (ec, false);
1424
if (d.IsNullableType) {
1425
var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1426
if (!ut.IsGenericParameter) {
1428
d_is_nullable = true;
1432
type = ec.BuiltinTypes.Bool;
1433
eclass = ExprClass.Value;
1434
TypeSpec t = probe_type_expr;
1435
bool t_is_nullable = false;
1436
if (t.IsNullableType) {
1437
var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1438
if (!ut.IsGenericParameter) {
1440
t_is_nullable = true;
1447
// D and T are the same value types but D can be null
1449
if (d_is_nullable && !t_is_nullable) {
1450
expr_unwrap = Nullable.Unwrap.Create (expr, false);
1455
// The result is true if D and T are the same value types
1457
return CreateConstantResult (ec, true);
1460
var tp = d as TypeParameterSpec;
1462
return ResolveGenericParameter (ec, t, tp);
1465
// An unboxing conversion exists
1467
if (Convert.ExplicitReferenceConversionExists (d, t))
1470
if (TypeManager.IsGenericParameter (t))
1471
return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
1473
if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1474
ec.Report.Warning (1981, 3, loc,
1475
"Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1476
OperatorName, t.GetSignatureForError ());
1479
if (TypeManager.IsGenericParameter (d))
1480
return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1482
if (TypeSpec.IsValueType (d)) {
1483
if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1484
if (d_is_nullable && !t_is_nullable) {
1485
expr_unwrap = Nullable.Unwrap.Create (expr, false);
1489
return CreateConstantResult (ec, true);
1492
// if (InflatedTypeSpec.ContainsTypeParameter (d))
1495
if (Convert.ImplicitReferenceConversionExists (d, t) ||
1496
Convert.ExplicitReferenceConversionExists (d, t)) {
1502
return CreateConstantResult (ec, false);
1505
Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1507
if (t.IsReferenceType) {
1509
return CreateConstantResult (ec, false);
1512
if (TypeManager.IsGenericParameter (expr.Type)) {
1513
if (expr.Type == d && TypeSpec.IsValueType (t))
1514
return CreateConstantResult (ec, true);
1516
expr = new BoxedCast (expr, d);
1522
protected override string OperatorName {
1523
get { return "is"; }
1526
public override object Accept (StructuralVisitor visitor)
1528
return visitor.Visit (this);
1533
/// Implementation of the `as' operator.
1535
public class As : Probe {
1536
Expression resolved_type;
1538
public As (Expression expr, Expression probe_type, Location l)
1539
: base (expr, probe_type, l)
1543
public override Expression CreateExpressionTree (ResolveContext ec)
1545
Arguments args = Arguments.CreateForExpressionTree (ec, null,
1546
expr.CreateExpressionTree (ec),
1547
new TypeOf (probe_type_expr, loc));
1549
return CreateExpressionFactoryCall (ec, "TypeAs", args);
1552
public override void Emit (EmitContext ec)
1556
ec.Emit (OpCodes.Isinst, type);
1558
if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
1559
ec.Emit (OpCodes.Unbox_Any, type);
1562
protected override Expression DoResolve (ResolveContext ec)
1564
if (resolved_type == null) {
1565
resolved_type = base.DoResolve (ec);
1567
if (resolved_type == null)
1571
type = probe_type_expr;
1572
eclass = ExprClass.Value;
1573
TypeSpec etype = expr.Type;
1575
if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
1576
if (TypeManager.IsGenericParameter (type)) {
1577
ec.Report.Error (413, loc,
1578
"The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1579
probe_type_expr.GetSignatureForError ());
1581
ec.Report.Error (77, loc,
1582
"The `as' operator cannot be used with a non-nullable value type `{0}'",
1583
TypeManager.CSharpName (type));
1588
if (expr.IsNull && type.IsNullableType) {
1589
return Nullable.LiftedNull.CreateFromExpression (ec, this);
1592
// If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
1593
if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1597
Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
1599
e = EmptyCast.Create (e, type);
1600
return ReducedExpression.Create (e, this).Resolve (ec);
1603
if (Convert.ExplicitReferenceConversionExists (etype, type)){
1604
if (TypeManager.IsGenericParameter (etype))
1605
expr = new BoxedCast (expr, etype);
1610
if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
1611
expr = new BoxedCast (expr, etype);
1615
ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1616
TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1621
protected override string OperatorName {
1622
get { return "as"; }
1624
public override object Accept (StructuralVisitor visitor)
1626
return visitor.Visit (this);
1632
// This represents a typecast in the source language.
1634
public class Cast : ShimExpression {
1635
Expression target_type;
1637
public Cast (Expression cast_type, Expression expr, Location loc)
1640
this.target_type = cast_type;
1644
public Expression TargetType {
1645
get { return target_type; }
1648
protected override Expression DoResolve (ResolveContext ec)
1650
expr = expr.Resolve (ec);
1654
type = target_type.ResolveAsType (ec);
1658
if (type.IsStatic) {
1659
ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1663
eclass = ExprClass.Value;
1665
Constant c = expr as Constant;
1667
c = c.TryReduce (ec, type, loc);
1672
if (type.IsPointer && !ec.IsUnsafe) {
1673
UnsafeError (ec, loc);
1676
var res = Convert.ExplicitConversion (ec, expr, type, loc);
1678
return EmptyCast.Create (res, type);
1683
protected override void CloneTo (CloneContext clonectx, Expression t)
1685
Cast target = (Cast) t;
1687
target.target_type = target_type.Clone (clonectx);
1688
target.expr = expr.Clone (clonectx);
1691
public override object Accept (StructuralVisitor visitor)
1693
return visitor.Visit (this);
1697
public class ImplicitCast : ShimExpression
1701
public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
1704
this.loc = expr.Location;
1706
this.arrayAccess = arrayAccess;
1709
protected override Expression DoResolve (ResolveContext ec)
1711
expr = expr.Resolve (ec);
1716
expr = ConvertExpressionToArrayIndex (ec, expr);
1718
expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1725
// C# 2.0 Default value expression
1727
public class DefaultValueExpression : Expression
1732
public Expression Expr {
1738
public DefaultValueExpression (Expression expr, Location loc)
1744
public override Expression CreateExpressionTree (ResolveContext ec)
1746
Arguments args = new Arguments (2);
1747
args.Add (new Argument (this));
1748
args.Add (new Argument (new TypeOf (type, loc)));
1749
return CreateExpressionFactoryCall (ec, "Constant", args);
1752
protected override Expression DoResolve (ResolveContext ec)
1754
type = expr.ResolveAsType (ec);
1758
if (type.IsStatic) {
1759
ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1763
return new NullLiteral (Location).ConvertImplicitly (type);
1765
if (TypeSpec.IsReferenceType (type))
1766
return new NullConstant (type, loc);
1768
Constant c = New.Constantify (type, expr.Location);
1772
eclass = ExprClass.Variable;
1776
public override void Emit (EmitContext ec)
1778
LocalTemporary temp_storage = new LocalTemporary(type);
1780
temp_storage.AddressOf(ec, AddressOp.LoadStore);
1781
ec.Emit(OpCodes.Initobj, type);
1782
temp_storage.Emit(ec);
1785
#if NET_4_0 && !STATIC
1786
public override SLE.Expression MakeExpression (BuilderContext ctx)
1788
return SLE.Expression.Default (type.GetMetaInfo ());
1792
protected override void CloneTo (CloneContext clonectx, Expression t)
1794
DefaultValueExpression target = (DefaultValueExpression) t;
1796
target.expr = expr.Clone (clonectx);
1799
public override object Accept (StructuralVisitor visitor)
1801
return visitor.Visit (this);
1806
/// Binary operators
1808
public class Binary : Expression, IDynamicBinder
1810
public class PredefinedOperator
1812
protected readonly TypeSpec left;
1813
protected readonly TypeSpec right;
1814
public readonly Operator OperatorsMask;
1815
public TypeSpec ReturnType;
1817
public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1818
: this (ltype, rtype, op_mask, ltype)
1822
public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
1823
: this (type, type, op_mask, return_type)
1827
public PredefinedOperator (TypeSpec type, Operator op_mask)
1828
: this (type, type, op_mask, type)
1832
public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
1834
if ((op_mask & Operator.ValuesOnlyMask) != 0)
1835
throw new InternalErrorException ("Only masked values can be used");
1839
this.OperatorsMask = op_mask;
1840
this.ReturnType = return_type;
1843
public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1845
b.type = ReturnType;
1847
b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1848
b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1851
// A user operators does not support multiple user conversions, but decimal type
1852
// is considered to be predefined type therefore we apply predefined operators rules
1853
// and then look for decimal user-operator implementation
1855
if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal)
1856
return b.ResolveUserOperator (ec, b.left, b.right);
1858
var c = b.right as Constant;
1860
if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1861
return ReducedExpression.Create (b.left, b).Resolve (ec);
1862
if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1863
return ReducedExpression.Create (b.left, b).Resolve (ec);
1867
c = b.left as Constant;
1869
if (c.IsDefaultValue && (b.oper == Operator.Addition || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
1870
return ReducedExpression.Create (b.right, b).Resolve (ec);
1871
if (b.oper == Operator.Multiply && c.IsOneInteger)
1872
return ReducedExpression.Create (b.right, b).Resolve (ec);
1879
public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
1882
// We are dealing with primitive types only
1884
return left == ltype && ltype == rtype;
1887
public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1890
if (left == lexpr.Type && right == rexpr.Type)
1893
return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1894
Convert.ImplicitConversionExists (ec, rexpr, right);
1897
public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1900
if (left != null && best_operator.left != null) {
1901
result = OverloadResolver.BetterTypeConversion (ec, best_operator.left, left);
1905
// When second argument is same as the first one, the result is same
1907
if (right != null && (left != right || best_operator.left != best_operator.right)) {
1908
result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right, right);
1911
if (result == 0 || result > 2)
1914
return result == 1 ? best_operator : this;
1918
sealed class PredefinedStringOperator : PredefinedOperator
1920
public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
1921
: base (type, type, op_mask, retType)
1925
public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
1926
: base (ltype, rtype, op_mask, retType)
1930
public override Expression ConvertResult (ResolveContext ec, Binary b)
1933
// Use original expression for nullable arguments
1935
Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1937
b.left = unwrap.Original;
1939
unwrap = b.right as Nullable.Unwrap;
1941
b.right = unwrap.Original;
1943
b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1944
b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1947
// Start a new concat expression using converted expression
1949
return StringConcat.Create (ec, b.left, b.right, b.loc);
1953
sealed class PredefinedShiftOperator : PredefinedOperator
1955
public PredefinedShiftOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
1956
: base (ltype, rtype, op_mask)
1960
public override Expression ConvertResult (ResolveContext ec, Binary b)
1962
b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1964
Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1966
int right_mask = left.BuiltinType == BuiltinTypeSpec.Type.Int || left.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
1969
// b = b.left >> b.right & (0x1f|0x3f)
1971
b.right = new Binary (Operator.BitwiseAnd,
1972
b.right, new IntConstant (ec.BuiltinTypes, right_mask, b.right.Location), b.loc).Resolve (ec);
1975
// Expression tree representation does not use & mask
1977
b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1978
b.type = ReturnType;
1981
// Optimize shift by 0
1983
var c = b.right as Constant;
1984
if (c != null && c.IsDefaultValue)
1985
return ReducedExpression.Create (b.left, b).Resolve (ec);
1991
sealed class PredefinedEqualityOperator : PredefinedOperator
1993
MethodSpec equal_method, inequal_method;
1995
public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
1996
: base (arg, arg, Operator.EqualityMask, retType)
2000
public override Expression ConvertResult (ResolveContext ec, Binary b)
2002
b.type = ReturnType;
2004
b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2005
b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2007
Arguments args = new Arguments (2);
2008
args.Add (new Argument (b.left));
2009
args.Add (new Argument (b.right));
2012
if (b.oper == Operator.Equality) {
2013
if (equal_method == null) {
2014
if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2015
equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
2016
else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2017
equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
2019
throw new NotImplementedException (left.GetSignatureForError ());
2022
method = equal_method;
2024
if (inequal_method == null) {
2025
if (left.BuiltinType == BuiltinTypeSpec.Type.String)
2026
inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
2027
else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
2028
inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
2030
throw new NotImplementedException (left.GetSignatureForError ());
2033
method = inequal_method;
2036
return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
2040
class PredefinedPointerOperator : PredefinedOperator
2042
public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2043
: base (ltype, rtype, op_mask)
2047
public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2048
: base (ltype, rtype, op_mask, retType)
2052
public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2053
: base (type, op_mask, return_type)
2057
public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2060
if (!lexpr.Type.IsPointer)
2063
if (!Convert.ImplicitConversionExists (ec, lexpr, left))
2067
if (right == null) {
2068
if (!rexpr.Type.IsPointer)
2071
if (!Convert.ImplicitConversionExists (ec, rexpr, right))
2078
public override Expression ConvertResult (ResolveContext ec, Binary b)
2081
b.left = EmptyCast.Create (b.left, left);
2082
} else if (right != null) {
2083
b.right = EmptyCast.Create (b.right, right);
2086
TypeSpec r_type = ReturnType;
2087
Expression left_arg, right_arg;
2088
if (r_type == null) {
2091
right_arg = b.right;
2092
r_type = b.left.Type;
2096
r_type = b.right.Type;
2100
right_arg = b.right;
2103
return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
2108
public enum Operator {
2109
Multiply = 0 | ArithmeticMask,
2110
Division = 1 | ArithmeticMask,
2111
Modulus = 2 | ArithmeticMask,
2112
Addition = 3 | ArithmeticMask | AdditionMask,
2113
Subtraction = 4 | ArithmeticMask | SubtractionMask,
2115
LeftShift = 5 | ShiftMask,
2116
RightShift = 6 | ShiftMask,
2118
LessThan = 7 | ComparisonMask | RelationalMask,
2119
GreaterThan = 8 | ComparisonMask | RelationalMask,
2120
LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
2121
GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
2122
Equality = 11 | ComparisonMask | EqualityMask,
2123
Inequality = 12 | ComparisonMask | EqualityMask,
2125
BitwiseAnd = 13 | BitwiseMask,
2126
ExclusiveOr = 14 | BitwiseMask,
2127
BitwiseOr = 15 | BitwiseMask,
2129
LogicalAnd = 16 | LogicalMask,
2130
LogicalOr = 17 | LogicalMask,
2135
ValuesOnlyMask = ArithmeticMask - 1,
2136
ArithmeticMask = 1 << 5,
2138
ComparisonMask = 1 << 7,
2139
EqualityMask = 1 << 8,
2140
BitwiseMask = 1 << 9,
2141
LogicalMask = 1 << 10,
2142
AdditionMask = 1 << 11,
2143
SubtractionMask = 1 << 12,
2144
RelationalMask = 1 << 13
2147
protected enum State
2151
LeftNullLifted = 1 << 2,
2152
RightNullLifted = 1 << 3
2155
readonly Operator oper;
2156
protected Expression left, right;
2157
protected State state;
2158
Expression enum_conversion;
2160
public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
2161
: this (oper, left, right, loc)
2164
state |= State.Compound;
2167
public Binary (Operator oper, Expression left, Expression right, Location loc)
2177
public bool IsCompound {
2179
return (state & State.Compound) != 0;
2183
public Operator Oper {
2189
public Expression Left {
2190
get { return this.left; }
2193
public Expression Right {
2194
get { return this.right; }
2200
/// Returns a stringified representation of the Operator
2202
string OperName (Operator oper)
2206
case Operator.Multiply:
2209
case Operator.Division:
2212
case Operator.Modulus:
2215
case Operator.Addition:
2218
case Operator.Subtraction:
2221
case Operator.LeftShift:
2224
case Operator.RightShift:
2227
case Operator.LessThan:
2230
case Operator.GreaterThan:
2233
case Operator.LessThanOrEqual:
2236
case Operator.GreaterThanOrEqual:
2239
case Operator.Equality:
2242
case Operator.Inequality:
2245
case Operator.BitwiseAnd:
2248
case Operator.BitwiseOr:
2251
case Operator.ExclusiveOr:
2254
case Operator.LogicalOr:
2257
case Operator.LogicalAnd:
2261
s = oper.ToString ();
2271
public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2273
new Binary (oper, left, right, loc).Error_OperatorCannotBeApplied (ec, left, right);
2276
public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2278
if (left.Type == InternalType.FakeInternalType || right.Type == InternalType.FakeInternalType)
2282
l = TypeManager.CSharpName (left.Type);
2283
r = TypeManager.CSharpName (right.Type);
2285
ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2289
protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2291
Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2295
// Converts operator to System.Linq.Expressions.ExpressionType enum name
2297
string GetOperatorExpressionTypeName ()
2300
case Operator.Addition:
2301
return IsCompound ? "AddAssign" : "Add";
2302
case Operator.BitwiseAnd:
2303
return IsCompound ? "AndAssign" : "And";
2304
case Operator.BitwiseOr:
2305
return IsCompound ? "OrAssign" : "Or";
2306
case Operator.Division:
2307
return IsCompound ? "DivideAssign" : "Divide";
2308
case Operator.ExclusiveOr:
2309
return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
2310
case Operator.Equality:
2312
case Operator.GreaterThan:
2313
return "GreaterThan";
2314
case Operator.GreaterThanOrEqual:
2315
return "GreaterThanOrEqual";
2316
case Operator.Inequality:
2318
case Operator.LeftShift:
2319
return IsCompound ? "LeftShiftAssign" : "LeftShift";
2320
case Operator.LessThan:
2322
case Operator.LessThanOrEqual:
2323
return "LessThanOrEqual";
2324
case Operator.LogicalAnd:
2326
case Operator.LogicalOr:
2328
case Operator.Modulus:
2329
return IsCompound ? "ModuloAssign" : "Modulo";
2330
case Operator.Multiply:
2331
return IsCompound ? "MultiplyAssign" : "Multiply";
2332
case Operator.RightShift:
2333
return IsCompound ? "RightShiftAssign" : "RightShift";
2334
case Operator.Subtraction:
2335
return IsCompound ? "SubtractAssign" : "Subtract";
2337
throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2341
static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
2344
case Operator.Addition:
2345
return CSharp.Operator.OpType.Addition;
2346
case Operator.BitwiseAnd:
2347
case Operator.LogicalAnd:
2348
return CSharp.Operator.OpType.BitwiseAnd;
2349
case Operator.BitwiseOr:
2350
case Operator.LogicalOr:
2351
return CSharp.Operator.OpType.BitwiseOr;
2352
case Operator.Division:
2353
return CSharp.Operator.OpType.Division;
2354
case Operator.Equality:
2355
return CSharp.Operator.OpType.Equality;
2356
case Operator.ExclusiveOr:
2357
return CSharp.Operator.OpType.ExclusiveOr;
2358
case Operator.GreaterThan:
2359
return CSharp.Operator.OpType.GreaterThan;
2360
case Operator.GreaterThanOrEqual:
2361
return CSharp.Operator.OpType.GreaterThanOrEqual;
2362
case Operator.Inequality:
2363
return CSharp.Operator.OpType.Inequality;
2364
case Operator.LeftShift:
2365
return CSharp.Operator.OpType.LeftShift;
2366
case Operator.LessThan:
2367
return CSharp.Operator.OpType.LessThan;
2368
case Operator.LessThanOrEqual:
2369
return CSharp.Operator.OpType.LessThanOrEqual;
2370
case Operator.Modulus:
2371
return CSharp.Operator.OpType.Modulus;
2372
case Operator.Multiply:
2373
return CSharp.Operator.OpType.Multiply;
2374
case Operator.RightShift:
2375
return CSharp.Operator.OpType.RightShift;
2376
case Operator.Subtraction:
2377
return CSharp.Operator.OpType.Subtraction;
2379
throw new InternalErrorException (op.ToString ());
2383
public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
2388
case Operator.Multiply:
2389
if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2390
if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2391
opcode = OpCodes.Mul_Ovf;
2392
else if (!IsFloat (l))
2393
opcode = OpCodes.Mul_Ovf_Un;
2395
opcode = OpCodes.Mul;
2397
opcode = OpCodes.Mul;
2401
case Operator.Division:
2403
opcode = OpCodes.Div_Un;
2405
opcode = OpCodes.Div;
2408
case Operator.Modulus:
2410
opcode = OpCodes.Rem_Un;
2412
opcode = OpCodes.Rem;
2415
case Operator.Addition:
2416
if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2417
if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2418
opcode = OpCodes.Add_Ovf;
2419
else if (!IsFloat (l))
2420
opcode = OpCodes.Add_Ovf_Un;
2422
opcode = OpCodes.Add;
2424
opcode = OpCodes.Add;
2427
case Operator.Subtraction:
2428
if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2429
if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
2430
opcode = OpCodes.Sub_Ovf;
2431
else if (!IsFloat (l))
2432
opcode = OpCodes.Sub_Ovf_Un;
2434
opcode = OpCodes.Sub;
2436
opcode = OpCodes.Sub;
2439
case Operator.RightShift:
2441
opcode = OpCodes.Shr_Un;
2443
opcode = OpCodes.Shr;
2446
case Operator.LeftShift:
2447
opcode = OpCodes.Shl;
2450
case Operator.Equality:
2451
opcode = OpCodes.Ceq;
2454
case Operator.Inequality:
2455
ec.Emit (OpCodes.Ceq);
2456
ec.Emit (OpCodes.Ldc_I4_0);
2458
opcode = OpCodes.Ceq;
2461
case Operator.LessThan:
2463
opcode = OpCodes.Clt_Un;
2465
opcode = OpCodes.Clt;
2468
case Operator.GreaterThan:
2470
opcode = OpCodes.Cgt_Un;
2472
opcode = OpCodes.Cgt;
2475
case Operator.LessThanOrEqual:
2476
if (IsUnsigned (l) || IsFloat (l))
2477
ec.Emit (OpCodes.Cgt_Un);
2479
ec.Emit (OpCodes.Cgt);
2480
ec.Emit (OpCodes.Ldc_I4_0);
2482
opcode = OpCodes.Ceq;
2485
case Operator.GreaterThanOrEqual:
2486
if (IsUnsigned (l) || IsFloat (l))
2487
ec.Emit (OpCodes.Clt_Un);
2489
ec.Emit (OpCodes.Clt);
2491
ec.Emit (OpCodes.Ldc_I4_0);
2493
opcode = OpCodes.Ceq;
2496
case Operator.BitwiseOr:
2497
opcode = OpCodes.Or;
2500
case Operator.BitwiseAnd:
2501
opcode = OpCodes.And;
2504
case Operator.ExclusiveOr:
2505
opcode = OpCodes.Xor;
2509
throw new InternalErrorException (oper.ToString ());
2515
static bool IsUnsigned (TypeSpec t)
2517
switch (t.BuiltinType) {
2518
case BuiltinTypeSpec.Type.Char:
2519
case BuiltinTypeSpec.Type.UInt:
2520
case BuiltinTypeSpec.Type.ULong:
2521
case BuiltinTypeSpec.Type.UShort:
2522
case BuiltinTypeSpec.Type.Byte:
2529
static bool IsFloat (TypeSpec t)
2531
return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
2534
Expression ResolveOperator (ResolveContext ec)
2536
TypeSpec l = left.Type;
2537
TypeSpec r = right.Type;
2539
bool primitives_only = false;
2542
// Handles predefined primitive types
2544
if (BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r)) {
2545
if ((oper & Operator.ShiftMask) == 0) {
2546
if (l.BuiltinType != BuiltinTypeSpec.Type.Bool && !DoBinaryOperatorPromotion (ec))
2549
primitives_only = true;
2553
if (l.IsPointer || r.IsPointer)
2554
return ResolveOperatorPointer (ec, l, r);
2557
bool lenum = l.IsEnum;
2558
bool renum = r.IsEnum;
2559
if (lenum || renum) {
2560
expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2567
if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
2569
expr = ResolveOperatorDelegate (ec, l, r);
2571
// TODO: Can this be ambiguous
2577
expr = ResolveUserOperator (ec, left, right);
2581
// Predefined reference types equality
2582
if ((oper & Operator.EqualityMask) != 0) {
2583
expr = ResolveOperatorEquality (ec, l, r);
2589
return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, primitives_only, null);
2592
// at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2593
// if 'left' is not an enumeration constant, create one from the type of 'right'
2594
Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2597
case Operator.BitwiseOr:
2598
case Operator.BitwiseAnd:
2599
case Operator.ExclusiveOr:
2600
case Operator.Equality:
2601
case Operator.Inequality:
2602
case Operator.LessThan:
2603
case Operator.LessThanOrEqual:
2604
case Operator.GreaterThan:
2605
case Operator.GreaterThanOrEqual:
2606
if (TypeManager.IsEnumType (left.Type))
2609
if (left.IsZeroInteger)
2610
return left.TryReduce (ec, right.Type, loc);
2614
case Operator.Addition:
2615
case Operator.Subtraction:
2618
case Operator.Multiply:
2619
case Operator.Division:
2620
case Operator.Modulus:
2621
case Operator.LeftShift:
2622
case Operator.RightShift:
2623
if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2632
// The `|' operator used on types which were extended is dangerous
2634
void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2636
OpcodeCast lcast = left as OpcodeCast;
2637
if (lcast != null) {
2638
if (IsUnsigned (lcast.UnderlyingType))
2642
OpcodeCast rcast = right as OpcodeCast;
2643
if (rcast != null) {
2644
if (IsUnsigned (rcast.UnderlyingType))
2648
if (lcast == null && rcast == null)
2651
// FIXME: consider constants
2653
ec.Report.Warning (675, 3, loc,
2654
"The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2655
TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2658
public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
2660
return new PredefinedOperator[] {
2662
// Pointer arithmetic:
2664
// T* operator + (T* x, int y); T* operator - (T* x, int y);
2665
// T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2666
// T* operator + (T* x, long y); T* operator - (T* x, long y);
2667
// T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2669
new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
2670
new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
2671
new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
2672
new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
2675
// T* operator + (int y, T* x);
2676
// T* operator + (uint y, T *x);
2677
// T* operator + (long y, T *x);
2678
// T* operator + (ulong y, T *x);
2680
new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
2681
new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
2682
new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
2683
new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
2686
// long operator - (T* x, T *y)
2688
new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
2692
public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
2694
TypeSpec bool_type = types.Bool;
2695
return new PredefinedOperator[] {
2696
new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask),
2697
new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
2698
new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
2699
new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
2700
new PredefinedOperator (types.Float, Operator.ArithmeticMask),
2701
new PredefinedOperator (types.Double, Operator.ArithmeticMask),
2702
new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
2704
new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
2705
new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
2706
new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
2707
new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
2708
new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
2709
new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
2710
new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
2712
new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
2713
new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
2714
new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
2716
new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
2718
new PredefinedShiftOperator (types.Int, types.Int, Operator.ShiftMask),
2719
new PredefinedShiftOperator (types.UInt, types.Int, Operator.ShiftMask),
2720
new PredefinedShiftOperator (types.Long, types.Int, Operator.ShiftMask),
2721
new PredefinedShiftOperator (types.ULong, types.Int, Operator.ShiftMask)
2725
public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
2727
TypeSpec bool_type = types.Bool;
2729
return new PredefinedOperator[] {
2730
new PredefinedEqualityOperator (types.String, bool_type),
2731
new PredefinedEqualityOperator (types.Delegate, bool_type),
2732
new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
2737
// Rules used during binary numeric promotion
2739
static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, TypeSpec type)
2743
Constant c = prim_expr as Constant;
2745
temp = c.ConvertImplicitly (type);
2752
if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
2753
switch (prim_expr.Type.BuiltinType) {
2754
case BuiltinTypeSpec.Type.Int:
2755
case BuiltinTypeSpec.Type.Short:
2756
case BuiltinTypeSpec.Type.SByte:
2757
case BuiltinTypeSpec.Type.Long:
2758
type = rc.BuiltinTypes.Long;
2760
if (type != second_expr.Type) {
2761
c = second_expr as Constant;
2763
temp = c.ConvertImplicitly (type);
2765
temp = Convert.ImplicitNumericConversion (second_expr, type);
2772
} else if (type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
2774
// A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2776
switch (type.BuiltinType) {
2777
case BuiltinTypeSpec.Type.Int:
2778
case BuiltinTypeSpec.Type.Long:
2779
case BuiltinTypeSpec.Type.Short:
2780
case BuiltinTypeSpec.Type.SByte:
2785
temp = Convert.ImplicitNumericConversion (prim_expr, type);
2794
// 7.2.6.2 Binary numeric promotions
2796
public bool DoBinaryOperatorPromotion (ResolveContext ec)
2798
TypeSpec ltype = left.Type;
2799
TypeSpec rtype = right.Type;
2802
foreach (TypeSpec t in ec.BuiltinTypes.BinaryPromotionsTypes) {
2804
return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2807
return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2810
TypeSpec int32 = ec.BuiltinTypes.Int;
2811
if (ltype != int32) {
2812
Constant c = left as Constant;
2814
temp = c.ConvertImplicitly (int32);
2816
temp = Convert.ImplicitNumericConversion (left, int32);
2823
if (rtype != int32) {
2824
Constant c = right as Constant;
2826
temp = c.ConvertImplicitly (int32);
2828
temp = Convert.ImplicitNumericConversion (right, int32);
2838
protected override Expression DoResolve (ResolveContext ec)
2843
if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2844
left = ((ParenthesizedExpression) left).Expr;
2845
left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2849
if (left.eclass == ExprClass.Type) {
2850
ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2854
left = left.Resolve (ec);
2859
Constant lc = left as Constant;
2861
if (lc != null && lc.Type.BuiltinType == BuiltinTypeSpec.Type.Bool &&
2862
((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2863
(oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2865
// FIXME: resolve right expression as unreachable
2866
// right.Resolve (ec);
2868
ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2872
right = right.Resolve (ec);
2876
eclass = ExprClass.Value;
2877
Constant rc = right as Constant;
2879
// The conversion rules are ignored in enum context but why
2880
if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2881
lc = EnumLiftUp (ec, lc, rc, loc);
2883
rc = EnumLiftUp (ec, rc, lc, loc);
2886
if (rc != null && lc != null) {
2887
int prev_e = ec.Report.Errors;
2888
Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2889
if (e != null || ec.Report.Errors != prev_e)
2893
// Comparison warnings
2894
if ((oper & Operator.ComparisonMask) != 0) {
2895
if (left.Equals (right)) {
2896
ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2898
CheckOutOfRangeComparison (ec, lc, right.Type);
2899
CheckOutOfRangeComparison (ec, rc, left.Type);
2902
if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2904
var rt = right.Type;
2905
if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
2906
rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
2907
Error_OperatorCannotBeApplied (ec, left, right);
2914
// Special handling for logical boolean operators which require rhs not to be
2915
// evaluated based on lhs value
2917
if ((oper & Operator.LogicalMask) != 0) {
2918
Expression cond_left, cond_right, expr;
2920
args = new Arguments (2);
2922
if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2923
LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, ec.CurrentBlock, loc);
2925
var cond_args = new Arguments (1);
2926
cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left).Resolve (ec)));
2929
// dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
2930
// dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
2932
left = temp.CreateReferenceExpression (ec, loc);
2933
if (oper == Operator.LogicalAnd) {
2934
expr = DynamicUnaryConversion.CreateIsFalse (ec, cond_args, loc);
2937
expr = DynamicUnaryConversion.CreateIsTrue (ec, cond_args, loc);
2941
args.Add (new Argument (left));
2942
args.Add (new Argument (right));
2943
cond_right = new DynamicExpressionStatement (this, args, loc);
2945
LocalVariable temp = LocalVariable.CreateCompilerGenerated (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
2947
args.Add (new Argument (temp.CreateReferenceExpression (ec, loc).Resolve (ec)));
2948
args.Add (new Argument (right));
2949
right = new DynamicExpressionStatement (this, args, loc);
2952
// bool && dynamic => (temp = left) ? temp && right : temp;
2953
// bool || dynamic => (temp = left) ? temp : temp || right;
2955
if (oper == Operator.LogicalAnd) {
2957
cond_right = temp.CreateReferenceExpression (ec, loc);
2959
cond_left = temp.CreateReferenceExpression (ec, loc);
2963
expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (ec, loc), left));
2966
return new Conditional (expr, cond_left, cond_right, loc).Resolve (ec);
2969
args = new Arguments (2);
2970
args.Add (new Argument (left));
2971
args.Add (new Argument (right));
2972
return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2975
if (ec.Module.Compiler.Settings.Version >= LanguageVersion.ISO_2 &&
2976
((left.Type.IsNullableType && (right is NullLiteral || right.Type.IsNullableType || TypeSpec.IsValueType (right.Type))) ||
2977
(TypeSpec.IsValueType (left.Type) && right is NullLiteral) ||
2978
(right.Type.IsNullableType && (left is NullLiteral || left.Type.IsNullableType || TypeSpec.IsValueType (left.Type))) ||
2979
(TypeSpec.IsValueType (right.Type) && left is NullLiteral))) {
2980
var lifted = new Nullable.LiftedBinaryOperator (oper, left, right, loc);
2981
lifted.state = state;
2982
return lifted.Resolve (ec);
2985
return DoResolveCore (ec, left, right);
2988
protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2990
Expression expr = ResolveOperator (ec);
2992
Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2994
if (left == null || right == null)
2995
throw new InternalErrorException ("Invalid conversion");
2997
if (oper == Operator.BitwiseOr)
2998
CheckBitwiseOrOnSignExtended (ec);
3003
public override SLE.Expression MakeExpression (BuilderContext ctx)
3005
var le = left.MakeExpression (ctx);
3006
var re = right.MakeExpression (ctx);
3007
bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
3010
case Operator.Addition:
3011
return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
3012
case Operator.BitwiseAnd:
3013
return SLE.Expression.And (le, re);
3014
case Operator.BitwiseOr:
3015
return SLE.Expression.Or (le, re);
3016
case Operator.Division:
3017
return SLE.Expression.Divide (le, re);
3018
case Operator.Equality:
3019
return SLE.Expression.Equal (le, re);
3020
case Operator.ExclusiveOr:
3021
return SLE.Expression.ExclusiveOr (le, re);
3022
case Operator.GreaterThan:
3023
return SLE.Expression.GreaterThan (le, re);
3024
case Operator.GreaterThanOrEqual:
3025
return SLE.Expression.GreaterThanOrEqual (le, re);
3026
case Operator.Inequality:
3027
return SLE.Expression.NotEqual (le, re);
3028
case Operator.LeftShift:
3029
return SLE.Expression.LeftShift (le, re);
3030
case Operator.LessThan:
3031
return SLE.Expression.LessThan (le, re);
3032
case Operator.LessThanOrEqual:
3033
return SLE.Expression.LessThanOrEqual (le, re);
3034
case Operator.LogicalAnd:
3035
return SLE.Expression.AndAlso (le, re);
3036
case Operator.LogicalOr:
3037
return SLE.Expression.OrElse (le, re);
3038
case Operator.Modulus:
3039
return SLE.Expression.Modulo (le, re);
3040
case Operator.Multiply:
3041
return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
3042
case Operator.RightShift:
3043
return SLE.Expression.RightShift (le, re);
3044
case Operator.Subtraction:
3045
return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
3047
throw new NotImplementedException (oper.ToString ());
3052
// D operator + (D x, D y)
3053
// D operator - (D x, D y)
3055
Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
3057
if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
3059
if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
3060
tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
3065
} else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
3066
tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
3076
MethodSpec method = null;
3077
Arguments args = new Arguments (2);
3078
args.Add (new Argument (left));
3079
args.Add (new Argument (right));
3081
if (oper == Operator.Addition) {
3082
method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
3083
} else if (oper == Operator.Subtraction) {
3084
method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
3088
return new EmptyExpression (ec.BuiltinTypes.Decimal);
3090
MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, ec.BuiltinTypes.Delegate, loc);
3091
Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
3092
return new ClassCast (expr, l);
3096
// Enumeration operators
3098
Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
3101
// bool operator == (E x, E y);
3102
// bool operator != (E x, E y);
3103
// bool operator < (E x, E y);
3104
// bool operator > (E x, E y);
3105
// bool operator <= (E x, E y);
3106
// bool operator >= (E x, E y);
3108
// E operator & (E x, E y);
3109
// E operator | (E x, E y);
3110
// E operator ^ (E x, E y);
3112
// U operator - (E e, E f)
3113
// E operator - (E e, U x)
3114
// E operator - (U x, E e) // LAMESPEC: Not covered by the specification
3116
// E operator + (E e, U x)
3117
// E operator + (U x, E e)
3119
Expression ltemp = left;
3120
Expression rtemp = right;
3121
TypeSpec underlying_type;
3122
TypeSpec underlying_type_result;
3127
// LAMESPEC: There is never ambiguous conversion between enum operators
3128
// the one which contains more enum parameters always wins even if there
3129
// is an implicit conversion involved
3131
if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3133
underlying_type = EnumSpec.GetUnderlyingType (rtype);
3134
expr = Convert.ImplicitConversion (ec, left, rtype, loc);
3141
underlying_type = EnumSpec.GetUnderlyingType (ltype);
3142
expr = Convert.ImplicitConversion (ec, right, ltype, loc);
3152
if ((oper & Operator.BitwiseMask) != 0) {
3154
underlying_type_result = underlying_type;
3157
underlying_type_result = null;
3159
} else if (oper == Operator.Subtraction) {
3161
underlying_type = EnumSpec.GetUnderlyingType (rtype);
3162
if (ltype != rtype) {
3163
expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
3165
expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3171
res_type = underlying_type;
3176
res_type = underlying_type;
3179
underlying_type_result = underlying_type;
3181
underlying_type = EnumSpec.GetUnderlyingType (ltype);
3182
expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
3183
if (expr == null || expr is EnumConstant) {
3184
expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3190
res_type = underlying_type;
3194
underlying_type_result = underlying_type;
3198
} else if (oper == Operator.Addition) {
3200
underlying_type = EnumSpec.GetUnderlyingType (ltype);
3203
if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
3204
expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
3211
underlying_type = EnumSpec.GetUnderlyingType (rtype);
3213
if (ltype != underlying_type) {
3214
expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
3222
underlying_type_result = underlying_type;
3227
// Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
3228
// with constants and expressions
3229
if (left.Type != underlying_type) {
3230
if (left is Constant)
3231
left = ((Constant) left).ConvertExplicitly (false, underlying_type);
3233
left = EmptyCast.Create (left, underlying_type);
3236
if (right.Type != underlying_type) {
3237
if (right is Constant)
3238
right = ((Constant) right).ConvertExplicitly (false, underlying_type);
3240
right = EmptyCast.Create (right, underlying_type);
3244
// C# specification uses explicit cast syntax which means binary promotion
3245
// should happen, however it seems that csc does not do that
3247
if (!DoBinaryOperatorPromotion (ec)) {
3253
if (underlying_type_result != null && left.Type != underlying_type_result) {
3254
enum_conversion = Convert.ExplicitNumericConversion (ec, new EmptyExpression (left.Type), underlying_type_result);
3257
expr = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryStandard, true, res_type);
3269
// If the return type of the selected operator is implicitly convertible to the type of x
3271
if (Convert.ImplicitConversionExists (ec, expr, ltype))
3275
// Otherwise, if the selected operator is a predefined operator, if the return type of the
3276
// selected operator is explicitly convertible to the type of x, and if y is implicitly
3277
// convertible to the type of x or the operator is a shift operator, then the operation
3278
// is evaluated as x = (T)(x op y), where T is the type of x
3280
expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
3284
if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
3291
// 7.9.6 Reference type equality operators
3293
Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
3296
type = ec.BuiltinTypes.Bool;
3299
// a, Both operands are reference-type values or the value null
3300
// b, One operand is a value of type T where T is a type-parameter and
3301
// the other operand is the value null. Furthermore T does not have the
3302
// value type constraint
3304
// LAMESPEC: Very confusing details in the specification, basically any
3305
// reference like type-parameter is allowed
3307
var tparam_l = l as TypeParameterSpec;
3308
var tparam_r = r as TypeParameterSpec;
3309
if (tparam_l != null) {
3310
if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
3311
left = new BoxedCast (left, ec.BuiltinTypes.Object);
3315
if (!tparam_l.IsReferenceType)
3318
l = tparam_l.GetEffectiveBase ();
3319
left = new BoxedCast (left, l);
3320
} else if (left is NullLiteral && tparam_r == null) {
3321
if (!TypeSpec.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
3327
if (tparam_r != null) {
3328
if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
3329
right = new BoxedCast (right, ec.BuiltinTypes.Object);
3333
if (!tparam_r.IsReferenceType)
3336
r = tparam_r.GetEffectiveBase ();
3337
right = new BoxedCast (right, r);
3338
} else if (right is NullLiteral) {
3339
if (!TypeSpec.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
3346
// LAMESPEC: method groups can be compared when they convert to other side delegate
3349
if (right.eclass == ExprClass.MethodGroup) {
3350
result = Convert.ImplicitConversion (ec, right, l, loc);
3356
} else if (r.IsDelegate && l != r) {
3359
} else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
3360
result = Convert.ImplicitConversionRequired (ec, left, r, loc);
3369
// bool operator != (string a, string b)
3370
// bool operator == (string a, string b)
3372
// bool operator != (Delegate a, Delegate b)
3373
// bool operator == (Delegate a, Delegate b)
3375
// bool operator != (bool a, bool b)
3376
// bool operator == (bool a, bool b)
3378
// LAMESPEC: Reference equality comparison can apply to value types when
3379
// they implement an implicit conversion to any of types above.
3381
if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
3382
result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, false, null);
3388
// bool operator != (object a, object b)
3389
// bool operator == (object a, object b)
3391
// An explicit reference conversion exists from the
3392
// type of either operand to the type of the other operand.
3395
// Optimize common path
3397
return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
3400
if (!Convert.ExplicitReferenceConversionExists (l, r) &&
3401
!Convert.ExplicitReferenceConversionExists (r, l))
3404
// Reject allowed explicit conversions like int->object
3405
if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
3408
if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
3409
ec.Report.Warning (253, 2, loc,
3410
"Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
3411
l.GetSignatureForError ());
3413
if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
3414
ec.Report.Warning (252, 2, loc,
3415
"Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
3416
r.GetSignatureForError ());
3422
Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
3425
// bool operator == (void* x, void* y);
3426
// bool operator != (void* x, void* y);
3427
// bool operator < (void* x, void* y);
3428
// bool operator > (void* x, void* y);
3429
// bool operator <= (void* x, void* y);
3430
// bool operator >= (void* x, void* y);
3432
if ((oper & Operator.ComparisonMask) != 0) {
3435
temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3442
temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3448
type = ec.BuiltinTypes.Bool;
3452
return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false, null);
3456
// Build-in operators method overloading
3458
protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
3460
PredefinedOperator best_operator = null;
3461
TypeSpec l = left.Type;
3462
TypeSpec r = right.Type;
3463
Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3465
foreach (PredefinedOperator po in operators) {
3466
if ((po.OperatorsMask & oper_mask) == 0)
3469
if (primitives_only) {
3470
if (!po.IsPrimitiveApplicable (l, r))
3473
if (!po.IsApplicable (ec, left, right))
3477
if (best_operator == null) {
3479
if (primitives_only)
3485
best_operator = po.ResolveBetterOperator (ec, best_operator);
3487
if (best_operator == null) {
3488
ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3489
OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3496
if (best_operator == null)
3499
Expression expr = best_operator.ConvertResult (ec, this);
3502
// Optimize &/&& constant expressions with 0 value
3504
if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3505
Constant rc = right as Constant;
3506
Constant lc = left as Constant;
3507
if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
3509
// The result is a constant with side-effect
3511
Constant side_effect = rc == null ?
3512
new SideEffectConstant (lc, right, loc) :
3513
new SideEffectConstant (rc, left, loc);
3515
return ReducedExpression.Create (side_effect, expr);
3519
if (enum_type == null)
3523
// HACK: required by enum_conversion
3525
expr.Type = enum_type;
3526
return EmptyCast.Create (expr, enum_type);
3530
// Performs user-operator overloading
3532
protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right)
3534
var op = ConvertBinaryToUserOperator (oper);
3536
if (l.IsNullableType)
3537
l = Nullable.NullableInfo.GetUnderlyingType (l);
3539
if (r.IsNullableType)
3540
r = Nullable.NullableInfo.GetUnderlyingType (r);
3542
IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
3543
IList<MemberSpec> right_operators = null;
3546
right_operators = MemberCache.GetUserOperator (r, op, false);
3547
if (right_operators == null && left_operators == null)
3549
} else if (left_operators == null) {
3553
Arguments args = new Arguments (2);
3554
Argument larg = new Argument (left);
3556
Argument rarg = new Argument (right);
3560
// User-defined operator implementations always take precedence
3561
// over predefined operator implementations
3563
if (left_operators != null && right_operators != null) {
3564
left_operators = CombineUserOperators (left_operators, right_operators);
3565
} else if (right_operators != null) {
3566
left_operators = right_operators;
3569
var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
3570
OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
3572
var oper_method = res.ResolveOperator (ec, ref args);
3573
if (oper_method == null)
3576
var llifted = (state & State.LeftNullLifted) != 0;
3577
var rlifted = (state & State.RightNullLifted) != 0;
3578
if ((Oper & Operator.EqualityMask) != 0) {
3579
var parameters = oper_method.Parameters;
3580
// LAMESPEC: No idea why this is not allowed
3581
if ((left is Nullable.Unwrap || right is Nullable.Unwrap) && parameters.Types [0] != parameters.Types [1])
3584
// Binary operation was lifted but we have found a user operator
3585
// which requires value-type argument, we downgrade ourself back to
3587
// LAMESPEC: The user operator is not called (it cannot be we are passing null to struct)
3588
// but compilation succeeds
3589
if ((llifted && !parameters.Types[0].IsStruct) || (rlifted && !parameters.Types[1].IsStruct)) {
3590
state &= ~(State.LeftNullLifted | State.RightNullLifted);
3594
Expression oper_expr;
3596
// TODO: CreateExpressionTree is allocated every time
3597
if ((oper & Operator.LogicalMask) != 0) {
3598
oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
3599
oper == Operator.LogicalAnd, loc).Resolve (ec);
3601
oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
3605
this.left = larg.Expr;
3608
this.right = rarg.Expr;
3614
// Merge two sets of user operators into one, they are mostly distinguish
3615
// expect when they share base type and it contains an operator
3617
static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
3619
var combined = new List<MemberSpec> (left.Count + right.Count);
3620
combined.AddRange (left);
3621
foreach (var r in right) {
3623
foreach (var l in left) {
3624
if (l.DeclaringType == r.DeclaringType) {
3637
void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
3639
if (c is IntegralConstant || c is CharConstant) {
3641
c.ConvertExplicitly (true, type);
3642
} catch (OverflowException) {
3643
ec.Report.Warning (652, 2, loc,
3644
"A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
3645
TypeManager.CSharpName (type));
3651
/// EmitBranchable is called from Statement.EmitBoolExpression in the
3652
/// context of a conditional bool expression. This function will return
3653
/// false if it is was possible to use EmitBranchable, or true if it was.
3655
/// The expression's code is generated, and we will generate a branch to `target'
3656
/// if the resulting expression value is equal to isTrue
3658
public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3661
// This is more complicated than it looks, but its just to avoid
3662
// duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3663
// but on top of that we want for == and != to use a special path
3664
// if we are comparing against null
3666
if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
3667
bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3670
// put the constant on the rhs, for simplicity
3672
if (left is Constant) {
3673
Expression swap = right;
3679
// brtrue/brfalse works with native int only
3681
if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
3682
left.EmitBranchable (ec, target, my_on_true);
3685
if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
3686
// right is a boolean, and it's not 'false' => it is 'true'
3687
left.EmitBranchable (ec, target, !my_on_true);
3691
} else if (oper == Operator.LogicalAnd) {
3694
Label tests_end = ec.DefineLabel ();
3696
left.EmitBranchable (ec, tests_end, false);
3697
right.EmitBranchable (ec, target, true);
3698
ec.MarkLabel (tests_end);
3701
// This optimizes code like this
3702
// if (true && i > 4)
3704
if (!(left is Constant))
3705
left.EmitBranchable (ec, target, false);
3707
if (!(right is Constant))
3708
right.EmitBranchable (ec, target, false);
3713
} else if (oper == Operator.LogicalOr){
3715
left.EmitBranchable (ec, target, true);
3716
right.EmitBranchable (ec, target, true);
3719
Label tests_end = ec.DefineLabel ();
3720
left.EmitBranchable (ec, tests_end, true);
3721
right.EmitBranchable (ec, target, false);
3722
ec.MarkLabel (tests_end);
3727
} else if ((oper & Operator.ComparisonMask) == 0) {
3728
base.EmitBranchable (ec, target, on_true);
3735
TypeSpec t = left.Type;
3736
bool is_float = IsFloat (t);
3737
bool is_unsigned = is_float || IsUnsigned (t);
3740
case Operator.Equality:
3742
ec.Emit (OpCodes.Beq, target);
3744
ec.Emit (OpCodes.Bne_Un, target);
3747
case Operator.Inequality:
3749
ec.Emit (OpCodes.Bne_Un, target);
3751
ec.Emit (OpCodes.Beq, target);
3754
case Operator.LessThan:
3756
if (is_unsigned && !is_float)
3757
ec.Emit (OpCodes.Blt_Un, target);
3759
ec.Emit (OpCodes.Blt, target);
3762
ec.Emit (OpCodes.Bge_Un, target);
3764
ec.Emit (OpCodes.Bge, target);
3767
case Operator.GreaterThan:
3769
if (is_unsigned && !is_float)
3770
ec.Emit (OpCodes.Bgt_Un, target);
3772
ec.Emit (OpCodes.Bgt, target);
3775
ec.Emit (OpCodes.Ble_Un, target);
3777
ec.Emit (OpCodes.Ble, target);
3780
case Operator.LessThanOrEqual:
3782
if (is_unsigned && !is_float)
3783
ec.Emit (OpCodes.Ble_Un, target);
3785
ec.Emit (OpCodes.Ble, target);
3788
ec.Emit (OpCodes.Bgt_Un, target);
3790
ec.Emit (OpCodes.Bgt, target);
3794
case Operator.GreaterThanOrEqual:
3796
if (is_unsigned && !is_float)
3797
ec.Emit (OpCodes.Bge_Un, target);
3799
ec.Emit (OpCodes.Bge, target);
3802
ec.Emit (OpCodes.Blt_Un, target);
3804
ec.Emit (OpCodes.Blt, target);
3807
throw new InternalErrorException (oper.ToString ());
3811
public override void Emit (EmitContext ec)
3813
EmitOperator (ec, left.Type);
3816
protected virtual void EmitOperator (EmitContext ec, TypeSpec l)
3819
// Handle short-circuit operators differently
3822
if ((oper & Operator.LogicalMask) != 0) {
3823
Label load_result = ec.DefineLabel ();
3824
Label end = ec.DefineLabel ();
3826
bool is_or = oper == Operator.LogicalOr;
3827
left.EmitBranchable (ec, load_result, is_or);
3829
ec.Emit (OpCodes.Br_S, end);
3831
ec.MarkLabel (load_result);
3832
ec.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3838
// Optimize zero-based operations which cannot be optimized at expression level
3840
if (oper == Operator.Subtraction) {
3841
var lc = left as IntegralConstant;
3842
if (lc != null && lc.IsDefaultValue) {
3844
ec.Emit (OpCodes.Neg);
3851
EmitOperatorOpcode (ec, oper, l);
3854
// Nullable enum could require underlying type cast and we cannot simply wrap binary
3855
// expression because that would wrap lifted binary operation
3857
if (enum_conversion != null)
3858
enum_conversion.Emit (ec);
3861
public override void EmitSideEffect (EmitContext ec)
3863
if ((oper & Operator.LogicalMask) != 0 ||
3864
(ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3865
base.EmitSideEffect (ec);
3867
left.EmitSideEffect (ec);
3868
right.EmitSideEffect (ec);
3872
protected override void CloneTo (CloneContext clonectx, Expression t)
3874
Binary target = (Binary) t;
3876
target.left = left.Clone (clonectx);
3877
target.right = right.Clone (clonectx);
3880
public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3882
Arguments binder_args = new Arguments (4);
3884
MemberAccess sle = new MemberAccess (new MemberAccess (
3885
new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3887
CSharpBinderFlags flags = 0;
3888
if (ec.HasSet (ResolveContext.Options.CheckedScope))
3889
flags = CSharpBinderFlags.CheckedContext;
3891
if ((oper & Operator.LogicalMask) != 0)
3892
flags |= CSharpBinderFlags.BinaryOperationLogical;
3894
binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
3895
binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3896
binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
3897
binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
3899
return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
3902
public override Expression CreateExpressionTree (ResolveContext ec)
3904
return CreateExpressionTree (ec, null);
3907
Expression CreateExpressionTree (ResolveContext ec, Expression method)
3910
bool lift_arg = false;
3913
case Operator.Addition:
3914
if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3915
method_name = "AddChecked";
3917
method_name = "Add";
3919
case Operator.BitwiseAnd:
3920
method_name = "And";
3922
case Operator.BitwiseOr:
3925
case Operator.Division:
3926
method_name = "Divide";
3928
case Operator.Equality:
3929
method_name = "Equal";
3932
case Operator.ExclusiveOr:
3933
method_name = "ExclusiveOr";
3935
case Operator.GreaterThan:
3936
method_name = "GreaterThan";
3939
case Operator.GreaterThanOrEqual:
3940
method_name = "GreaterThanOrEqual";
3943
case Operator.Inequality:
3944
method_name = "NotEqual";
3947
case Operator.LeftShift:
3948
method_name = "LeftShift";
3950
case Operator.LessThan:
3951
method_name = "LessThan";
3954
case Operator.LessThanOrEqual:
3955
method_name = "LessThanOrEqual";
3958
case Operator.LogicalAnd:
3959
method_name = "AndAlso";
3961
case Operator.LogicalOr:
3962
method_name = "OrElse";
3964
case Operator.Modulus:
3965
method_name = "Modulo";
3967
case Operator.Multiply:
3968
if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3969
method_name = "MultiplyChecked";
3971
method_name = "Multiply";
3973
case Operator.RightShift:
3974
method_name = "RightShift";
3976
case Operator.Subtraction:
3977
if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3978
method_name = "SubtractChecked";
3980
method_name = "Subtract";
3984
throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3987
Arguments args = new Arguments (2);
3988
args.Add (new Argument (left.CreateExpressionTree (ec)));
3989
args.Add (new Argument (right.CreateExpressionTree (ec)));
3990
if (method != null) {
3992
args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
3994
args.Add (new Argument (method));
3997
return CreateExpressionFactoryCall (ec, method_name, args);
4000
public override object Accept (StructuralVisitor visitor)
4002
return visitor.Visit (this);
4008
// Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
4009
// b, c, d... may be strings or objects.
4011
public class StringConcat : Expression
4013
Arguments arguments;
4015
StringConcat (Location loc)
4018
arguments = new Arguments (2);
4021
public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
4023
if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
4024
throw new ArgumentException ();
4026
var s = new StringConcat (loc);
4027
s.type = rc.BuiltinTypes.String;
4028
s.eclass = ExprClass.Value;
4030
s.Append (rc, left);
4031
s.Append (rc, right);
4035
public override Expression CreateExpressionTree (ResolveContext ec)
4037
Argument arg = arguments [0];
4038
return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
4042
// Creates nested calls tree from an array of arguments used for IL emit
4044
Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
4046
Arguments concat_args = new Arguments (2);
4047
Arguments add_args = new Arguments (3);
4049
concat_args.Add (left);
4050
add_args.Add (new Argument (left_etree));
4052
concat_args.Add (arguments [pos]);
4053
add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
4055
var methods = GetConcatMethodCandidates ();
4056
if (methods == null)
4059
var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
4060
var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
4064
add_args.Add (new Argument (new TypeOfMethod (method, loc)));
4066
Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
4067
if (++pos == arguments.Count)
4070
left = new Argument (new EmptyExpression (method.ReturnType));
4071
return CreateExpressionAddCall (ec, left, expr, pos);
4074
protected override Expression DoResolve (ResolveContext ec)
4079
void Append (ResolveContext rc, Expression operand)
4084
StringConstant sc = operand as StringConstant;
4086
if (arguments.Count != 0) {
4087
Argument last_argument = arguments [arguments.Count - 1];
4088
StringConstant last_expr_constant = last_argument.Expr as StringConstant;
4089
if (last_expr_constant != null) {
4090
last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
4096
// Multiple (3+) concatenation are resolved as multiple StringConcat instances
4098
StringConcat concat_oper = operand as StringConcat;
4099
if (concat_oper != null) {
4100
arguments.AddRange (concat_oper.arguments);
4105
arguments.Add (new Argument (operand));
4108
IList<MemberSpec> GetConcatMethodCandidates ()
4110
return MemberCache.FindMembers (type, "Concat", true);
4113
public override void Emit (EmitContext ec)
4115
var members = GetConcatMethodCandidates ();
4116
var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
4117
var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
4119
Invocation.EmitCall (ec, null, method, arguments, loc);
4122
public override SLE.Expression MakeExpression (BuilderContext ctx)
4124
if (arguments.Count != 2)
4125
throw new NotImplementedException ("arguments.Count != 2");
4127
var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
4128
return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
4133
// User-defined conditional logical operator
4135
public class ConditionalLogicalOperator : UserOperatorCall {
4136
readonly bool is_and;
4137
Expression oper_expr;
4139
public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
4140
: base (oper, arguments, expr_tree, loc)
4142
this.is_and = is_and;
4143
eclass = ExprClass.Unresolved;
4146
protected override Expression DoResolve (ResolveContext ec)
4148
AParametersCollection pd = oper.Parameters;
4149
if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
4150
ec.Report.Error (217, loc,
4151
"A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
4152
oper.GetSignatureForError ());
4156
Expression left_dup = new EmptyExpression (type);
4157
Expression op_true = GetOperatorTrue (ec, left_dup, loc);
4158
Expression op_false = GetOperatorFalse (ec, left_dup, loc);
4159
if (op_true == null || op_false == null) {
4160
ec.Report.Error (218, loc,
4161
"The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
4162
TypeManager.CSharpName (type), oper.GetSignatureForError ());
4166
oper_expr = is_and ? op_false : op_true;
4167
eclass = ExprClass.Value;
4171
public override void Emit (EmitContext ec)
4173
Label end_target = ec.DefineLabel ();
4176
// Emit and duplicate left argument
4178
arguments [0].Expr.Emit (ec);
4179
ec.Emit (OpCodes.Dup);
4180
arguments.RemoveAt (0);
4182
oper_expr.EmitBranchable (ec, end_target, true);
4184
ec.MarkLabel (end_target);
4188
public class PointerArithmetic : Expression {
4189
Expression left, right;
4193
// We assume that `l' is always a pointer
4195
public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
4204
public override Expression CreateExpressionTree (ResolveContext ec)
4206
Error_PointerInsideExpressionTree (ec);
4210
protected override Expression DoResolve (ResolveContext ec)
4212
eclass = ExprClass.Variable;
4214
var pc = left.Type as PointerContainer;
4215
if (pc != null && pc.Element.Kind == MemberKind.Void) {
4216
Error_VoidPointerOperation (ec);
4223
public override void Emit (EmitContext ec)
4225
TypeSpec op_type = left.Type;
4227
// It must be either array or fixed buffer
4229
if (TypeManager.HasElementType (op_type)) {
4230
element = TypeManager.GetElementType (op_type);
4232
FieldExpr fe = left as FieldExpr;
4234
element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4239
int size = BuiltinTypeSpec.GetSize(element);
4240
TypeSpec rtype = right.Type;
4242
if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4244
// handle (pointer - pointer)
4248
ec.Emit (OpCodes.Sub);
4252
ec.Emit (OpCodes.Sizeof, element);
4255
ec.Emit (OpCodes.Div);
4257
ec.Emit (OpCodes.Conv_I8);
4260
// handle + and - on (pointer op int)
4262
Constant left_const = left as Constant;
4263
if (left_const != null) {
4265
// Optimize ((T*)null) pointer operations
4267
if (left_const.IsDefaultValue) {
4268
left = EmptyExpression.Null;
4276
var right_const = right as Constant;
4277
if (right_const != null) {
4279
// Optimize 0-based arithmetic
4281
if (right_const.IsDefaultValue)
4285
right = new IntConstant (ec.BuiltinTypes, size, right.Location);
4287
right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4289
// TODO: Should be the checks resolve context sensitive?
4290
ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4291
right = new Binary (Binary.Operator.Multiply, right, right_const, loc).Resolve (rc);
4297
switch (rtype.BuiltinType) {
4298
case BuiltinTypeSpec.Type.SByte:
4299
case BuiltinTypeSpec.Type.Byte:
4300
case BuiltinTypeSpec.Type.Short:
4301
case BuiltinTypeSpec.Type.UShort:
4302
ec.Emit (OpCodes.Conv_I);
4304
case BuiltinTypeSpec.Type.UInt:
4305
ec.Emit (OpCodes.Conv_U);
4309
if (right_const == null && size != 1){
4311
ec.Emit (OpCodes.Sizeof, element);
4314
if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4315
ec.Emit (OpCodes.Conv_I8);
4317
Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4320
if (left_const == null) {
4321
if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
4322
ec.Emit (OpCodes.Conv_I);
4323
else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
4324
ec.Emit (OpCodes.Conv_U);
4326
Binary.EmitOperatorOpcode (ec, op, op_type);
4333
// A boolean-expression is an expression that yields a result
4336
public class BooleanExpression : ShimExpression
4338
public BooleanExpression (Expression expr)
4341
this.loc = expr.Location;
4344
public override Expression CreateExpressionTree (ResolveContext ec)
4346
// TODO: We should emit IsTrue (v4) instead of direct user operator
4347
// call but that would break csc compatibility
4348
return base.CreateExpressionTree (ec);
4351
protected override Expression DoResolve (ResolveContext ec)
4353
// A boolean-expression is required to be of a type
4354
// that can be implicitly converted to bool or of
4355
// a type that implements operator true
4357
expr = expr.Resolve (ec);
4361
Assign ass = expr as Assign;
4362
if (ass != null && ass.Source is Constant) {
4363
ec.Report.Warning (665, 3, loc,
4364
"Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4367
if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
4370
if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4371
Arguments args = new Arguments (1);
4372
args.Add (new Argument (expr));
4373
return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
4376
type = ec.BuiltinTypes.Bool;
4377
Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4378
if (converted != null)
4382
// If no implicit conversion to bool exists, try using `operator true'
4384
converted = GetOperatorTrue (ec, expr, loc);
4385
if (converted == null) {
4386
expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4393
public override object Accept (StructuralVisitor visitor)
4395
return visitor.Visit (this);
4399
public class BooleanExpressionFalse : Unary
4401
public BooleanExpressionFalse (Expression expr)
4402
: base (Operator.LogicalNot, expr, expr.Location)
4406
protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
4408
return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
4413
/// Implements the ternary conditional operator (?:)
4415
public class Conditional : Expression {
4416
Expression expr, true_expr, false_expr;
4418
public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
4421
this.true_expr = true_expr;
4422
this.false_expr = false_expr;
4426
public Expression Expr {
4432
public Expression TrueExpr {
4438
public Expression FalseExpr {
4444
public override Expression CreateExpressionTree (ResolveContext ec)
4446
Arguments args = new Arguments (3);
4447
args.Add (new Argument (expr.CreateExpressionTree (ec)));
4448
args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4449
args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4450
return CreateExpressionFactoryCall (ec, "Condition", args);
4453
protected override Expression DoResolve (ResolveContext ec)
4455
expr = expr.Resolve (ec);
4456
true_expr = true_expr.Resolve (ec);
4457
false_expr = false_expr.Resolve (ec);
4459
if (true_expr == null || false_expr == null || expr == null)
4462
eclass = ExprClass.Value;
4463
TypeSpec true_type = true_expr.Type;
4464
TypeSpec false_type = false_expr.Type;
4468
// First, if an implicit conversion exists from true_expr
4469
// to false_expr, then the result type is of type false_expr.Type
4471
if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
4472
Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4473
if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
4475
// Check if both can convert implicitly to each other's type
4479
if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic && Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4480
ec.Report.Error (172, true_expr.Location,
4481
"Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4482
true_type.GetSignatureForError (), false_type.GetSignatureForError ());
4487
} else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4490
ec.Report.Error (173, true_expr.Location,
4491
"Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4492
TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4497
// Dead code optimalization
4498
Constant c = expr as Constant;
4500
bool is_false = c.IsDefaultValue;
4501
ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4502
return ReducedExpression.Create (
4503
is_false ? false_expr : true_expr, this,
4504
false_expr is Constant && true_expr is Constant).Resolve (ec);
4510
public override void Emit (EmitContext ec)
4512
Label false_target = ec.DefineLabel ();
4513
Label end_target = ec.DefineLabel ();
4515
expr.EmitBranchable (ec, false_target, false);
4516
true_expr.Emit (ec);
4518
if (type.IsInterface) {
4519
LocalBuilder temp = ec.GetTemporaryLocal (type);
4520
ec.Emit (OpCodes.Stloc, temp);
4521
ec.Emit (OpCodes.Ldloc, temp);
4522
ec.FreeTemporaryLocal (temp, type);
4525
ec.Emit (OpCodes.Br, end_target);
4526
ec.MarkLabel (false_target);
4527
false_expr.Emit (ec);
4528
ec.MarkLabel (end_target);
4531
protected override void CloneTo (CloneContext clonectx, Expression t)
4533
Conditional target = (Conditional) t;
4535
target.expr = expr.Clone (clonectx);
4536
target.true_expr = true_expr.Clone (clonectx);
4537
target.false_expr = false_expr.Clone (clonectx);
4540
public override object Accept (StructuralVisitor visitor)
4542
return visitor.Visit (this);
4546
public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4547
LocalTemporary temp;
4550
public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4552
public abstract bool IsLockedByStatement { get; set; }
4554
public abstract bool IsFixed { get; }
4555
public abstract bool IsRef { get; }
4556
public abstract string Name { get; }
4557
public abstract void SetHasAddressTaken ();
4560
// Variable IL data, it has to be protected to encapsulate hoisted variables
4562
protected abstract ILocalVariable Variable { get; }
4565
// Variable flow-analysis data
4567
public abstract VariableInfo VariableInfo { get; }
4570
public virtual void AddressOf (EmitContext ec, AddressOp mode)
4572
HoistedVariable hv = GetHoistedVariable (ec);
4574
hv.AddressOf (ec, mode);
4578
Variable.EmitAddressOf (ec);
4581
public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
4583
if (IsLockedByStatement) {
4584
rc.Report.Warning (728, 2, loc,
4585
"Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
4592
public override void Emit (EmitContext ec)
4597
public override void EmitSideEffect (EmitContext ec)
4603
// This method is used by parameters that are references, that are
4604
// being passed as references: we only want to pass the pointer (that
4605
// is already stored in the parameter, not the address of the pointer,
4606
// and not the value of the variable).
4608
public void EmitLoad (EmitContext ec)
4613
public void Emit (EmitContext ec, bool leave_copy)
4615
HoistedVariable hv = GetHoistedVariable (ec);
4617
hv.Emit (ec, leave_copy);
4625
// If we are a reference, we loaded on the stack a pointer
4626
// Now lets load the real value
4628
ec.EmitLoadFromPtr (type);
4632
ec.Emit (OpCodes.Dup);
4635
temp = new LocalTemporary (Type);
4641
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4642
bool prepare_for_load)
4644
HoistedVariable hv = GetHoistedVariable (ec);
4646
hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4650
New n_source = source as New;
4651
if (n_source != null) {
4652
if (!n_source.Emit (ec, this)) {
4656
ec.EmitLoadFromPtr (type);
4668
ec.Emit (OpCodes.Dup);
4670
temp = new LocalTemporary (Type);
4676
ec.EmitStoreFromPtr (type);
4678
Variable.EmitAssign (ec);
4687
public HoistedVariable GetHoistedVariable (ResolveContext rc)
4689
return GetHoistedVariable (rc.CurrentAnonymousMethod);
4692
public HoistedVariable GetHoistedVariable (EmitContext ec)
4694
return GetHoistedVariable (ec.CurrentAnonymousMethod);
4697
public override string GetSignatureForError ()
4702
public bool IsHoisted {
4703
get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4708
// Resolved reference to a local variable
4710
public class LocalVariableReference : VariableReference
4712
public LocalVariable local_info;
4714
public LocalVariableReference (LocalVariable li, Location l)
4716
this.local_info = li;
4720
public override VariableInfo VariableInfo {
4721
get { return local_info.VariableInfo; }
4724
public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4726
return local_info.HoistedVariant;
4732
// A local variable is always fixed
4734
public override bool IsFixed {
4740
public override bool IsLockedByStatement {
4742
return local_info.IsLocked;
4745
local_info.IsLocked = value;
4749
public override bool IsRef {
4750
get { return false; }
4753
public override string Name {
4754
get { return local_info.Name; }
4759
public bool VerifyAssigned (ResolveContext ec)
4761
VariableInfo variable_info = local_info.VariableInfo;
4762
return variable_info == null || variable_info.IsAssigned (ec, loc);
4765
public override void SetHasAddressTaken ()
4767
local_info.AddressTaken = true;
4770
public override Expression CreateExpressionTree (ResolveContext ec)
4772
HoistedVariable hv = GetHoistedVariable (ec);
4774
return hv.CreateExpressionTree ();
4776
Arguments arg = new Arguments (1);
4777
arg.Add (new Argument (this));
4778
return CreateExpressionFactoryCall (ec, "Constant", arg);
4781
void DoResolveBase (ResolveContext ec)
4783
VerifyAssigned (ec);
4786
// If we are referencing a variable from the external block
4787
// flag it for capturing
4789
if (ec.MustCaptureVariable (local_info)) {
4790
if (local_info.AddressTaken) {
4791
AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4792
} else if (local_info.IsFixed) {
4793
ec.Report.Error (1764, loc,
4794
"Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
4795
GetSignatureForError ());
4798
if (ec.IsVariableCapturingRequired) {
4799
AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4800
storey.CaptureLocalVariable (ec, local_info);
4804
eclass = ExprClass.Variable;
4805
type = local_info.Type;
4808
protected override Expression DoResolve (ResolveContext ec)
4810
local_info.SetIsUsed ();
4816
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4819
if (right_side == EmptyExpression.OutAccess)
4820
local_info.SetIsUsed ();
4822
if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
4825
if (right_side == EmptyExpression.OutAccess) {
4826
code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4827
} else if (right_side == EmptyExpression.LValueMemberAccess) {
4828
code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4829
} else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4830
code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4831
} else if (right_side == EmptyExpression.UnaryAddress) {
4832
code = 459; msg = "Cannot take the address of {1} `{0}'";
4834
code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4836
ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4837
} else if (VariableInfo != null) {
4838
VariableInfo.SetAssigned (ec);
4843
return base.DoResolveLValue (ec, right_side);
4846
public override int GetHashCode ()
4848
return local_info.GetHashCode ();
4851
public override bool Equals (object obj)
4853
LocalVariableReference lvr = obj as LocalVariableReference;
4857
return local_info == lvr.local_info;
4860
protected override ILocalVariable Variable {
4861
get { return local_info; }
4864
public override string ToString ()
4866
return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4869
protected override void CloneTo (CloneContext clonectx, Expression t)
4874
public override object Accept (StructuralVisitor visitor)
4876
return visitor.Visit (this);
4881
/// This represents a reference to a parameter in the intermediate
4884
public class ParameterReference : VariableReference
4886
protected ParametersBlock.ParameterInfo pi;
4888
public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
4896
public override bool IsLockedByStatement {
4901
pi.IsLocked = value;
4905
public override bool IsRef {
4906
get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4909
bool HasOutModifier {
4910
get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4913
public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4915
return pi.Parameter.HoistedVariant;
4919
// A ref or out parameter is classified as a moveable variable, even
4920
// if the argument given for the parameter is a fixed variable
4922
public override bool IsFixed {
4923
get { return !IsRef; }
4926
public override string Name {
4927
get { return Parameter.Name; }
4930
public Parameter Parameter {
4931
get { return pi.Parameter; }
4934
public override VariableInfo VariableInfo {
4935
get { return pi.VariableInfo; }
4938
protected override ILocalVariable Variable {
4939
get { return Parameter; }
4944
public bool IsAssigned (ResolveContext ec, Location loc)
4946
// HACK: Variables are not captured in probing mode
4947
if (ec.IsInProbingMode)
4950
if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4953
ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4957
public override void SetHasAddressTaken ()
4959
Parameter.HasAddressTaken = true;
4962
void SetAssigned (ResolveContext ec)
4964
if (HasOutModifier && ec.DoFlowAnalysis)
4965
ec.CurrentBranching.SetAssigned (VariableInfo);
4968
bool DoResolveBase (ResolveContext ec)
4970
if (eclass != ExprClass.Unresolved)
4973
type = pi.ParameterType;
4974
eclass = ExprClass.Variable;
4977
// If we are referencing a parameter from the external block
4978
// flag it for capturing
4980
if (ec.MustCaptureVariable (pi)) {
4981
if (Parameter.HasAddressTaken)
4982
AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4985
ec.Report.Error (1628, loc,
4986
"Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4987
Name, ec.CurrentAnonymousMethod.ContainerType);
4990
if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
4991
AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
4992
storey.CaptureParameter (ec, this);
4999
public override int GetHashCode ()
5001
return Name.GetHashCode ();
5004
public override bool Equals (object obj)
5006
ParameterReference pr = obj as ParameterReference;
5010
return Name == pr.Name;
5013
public override void AddressOf (EmitContext ec, AddressOp mode)
5016
// ParameterReferences might already be a reference
5023
base.AddressOf (ec, mode);
5026
protected override void CloneTo (CloneContext clonectx, Expression target)
5032
public override Expression CreateExpressionTree (ResolveContext ec)
5034
HoistedVariable hv = GetHoistedVariable (ec);
5036
return hv.CreateExpressionTree ();
5038
return Parameter.ExpressionTreeVariableReference ();
5042
// Notice that for ref/out parameters, the type exposed is not the
5043
// same type exposed externally.
5046
// externally we expose "int&"
5047
// here we expose "int".
5049
// We record this in "is_ref". This means that the type system can treat
5050
// the type as it is expected, but when we generate the code, we generate
5051
// the alternate kind of code.
5053
protected override Expression DoResolve (ResolveContext ec)
5055
if (!DoResolveBase (ec))
5058
// HACK: Variables are not captured in probing mode
5059
if (ec.IsInProbingMode)
5062
if (HasOutModifier && ec.DoFlowAnalysis &&
5063
(!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
5069
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5071
if (!DoResolveBase (ec))
5075
return base.DoResolveLValue (ec, right_side);
5078
static public void EmitLdArg (EmitContext ec, int x)
5081
case 0: ec.Emit (OpCodes.Ldarg_0); break;
5082
case 1: ec.Emit (OpCodes.Ldarg_1); break;
5083
case 2: ec.Emit (OpCodes.Ldarg_2); break;
5084
case 3: ec.Emit (OpCodes.Ldarg_3); break;
5086
if (x > byte.MaxValue)
5087
ec.Emit (OpCodes.Ldarg, x);
5089
ec.Emit (OpCodes.Ldarg_S, (byte) x);
5096
/// Invocation of methods or delegates.
5098
public class Invocation : ExpressionStatement
5100
protected Arguments arguments;
5101
protected Expression expr;
5102
protected MethodGroupExpr mg;
5105
// arguments is an ArrayList, but we do not want to typecast,
5106
// as it might be null.
5108
public Invocation (Expression expr, Arguments arguments)
5111
this.arguments = arguments;
5113
loc = expr.Location;
5117
public Arguments Arguments {
5123
public Expression Expression {
5130
protected override void CloneTo (CloneContext clonectx, Expression t)
5132
Invocation target = (Invocation) t;
5134
if (arguments != null)
5135
target.arguments = arguments.Clone (clonectx);
5137
target.expr = expr.Clone (clonectx);
5141
public override Expression CreateExpressionTree (ResolveContext ec)
5143
Expression instance = mg.IsInstance ?
5144
mg.InstanceExpression.CreateExpressionTree (ec) :
5145
new NullLiteral (loc);
5147
var args = Arguments.CreateForExpressionTree (ec, arguments,
5149
mg.CreateExpressionTree (ec));
5151
return CreateExpressionFactoryCall (ec, "Call", args);
5154
protected override Expression DoResolve (ResolveContext ec)
5156
Expression member_expr;
5157
var atn = expr as ATypeNameExpression;
5159
member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
5160
if (member_expr != null)
5161
member_expr = member_expr.Resolve (ec);
5163
member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5166
if (member_expr == null)
5170
// Next, evaluate all the expressions in the argument list
5172
bool dynamic_arg = false;
5173
if (arguments != null)
5174
arguments.Resolve (ec, out dynamic_arg);
5176
TypeSpec expr_type = member_expr.Type;
5177
if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5178
return DoResolveDynamic (ec, member_expr);
5180
mg = member_expr as MethodGroupExpr;
5181
Expression invoke = null;
5184
if (expr_type != null && TypeManager.IsDelegateType (expr_type)) {
5185
invoke = new DelegateInvocation (member_expr, arguments, loc);
5186
invoke = invoke.Resolve (ec);
5187
if (invoke == null || !dynamic_arg)
5190
if (member_expr is RuntimeValueExpression) {
5191
ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
5192
member_expr.Type.GetSignatureForError ()); ;
5196
MemberExpr me = member_expr as MemberExpr;
5198
member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5202
ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
5203
member_expr.GetSignatureForError ());
5208
if (invoke == null) {
5209
mg = DoResolveOverload (ec);
5215
return DoResolveDynamic (ec, member_expr);
5217
var method = mg.BestCandidate;
5218
type = mg.BestCandidateReturnType;
5220
if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
5222
ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5224
ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5228
IsSpecialMethodInvocation (ec, method, loc);
5230
eclass = ExprClass.Value;
5234
protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5237
DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5239
args = dmb.Arguments;
5240
if (arguments != null)
5241
args.AddRange (arguments);
5242
} else if (mg == null) {
5243
if (arguments == null)
5244
args = new Arguments (1);
5248
args.Insert (0, new Argument (memberExpr));
5252
ec.Report.Error (1971, loc,
5253
"The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5258
if (arguments == null)
5259
args = new Arguments (1);
5263
MemberAccess ma = expr as MemberAccess;
5265
var left_type = ma.LeftExpression as TypeExpr;
5266
if (left_type != null) {
5267
args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5270
// Any value type has to be pass as by-ref to get back the same
5271
// instance on which the member was called
5273
var mod = TypeSpec.IsValueType (ma.LeftExpression.Type) ? Argument.AType.Ref : Argument.AType.None;
5274
args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec), mod));
5276
} else { // is SimpleName
5278
args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5280
args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5285
return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5288
protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5290
return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
5293
static MetaType[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
5295
AParametersCollection pd = mb.Parameters;
5297
Argument a = arguments[pd.Count - 1];
5298
Arglist list = (Arglist) a.Expr;
5300
return list.ArgumentTypes;
5304
// If a member is a method or event, or if it is a constant, field or property of either a delegate type
5305
// or the type dynamic, then the member is invocable
5307
public static bool IsMemberInvocable (MemberSpec member)
5309
switch (member.Kind) {
5310
case MemberKind.Event:
5312
case MemberKind.Field:
5313
case MemberKind.Property:
5314
var m = member as IInterfaceMemberSpec;
5315
return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
5321
public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5323
if (!method.IsReservedMethod)
5326
if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
5329
ec.Report.SymbolRelatedToPreviousError (method);
5330
ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5331
method.GetSignatureForError ());
5337
// Used to decide whether call or callvirt is needed
5339
static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
5342
// There are 2 scenarious where we emit callvirt
5344
// Case 1: A method is virtual and it's not used to call base
5345
// Case 2: A method instance expression can be null. In this casen callvirt ensures
5346
// correct NRE exception when the method is called
5348
var decl_type = method.DeclaringType;
5349
if (decl_type.IsStruct || decl_type.IsEnum)
5352
if (instance is BaseThis)
5356
// It's non-virtual and will never be null
5358
if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation))
5365
/// is_base tells whether we want to force the use of the `call'
5366
/// opcode instead of using callvirt. Call is required to call
5367
/// a specific method, while callvirt will always use the most
5368
/// recent method in the vtable.
5370
/// is_static tells whether this is an invocation on a static method
5372
/// instance_expr is an expression that represents the instance
5373
/// it must be non-null if is_static is false.
5375
/// method is the method to invoke.
5377
/// Arguments is the list of arguments to pass to the method or constructor.
5379
public static void EmitCall (EmitContext ec, Expression instance_expr,
5380
MethodSpec method, Arguments Arguments, Location loc)
5382
EmitCall (ec, instance_expr, method, Arguments, loc, false, false);
5385
// `dup_args' leaves an extra copy of the arguments on the stack
5386
// `omit_args' does not leave any arguments at all.
5387
// So, basically, you could make one call with `dup_args' set to true,
5388
// and then another with `omit_args' set to true, and the two calls
5389
// would have the same set of arguments. However, each argument would
5390
// only have been evaluated once.
5391
public static void EmitCall (EmitContext ec, Expression instance_expr,
5392
MethodSpec method, Arguments Arguments, Location loc,
5393
bool dup_args, bool omit_args)
5395
LocalTemporary this_arg = null;
5397
// Speed up the check by not doing it on not allowed targets
5398
if (method.ReturnType.Kind == MemberKind.Void && method.IsConditionallyExcluded (ec.Module.Compiler, loc))
5402
TypeSpec iexpr_type;
5404
if (method.IsStatic) {
5406
call_op = OpCodes.Call;
5408
iexpr_type = instance_expr.Type;
5410
if (IsVirtualCallRequired (instance_expr, method)) {
5411
call_op = OpCodes.Callvirt;
5413
call_op = OpCodes.Call;
5417
// If this is ourselves, push "this"
5420
TypeSpec t = iexpr_type;
5423
// Push the instance expression
5425
if ((iexpr_type.IsStruct && (call_op == OpCodes.Callvirt || (call_op == OpCodes.Call && method.DeclaringType == iexpr_type))) ||
5426
iexpr_type.IsGenericParameter || method.DeclaringType.IsNullableType) {
5428
// If the expression implements IMemoryLocation, then
5429
// we can optimize and use AddressOf on the
5432
// If not we have to use some temporary storage for
5434
var iml = instance_expr as IMemoryLocation;
5436
iml.AddressOf (ec, AddressOp.Load);
5438
LocalTemporary temp = new LocalTemporary (iexpr_type);
5439
instance_expr.Emit (ec);
5441
temp.AddressOf (ec, AddressOp.Load);
5444
// avoid the overhead of doing this all the time.
5446
t = ReferenceContainer.MakeType (ec.Module, iexpr_type);
5447
} else if (iexpr_type.IsEnum || iexpr_type.IsStruct) {
5448
instance_expr.Emit (ec);
5449
ec.Emit (OpCodes.Box, iexpr_type);
5450
t = iexpr_type = ec.BuiltinTypes.Object;
5452
instance_expr.Emit (ec);
5456
ec.Emit (OpCodes.Dup);
5457
if (Arguments != null && Arguments.Count != 0) {
5458
this_arg = new LocalTemporary (t);
5459
this_arg.Store (ec);
5465
if (!omit_args && Arguments != null) {
5466
var dup_arg_exprs = Arguments.Emit (ec, dup_args);
5470
foreach (var dup in dup_arg_exprs) {
5472
lt = dup as LocalTemporary;
5479
if (call_op == OpCodes.Callvirt && (iexpr_type.IsGenericParameter || iexpr_type.IsStruct)) {
5480
ec.Emit (OpCodes.Constrained, iexpr_type);
5483
if (method.Parameters.HasArglist) {
5484
var varargs_types = GetVarargsTypes (method, Arguments);
5485
ec.Emit (call_op, method, varargs_types);
5492
// and DoFoo is not virtual, you can omit the callvirt,
5493
// because you don't need the null checking behavior.
5495
ec.Emit (call_op, method);
5498
public override void Emit (EmitContext ec)
5500
mg.EmitCall (ec, arguments);
5503
public override void EmitStatement (EmitContext ec)
5508
// Pop the return value if there is one
5510
if (type.Kind != MemberKind.Void)
5511
ec.Emit (OpCodes.Pop);
5514
public override SLE.Expression MakeExpression (BuilderContext ctx)
5516
return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
5519
public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5522
throw new NotSupportedException ();
5524
var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5525
return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
5528
public override object Accept (StructuralVisitor visitor)
5530
return visitor.Visit (this);
5535
// Implements simple new expression
5537
public class New : ExpressionStatement, IMemoryLocation
5539
protected Arguments arguments;
5542
// During bootstrap, it contains the RequestedType,
5543
// but if `type' is not null, it *might* contain a NewDelegate
5544
// (because of field multi-initialization)
5546
protected Expression RequestedType;
5548
protected MethodSpec method;
5550
public New (Expression requested_type, Arguments arguments, Location l)
5552
RequestedType = requested_type;
5553
this.arguments = arguments;
5558
public Arguments Arguments {
5564
public Expression TypeRequested {
5566
return RequestedType;
5571
// Returns true for resolved `new S()'
5573
public bool IsDefaultStruct {
5575
return arguments == null && type.IsStruct && GetType () == typeof (New);
5582
/// Converts complex core type syntax like 'new int ()' to simple constant
5584
public static Constant Constantify (TypeSpec t, Location loc)
5586
switch (t.BuiltinType) {
5587
case BuiltinTypeSpec.Type.Int:
5588
return new IntConstant (t, 0, loc);
5589
case BuiltinTypeSpec.Type.UInt:
5590
return new UIntConstant (t, 0, loc);
5591
case BuiltinTypeSpec.Type.Long:
5592
return new LongConstant (t, 0, loc);
5593
case BuiltinTypeSpec.Type.ULong:
5594
return new ULongConstant (t, 0, loc);
5595
case BuiltinTypeSpec.Type.Float:
5596
return new FloatConstant (t, 0, loc);
5597
case BuiltinTypeSpec.Type.Double:
5598
return new DoubleConstant (t, 0, loc);
5599
case BuiltinTypeSpec.Type.Short:
5600
return new ShortConstant (t, 0, loc);
5601
case BuiltinTypeSpec.Type.UShort:
5602
return new UShortConstant (t, 0, loc);
5603
case BuiltinTypeSpec.Type.SByte:
5604
return new SByteConstant (t, 0, loc);
5605
case BuiltinTypeSpec.Type.Byte:
5606
return new ByteConstant (t, 0, loc);
5607
case BuiltinTypeSpec.Type.Char:
5608
return new CharConstant (t, '\0', loc);
5609
case BuiltinTypeSpec.Type.Bool:
5610
return new BoolConstant (t, false, loc);
5611
case BuiltinTypeSpec.Type.Decimal:
5612
return new DecimalConstant (t, 0, loc);
5616
return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
5618
if (t.IsNullableType)
5619
return Nullable.LiftedNull.Create (t, loc);
5625
// Checks whether the type is an interface that has the
5626
// [ComImport, CoClass] attributes and must be treated
5629
public Expression CheckComImport (ResolveContext ec)
5631
if (!type.IsInterface)
5635
// Turn the call into:
5636
// (the-interface-stated) (new class-referenced-in-coclassattribute ())
5638
var real_class = type.MemberDefinition.GetAttributeCoClass ();
5639
if (real_class == null)
5642
New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
5643
Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5644
return cast.Resolve (ec);
5647
public override Expression CreateExpressionTree (ResolveContext ec)
5650
if (method == null) {
5651
args = new Arguments (1);
5652
args.Add (new Argument (new TypeOf (type, loc)));
5654
args = Arguments.CreateForExpressionTree (ec,
5655
arguments, new TypeOfMethod (method, loc));
5658
return CreateExpressionFactoryCall (ec, "New", args);
5661
protected override Expression DoResolve (ResolveContext ec)
5663
type = RequestedType.ResolveAsType (ec);
5667
eclass = ExprClass.Value;
5669
if (type.IsPointer) {
5670
ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5671
TypeManager.CSharpName (type));
5675
if (arguments == null) {
5676
Constant c = Constantify (type, RequestedType.Location);
5678
return ReducedExpression.Create (c, this);
5681
if (TypeManager.IsDelegateType (type)) {
5682
return (new NewDelegate (type, arguments, loc)).Resolve (ec);
5685
var tparam = type as TypeParameterSpec;
5686
if (tparam != null) {
5688
// Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
5689
// where type parameter constraint is inflated to struct
5691
if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !tparam.BaseType.IsStruct) {
5692
ec.Report.Error (304, loc,
5693
"Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
5694
TypeManager.CSharpName (type));
5697
if ((arguments != null) && (arguments.Count != 0)) {
5698
ec.Report.Error (417, loc,
5699
"`{0}': cannot provide arguments when creating an instance of a variable type",
5700
TypeManager.CSharpName (type));
5706
if (type.IsStatic) {
5707
ec.Report.SymbolRelatedToPreviousError (type);
5708
ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5712
if (type.IsInterface || type.IsAbstract){
5713
if (!TypeManager.IsGenericType (type)) {
5714
RequestedType = CheckComImport (ec);
5715
if (RequestedType != null)
5716
return RequestedType;
5719
ec.Report.SymbolRelatedToPreviousError (type);
5720
ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5725
// Any struct always defines parameterless constructor
5727
if (type.IsStruct && arguments == null)
5731
if (arguments != null) {
5732
arguments.Resolve (ec, out dynamic);
5737
method = ConstructorLookup (ec, type, ref arguments, loc);
5740
arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5741
return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
5747
bool DoEmitTypeParameter (EmitContext ec)
5749
var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
5753
var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
5754
var tparam = (TypeParameterSpec) type;
5756
if (tparam.IsReferenceType) {
5757
ec.Emit (OpCodes.Call, ctor_factory);
5761
// Allow DoEmit() to be called multiple times.
5762
// We need to create a new LocalTemporary each time since
5763
// you can't share LocalBuilders among ILGeneators.
5764
LocalTemporary temp = new LocalTemporary (type);
5766
Label label_activator = ec.DefineLabel ();
5767
Label label_end = ec.DefineLabel ();
5769
temp.AddressOf (ec, AddressOp.Store);
5770
ec.Emit (OpCodes.Initobj, type);
5773
ec.Emit (OpCodes.Box, type);
5774
ec.Emit (OpCodes.Brfalse, label_activator);
5776
temp.AddressOf (ec, AddressOp.Store);
5777
ec.Emit (OpCodes.Initobj, type);
5779
ec.Emit (OpCodes.Br_S, label_end);
5781
ec.MarkLabel (label_activator);
5783
ec.Emit (OpCodes.Call, ctor_factory);
5784
ec.MarkLabel (label_end);
5789
// This Emit can be invoked in two contexts:
5790
// * As a mechanism that will leave a value on the stack (new object)
5791
// * As one that wont (init struct)
5793
// If we are dealing with a ValueType, we have a few
5794
// situations to deal with:
5796
// * The target is a ValueType, and we have been provided
5797
// the instance (this is easy, we are being assigned).
5799
// * The target of New is being passed as an argument,
5800
// to a boxing operation or a function that takes a
5803
// In this case, we need to create a temporary variable
5804
// that is the argument of New.
5806
// Returns whether a value is left on the stack
5808
// *** Implementation note ***
5810
// To benefit from this optimization, each assignable expression
5811
// has to manually cast to New and call this Emit.
5813
// TODO: It's worth to implement it for arrays and fields
5815
public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5817
bool is_value_type = TypeSpec.IsValueType (type);
5818
VariableReference vr = target as VariableReference;
5820
if (target != null && is_value_type && (vr != null || method == null)) {
5821
target.AddressOf (ec, AddressOp.Store);
5822
} else if (vr != null && vr.IsRef) {
5826
if (arguments != null)
5827
arguments.Emit (ec);
5829
if (is_value_type) {
5830
if (method == null) {
5831
ec.Emit (OpCodes.Initobj, type);
5836
ec.Emit (OpCodes.Call, method);
5841
if (type is TypeParameterSpec)
5842
return DoEmitTypeParameter (ec);
5844
ec.Emit (OpCodes.Newobj, method);
5848
public override void Emit (EmitContext ec)
5850
LocalTemporary v = null;
5851
if (method == null && TypeSpec.IsValueType (type)) {
5852
// TODO: Use temporary variable from pool
5853
v = new LocalTemporary (type);
5860
public override void EmitStatement (EmitContext ec)
5862
LocalTemporary v = null;
5863
if (method == null && TypeSpec.IsValueType (type)) {
5864
// TODO: Use temporary variable from pool
5865
v = new LocalTemporary (type);
5869
ec.Emit (OpCodes.Pop);
5872
public void AddressOf (EmitContext ec, AddressOp mode)
5874
EmitAddressOf (ec, mode);
5877
protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5879
LocalTemporary value_target = new LocalTemporary (type);
5881
if (type is TypeParameterSpec) {
5882
DoEmitTypeParameter (ec);
5883
value_target.Store (ec);
5884
value_target.AddressOf (ec, mode);
5885
return value_target;
5888
value_target.AddressOf (ec, AddressOp.Store);
5890
if (method == null) {
5891
ec.Emit (OpCodes.Initobj, type);
5893
if (arguments != null)
5894
arguments.Emit (ec);
5896
ec.Emit (OpCodes.Call, method);
5899
value_target.AddressOf (ec, mode);
5900
return value_target;
5903
protected override void CloneTo (CloneContext clonectx, Expression t)
5905
New target = (New) t;
5907
target.RequestedType = RequestedType.Clone (clonectx);
5908
if (arguments != null){
5909
target.arguments = arguments.Clone (clonectx);
5913
public override SLE.Expression MakeExpression (BuilderContext ctx)
5916
return base.MakeExpression (ctx);
5918
return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
5922
public override object Accept (StructuralVisitor visitor)
5924
return visitor.Visit (this);
5929
// Array initializer expression, the expression is allowed in
5930
// variable or field initialization only which makes it tricky as
5931
// the type has to be infered based on the context either from field
5932
// type or variable type (think of multiple declarators)
5934
public class ArrayInitializer : Expression
5936
List<Expression> elements;
5937
BlockVariableDeclaration variable;
5939
public ArrayInitializer (List<Expression> init, Location loc)
5945
public ArrayInitializer (int count, Location loc)
5946
: this (new List<Expression> (count), loc)
5950
public ArrayInitializer (Location loc)
5958
get { return elements.Count; }
5961
public Expression this [int index] {
5963
return elements [index];
5967
public BlockVariableDeclaration VariableDeclaration {
5976
public List<Expression> Elements {
5978
return this.elements;
5983
public void Add (Expression expr)
5985
elements.Add (expr);
5988
public override Expression CreateExpressionTree (ResolveContext ec)
5990
throw new NotSupportedException ("ET");
5993
protected override void CloneTo (CloneContext clonectx, Expression t)
5995
var target = (ArrayInitializer) t;
5997
target.elements = new List<Expression> (elements.Count);
5998
foreach (var element in elements)
5999
target.elements.Add (element.Clone (clonectx));
6002
protected override Expression DoResolve (ResolveContext rc)
6004
var current_field = rc.CurrentMemberDefinition as FieldBase;
6005
TypeExpression type;
6006
if (current_field != null) {
6007
type = new TypeExpression (current_field.MemberType, current_field.Location);
6008
} else if (variable != null) {
6009
if (variable.TypeExpression is VarExpr) {
6010
rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6011
return EmptyExpression.Null;
6014
type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
6016
throw new NotImplementedException ("Unexpected array initializer context");
6019
return new ArrayCreation (type, this).Resolve (rc);
6022
public override void Emit (EmitContext ec)
6024
throw new InternalErrorException ("Missing Resolve call");
6027
public override object Accept (StructuralVisitor visitor)
6029
return visitor.Visit (this);
6034
/// 14.5.10.2: Represents an array creation expression.
6038
/// There are two possible scenarios here: one is an array creation
6039
/// expression that specifies the dimensions and optionally the
6040
/// initialization data and the other which does not need dimensions
6041
/// specified but where initialization data is mandatory.
6043
public class ArrayCreation : Expression
6045
FullNamedExpression requested_base_type;
6046
ArrayInitializer initializers;
6049
// The list of Argument types.
6050
// This is used to construct the `newarray' or constructor signature
6052
protected List<Expression> arguments;
6054
protected TypeSpec array_element_type;
6055
int num_arguments = 0;
6056
protected int dimensions;
6057
protected readonly ComposedTypeSpecifier rank;
6058
Expression first_emit;
6059
LocalTemporary first_emit_temp;
6061
protected List<Expression> array_data;
6063
Dictionary<int, int> bounds;
6065
// The number of constants in array initializers
6066
int const_initializers_count;
6067
bool only_constant_initializers;
6069
public List<Expression> Arguments {
6070
get { return this.arguments; }
6073
public ComposedTypeSpecifier Rank {
6074
get { return this.rank; }
6077
public FullNamedExpression NewType {
6078
get { return this.requested_base_type; }
6081
public ArrayInitializer Initializers {
6082
get { return this.initializers; }
6085
public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
6086
: this (requested_base_type, rank, initializers, l)
6089
num_arguments = arguments.Count;
6093
// For expressions like int[] foo = new int[] { 1, 2, 3 };
6095
public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6097
this.requested_base_type = requested_base_type;
6099
this.initializers = initializers;
6103
num_arguments = rank.Dimension;
6107
// For compiler generated single dimensional arrays only
6109
public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
6110
: this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
6115
// For expressions like int[] foo = { 1, 2, 3 };
6117
public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
6118
: this (requested_base_type, null, initializers, initializers.Location)
6122
protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
6124
ec.Report.Error (248, loc, "Cannot create an array with a negative size");
6127
bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
6129
if (initializers != null && bounds == null) {
6131
// We use this to store all the date values in the order in which we
6132
// will need to store them in the byte blob later
6134
array_data = new List<Expression> ();
6135
bounds = new Dictionary<int, int> ();
6138
if (specified_dims) {
6139
Expression a = arguments [idx];
6144
a = ConvertExpressionToArrayIndex (ec, a);
6150
if (initializers != null) {
6151
Constant c = a as Constant;
6152
if (c == null && a is ArrayIndexCast)
6153
c = ((ArrayIndexCast) a).Child as Constant;
6156
ec.Report.Error (150, a.Location, "A constant value is expected");
6162
value = System.Convert.ToInt32 (c.GetValue ());
6164
ec.Report.Error (150, a.Location, "A constant value is expected");
6168
// TODO: probe.Count does not fit ulong in
6169
if (value != probe.Count) {
6170
ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
6174
bounds[idx] = value;
6178
if (initializers == null)
6181
for (int i = 0; i < probe.Count; ++i) {
6183
if (o is ArrayInitializer) {
6184
var sub_probe = o as ArrayInitializer;
6185
if (idx + 1 >= dimensions){
6186
ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6190
bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
6193
} else if (child_bounds > 1) {
6194
ec.Report.Error (846, o.Location, "A nested array initializer was expected");
6196
Expression element = ResolveArrayElement (ec, o);
6197
if (element == null)
6200
// Initializers with the default values can be ignored
6201
Constant c = element as Constant;
6203
if (!c.IsDefaultInitializer (array_element_type)) {
6204
++const_initializers_count;
6207
only_constant_initializers = false;
6210
array_data.Add (element);
6217
public override Expression CreateExpressionTree (ResolveContext ec)
6221
if (array_data == null) {
6222
args = new Arguments (arguments.Count + 1);
6223
args.Add (new Argument (new TypeOf (array_element_type, loc)));
6224
foreach (Expression a in arguments)
6225
args.Add (new Argument (a.CreateExpressionTree (ec)));
6227
return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
6230
if (dimensions > 1) {
6231
ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
6235
args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
6236
args.Add (new Argument (new TypeOf (array_element_type, loc)));
6237
if (array_data != null) {
6238
for (int i = 0; i < array_data.Count; ++i) {
6239
Expression e = array_data [i];
6240
args.Add (new Argument (e.CreateExpressionTree (ec)));
6244
return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
6247
void UpdateIndices (ResolveContext rc)
6250
for (var probe = initializers; probe != null;) {
6251
Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
6253
bounds[i++] = probe.Count;
6255
if (probe.Count > 0 && probe [0] is ArrayInitializer) {
6256
probe = (ArrayInitializer) probe[0];
6257
} else if (dimensions > i) {
6265
protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6267
element = element.Resolve (ec);
6268
if (element == null)
6271
if (element is CompoundAssign.TargetExpression) {
6272
if (first_emit != null)
6273
throw new InternalErrorException ("Can only handle one mutator at a time");
6274
first_emit = element;
6275
element = first_emit_temp = new LocalTemporary (element.Type);
6278
return Convert.ImplicitConversionRequired (
6279
ec, element, array_element_type, loc);
6282
protected bool ResolveInitializers (ResolveContext ec)
6284
only_constant_initializers = true;
6286
if (arguments != null) {
6288
for (int i = 0; i < arguments.Count; ++i) {
6289
res &= CheckIndices (ec, initializers, i, true, dimensions);
6290
if (initializers != null)
6297
arguments = new List<Expression> ();
6299
if (!CheckIndices (ec, initializers, 0, false, dimensions))
6308
// Resolved the type of the array
6310
bool ResolveArrayType (ResolveContext ec)
6315
FullNamedExpression array_type_expr;
6316
if (num_arguments > 0) {
6317
array_type_expr = new ComposedCast (requested_base_type, rank);
6319
array_type_expr = requested_base_type;
6322
type = array_type_expr.ResolveAsType (ec);
6323
if (array_type_expr == null)
6326
var ac = type as ArrayContainer;
6328
ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6332
array_element_type = ac.Element;
6333
dimensions = ac.Rank;
6338
protected override Expression DoResolve (ResolveContext ec)
6343
if (!ResolveArrayType (ec))
6347
// validate the initializers and fill in any missing bits
6349
if (!ResolveInitializers (ec))
6352
eclass = ExprClass.Value;
6356
byte [] MakeByteBlob ()
6361
int count = array_data.Count;
6363
TypeSpec element_type = array_element_type;
6364
if (TypeManager.IsEnumType (element_type))
6365
element_type = EnumSpec.GetUnderlyingType (element_type);
6367
factor = BuiltinTypeSpec.GetSize (element_type);
6369
throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6371
data = new byte [(count * factor + 3) & ~3];
6374
for (int i = 0; i < count; ++i) {
6375
var c = array_data[i] as Constant;
6381
object v = c.GetValue ();
6383
switch (element_type.BuiltinType) {
6384
case BuiltinTypeSpec.Type.Long:
6385
long lval = (long) v;
6387
for (int j = 0; j < factor; ++j) {
6388
data[idx + j] = (byte) (lval & 0xFF);
6392
case BuiltinTypeSpec.Type.ULong:
6393
ulong ulval = (ulong) v;
6395
for (int j = 0; j < factor; ++j) {
6396
data[idx + j] = (byte) (ulval & 0xFF);
6397
ulval = (ulval >> 8);
6400
case BuiltinTypeSpec.Type.Float:
6401
element = BitConverter.GetBytes ((float) v);
6403
for (int j = 0; j < factor; ++j)
6404
data[idx + j] = element[j];
6405
if (!BitConverter.IsLittleEndian)
6406
System.Array.Reverse (data, idx, 4);
6408
case BuiltinTypeSpec.Type.Double:
6409
element = BitConverter.GetBytes ((double) v);
6411
for (int j = 0; j < factor; ++j)
6412
data[idx + j] = element[j];
6414
// FIXME: Handle the ARM float format.
6415
if (!BitConverter.IsLittleEndian)
6416
System.Array.Reverse (data, idx, 8);
6418
case BuiltinTypeSpec.Type.Char:
6419
int chval = (int) ((char) v);
6421
data[idx] = (byte) (chval & 0xff);
6422
data[idx + 1] = (byte) (chval >> 8);
6424
case BuiltinTypeSpec.Type.Short:
6425
int sval = (int) ((short) v);
6427
data[idx] = (byte) (sval & 0xff);
6428
data[idx + 1] = (byte) (sval >> 8);
6430
case BuiltinTypeSpec.Type.UShort:
6431
int usval = (int) ((ushort) v);
6433
data[idx] = (byte) (usval & 0xff);
6434
data[idx + 1] = (byte) (usval >> 8);
6436
case BuiltinTypeSpec.Type.Int:
6439
data[idx] = (byte) (val & 0xff);
6440
data[idx + 1] = (byte) ((val >> 8) & 0xff);
6441
data[idx + 2] = (byte) ((val >> 16) & 0xff);
6442
data[idx + 3] = (byte) (val >> 24);
6444
case BuiltinTypeSpec.Type.UInt:
6445
uint uval = (uint) v;
6447
data[idx] = (byte) (uval & 0xff);
6448
data[idx + 1] = (byte) ((uval >> 8) & 0xff);
6449
data[idx + 2] = (byte) ((uval >> 16) & 0xff);
6450
data[idx + 3] = (byte) (uval >> 24);
6452
case BuiltinTypeSpec.Type.SByte:
6453
data[idx] = (byte) (sbyte) v;
6455
case BuiltinTypeSpec.Type.Byte:
6456
data[idx] = (byte) v;
6458
case BuiltinTypeSpec.Type.Bool:
6459
data[idx] = (byte) ((bool) v ? 1 : 0);
6461
case BuiltinTypeSpec.Type.Decimal:
6462
int[] bits = Decimal.GetBits ((decimal) v);
6465
// FIXME: For some reason, this doesn't work on the MS runtime.
6466
int[] nbits = new int[4];
6472
for (int j = 0; j < 4; j++) {
6473
data[p++] = (byte) (nbits[j] & 0xff);
6474
data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
6475
data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
6476
data[p++] = (byte) (nbits[j] >> 24);
6480
throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6490
public override SLE.Expression MakeExpression (BuilderContext ctx)
6493
return base.MakeExpression (ctx);
6495
var initializers = new SLE.Expression [array_data.Count];
6496
for (var i = 0; i < initializers.Length; i++) {
6497
if (array_data [i] == null)
6498
initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
6500
initializers [i] = array_data [i].MakeExpression (ctx);
6503
return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
6509
// Emits the initializers for the array
6511
void EmitStaticInitializers (EmitContext ec)
6513
var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
6518
// First, the static data
6520
byte [] data = MakeByteBlob ();
6521
var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
6523
ec.Emit (OpCodes.Dup);
6524
ec.Emit (OpCodes.Ldtoken, fb);
6525
ec.Emit (OpCodes.Call, m);
6530
// Emits pieces of the array that can not be computed at compile
6531
// time (variables and string locations).
6533
// This always expect the top value on the stack to be the array
6535
void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6537
int dims = bounds.Count;
6538
var current_pos = new int [dims];
6540
for (int i = 0; i < array_data.Count; i++){
6542
Expression e = array_data [i];
6543
var c = e as Constant;
6545
// Constant can be initialized via StaticInitializer
6546
if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
6547
TypeSpec etype = e.Type;
6549
ec.Emit (OpCodes.Dup);
6551
for (int idx = 0; idx < dims; idx++)
6552
ec.EmitInt (current_pos [idx]);
6555
// If we are dealing with a struct, get the
6556
// address of it, so we can store it.
6558
if (dims == 1 && etype.IsStruct) {
6559
switch (etype.BuiltinType) {
6560
case BuiltinTypeSpec.Type.Byte:
6561
case BuiltinTypeSpec.Type.SByte:
6562
case BuiltinTypeSpec.Type.Bool:
6563
case BuiltinTypeSpec.Type.Short:
6564
case BuiltinTypeSpec.Type.UShort:
6565
case BuiltinTypeSpec.Type.Char:
6566
case BuiltinTypeSpec.Type.Int:
6567
case BuiltinTypeSpec.Type.UInt:
6568
case BuiltinTypeSpec.Type.Long:
6569
case BuiltinTypeSpec.Type.ULong:
6570
case BuiltinTypeSpec.Type.Float:
6571
case BuiltinTypeSpec.Type.Double:
6574
ec.Emit (OpCodes.Ldelema, etype);
6581
ec.EmitArrayStore ((ArrayContainer) type);
6587
for (int j = dims - 1; j >= 0; j--){
6589
if (current_pos [j] < bounds [j])
6591
current_pos [j] = 0;
6596
public override void Emit (EmitContext ec)
6598
if (first_emit != null) {
6599
first_emit.Emit (ec);
6600
first_emit_temp.Store (ec);
6603
foreach (Expression e in arguments)
6606
ec.EmitArrayNew ((ArrayContainer) type);
6608
if (initializers == null)
6612
// Emit static initializer for arrays which have contain more than 2 items and
6613
// the static initializer will initialize at least 25% of array values or there
6614
// is more than 10 items to be initialized
6615
// NOTE: const_initializers_count does not contain default constant values.
6616
if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
6617
(BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
6618
EmitStaticInitializers (ec);
6620
if (!only_constant_initializers)
6621
EmitDynamicInitializers (ec, false);
6625
EmitDynamicInitializers (ec, true);
6628
if (first_emit_temp != null)
6629
first_emit_temp.Release (ec);
6632
public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
6634
// no multi dimensional or jagged arrays
6635
if (arguments.Count != 1 || array_element_type.IsArray) {
6636
base.EncodeAttributeValue (rc, enc, targetType);
6640
// No array covariance, except for array -> object
6641
if (type != targetType) {
6642
if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
6643
base.EncodeAttributeValue (rc, enc, targetType);
6647
if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
6648
Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
6653
// Single dimensional array of 0 size
6654
if (array_data == null) {
6655
IntConstant ic = arguments[0] as IntConstant;
6656
if (ic == null || !ic.IsDefaultValue) {
6657
base.EncodeAttributeValue (rc, enc, targetType);
6665
enc.Encode (array_data.Count);
6666
foreach (var element in array_data) {
6667
element.EncodeAttributeValue (rc, enc, array_element_type);
6671
protected override void CloneTo (CloneContext clonectx, Expression t)
6673
ArrayCreation target = (ArrayCreation) t;
6675
if (requested_base_type != null)
6676
target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6678
if (arguments != null){
6679
target.arguments = new List<Expression> (arguments.Count);
6680
foreach (Expression e in arguments)
6681
target.arguments.Add (e.Clone (clonectx));
6684
if (initializers != null)
6685
target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6688
public override object Accept (StructuralVisitor visitor)
6690
return visitor.Visit (this);
6695
// Represents an implicitly typed array epxression
6697
class ImplicitlyTypedArrayCreation : ArrayCreation
6699
sealed class InferenceContext : TypeInferenceContext
6701
class ExpressionBoundInfo : BoundInfo
6703
readonly Expression expr;
6705
public ExpressionBoundInfo (Expression expr)
6706
: base (expr.Type, BoundKind.Lower)
6711
public override bool Equals (BoundInfo other)
6713
// We are using expression not type for conversion check
6714
// no optimization based on types is possible
6718
public override Expression GetTypeExpression ()
6724
public void AddExpression (Expression expr)
6726
AddToBounds (new ExpressionBoundInfo (expr), 0);
6730
InferenceContext best_type_inference;
6732
public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
6733
: base (null, rank, initializers, loc)
6737
public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
6738
: base (null, initializers, loc)
6742
protected override Expression DoResolve (ResolveContext ec)
6747
dimensions = rank.Dimension;
6749
best_type_inference = new InferenceContext ();
6751
if (!ResolveInitializers (ec))
6754
best_type_inference.FixAllTypes (ec);
6755
array_element_type = best_type_inference.InferredTypeArguments[0];
6756
best_type_inference = null;
6758
if (array_element_type == null || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
6759
arguments.Count != rank.Dimension) {
6760
ec.Report.Error (826, loc,
6761
"The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6766
// At this point we found common base type for all initializer elements
6767
// but we have to be sure that all static initializer elements are of
6770
UnifyInitializerElement (ec);
6772
type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
6773
eclass = ExprClass.Value;
6778
// Converts static initializer only
6780
void UnifyInitializerElement (ResolveContext ec)
6782
for (int i = 0; i < array_data.Count; ++i) {
6783
Expression e = array_data[i];
6785
array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6789
protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6791
element = element.Resolve (ec);
6792
if (element != null)
6793
best_type_inference.AddExpression (element);
6799
sealed class CompilerGeneratedThis : This
6801
public CompilerGeneratedThis (TypeSpec type, Location loc)
6805
eclass = ExprClass.Variable;
6808
protected override Expression DoResolve (ResolveContext ec)
6813
public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6820
/// Represents the `this' construct
6823
public class This : VariableReference
6825
sealed class ThisVariable : ILocalVariable
6827
public static readonly ILocalVariable Instance = new ThisVariable ();
6829
public void Emit (EmitContext ec)
6831
ec.Emit (OpCodes.Ldarg_0);
6834
public void EmitAssign (EmitContext ec)
6836
throw new InvalidOperationException ();
6839
public void EmitAddressOf (EmitContext ec)
6841
ec.Emit (OpCodes.Ldarg_0);
6845
VariableInfo variable_info;
6847
public This (Location loc)
6854
public override string Name {
6855
get { return "this"; }
6858
public override bool IsLockedByStatement {
6866
public override bool IsRef {
6867
get { return type.IsStruct; }
6870
protected override ILocalVariable Variable {
6871
get { return ThisVariable.Instance; }
6874
public override VariableInfo VariableInfo {
6875
get { return variable_info; }
6878
public override bool IsFixed {
6879
get { return false; }
6884
public void CheckStructThisDefiniteAssignment (ResolveContext rc)
6886
if (variable_info != null && !variable_info.IsAssigned (rc)) {
6887
rc.Report.Error (188, loc,
6888
"The `this' object cannot be used before all of its fields are assigned to");
6892
protected virtual void Error_ThisNotAvailable (ResolveContext ec)
6894
if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6895
ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6896
} else if (ec.CurrentAnonymousMethod != null) {
6897
ec.Report.Error (1673, loc,
6898
"Anonymous methods inside structs cannot access instance members of `this'. " +
6899
"Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6901
ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6905
public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6910
AnonymousMethodStorey storey = ae.Storey;
6911
while (storey != null) {
6912
AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6914
return storey.HoistedThis;
6922
public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
6924
if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6927
if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
6930
if (ec.CurrentType.IsStruct && ec.CurrentIterator == null)
6936
public virtual void ResolveBase (ResolveContext ec)
6938
eclass = ExprClass.Variable;
6939
type = ec.CurrentType;
6941
if (!IsThisAvailable (ec, false)) {
6942
Error_ThisNotAvailable (ec);
6946
var block = ec.CurrentBlock;
6947
if (block != null) {
6948
if (block.ParametersBlock.TopBlock.ThisVariable != null)
6949
variable_info = block.ParametersBlock.TopBlock.ThisVariable.VariableInfo;
6951
AnonymousExpression am = ec.CurrentAnonymousMethod;
6952
if (am != null && ec.IsVariableCapturingRequired) {
6953
am.SetHasThisAccess ();
6958
public override Expression CreateExpressionTree (ResolveContext ec)
6960
Arguments args = new Arguments (1);
6961
args.Add (new Argument (this));
6963
// Use typeless constant for ldarg.0 to save some
6964
// space and avoid problems with anonymous stories
6965
return CreateExpressionFactoryCall (ec, "Constant", args);
6968
protected override Expression DoResolve (ResolveContext ec)
6972
if (variable_info != null && type.IsStruct) {
6973
CheckStructThisDefiniteAssignment (ec);
6979
override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6983
if (variable_info != null)
6984
variable_info.SetAssigned (ec);
6987
if (right_side == EmptyExpression.UnaryAddress)
6988
ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6989
else if (right_side == EmptyExpression.OutAccess)
6990
ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6992
ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6998
public override int GetHashCode()
7000
throw new NotImplementedException ();
7003
public override bool Equals (object obj)
7005
This t = obj as This;
7012
protected override void CloneTo (CloneContext clonectx, Expression t)
7017
public override void SetHasAddressTaken ()
7022
public override object Accept (StructuralVisitor visitor)
7024
return visitor.Visit (this);
7029
/// Represents the `__arglist' construct
7031
public class ArglistAccess : Expression
7033
public ArglistAccess (Location loc)
7038
public override Expression CreateExpressionTree (ResolveContext ec)
7040
throw new NotSupportedException ("ET");
7043
protected override Expression DoResolve (ResolveContext ec)
7045
eclass = ExprClass.Variable;
7046
type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
7048
if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
7049
ec.Report.Error (190, loc,
7050
"The __arglist construct is valid only within a variable argument method");
7056
public override void Emit (EmitContext ec)
7058
ec.Emit (OpCodes.Arglist);
7061
protected override void CloneTo (CloneContext clonectx, Expression target)
7065
public override object Accept (StructuralVisitor visitor)
7067
return visitor.Visit (this);
7072
/// Represents the `__arglist (....)' construct
7074
public class Arglist : Expression
7076
public Arguments Arguments { get; private set; }
7078
public Arglist (Location loc)
7083
public Arglist (Arguments args, Location l)
7089
public MetaType[] ArgumentTypes {
7091
if (Arguments == null)
7092
return MetaType.EmptyTypes;
7094
var retval = new MetaType[Arguments.Count];
7095
for (int i = 0; i < retval.Length; i++)
7096
retval[i] = Arguments[i].Expr.Type.GetMetaInfo ();
7102
public override Expression CreateExpressionTree (ResolveContext ec)
7104
ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
7108
protected override Expression DoResolve (ResolveContext ec)
7110
eclass = ExprClass.Variable;
7111
type = InternalType.Arglist;
7112
if (Arguments != null) {
7113
bool dynamic; // Can be ignored as there is always only 1 overload
7114
Arguments.Resolve (ec, out dynamic);
7120
public override void Emit (EmitContext ec)
7122
if (Arguments != null)
7123
Arguments.Emit (ec);
7126
protected override void CloneTo (CloneContext clonectx, Expression t)
7128
Arglist target = (Arglist) t;
7130
if (Arguments != null)
7131
target.Arguments = Arguments.Clone (clonectx);
7133
public override object Accept (StructuralVisitor visitor)
7135
return visitor.Visit (this);
7139
public class RefValueExpr : ShimExpression
7141
FullNamedExpression texpr;
7143
public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
7150
protected override Expression DoResolve (ResolveContext rc)
7152
expr = expr.Resolve (rc);
7153
type = texpr.ResolveAsType (rc);
7154
if (expr == null || type == null)
7157
expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7158
eclass = ExprClass.Value;
7162
public override void Emit (EmitContext ec)
7165
ec.Emit (OpCodes.Refanyval, type);
7166
ec.EmitLoadFromPtr (type);
7169
public override object Accept (StructuralVisitor visitor)
7171
return visitor.Visit (this);
7175
public class RefTypeExpr : ShimExpression
7177
public RefTypeExpr (Expression expr, Location loc)
7183
protected override Expression DoResolve (ResolveContext rc)
7185
expr = expr.Resolve (rc);
7189
expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
7193
type = rc.BuiltinTypes.Type;
7194
eclass = ExprClass.Value;
7198
public override void Emit (EmitContext ec)
7201
ec.Emit (OpCodes.Refanytype);
7202
var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7204
ec.Emit (OpCodes.Call, m);
7207
public override object Accept (StructuralVisitor visitor)
7209
return visitor.Visit (this);
7213
public class MakeRefExpr : ShimExpression
7215
public MakeRefExpr (Expression expr, Location loc)
7221
protected override Expression DoResolve (ResolveContext rc)
7223
expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
7224
type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
7225
eclass = ExprClass.Value;
7229
public override void Emit (EmitContext ec)
7231
((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
7232
ec.Emit (OpCodes.Mkrefany, expr.Type);
7235
public override object Accept (StructuralVisitor visitor)
7237
return visitor.Visit (this);
7242
/// Implements the typeof operator
7244
public class TypeOf : Expression {
7245
FullNamedExpression QueriedType;
7248
public TypeOf (FullNamedExpression queried_type, Location l)
7250
QueriedType = queried_type;
7255
// Use this constructor for any compiler generated typeof expression
7257
public TypeOf (TypeSpec type, Location loc)
7259
this.typearg = type;
7264
public TypeSpec TypeArgument {
7270
public FullNamedExpression TypeExpression {
7278
public override Expression CreateExpressionTree (ResolveContext ec)
7280
Arguments args = new Arguments (2);
7281
args.Add (new Argument (this));
7282
args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7283
return CreateExpressionFactoryCall (ec, "Constant", args);
7286
protected override Expression DoResolve (ResolveContext ec)
7288
if (eclass != ExprClass.Unresolved)
7291
if (typearg == null) {
7293
// Pointer types are allowed without explicit unsafe, they are just tokens
7295
using (ec.Set (ResolveContext.Options.UnsafeScope)) {
7296
typearg = QueriedType.ResolveAsType (ec);
7299
if (typearg == null)
7302
if (typearg.Kind == MemberKind.Void && !(QueriedType is TypeExpression)) {
7303
ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
7304
} else if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7305
ec.Report.Error (1962, QueriedType.Location,
7306
"The typeof operator cannot be used on the dynamic type");
7310
type = ec.BuiltinTypes.Type;
7312
// Even though what is returned is a type object, it's treated as a value by the compiler.
7313
// In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7314
eclass = ExprClass.Value;
7318
static bool ContainsDynamicType (TypeSpec type)
7320
if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7323
var element_container = type as ElementTypeSpec;
7324
if (element_container != null)
7325
return ContainsDynamicType (element_container.Element);
7327
foreach (var t in type.TypeArguments) {
7328
if (ContainsDynamicType (t)) {
7336
public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
7338
// Target type is not System.Type therefore must be object
7339
// and we need to use different encoding sequence
7340
if (targetType != type)
7343
if (typearg is InflatedTypeSpec) {
7346
if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
7347
rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7348
typearg.GetSignatureForError ());
7352
gt = gt.DeclaringType;
7353
} while (gt != null);
7356
if (ContainsDynamicType (typearg)) {
7357
Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
7361
enc.EncodeTypeName (typearg);
7364
public override void Emit (EmitContext ec)
7366
ec.Emit (OpCodes.Ldtoken, typearg);
7367
var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
7369
ec.Emit (OpCodes.Call, m);
7372
protected override void CloneTo (CloneContext clonectx, Expression t)
7374
TypeOf target = (TypeOf) t;
7375
if (QueriedType != null)
7376
target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
7379
public override object Accept (StructuralVisitor visitor)
7381
return visitor.Visit (this);
7385
sealed class TypeOfMethod : TypeOfMember<MethodSpec>
7387
public TypeOfMethod (MethodSpec method, Location loc)
7388
: base (method, loc)
7392
protected override Expression DoResolve (ResolveContext ec)
7394
if (member.IsConstructor) {
7395
type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
7397
type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
7403
return base.DoResolve (ec);
7406
public override void Emit (EmitContext ec)
7408
ec.Emit (OpCodes.Ldtoken, member);
7411
ec.Emit (OpCodes.Castclass, type);
7414
protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7416
return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
7419
protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7421
return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
7425
abstract class TypeOfMember<T> : Expression where T : MemberSpec
7427
protected readonly T member;
7429
protected TypeOfMember (T member, Location loc)
7431
this.member = member;
7435
public override Expression CreateExpressionTree (ResolveContext ec)
7437
Arguments args = new Arguments (2);
7438
args.Add (new Argument (this));
7439
args.Add (new Argument (new TypeOf (type, loc)));
7440
return CreateExpressionFactoryCall (ec, "Constant", args);
7443
protected override Expression DoResolve (ResolveContext ec)
7445
eclass = ExprClass.Value;
7449
public override void Emit (EmitContext ec)
7451
bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
7452
PredefinedMember<MethodSpec> p;
7454
p = GetTypeFromHandleGeneric (ec);
7455
ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
7457
p = GetTypeFromHandle (ec);
7460
var mi = p.Resolve (loc);
7462
ec.Emit (OpCodes.Call, mi);
7465
protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
7466
protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
7469
sealed class TypeOfField : TypeOfMember<FieldSpec>
7471
public TypeOfField (FieldSpec field, Location loc)
7476
protected override Expression DoResolve (ResolveContext ec)
7478
type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
7482
return base.DoResolve (ec);
7485
public override void Emit (EmitContext ec)
7487
ec.Emit (OpCodes.Ldtoken, member);
7491
protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
7493
return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
7496
protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
7498
return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
7503
/// Implements the sizeof expression
7505
public class SizeOf : Expression {
7506
public readonly Expression QueriedType;
7507
TypeSpec type_queried;
7509
public SizeOf (Expression queried_type, Location l)
7511
this.QueriedType = queried_type;
7515
public override Expression CreateExpressionTree (ResolveContext ec)
7517
Error_PointerInsideExpressionTree (ec);
7521
protected override Expression DoResolve (ResolveContext ec)
7523
type_queried = QueriedType.ResolveAsType (ec);
7524
if (type_queried == null)
7527
if (TypeManager.IsEnumType (type_queried))
7528
type_queried = EnumSpec.GetUnderlyingType (type_queried);
7530
int size_of = BuiltinTypeSpec.GetSize (type_queried);
7532
return new IntConstant (ec.BuiltinTypes, size_of, loc);
7535
if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
7540
ec.Report.Error (233, loc,
7541
"`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7542
TypeManager.CSharpName (type_queried));
7545
type = ec.BuiltinTypes.Int;
7546
eclass = ExprClass.Value;
7550
public override void Emit (EmitContext ec)
7552
ec.Emit (OpCodes.Sizeof, type_queried);
7555
protected override void CloneTo (CloneContext clonectx, Expression t)
7559
public override object Accept (StructuralVisitor visitor)
7561
return visitor.Visit (this);
7566
/// Implements the qualified-alias-member (::) expression.
7568
public class QualifiedAliasMember : MemberAccess
7570
public readonly string alias;
7571
public static readonly string GlobalAlias = "global";
7573
public QualifiedAliasMember (string alias, string identifier, Location l)
7574
: base (null, identifier, l)
7579
public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7580
: base (null, identifier, targs, l)
7585
public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
7586
: base (null, identifier, arity, l)
7591
public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
7593
if (alias == GlobalAlias) {
7594
expr = ec.Module.GlobalRootNamespace;
7595
return base.ResolveAsTypeOrNamespace (ec);
7598
int errors = ec.Module.Compiler.Report.Errors;
7599
expr = ec.LookupNamespaceAlias (alias);
7601
if (errors == ec.Module.Compiler.Report.Errors)
7602
ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7606
FullNamedExpression fne = base.ResolveAsTypeOrNamespace (ec);
7610
if (expr.eclass == ExprClass.Type) {
7611
ec.Module.Compiler.Report.Error (431, loc,
7612
"Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7620
protected override Expression DoResolve (ResolveContext ec)
7622
return ResolveAsTypeOrNamespace (ec);
7625
protected override void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7627
rc.Module.Compiler.Report.Error (687, loc,
7628
"A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7629
GetSignatureForError ());
7632
public override string GetSignatureForError ()
7635
if (targs != null) {
7636
name = Name + "<" + targs.GetSignatureForError () + ">";
7639
return alias + "::" + name;
7642
public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7644
return DoResolve (rc);
7647
protected override void CloneTo (CloneContext clonectx, Expression t)
7652
public override object Accept (StructuralVisitor visitor)
7654
return visitor.Visit (this);
7659
/// Implements the member access expression
7661
public class MemberAccess : ATypeNameExpression
7663
protected Expression expr;
7665
public MemberAccess (Expression expr, string id)
7666
: base (id, expr.Location)
7671
public MemberAccess (Expression expr, string identifier, Location loc)
7672
: base (identifier, loc)
7677
public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7678
: base (identifier, args, loc)
7683
public MemberAccess (Expression expr, string identifier, int arity, Location loc)
7684
: base (identifier, arity, loc)
7689
public Expression LeftExpression {
7695
protected override Expression DoResolve (ResolveContext ec)
7697
return DoResolveName (ec, null);
7700
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7702
return DoResolveName (ec, right_side);
7705
Expression DoResolveName (ResolveContext rc, Expression right_side)
7707
Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
7711
if (right_side != null) {
7712
if (e is TypeExpr) {
7713
e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
7717
e = e.ResolveLValue (rc, right_side);
7719
e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7725
public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
7727
var sn = expr as SimpleName;
7728
const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
7731
// Resolve the expression with flow analysis turned off, we'll do the definite
7732
// assignment checks later. This is because we don't know yet what the expression
7733
// will resolve to - it may resolve to a FieldExpr and in this case we must do the
7734
// definite assignment check on the actual field and not on the whole struct.
7736
using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7738
expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
7740
// Call resolve on expression which does have type set as we need expression type
7741
// TODO: I should probably ensure that the type is always set and leave resolve for the final
7742
if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
7743
using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
7744
expr = expr.Resolve (rc);
7746
} else if (expr is TypeParameterExpr) {
7747
expr.Error_UnexpectedKind (rc, flags, sn.Location);
7751
expr = expr.Resolve (rc, flags);
7758
Namespace ns = expr as Namespace;
7760
var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
7762
if (retval == null) {
7763
ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
7767
if (HasTypeArguments)
7768
return new GenericTypeExpr (retval.Type, targs, loc);
7774
TypeSpec expr_type = expr.Type;
7775
if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7776
me = expr as MemberExpr;
7778
me.ResolveInstanceExpression (rc, null);
7780
Arguments args = new Arguments (1);
7781
args.Add (new Argument (expr));
7782
return new DynamicMemberBinder (Name, args, loc);
7785
const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
7786
MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
7788
if ((expr_type.Kind & dot_kinds) == 0) {
7789
if (expr_type == InternalType.NullLiteral && rc.IsRuntimeBinder)
7790
rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
7792
Unary.Error_OperatorCannotBeApplied (rc, loc, ".", expr_type);
7796
var lookup_arity = Arity;
7797
bool errorMode = false;
7798
Expression member_lookup;
7800
member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
7801
if (member_lookup == null) {
7803
// Try to look for extension method when member lookup failed
7805
if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
7806
NamespaceContainer scope = null;
7807
var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity, ref scope);
7808
if (methods != null) {
7809
var emg = new ExtensionMethodGroupExpr (methods, scope, expr, loc);
7810
if (HasTypeArguments) {
7811
if (!targs.Resolve (rc))
7814
emg.SetTypeArguments (rc, targs);
7817
// TODO: it should really skip the checks bellow
7818
return emg.Resolve (rc);
7824
if (member_lookup == null) {
7825
var dep = expr_type.GetMissingDependencies ();
7827
ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
7828
} else if (expr is TypeExpr) {
7829
base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7831
Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
7837
if (member_lookup is MethodGroupExpr) {
7838
// Leave it to overload resolution to report correct error
7839
} else if (!(member_lookup is TypeExpr)) {
7840
// TODO: rc.SymbolRelatedToPreviousError
7841
ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
7846
if (member_lookup != null)
7850
restrictions &= ~MemberLookupRestrictions.InvocableOnly;
7854
TypeExpr texpr = member_lookup as TypeExpr;
7855
if (texpr != null) {
7856
if (!(expr is TypeExpr)) {
7857
me = expr as MemberExpr;
7858
if (me == null || me.ProbeIdenticalTypeName (rc, expr, sn) == expr) {
7859
rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7860
Name, member_lookup.GetSignatureForError ());
7865
if (!texpr.Type.IsAccessible (rc)) {
7866
rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7867
ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
7871
if (HasTypeArguments) {
7872
return new GenericTypeExpr (member_lookup.Type, targs, loc);
7875
return member_lookup;
7878
me = member_lookup as MemberExpr;
7880
if (sn != null && me.IsStatic)
7881
expr = me.ProbeIdenticalTypeName (rc, expr, sn);
7883
me = me.ResolveMemberAccess (rc, expr, sn);
7886
if (!targs.Resolve (rc))
7889
me.SetTypeArguments (rc, targs);
7892
if (sn != null && (!TypeSpec.IsValueType (expr_type) || me is PropertyExpr)) {
7893
if (me.IsInstance) {
7894
LocalVariableReference var = expr as LocalVariableReference;
7895
if (var != null && !var.VerifyAssigned (rc))
7903
public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc)
7905
FullNamedExpression fexpr = expr as FullNamedExpression;
7906
if (fexpr == null) {
7907
expr.ResolveAsType (rc);
7911
FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc);
7913
if (expr_resolved == null)
7916
Namespace ns = expr_resolved as Namespace;
7918
FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
7920
if (retval == null) {
7921
ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
7922
} else if (HasTypeArguments) {
7923
retval = new GenericTypeExpr (retval.Type, targs, loc);
7924
if (retval.ResolveAsType (rc) == null)
7931
var tnew_expr = expr_resolved.ResolveAsType (rc);
7932
if (tnew_expr == null)
7935
TypeSpec expr_type = tnew_expr;
7936
if (TypeManager.IsGenericParameter (expr_type)) {
7937
rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7938
tnew_expr.GetSignatureForError ());
7942
TypeSpec nested = null;
7943
while (expr_type != null) {
7944
nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7945
if (nested == null) {
7946
if (expr_type == tnew_expr) {
7947
Error_IdentifierNotFound (rc, expr_type, Name);
7951
expr_type = tnew_expr;
7952
nested = MemberCache.FindNestedType (expr_type, Name, Arity);
7953
ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
7957
if (nested.IsAccessible (rc))
7960
// Keep looking after inaccessible candidate
7961
expr_type = nested.DeclaringType.BaseType;
7966
if (HasTypeArguments) {
7967
texpr = new GenericTypeExpr (nested, targs, loc);
7969
texpr = new GenericOpenTypeExpr (nested, loc);
7972
texpr = new TypeExpression (nested, loc);
7975
if (texpr.ResolveAsType (rc) == null)
7981
protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
7983
var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
7985
if (nested != null) {
7986
Error_TypeArgumentsCannotBeUsed (rc, nested, Arity, expr.Location);
7990
var any_other_member = MemberLookup (rc, true, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
7991
if (any_other_member != null) {
7992
any_other_member.Error_UnexpectedKind (rc.Module.Compiler.Report, null, "type", loc);
7996
rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7997
Name, expr_type.GetSignatureForError ());
8000
protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
8002
if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
8003
ec.Report.SymbolRelatedToPreviousError (type);
8004
ec.Report.Error (1061, loc,
8005
"Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found (are you missing a using directive or an assembly reference?)",
8006
type.GetSignatureForError (), name);
8010
base.Error_TypeDoesNotContainDefinition (ec, type, name);
8013
public override string GetSignatureForError ()
8015
return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
8018
protected override void CloneTo (CloneContext clonectx, Expression t)
8020
MemberAccess target = (MemberAccess) t;
8022
target.expr = expr.Clone (clonectx);
8025
public override object Accept (StructuralVisitor visitor)
8027
return visitor.Visit (this);
8032
/// Implements checked expressions
8034
public class CheckedExpr : Expression {
8036
public Expression Expr;
8038
public CheckedExpr (Expression e, Location l)
8044
public override Expression CreateExpressionTree (ResolveContext ec)
8046
using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8047
return Expr.CreateExpressionTree (ec);
8050
protected override Expression DoResolve (ResolveContext ec)
8052
using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
8053
Expr = Expr.Resolve (ec);
8058
if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8061
eclass = Expr.eclass;
8066
public override void Emit (EmitContext ec)
8068
using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
8072
public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8074
using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
8075
Expr.EmitBranchable (ec, target, on_true);
8078
public override SLE.Expression MakeExpression (BuilderContext ctx)
8080
using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
8081
return Expr.MakeExpression (ctx);
8085
protected override void CloneTo (CloneContext clonectx, Expression t)
8087
CheckedExpr target = (CheckedExpr) t;
8089
target.Expr = Expr.Clone (clonectx);
8091
public override object Accept (StructuralVisitor visitor)
8093
return visitor.Visit (this);
8098
/// Implements the unchecked expression
8100
public class UnCheckedExpr : Expression {
8102
public Expression Expr;
8104
public UnCheckedExpr (Expression e, Location l)
8110
public override Expression CreateExpressionTree (ResolveContext ec)
8112
using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8113
return Expr.CreateExpressionTree (ec);
8116
protected override Expression DoResolve (ResolveContext ec)
8118
using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
8119
Expr = Expr.Resolve (ec);
8124
if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
8127
eclass = Expr.eclass;
8132
public override void Emit (EmitContext ec)
8134
using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
8138
public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
8140
using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
8141
Expr.EmitBranchable (ec, target, on_true);
8144
protected override void CloneTo (CloneContext clonectx, Expression t)
8146
UnCheckedExpr target = (UnCheckedExpr) t;
8148
target.Expr = Expr.Clone (clonectx);
8150
public override object Accept (StructuralVisitor visitor)
8152
return visitor.Visit (this);
8157
/// An Element Access expression.
8159
/// During semantic analysis these are transformed into
8160
/// IndexerAccess, ArrayAccess or a PointerArithmetic.
8162
public class ElementAccess : Expression {
8163
public Arguments Arguments;
8164
public Expression Expr;
8166
public ElementAccess (Expression e, Arguments args, Location loc)
8170
this.Arguments = args;
8174
// We perform some simple tests, and then to "split" the emit and store
8175
// code we create an instance of a different class, and return that.
8177
Expression CreateAccessExpression (ResolveContext ec)
8180
return (new ArrayAccess (this, loc));
8183
return MakePointerAccess (ec, type);
8185
FieldExpr fe = Expr as FieldExpr;
8187
var ff = fe.Spec as FixedFieldSpec;
8189
return MakePointerAccess (ec, ff.ElementType);
8193
var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
8194
if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8195
return new IndexerExpr (indexers, type, this);
8198
ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8199
type.GetSignatureForError ());
8203
public override Expression CreateExpressionTree (ResolveContext ec)
8205
Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
8206
Expr.CreateExpressionTree (ec));
8208
return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
8211
Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
8213
if (Arguments.Count != 1){
8214
ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
8218
if (Arguments [0] is NamedArgument)
8219
Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
8221
Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
8222
return new Indirection (p, loc);
8225
protected override Expression DoResolve (ResolveContext ec)
8227
Expr = Expr.Resolve (ec);
8233
// TODO: Create 1 result for Resolve and ResolveLValue ?
8234
var res = CreateAccessExpression (ec);
8238
return res.Resolve (ec);
8241
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8243
Expr = Expr.Resolve (ec);
8249
var res = CreateAccessExpression (ec);
8253
return res.ResolveLValue (ec, right_side);
8256
public override void Emit (EmitContext ec)
8258
throw new Exception ("Should never be reached");
8261
public static void Error_NamedArgument (NamedArgument na, Report Report)
8263
Report.Error (1742, na.Location, "An element access expression cannot use named argument");
8266
public override string GetSignatureForError ()
8268
return Expr.GetSignatureForError ();
8271
protected override void CloneTo (CloneContext clonectx, Expression t)
8273
ElementAccess target = (ElementAccess) t;
8275
target.Expr = Expr.Clone (clonectx);
8276
if (Arguments != null)
8277
target.Arguments = Arguments.Clone (clonectx);
8280
public override object Accept (StructuralVisitor visitor)
8282
return visitor.Visit (this);
8287
/// Implements array access
8289
public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
8291
// Points to our "data" repository
8295
LocalTemporary temp, expr_copy;
8296
Expression[] prepared_arguments;
8299
public ArrayAccess (ElementAccess ea_data, Location l)
8305
public override Expression CreateExpressionTree (ResolveContext ec)
8307
return ea.CreateExpressionTree (ec);
8310
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8312
return DoResolve (ec);
8315
protected override Expression DoResolve (ResolveContext ec)
8317
// dynamic is used per argument in ConvertExpressionToArrayIndex case
8319
ea.Arguments.Resolve (ec, out dynamic);
8321
var ac = ea.Expr.Type as ArrayContainer;
8322
int rank = ea.Arguments.Count;
8323
if (ac.Rank != rank) {
8324
ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8325
rank.ToString (), ac.Rank.ToString ());
8330
if (type.IsPointer && !ec.IsUnsafe) {
8331
UnsafeError (ec, ea.Location);
8334
foreach (Argument a in ea.Arguments) {
8335
if (a is NamedArgument)
8336
ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8338
a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8341
eclass = ExprClass.Variable;
8346
protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8348
ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8352
// Load the array arguments into the stack.
8354
void LoadArrayAndArguments (EmitContext ec)
8357
ea.Arguments.Emit (ec);
8360
public void Emit (EmitContext ec, bool leave_copy)
8362
var ac = ea.Expr.Type as ArrayContainer;
8365
ec.EmitLoadFromPtr (type);
8367
if (prepared_arguments == null) {
8368
LoadArrayAndArguments (ec);
8370
expr_copy.Emit (ec);
8372
foreach (var expr in prepared_arguments) {
8374
lt = expr as LocalTemporary;
8380
ec.EmitArrayLoad (ac);
8384
ec.Emit (OpCodes.Dup);
8385
temp = new LocalTemporary (this.type);
8390
public override void Emit (EmitContext ec)
8395
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8397
var ac = (ArrayContainer) ea.Expr.Type;
8398
TypeSpec t = source.Type;
8401
// When we are dealing with a struct, get the address of it to avoid value copy
8402
// Same cannot be done for reference type because array covariance and the
8403
// check in ldelema requires to specify the type of array element stored at the index
8405
if (t.IsStruct && ((prepare_for_load && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
8406
LoadArrayAndArguments (ec);
8407
ec.EmitArrayAddress (ac);
8409
if (prepare_for_load) {
8410
ec.Emit (OpCodes.Dup);
8414
} else if (prepare_for_load) {
8416
ec.Emit (OpCodes.Dup);
8418
expr_copy = new LocalTemporary (ea.Expr.Type);
8419
expr_copy.Store (ec);
8420
prepared_arguments = ea.Arguments.Emit (ec, true);
8422
LoadArrayAndArguments (ec);
8427
if (expr_copy != null) {
8428
expr_copy.Release (ec);
8432
ec.Emit (OpCodes.Dup);
8433
temp = new LocalTemporary (this.type);
8438
ec.EmitStoreFromPtr (t);
8440
ec.EmitArrayStore (ac);
8449
public void EmitNew (EmitContext ec, New source, bool leave_copy)
8451
if (!source.Emit (ec, this)) {
8453
throw new NotImplementedException ();
8458
throw new NotImplementedException ();
8461
public void AddressOf (EmitContext ec, AddressOp mode)
8463
var ac = (ArrayContainer) ea.Expr.Type;
8465
LoadArrayAndArguments (ec);
8467
if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
8468
ec.Emit (OpCodes.Readonly);
8470
ec.EmitArrayAddress (ac);
8473
public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8476
return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8478
throw new NotImplementedException ();
8482
public override SLE.Expression MakeExpression (BuilderContext ctx)
8484
return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
8487
SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
8489
using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
8490
return Arguments.MakeExpression (ea.Arguments, ctx);
8496
// Indexer access expression
8498
class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
8500
LocalTemporary prepared_value;
8501
IList<MemberSpec> indexers;
8502
Arguments arguments;
8503
TypeSpec queried_type;
8505
public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
8506
: base (ea.Location)
8508
this.indexers = indexers;
8509
this.queried_type = queriedType;
8510
this.InstanceExpression = ea.Expr;
8511
this.arguments = ea.Arguments;
8515
protected override TypeSpec DeclaringType {
8517
return best_candidate.DeclaringType;
8521
public override bool IsInstance {
8527
public override bool IsStatic {
8533
public override string Name {
8541
public override Expression CreateExpressionTree (ResolveContext ec)
8543
Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8544
InstanceExpression.CreateExpressionTree (ec),
8545
new TypeOfMethod (Getter, loc));
8547
return CreateExpressionFactoryCall (ec, "Call", args);
8550
public override void Emit (EmitContext ec, bool leave_copy)
8553
prepared_value.Emit (ec);
8555
Invocation.EmitCall (ec, InstanceExpression, Getter, arguments, loc);
8559
ec.Emit (OpCodes.Dup);
8560
temp = new LocalTemporary (Type);
8565
public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8567
prepared = prepare_for_load;
8568
Expression value = source;
8571
Invocation.EmitCall (ec, InstanceExpression, Getter, arguments, loc, true, false);
8573
prepared_value = new LocalTemporary (type);
8574
prepared_value.Store (ec);
8576
prepared_value.Release (ec);
8579
ec.Emit (OpCodes.Dup);
8580
temp = new LocalTemporary (Type);
8583
} else if (leave_copy) {
8584
temp = new LocalTemporary (Type);
8591
arguments.Add (new Argument (value));
8593
Invocation.EmitCall (ec, InstanceExpression, Setter, arguments, loc, false, prepared);
8601
public override string GetSignatureForError ()
8603
return best_candidate.GetSignatureForError ();
8606
public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
8609
throw new NotSupportedException ();
8611
var value = new[] { source.MakeExpression (ctx) };
8612
var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8614
return SLE.Expression.Block (
8615
SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
8618
return args.First ();
8623
public override SLE.Expression MakeExpression (BuilderContext ctx)
8626
return base.MakeExpression (ctx);
8628
var args = Arguments.MakeExpression (arguments, ctx);
8629
return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
8633
protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
8635
if (best_candidate != null)
8638
eclass = ExprClass.IndexerAccess;
8641
arguments.Resolve (rc, out dynamic);
8643
if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
8646
var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
8647
res.BaseMembersProvider = this;
8649
// TODO: Do I need 2 argument sets?
8650
best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
8651
if (best_candidate != null)
8652
type = res.BestCandidateReturnType;
8653
else if (!res.BestCandidateIsDynamic)
8658
// It has dynamic arguments
8661
Arguments args = new Arguments (arguments.Count + 1);
8663
rc.Report.Error (1972, loc,
8664
"The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8666
args.Add (new Argument (InstanceExpression));
8668
args.AddRange (arguments);
8670
best_candidate = null;
8671
return new DynamicIndexBinder (args, loc);
8674
ResolveInstanceExpression (rc, right_side);
8675
CheckProtectedMemberAccess (rc, best_candidate);
8679
protected override void CloneTo (CloneContext clonectx, Expression t)
8681
IndexerExpr target = (IndexerExpr) t;
8683
if (arguments != null)
8684
target.arguments = arguments.Clone (clonectx);
8687
public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
8689
Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
8692
#region IBaseMembersProvider Members
8694
IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
8696
return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
8699
IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
8701
if (queried_type == member.DeclaringType)
8704
var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
8705
return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
8708
MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
8717
// A base access expression
8719
public class BaseThis : This
8721
public BaseThis (Location loc)
8726
public BaseThis (TypeSpec type, Location loc)
8730
eclass = ExprClass.Variable;
8735
public override string Name {
8743
public override Expression CreateExpressionTree (ResolveContext ec)
8745
ec.Report.Error (831, loc, "An expression tree may not contain a base access");
8746
return base.CreateExpressionTree (ec);
8749
public override void Emit (EmitContext ec)
8753
var context_type = ec.CurrentType;
8754
if (context_type.IsStruct) {
8755
ec.Emit (OpCodes.Ldobj, context_type);
8756
ec.Emit (OpCodes.Box, context_type);
8760
protected override void Error_ThisNotAvailable (ResolveContext ec)
8763
ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8765
ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8769
public override void ResolveBase (ResolveContext ec)
8771
base.ResolveBase (ec);
8772
type = ec.CurrentType.BaseType;
8775
public override object Accept (StructuralVisitor visitor)
8777
return visitor.Visit (this);
8782
/// This class exists solely to pass the Type around and to be a dummy
8783
/// that can be passed to the conversion functions (this is used by
8784
/// foreach implementation to typecast the object return value from
8785
/// get_Current into the proper type. All code has been generated and
8786
/// we only care about the side effect conversions to be performed
8788
/// This is also now used as a placeholder where a no-action expression
8789
/// is needed (the `New' class).
8791
class EmptyExpression : Expression
8793
sealed class OutAccessExpression : EmptyExpression
8795
public OutAccessExpression (TypeSpec t)
8800
public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8802
rc.Report.Error (206, right_side.Location,
8803
"A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8809
public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
8810
public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
8811
public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
8812
public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
8813
public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
8814
public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
8815
public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
8816
public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
8818
public EmptyExpression (TypeSpec t)
8821
eclass = ExprClass.Value;
8822
loc = Location.Null;
8825
public override Expression CreateExpressionTree (ResolveContext ec)
8827
throw new NotSupportedException ("ET");
8830
protected override Expression DoResolve (ResolveContext ec)
8835
public override void Emit (EmitContext ec)
8837
// nothing, as we only exist to not do anything.
8840
public override void EmitSideEffect (EmitContext ec)
8846
// Empty statement expression
8848
public sealed class EmptyExpressionStatement : ExpressionStatement
8850
public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8852
private EmptyExpressionStatement ()
8854
loc = Location.Null;
8857
public override Expression CreateExpressionTree (ResolveContext ec)
8862
public override void EmitStatement (EmitContext ec)
8867
protected override Expression DoResolve (ResolveContext ec)
8869
eclass = ExprClass.Value;
8870
type = ec.BuiltinTypes.Object;
8874
public override void Emit (EmitContext ec)
8879
public override object Accept (StructuralVisitor visitor)
8881
return visitor.Visit (this);
8885
class ErrorExpression : EmptyExpression
8887
public static readonly ErrorExpression Instance = new ErrorExpression ();
8889
private ErrorExpression ()
8890
: base (InternalType.FakeInternalType)
8894
public override Expression CreateExpressionTree (ResolveContext ec)
8899
public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8904
public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
8909
public class UserCast : Expression {
8913
public UserCast (MethodSpec method, Expression source, Location l)
8915
this.method = method;
8916
this.source = source;
8917
type = method.ReturnType;
8921
public Expression Source {
8927
public override Expression CreateExpressionTree (ResolveContext ec)
8929
Arguments args = new Arguments (3);
8930
args.Add (new Argument (source.CreateExpressionTree (ec)));
8931
args.Add (new Argument (new TypeOf (type, loc)));
8932
args.Add (new Argument (new TypeOfMethod (method, loc)));
8933
return CreateExpressionFactoryCall (ec, "Convert", args);
8936
protected override Expression DoResolve (ResolveContext ec)
8938
ObsoleteAttribute oa = method.GetAttributeObsolete ();
8940
AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
8942
eclass = ExprClass.Value;
8946
public override void Emit (EmitContext ec)
8949
ec.Emit (OpCodes.Call, method);
8952
public override string GetSignatureForError ()
8954
return TypeManager.CSharpSignature (method);
8957
public override SLE.Expression MakeExpression (BuilderContext ctx)
8960
return base.MakeExpression (ctx);
8962
return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
8968
// Holds additional type specifiers like ?, *, []
8970
public class ComposedTypeSpecifier
8972
public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
8974
public readonly int Dimension;
8975
public readonly Location Location;
8977
public ComposedTypeSpecifier (int specifier, Location loc)
8979
this.Dimension = specifier;
8980
this.Location = loc;
8984
public bool IsNullable {
8986
return Dimension == -1;
8990
public bool IsPointer {
8992
return Dimension == -2;
8996
public ComposedTypeSpecifier Next { get; set; }
9000
public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
9002
return new ComposedTypeSpecifier (dimension, loc);
9005
public static ComposedTypeSpecifier CreateNullable (Location loc)
9007
return new ComposedTypeSpecifier (-1, loc);
9010
public static ComposedTypeSpecifier CreatePointer (Location loc)
9012
return new ComposedTypeSpecifier (-2, loc);
9015
public string GetSignatureForError ()
9020
ArrayContainer.GetPostfixSignature (Dimension);
9022
return Next != null ? s + Next.GetSignatureForError () : s;
9027
// This class is used to "construct" the type during a typecast
9028
// operation. Since the Type.GetType class in .NET can parse
9029
// the type specification, we just use this to construct the type
9030
// one bit at a time.
9032
public class ComposedCast : TypeExpr {
9033
FullNamedExpression left;
9034
ComposedTypeSpecifier spec;
9036
public FullNamedExpression Left {
9037
get { return this.left; }
9040
public ComposedTypeSpecifier Spec {
9046
public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
9049
throw new ArgumentNullException ("spec");
9053
this.loc = spec.Location;
9056
public override TypeSpec ResolveAsType (IMemberContext ec)
9058
type = left.ResolveAsType (ec);
9062
eclass = ExprClass.Type;
9064
var single_spec = spec;
9066
if (single_spec.IsNullable) {
9067
type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
9071
single_spec = single_spec.Next;
9072
} else if (single_spec.IsPointer) {
9073
if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
9077
UnsafeError (ec.Module.Compiler.Report, loc);
9081
type = PointerContainer.MakeType (ec.Module, type);
9082
single_spec = single_spec.Next;
9083
} while (single_spec != null && single_spec.IsPointer);
9086
if (single_spec != null && single_spec.Dimension > 0) {
9087
if (type.IsSpecialRuntimeType) {
9088
ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
9089
} else if (type.IsStatic) {
9090
ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
9091
ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9092
type.GetSignatureForError ());
9094
MakeArray (ec.Module, single_spec);
9101
void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
9103
if (spec.Next != null)
9104
MakeArray (module, spec.Next);
9106
type = ArrayContainer.MakeType (module, type, spec.Dimension);
9109
public override string GetSignatureForError ()
9111
return left.GetSignatureForError () + spec.GetSignatureForError ();
9114
public override object Accept (StructuralVisitor visitor)
9116
return visitor.Visit (this);
9120
class FixedBufferPtr : Expression
9122
readonly Expression array;
9124
public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
9126
this.type = array_type;
9131
public override Expression CreateExpressionTree (ResolveContext ec)
9133
Error_PointerInsideExpressionTree (ec);
9137
public override void Emit(EmitContext ec)
9142
protected override Expression DoResolve (ResolveContext ec)
9144
type = PointerContainer.MakeType (ec.Module, type);
9145
eclass = ExprClass.Value;
9152
// This class is used to represent the address of an array, used
9153
// only by the Fixed statement, this generates "&a [0]" construct
9154
// for fixed (char *pa = a)
9156
class ArrayPtr : FixedBufferPtr
9158
public ArrayPtr (Expression array, TypeSpec array_type, Location l):
9159
base (array, array_type, l)
9163
public override void Emit (EmitContext ec)
9168
ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
9173
// Encapsulates a conversion rules required for array indexes
9175
public class ArrayIndexCast : TypeCast
9177
public ArrayIndexCast (Expression expr, TypeSpec returnType)
9178
: base (expr, returnType)
9180
if (expr.Type == returnType) // int -> int
9181
throw new ArgumentException ("unnecessary array index conversion");
9184
public override Expression CreateExpressionTree (ResolveContext ec)
9186
using (ec.Set (ResolveContext.Options.CheckedScope)) {
9187
return base.CreateExpressionTree (ec);
9191
public override void Emit (EmitContext ec)
9195
switch (child.Type.BuiltinType) {
9196
case BuiltinTypeSpec.Type.UInt:
9197
ec.Emit (OpCodes.Conv_U);
9199
case BuiltinTypeSpec.Type.Long:
9200
ec.Emit (OpCodes.Conv_Ovf_I);
9202
case BuiltinTypeSpec.Type.ULong:
9203
ec.Emit (OpCodes.Conv_Ovf_I_Un);
9206
throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9212
// Implements the `stackalloc' keyword
9214
public class StackAlloc : Expression {
9219
public Expression TypeExpression {
9220
get { return this.t; }
9223
public Expression CountExpression {
9224
get { return this.count; }
9227
public StackAlloc (Expression type, Expression count, Location l)
9234
public override Expression CreateExpressionTree (ResolveContext ec)
9236
throw new NotSupportedException ("ET");
9239
protected override Expression DoResolve (ResolveContext ec)
9241
count = count.Resolve (ec);
9245
if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
9246
count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
9251
Constant c = count as Constant;
9252
if (c != null && c.IsNegative) {
9253
ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9256
if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9257
ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9260
otype = t.ResolveAsType (ec);
9264
if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
9267
type = PointerContainer.MakeType (ec.Module, otype);
9268
eclass = ExprClass.Value;
9273
public override void Emit (EmitContext ec)
9275
int size = BuiltinTypeSpec.GetSize (otype);
9280
ec.Emit (OpCodes.Sizeof, otype);
9284
ec.Emit (OpCodes.Mul_Ovf_Un);
9285
ec.Emit (OpCodes.Localloc);
9288
protected override void CloneTo (CloneContext clonectx, Expression t)
9290
StackAlloc target = (StackAlloc) t;
9291
target.count = count.Clone (clonectx);
9292
target.t = t.Clone (clonectx);
9295
public override object Accept (StructuralVisitor visitor)
9297
return visitor.Visit (this);
9302
// An object initializer expression
9304
public class ElementInitializer : Assign
9306
public readonly string Name;
9308
public ElementInitializer (string name, Expression initializer, Location loc)
9309
: base (null, initializer, loc)
9314
protected override void CloneTo (CloneContext clonectx, Expression t)
9316
ElementInitializer target = (ElementInitializer) t;
9317
target.source = source.Clone (clonectx);
9320
public override Expression CreateExpressionTree (ResolveContext ec)
9322
Arguments args = new Arguments (2);
9323
FieldExpr fe = target as FieldExpr;
9325
args.Add (new Argument (fe.CreateTypeOfExpression ()));
9327
args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9329
args.Add (new Argument (source.CreateExpressionTree (ec)));
9330
return CreateExpressionFactoryCall (ec,
9331
source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9335
protected override Expression DoResolve (ResolveContext ec)
9338
return EmptyExpressionStatement.Instance;
9340
var t = ec.CurrentInitializerVariable.Type;
9341
if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9342
Arguments args = new Arguments (1);
9343
args.Add (new Argument (ec.CurrentInitializerVariable));
9344
target = new DynamicMemberBinder (Name, args, loc);
9347
var member = MemberLookup (ec, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9348
if (member == null) {
9349
member = Expression.MemberLookup (ec, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
9351
if (member != null) {
9352
// TODO: ec.Report.SymbolRelatedToPreviousError (member);
9353
ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
9358
if (member == null) {
9359
Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
9363
if (!(member is PropertyExpr || member is FieldExpr)) {
9364
ec.Report.Error (1913, loc,
9365
"Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
9366
member.GetSignatureForError ());
9371
var me = member as MemberExpr;
9373
ec.Report.Error (1914, loc,
9374
"Static field or property `{0}' cannot be assigned in an object initializer",
9375
me.GetSignatureForError ());
9379
me.InstanceExpression = ec.CurrentInitializerVariable;
9382
if (source is CollectionOrObjectInitializers) {
9383
Expression previous = ec.CurrentInitializerVariable;
9384
ec.CurrentInitializerVariable = target;
9385
source = source.Resolve (ec);
9386
ec.CurrentInitializerVariable = previous;
9390
eclass = source.eclass;
9395
return base.DoResolve (ec);
9398
public override void EmitStatement (EmitContext ec)
9400
if (source is CollectionOrObjectInitializers)
9403
base.EmitStatement (ec);
9408
// A collection initializer expression
9410
class CollectionElementInitializer : Invocation
9412
public class ElementInitializerArgument : Argument
9414
public ElementInitializerArgument (Expression e)
9420
sealed class AddMemberAccess : MemberAccess
9422
public AddMemberAccess (Expression expr, Location loc)
9423
: base (expr, "Add", loc)
9427
protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9429
if (TypeManager.HasElementType (type))
9432
base.Error_TypeDoesNotContainDefinition (ec, type, name);
9436
public CollectionElementInitializer (Expression argument)
9437
: base (null, new Arguments (1))
9439
base.arguments.Add (new ElementInitializerArgument (argument));
9440
this.loc = argument.Location;
9443
public CollectionElementInitializer (List<Expression> arguments, Location loc)
9444
: base (null, new Arguments (arguments.Count))
9446
foreach (Expression e in arguments)
9447
base.arguments.Add (new ElementInitializerArgument (e));
9452
public override Expression CreateExpressionTree (ResolveContext ec)
9454
Arguments args = new Arguments (2);
9455
args.Add (new Argument (mg.CreateExpressionTree (ec)));
9457
var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9458
foreach (Argument a in arguments)
9459
expr_initializers.Add (a.CreateExpressionTree (ec));
9461
args.Add (new Argument (new ArrayCreation (
9462
CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
9463
return CreateExpressionFactoryCall (ec, "ElementInit", args);
9466
protected override void CloneTo (CloneContext clonectx, Expression t)
9468
CollectionElementInitializer target = (CollectionElementInitializer) t;
9469
if (arguments != null)
9470
target.arguments = arguments.Clone (clonectx);
9473
protected override Expression DoResolve (ResolveContext ec)
9475
base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9477
return base.DoResolve (ec);
9482
// A block of object or collection initializers
9484
public class CollectionOrObjectInitializers : ExpressionStatement
9486
IList<Expression> initializers;
9487
bool is_collection_initialization;
9489
public static readonly CollectionOrObjectInitializers Empty =
9490
new CollectionOrObjectInitializers (Array.AsReadOnly (new Expression [0]), Location.Null);
9492
public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9494
this.initializers = initializers;
9498
public bool IsEmpty {
9500
return initializers.Count == 0;
9504
public bool IsCollectionInitializer {
9506
return is_collection_initialization;
9510
protected override void CloneTo (CloneContext clonectx, Expression target)
9512
CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9514
t.initializers = new List<Expression> (initializers.Count);
9515
foreach (var e in initializers)
9516
t.initializers.Add (e.Clone (clonectx));
9519
public override Expression CreateExpressionTree (ResolveContext ec)
9521
var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9522
foreach (Expression e in initializers) {
9523
Expression expr = e.CreateExpressionTree (ec);
9525
expr_initializers.Add (expr);
9528
return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
9531
protected override Expression DoResolve (ResolveContext ec)
9533
List<string> element_names = null;
9534
for (int i = 0; i < initializers.Count; ++i) {
9535
Expression initializer = initializers [i];
9536
ElementInitializer element_initializer = initializer as ElementInitializer;
9539
if (element_initializer != null) {
9540
element_names = new List<string> (initializers.Count);
9541
element_names.Add (element_initializer.Name);
9542
} else if (initializer is CompletingExpression){
9543
initializer.Resolve (ec);
9544
throw new InternalErrorException ("This line should never be reached");
9546
var t = ec.CurrentInitializerVariable.Type;
9547
// LAMESPEC: The collection must implement IEnumerable only, no dynamic support
9548
if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
9549
ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9550
"object initializer because type `{1}' does not implement `{2}' interface",
9551
ec.CurrentInitializerVariable.GetSignatureForError (),
9552
TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9553
TypeManager.CSharpName (ec.BuiltinTypes.IEnumerable));
9556
is_collection_initialization = true;
9559
if (is_collection_initialization != (element_initializer == null)) {
9560
ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9561
is_collection_initialization ? "collection initializer" : "object initializer");
9565
if (!is_collection_initialization) {
9566
if (element_names.Contains (element_initializer.Name)) {
9567
ec.Report.Error (1912, element_initializer.Location,
9568
"An object initializer includes more than one member `{0}' initialization",
9569
element_initializer.Name);
9571
element_names.Add (element_initializer.Name);
9576
Expression e = initializer.Resolve (ec);
9577
if (e == EmptyExpressionStatement.Instance)
9578
initializers.RemoveAt (i--);
9580
initializers [i] = e;
9583
type = ec.CurrentInitializerVariable.Type;
9584
if (is_collection_initialization) {
9585
if (TypeManager.HasElementType (type)) {
9586
ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9587
TypeManager.CSharpName (type));
9591
eclass = ExprClass.Variable;
9595
public override void Emit (EmitContext ec)
9600
public override void EmitStatement (EmitContext ec)
9602
foreach (ExpressionStatement e in initializers)
9603
e.EmitStatement (ec);
9608
// New expression with element/object initializers
9610
public class NewInitialize : New
9613
// This class serves as a proxy for variable initializer target instances.
9614
// A real variable is assigned later when we resolve left side of an
9617
sealed class InitializerTargetExpression : Expression, IMemoryLocation
9619
NewInitialize new_instance;
9621
public InitializerTargetExpression (NewInitialize newInstance)
9623
this.type = newInstance.type;
9624
this.loc = newInstance.loc;
9625
this.eclass = newInstance.eclass;
9626
this.new_instance = newInstance;
9629
public override Expression CreateExpressionTree (ResolveContext ec)
9631
// Should not be reached
9632
throw new NotSupportedException ("ET");
9635
protected override Expression DoResolve (ResolveContext ec)
9640
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9645
public override void Emit (EmitContext ec)
9647
Expression e = (Expression) new_instance.instance;
9651
#region IMemoryLocation Members
9653
public void AddressOf (EmitContext ec, AddressOp mode)
9655
new_instance.instance.AddressOf (ec, mode);
9661
CollectionOrObjectInitializers initializers;
9662
IMemoryLocation instance;
9664
public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9665
: base (requested_type, arguments, l)
9667
this.initializers = initializers;
9670
protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9672
instance = base.EmitAddressOf (ec, Mode);
9674
if (!initializers.IsEmpty)
9675
initializers.Emit (ec);
9680
protected override void CloneTo (CloneContext clonectx, Expression t)
9682
base.CloneTo (clonectx, t);
9684
NewInitialize target = (NewInitialize) t;
9685
target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9688
public override Expression CreateExpressionTree (ResolveContext ec)
9690
Arguments args = new Arguments (2);
9691
args.Add (new Argument (base.CreateExpressionTree (ec)));
9692
if (!initializers.IsEmpty)
9693
args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9695
return CreateExpressionFactoryCall (ec,
9696
initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9700
protected override Expression DoResolve (ResolveContext ec)
9702
Expression e = base.DoResolve (ec);
9706
Expression previous = ec.CurrentInitializerVariable;
9707
ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9708
initializers.Resolve (ec);
9709
ec.CurrentInitializerVariable = previous;
9713
public override bool Emit (EmitContext ec, IMemoryLocation target)
9715
bool left_on_stack = base.Emit (ec, target);
9717
if (initializers.IsEmpty)
9718
return left_on_stack;
9720
LocalTemporary temp = target as LocalTemporary;
9722
if (!left_on_stack) {
9723
VariableReference vr = target as VariableReference;
9725
// FIXME: This still does not work correctly for pre-set variables
9726
if (vr != null && vr.IsRef)
9727
target.AddressOf (ec, AddressOp.Load);
9729
((Expression) target).Emit (ec);
9730
left_on_stack = true;
9733
temp = new LocalTemporary (type);
9740
initializers.Emit (ec);
9742
if (left_on_stack) {
9747
return left_on_stack;
9750
public override object Accept (StructuralVisitor visitor)
9752
return visitor.Visit (this);
9756
public class NewAnonymousType : New
9758
static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
9760
List<AnonymousTypeParameter> parameters;
9761
readonly TypeContainer parent;
9762
AnonymousTypeClass anonymous_type;
9764
public List<AnonymousTypeParameter> Parameters {
9765
get { return this.parameters; }
9768
public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
9769
: base (null, null, loc)
9771
this.parameters = parameters;
9772
this.parent = parent;
9775
protected override void CloneTo (CloneContext clonectx, Expression target)
9777
if (parameters == null)
9780
NewAnonymousType t = (NewAnonymousType) target;
9781
t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
9782
foreach (AnonymousTypeParameter atp in parameters)
9783
t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
9786
AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
9788
AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9792
type = AnonymousTypeClass.Create (parent, parameters, loc);
9798
type.ResolveTypeParameters ();
9801
if (ec.Report.Errors == 0)
9804
parent.Module.AddAnonymousType (type);
9808
public override Expression CreateExpressionTree (ResolveContext ec)
9810
if (parameters == null)
9811
return base.CreateExpressionTree (ec);
9813
var init = new ArrayInitializer (parameters.Count, loc);
9814
foreach (Property p in anonymous_type.Properties)
9815
init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
9817
var ctor_args = new ArrayInitializer (arguments.Count, loc);
9818
foreach (Argument a in arguments)
9819
ctor_args.Add (a.CreateExpressionTree (ec));
9821
Arguments args = new Arguments (3);
9822
args.Add (new Argument (new TypeOfMethod (method, loc)));
9823
args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
9824
args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
9826
return CreateExpressionFactoryCall (ec, "New", args);
9829
protected override Expression DoResolve (ResolveContext ec)
9831
if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9832
ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9836
if (parameters == null) {
9837
anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9838
RequestedType = new TypeExpression (anonymous_type.Definition, loc);
9839
return base.DoResolve (ec);
9843
arguments = new Arguments (parameters.Count);
9844
TypeExpression [] t_args = new TypeExpression [parameters.Count];
9845
for (int i = 0; i < parameters.Count; ++i) {
9846
Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9852
arguments.Add (new Argument (e));
9853
t_args [i] = new TypeExpression (e.Type, e.Location);
9859
anonymous_type = CreateAnonymousType (ec, parameters);
9860
if (anonymous_type == null)
9863
RequestedType = new GenericTypeExpr (anonymous_type.Definition, new TypeArguments (t_args), loc);
9864
return base.DoResolve (ec);
9867
public override object Accept (StructuralVisitor visitor)
9869
return visitor.Visit (this);
9873
public class AnonymousTypeParameter : ShimExpression
9875
public readonly string Name;
9877
public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9878
: base (initializer)
9884
public AnonymousTypeParameter (Parameter parameter)
9885
: base (new SimpleName (parameter.Name, parameter.Location))
9887
this.Name = parameter.Name;
9888
this.loc = parameter.Location;
9891
public override bool Equals (object o)
9893
AnonymousTypeParameter other = o as AnonymousTypeParameter;
9894
return other != null && Name == other.Name;
9897
public override int GetHashCode ()
9899
return Name.GetHashCode ();
9902
protected override Expression DoResolve (ResolveContext ec)
9904
Expression e = expr.Resolve (ec);
9908
if (e.eclass == ExprClass.MethodGroup) {
9909
Error_InvalidInitializer (ec, e.ExprClassName);
9914
if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
9915
Error_InvalidInitializer (ec, e.GetSignatureForError ());
9922
protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9924
ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9929
class Await : ExpressionStatement
9933
public Await (Expression expr, Location loc)
9939
public override Expression CreateExpressionTree (ResolveContext ec)
9941
throw new NotImplementedException ();
9944
public override void Emit (EmitContext ec)
9946
throw new NotImplementedException ();
9949
public override void EmitStatement (EmitContext ec)
9951
throw new NotImplementedException ();
9954
protected override Expression DoResolve (ResolveContext rc)
9956
expr = expr.Resolve (rc);
9960
// Iterator.CreateIterator
9963
eclass = expr.eclass;