public static Expression ImplicitBoxingConversion (Expression expr, TypeSpec expr_type, TypeSpec target_type) { // // From any value-type to the type object. // if (target_type == TypeManager.object_type || target_type == InternalType.Dynamic) { // // A pointer type cannot be converted to object // if (expr_type.IsPointer) return null; if (!TypeManager.IsValueType (expr_type)) return null; return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); } // // From any value-type to the type System.ValueType. // if (target_type == TypeManager.value_type) { if (!TypeManager.IsValueType (expr_type)) return null; return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); } if (target_type == TypeManager.enum_type) { // // From any enum-type to the type System.Enum. // if (TypeManager.IsEnumType (expr_type)) return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); } // // From a nullable-type to a reference type, if a boxing conversion exists from // the underlying type to the reference type // if (TypeManager.IsNullableType (expr_type)) { if (!TypeManager.IsReferenceType (target_type)) return null; var res = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type); // "cast" underlying type to target type to emit correct InvalidCastException when // underlying hierarchy changes without recompilation if (res != null && expr != null) res = new UnboxCast (res, target_type); return res; } if (TypeSpec.IsBaseClass (expr_type, target_type, false)) { // // Don't box same type arguments // if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type) return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); return null; } // This code is kind of mirrored inside ImplicitStandardConversionExists // with the small distinction that we only probe there // // Always ensure that the code here and there is in sync // from any class-type S to any interface-type T. if (target_type.IsInterface) { if (expr_type.ImplementsInterface (target_type, true) && (TypeManager.IsGenericParameter (expr_type) || TypeManager.IsValueType (expr_type))) { return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); } } return null; }
public static Expression ImplicitBoxingConversion (Expression expr, TypeSpec expr_type, TypeSpec target_type) { switch (target_type.BuiltinType) { // // From any non-nullable-value-type to the type object and dynamic // case BuiltinTypeSpec.Type.Object: case BuiltinTypeSpec.Type.Dynamic: // // From any non-nullable-value-type to the type System.ValueType // case BuiltinTypeSpec.Type.ValueType: // // No ned to check for nullable type as underlying type is always convertible // if (!TypeSpec.IsValueType (expr_type)) return null; return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); case BuiltinTypeSpec.Type.Enum: // // From any enum-type to the type System.Enum. // if (expr_type.IsEnum) return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); break; } // // From a nullable-type to a reference type, if a boxing conversion exists from // the underlying type to the reference type // if (expr_type.IsNullableType) { if (!TypeSpec.IsReferenceType (target_type)) return null; var res = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type); // "cast" underlying type to target type to emit correct InvalidCastException when // underlying hierarchy changes without recompilation if (res != null && expr != null) res = new UnboxCast (res, target_type); return res; } // // A value type has a boxing conversion to an interface type I if it has a boxing conversion // to an interface or delegate type I0 and I0 is variance-convertible to I // if (target_type.IsInterface && TypeSpec.IsValueType (expr_type) && expr_type.ImplementsInterface (target_type, true)) { return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); } return null; }
public override bool Resolve (BlockContext ec) { using (ec.With (ResolveContext.Options.CatchScope, true)) { if (type_expr != null) { TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false); if (te == null) return false; type = te.Type; if (type != TypeManager.exception_type && !TypeSpec.IsBaseClass (type, TypeManager.exception_type, false)) { ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception"); } else if (li != null) { li.Type = type; li.PrepareForFlowAnalysis (ec); // source variable is at the top of the stack Expression source = new EmptyExpression (li.Type); if (li.Type.IsGenericParameter) source = new UnboxCast (source, li.Type); assign = new CompilerAssign (new LocalVariableReference (li, loc), source, loc); Block.AddScopeStatement (new StatementExpression (assign)); } } return Block.Resolve (ec); } }