예제 #1
0
        protected override void emitCode(Context ctx, bool mustReturn)
        {
            var gen = ctx.CurrentMethod.Generator;

            var fromType = Expression.Resolve(ctx);
            var toType = Resolve(ctx);

            if (toType.IsExtendablyAssignableFrom(fromType, true))
                Expression.Emit(ctx, true);

            else if (fromType.IsNumericType() && toType.IsNumericType(true)) // (decimal -> T) is processed via op_Explicit()
                castNumeric(ctx, fromType, toType);

            else if(fromType.IsCallableType() && toType.IsCallableType())
                castDelegate(ctx, fromType, toType);

            else if (fromType == typeof (NullType))
            {
                if (toType.IsNullableType())
                {
                    var tmpVar = ctx.Scope.DeclareImplicit(ctx, toType, true);
                    gen.EmitLoadLocal(tmpVar.LocalBuilder, true);
                    gen.EmitInitObject(toType);
                    gen.EmitLoadLocal(tmpVar.LocalBuilder);
                }

                else if (!toType.IsValueType)
                    gen.EmitNull();

                else
                    error(CompilerMessages.CastNullValueType, toType);
            }

            else if (toType.IsNullableType())
            {
                Expression.Emit(ctx, true);

                var underlying = Nullable.GetUnderlyingType(toType);
                if(underlying.IsNumericType() && fromType.IsNumericType() && underlying != fromType)
                    gen.EmitConvert(underlying);
                else if(underlying != fromType)
                    error(fromType, toType);

                var ctor = toType.GetConstructor(new[] { underlying });
                gen.EmitCreateObject(ctor);
            }

            else if (toType.IsExtendablyAssignableFrom(fromType))
            {
                Expression.Emit(ctx, true);

                // box
                if (fromType.IsValueType && toType == typeof (object))
                    gen.EmitBox(fromType);

                else
                {
                    var castOp = ctx.ResolveConvertorToType(fromType, toType);
                    if (castOp != null)
                        gen.EmitCall(castOp.MethodInfo);
                    else
                        gen.EmitCast(toType);
                }
            }

            else if (fromType.IsExtendablyAssignableFrom(toType))
            {
                Expression.Emit(ctx, true);

                // unbox
                if (fromType == typeof (object) && toType.IsValueType)
                    gen.EmitUnbox(toType);

                // cast ancestor to descendant
                else if (!fromType.IsValueType && !toType.IsValueType)
                    gen.EmitCast(toType);

                else
                {
                    var castOp = ctx.ResolveConvertorToType(fromType, toType);
                    if (castOp != null)
                        gen.EmitCall(castOp.MethodInfo);
                    else
                        error(fromType, toType);
                }
            }

            else
                error(fromType, toType);
        }