5 // Jb Evain (jbevain@novell.com)
7 // (C) 2008 Novell, Inc. (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Reflection;
31 using System.Reflection.Emit;
33 namespace System.Linq.Expressions {
35 public sealed class UnaryExpression : Expression {
41 public Expression Operand {
42 get { return operand; }
45 public MethodInfo Method {
46 get { return method; }
49 public bool IsLifted {
50 get { return is_lifted; }
53 public bool IsLiftedToNull {
54 get { return is_lifted && IsNullable (this.Type); }
57 internal UnaryExpression (ExpressionType node_type, Expression operand, Type type)
58 : base (node_type, type)
60 this.operand = operand;
63 internal UnaryExpression (ExpressionType node_type, Expression operand, Type type, MethodInfo method, bool is_lifted)
64 : base (node_type, type)
66 this.operand = operand;
68 this.is_lifted = is_lifted;
71 void EmitArrayLength (EmitContext ec)
74 ec.ig.Emit (OpCodes.Ldlen);
77 void EmitTypeAs (EmitContext ec)
81 ec.EmitIsInst (operand, type);
83 if (IsNullable (type))
84 ec.ig.Emit (OpCodes.Unbox_Any, type);
87 void EmitUnaryOperator (EmitContext ec)
92 case ExpressionType.Not:
93 if (GetNotNullableOf (operand.Type) == typeof (bool)) {
94 ig.Emit (OpCodes.Ldc_I4_0);
95 ig.Emit (OpCodes.Ceq);
97 ig.Emit (OpCodes.Not);
99 case ExpressionType.Negate:
100 case ExpressionType.NegateChecked:
101 ig.Emit (OpCodes.Neg);
103 case ExpressionType.Convert:
104 case ExpressionType.ConvertChecked:
110 void EmitConvert (EmitContext ec)
112 var from = operand.Type;
117 else if (IsNullable (from) && !IsNullable (target))
118 EmitConvertFromNullable (ec);
119 else if (!IsNullable (from) && IsNullable (target))
120 EmitConvertToNullable (ec);
121 else if (IsNullable (from) && IsNullable (target))
122 EmitConvertFromNullableToNullable (ec);
123 else if (IsReferenceConversion (from, target))
125 else if (IsPrimitiveConversion (from, target))
126 EmitPrimitiveConversion (ec);
128 throw new NotImplementedException ();
131 static Type MakeNullableType (Type type)
133 return typeof (Nullable<>).MakeGenericType (type);
136 void EmitConvertFromNullableToNullable (EmitContext ec)
140 var from = ec.EmitStored (operand);
141 var to = ig.DeclareLocal (Type);
143 var has_value = ig.DefineLabel ();
144 var done = ig.DefineLabel ();
146 ig.Emit (OpCodes.Ldloca, from);
147 ig.Emit (OpCodes.Call, from.LocalType.GetMethod ("get_HasValue"));
148 ig.Emit (OpCodes.Brtrue, has_value);
151 ig.Emit (OpCodes.Ldloca, to);
152 ig.Emit (OpCodes.Initobj, to.LocalType);
153 ig.Emit (OpCodes.Ldloc, to);
155 ig.Emit (OpCodes.Br, done);
157 ig.MarkLabel (has_value);
159 ig.Emit (OpCodes.Ldloca, from);
160 ig.Emit (OpCodes.Call, from.LocalType.GetMethod ("GetValueOrDefault", Type.EmptyTypes));
161 ig.Emit (OpCodes.Newobj, to.LocalType.GetConstructor (
162 new [] { GetNotNullableOf (to.LocalType) }));
167 void EmitConvertToNullable (EmitContext ec)
170 ec.ig.Emit (OpCodes.Newobj,
171 MakeNullableType (operand.Type).GetConstructor (new [] { operand.Type }));
174 void EmitConvertFromNullable (EmitContext ec)
176 ec.EmitCall (operand, operand.Type.GetMethod ("get_Value"));
181 return operand.Type.IsValueType && !Type.IsValueType;
186 return !operand.Type.IsValueType && Type.IsValueType;
189 void EmitCast (EmitContext ec)
194 ec.ig.Emit (OpCodes.Box, operand.Type);
195 } else if (IsUnBoxing ()) {
196 ec.ig.Emit (OpCodes.Unbox_Any, Type);
198 ec.ig.Emit (OpCodes.Castclass, Type);
201 void EmitPrimitiveConversion (EmitContext ec,
202 OpCode signed, OpCode unsigned, OpCode signed_checked, OpCode unsigned_checked)
206 bool is_unsigned = IsUnsigned (operand.Type);
208 if (this.NodeType != ExpressionType.ConvertChecked)
209 ec.ig.Emit (is_unsigned ? unsigned : signed);
211 ec.ig.Emit (is_unsigned ? unsigned_checked : signed_checked);
214 void EmitPrimitiveConversion (EmitContext ec)
216 switch (Type.GetTypeCode (this.Type)) {
218 EmitPrimitiveConversion (ec,
222 OpCodes.Conv_Ovf_I1_Un);
225 EmitPrimitiveConversion (ec,
229 OpCodes.Conv_Ovf_U1_Un);
232 EmitPrimitiveConversion (ec,
236 OpCodes.Conv_Ovf_I2_Un);
238 case TypeCode.UInt16:
239 EmitPrimitiveConversion (ec,
243 OpCodes.Conv_Ovf_U2_Un);
246 EmitPrimitiveConversion (ec,
250 OpCodes.Conv_Ovf_I4_Un);
252 case TypeCode.UInt32:
253 EmitPrimitiveConversion (ec,
257 OpCodes.Conv_Ovf_U4_Un);
260 EmitPrimitiveConversion (ec,
264 OpCodes.Conv_Ovf_I8_Un);
266 case TypeCode.UInt64:
267 EmitPrimitiveConversion (ec,
271 OpCodes.Conv_Ovf_U8_Un);
273 case TypeCode.Single:
274 if (IsUnsigned (operand.Type))
275 ec.ig.Emit (OpCodes.Conv_R_Un);
276 ec.ig.Emit (OpCodes.Conv_R4);
278 case TypeCode.Double:
279 if (IsUnsigned (operand.Type))
280 ec.ig.Emit (OpCodes.Conv_R_Un);
281 ec.ig.Emit (OpCodes.Conv_R8);
284 throw new NotImplementedException (this.Type.ToString ());
288 internal override void Emit (EmitContext ec)
290 switch (this.NodeType) {
291 case ExpressionType.ArrayLength:
292 EmitArrayLength (ec);
294 case ExpressionType.TypeAs:
297 case ExpressionType.Convert:
298 case ExpressionType.ConvertChecked:
301 case ExpressionType.Not:
302 case ExpressionType.Negate:
303 case ExpressionType.NegateChecked:
304 case ExpressionType.UnaryPlus:
307 EmitUnaryOperator (ec);
309 throw new NotImplementedException ();
311 case ExpressionType.Quote:
312 ec.EmitReadGlobal (operand, typeof (Expression));
315 throw new NotImplementedException (this.NodeType.ToString ());