Fixing a bug where ReferenceEquals was called on value types.
[castle.git] / Tools / Castle.DynamicProxy2 / Castle.DynamicProxy / Generators / Emitters / SimpleAST / ConvertExpression.cs
blob0bceca05716d2c88f550e7f7aa40908d85a8bf58
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST
17 using System;
18 using System.Reflection.Emit;
20 public class ConvertExpression : Expression
22 private readonly Expression right;
23 private Type fromType;
24 private Type target;
26 public ConvertExpression(Type targetType, Expression right)
27 : this(targetType, typeof(object), right)
31 public ConvertExpression(Type targetType, Type fromType, Expression right)
33 target = targetType;
34 this.fromType = fromType;
35 this.right = right;
38 public override void Emit(IMemberEmitter member, ILGenerator gen)
40 right.Emit(member, gen);
42 if (fromType == target)
44 return;
47 if (fromType.IsByRef)
49 fromType = fromType.GetElementType();
52 if (target.IsByRef)
54 target = target.GetElementType();
57 if (target.IsValueType)
59 if (fromType.IsValueType)
61 throw new NotImplementedException("Cannot convert between distinct value types");
63 else
65 // Unbox conversion
66 // Assumes fromType is a boxed value
67 // if we can, we emit a box and ldind, otherwise, we will use unbox.any
68 if (LdindOpCodesDictionary.Instance[target] != LdindOpCodesDictionary.EmptyOpCode)
70 gen.Emit(OpCodes.Unbox, target);
71 OpCodeUtil.EmitLoadIndirectOpCodeForType(gen, target);
73 else
75 gen.Emit(OpCodes.Unbox_Any, target);
79 else
81 if (fromType.IsValueType)
83 // Box conversion
84 gen.Emit(OpCodes.Box, fromType);
85 EmitCastIfNeeded(typeof(object), target, gen);
87 else
89 // Possible down-cast
90 EmitCastIfNeeded(fromType, target, gen);
95 private static void EmitCastIfNeeded(Type from, Type target, ILGenerator gen)
97 if (target.IsGenericParameter)
99 gen.Emit(OpCodes.Unbox_Any, target);
101 else if (from.IsGenericParameter)
103 gen.Emit(OpCodes.Box, from);
105 else if (target.IsGenericType && target != from)
107 gen.Emit(OpCodes.Castclass, target);
109 else if (target.IsSubclassOf(from))
111 gen.Emit(OpCodes.Castclass, target);