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; }
/// <summary> /// Implements Explicit Reference conversions /// </summary> static Expression ExplicitReferenceConversion (Expression source, TypeSpec source_type, TypeSpec target_type) { // // From object to a generic parameter // if (source_type.BuiltinType == BuiltinTypeSpec.Type.Object && TypeManager.IsGenericParameter (target_type)) return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); // // Explicit type parameter conversion. // if (source_type.Kind == MemberKind.TypeParameter) return ExplicitTypeParameterConversion (source, source_type, target_type); bool target_is_value_type = target_type.Kind == MemberKind.Struct || target_type.Kind == MemberKind.Enum; // // Unboxing conversion from System.ValueType to any non-nullable-value-type // if (source_type.BuiltinType == BuiltinTypeSpec.Type.ValueType && target_is_value_type) return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); // // From object or dynamic to any reference type or value type (unboxing) // if (source_type.BuiltinType == BuiltinTypeSpec.Type.Object || source_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { if (target_type.IsPointer) return null; return source == null ? EmptyExpression.Null : target_is_value_type ? new UnboxCast (source, target_type) : source is Constant ? (Expression) new EmptyConstantCast ((Constant) source, target_type) : new ClassCast (source, target_type); } // // From any class S to any class-type T, provided S is a base class of T // if (source_type.Kind == MemberKind.Class && TypeSpec.IsBaseClass (target_type, source_type, true)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); // // From any interface-type S to to any class type T, provided T is not // sealed, or provided T implements S. // if (source_type.Kind == MemberKind.Interface) { if (!target_type.IsSealed || target_type.ImplementsInterface (source_type, true)) { if (source == null) return EmptyExpression.Null; // // Unboxing conversion from any interface-type to any non-nullable-value-type that // implements the interface-type // return target_is_value_type ? new UnboxCast (source, target_type) : (Expression) new ClassCast (source, target_type); } // // From System.Collections.Generic.IList<T> and its base interfaces to a one-dimensional // array type S[], provided there is an implicit or explicit reference conversion from S to T. // var target_array = target_type as ArrayContainer; if (target_array != null && IList_To_Array (source_type, target_array)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; } var source_array = source_type as ArrayContainer; if (source_array != null) { var target_array = target_type as ArrayContainer; if (target_array != null) { // // From System.Array to any array-type // if (source_type.BuiltinType == BuiltinTypeSpec.Type.Array) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); // // From an array type S with an element type Se to an array type T with an // element type Te provided all the following are true: // * S and T differe only in element type, in other words, S and T // have the same number of dimensions. // * Both Se and Te are reference types // * An explicit reference conversions exist from Se to Te // if (source_array.Rank == target_array.Rank) { source_type = source_array.Element; if (!TypeSpec.IsReferenceType (source_type)) return null; var target_element = target_array.Element; if (!TypeSpec.IsReferenceType (target_element)) return null; if (ExplicitReferenceConversionExists (source_type, target_element)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; } } // // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces, // provided that there is an explicit reference conversion from S to T // if (ArrayToIList (source_array, target_type, true)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; } // // From any class type S to any interface T, provides S is not sealed // and provided S does not implement T. // if (target_type.IsInterface && !source_type.IsSealed && !source_type.ImplementsInterface (target_type, true)) { return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); } // // From System delegate to any delegate-type // if (source_type.BuiltinType == BuiltinTypeSpec.Type.Delegate && target_type.IsDelegate) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); // // From variant generic delegate to same variant generic delegate type // if (source_type.IsDelegate && target_type.IsDelegate && source_type.MemberDefinition == target_type.MemberDefinition) { var tparams = source_type.MemberDefinition.TypeParameters; var targs_src = source_type.TypeArguments; var targs_dst = target_type.TypeArguments; int i; for (i = 0; i < tparams.Length; ++i) { // // If TP is invariant, types have to be identical // if (TypeSpecComparer.IsEqual (targs_src[i], targs_dst[i])) continue; if (tparams[i].Variance == Variance.Covariant) { // //If TP is covariant, an implicit or explicit identity or reference conversion is required // if (ImplicitReferenceConversionExists (targs_src[i], targs_dst[i])) continue; if (ExplicitReferenceConversionExists (targs_src[i], targs_dst[i])) continue; } else if (tparams[i].Variance == Variance.Contravariant) { // //If TP is contravariant, both are either identical or reference types // if (TypeSpec.IsReferenceType (targs_src[i]) && TypeSpec.IsReferenceType (targs_dst[i])) continue; } break; } if (i == tparams.Length) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); } return null; }
public static bool ImplicitReferenceConversionExists (TypeSpec expr_type, TypeSpec target_type, bool refOnlyTypeParameter) { // It's here only to speed things up if (target_type.IsStruct) return false; switch (expr_type.Kind) { case MemberKind.TypeParameter: return ImplicitTypeParameterConversion (null, (TypeParameterSpec) expr_type, target_type) != null && (!refOnlyTypeParameter || TypeSpec.IsReferenceType (expr_type)); case MemberKind.Class: // // From any class-type to dynamic (+object to speed up common path) // if (target_type.BuiltinType == BuiltinTypeSpec.Type.Object || target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) return true; if (target_type.IsClass) { // // Identity conversion, including dynamic erasure // if (TypeSpecComparer.IsEqual (expr_type, target_type)) return true; // // From any class-type S to any class-type T, provided S is derived from T // return TypeSpec.IsBaseClass (expr_type, target_type, true); } // // From any class-type S to any interface-type T, provided S implements T // if (target_type.IsInterface) return expr_type.ImplementsInterface (target_type, true); return false; case MemberKind.ArrayType: // // Identity array conversion // if (expr_type == target_type) return true; // // From any array-type to System.Array // switch (target_type.BuiltinType) { case BuiltinTypeSpec.Type.Array: case BuiltinTypeSpec.Type.Object: case BuiltinTypeSpec.Type.Dynamic: return true; } var expr_type_array = (ArrayContainer) expr_type; var target_type_array = target_type as ArrayContainer; // // From an array-type S to an array-type of type T // if (target_type_array != null && expr_type_array.Rank == target_type_array.Rank) { // // Both SE and TE are reference-types. TE check is defered // to ImplicitReferenceConversionExists // TypeSpec expr_element_type = expr_type_array.Element; if (!TypeSpec.IsReferenceType (expr_element_type)) return false; // // An implicit reference conversion exists from SE to TE // return ImplicitReferenceConversionExists (expr_element_type, target_type_array.Element); } // // From any array-type to the interfaces it implements // if (target_type.IsInterface) { if (expr_type.ImplementsInterface (target_type, false)) return true; // from an array-type of type T to IList<T> if (ArrayToIList (expr_type_array, target_type, false)) return true; } return false; case MemberKind.Delegate: // // From any delegate-type to System.Delegate (and its base types) // switch (target_type.BuiltinType) { case BuiltinTypeSpec.Type.Delegate: case BuiltinTypeSpec.Type.MulticastDelegate: case BuiltinTypeSpec.Type.Object: case BuiltinTypeSpec.Type.Dynamic: return true; } // // Identity conversion, including dynamic erasure // if (TypeSpecComparer.IsEqual (expr_type, target_type)) return true; // // From any delegate-type to the interfaces it implements // From any reference-type to an delegate type if is variance-convertible // return expr_type.ImplementsInterface (target_type, false) || TypeSpecComparer.Variant.IsEqual (expr_type, target_type); case MemberKind.Interface: // // Identity conversion, including dynamic erasure // if (TypeSpecComparer.IsEqual (expr_type, target_type)) return true; // // From any interface type S to interface-type T // From any reference-type to an interface if is variance-convertible // if (target_type.IsInterface) return TypeSpecComparer.Variant.IsEqual (expr_type, target_type) || expr_type.ImplementsInterface (target_type, true); return target_type.BuiltinType == BuiltinTypeSpec.Type.Object || target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; } // // from the null literal to any reference-type. // if (expr_type == InternalType.NullLiteral) { // Exlude internal compiler types if (target_type.Kind == MemberKind.InternalCompilerType) return target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; return TypeSpec.IsReferenceType (target_type); } return false; }
// // Return container with awaiter definition. It never returns null // but all container member can be null for easier error reporting // public AwaiterDefinition GetAwaiter (TypeSpec type) { AwaiterDefinition awaiter; if (awaiters.TryGetValue (type, out awaiter)) return awaiter; awaiter = new AwaiterDefinition (); // // Predefined: bool IsCompleted { get; } // awaiter.IsCompleted = MemberCache.FindMember (type, MemberFilter.Property ("IsCompleted", Compiler.BuiltinTypes.Bool), BindingRestriction.InstanceOnly) as PropertySpec; // // Predefined: GetResult () // // The method return type is also result type of await expression // awaiter.GetResult = MemberCache.FindMember (type, MemberFilter.Method ("GetResult", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.InstanceOnly) as MethodSpec; // // Predefined: INotifyCompletion.OnCompleted (System.Action) // var nc = PredefinedTypes.INotifyCompletion; awaiter.INotifyCompletion = !nc.Define () || type.ImplementsInterface (nc.TypeSpec, false); awaiters.Add (type, awaiter); return awaiter; }
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 bool ImplicitBoxingConversionExists(TypeSpec expr_type, TypeSpec target_type, out bool use_class_cast) { use_class_cast = false; // // 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 false; return TypeManager.IsValueType (expr_type); } // // From any value-type to the type System.ValueType. // if (target_type == TypeManager.value_type) return TypeManager.IsValueType (expr_type); if (target_type == TypeManager.enum_type) { // // From any enum-type to the type System.Enum. // if (TypeManager.IsEnumType (expr_type)) return true; } // // 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 false; return ImplicitBoxingConversionExists (Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type, out use_class_cast); } if (TypeManager.IsSubclassOf (expr_type, target_type)) { // // Don't box same type arguments // if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type) return true; return false; } // 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)) return TypeManager.IsGenericParameter (expr_type) || TypeManager.IsValueType (expr_type); } return false; }
/// <summary> /// Implements Explicit Reference conversions /// </summary> static Expression ExplicitReferenceConversion(Expression source, TypeSpec source_type, TypeSpec target_type) { // // From object to a generic parameter // if (source_type == TypeManager.object_type && TypeManager.IsGenericParameter (target_type)) return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); // // Explicit type parameter conversion. // if (TypeManager.IsGenericParameter (source_type)) return ExplicitTypeParameterConversion (source, source_type, target_type); bool target_is_value_type = TypeManager.IsStruct (target_type) || TypeManager.IsEnumType (target_type); // // Unboxing conversion from System.ValueType to any non-nullable-value-type // if (source_type == TypeManager.value_type && target_is_value_type) return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); // // From object to any reference type or value type (unboxing) // if (source_type == TypeManager.object_type) return source == null ? EmptyExpression.Null : target_is_value_type ? (Expression) new UnboxCast (source, target_type) : new ClassCast (source, target_type); // // From any class S to any class-type T, provided S is a base class of T // if (TypeManager.IsSubclassOf (target_type, source_type)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); // // From any interface-type S to to any class type T, provided T is not // sealed, or provided T implements S. // if (source_type.IsInterface) { if (!target_type.IsSealed || target_type.ImplementsInterface (source_type)) { if (target_type.IsClass) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); // // Unboxing conversion from any interface-type to any non-nullable-value-type that // implements the interface-type // return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); } // // From System.Collections.Generic.IList<T> and its base interfaces to a one-dimensional // array type S[], provided there is an implicit or explicit reference conversion from S to T. // var target_array = target_type as ArrayContainer; if (target_array != null && IList_To_Array (source_type, target_array)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; } var source_array = source_type as ArrayContainer; if (source_array != null) { var target_array = target_type as ArrayContainer; if (target_array != null) { // // From System.Array to any array-type // if (source_type == TypeManager.array_type) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); // // From an array type S with an element type Se to an array type T with an // element type Te provided all the following are true: // * S and T differe only in element type, in other words, S and T // have the same number of dimensions. // * Both Se and Te are reference types // * An explicit reference conversions exist from Se to Te // if (source_array.Rank == target_array.Rank) { source_type = source_array.Element; if (!TypeManager.IsReferenceType (source_type)) return null; var target_element = target_array.Element; if (!TypeManager.IsReferenceType (target_element)) return null; if (ExplicitReferenceConversionExists (source_type, target_element)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; } } // // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces, // provided that there is an explicit reference conversion from S to T // if (ArrayToIList (source_array, target_type, true)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; } // // From any class type S to any interface T, provides S is not sealed // and provided S does not implement T. // if (target_type.IsInterface && !source_type.IsSealed && !source_type.ImplementsInterface (target_type)) { return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); } // // From System delegate to any delegate-type // if (source_type == TypeManager.delegate_type && TypeManager.IsDelegateType (target_type)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; }
// // 6.1.6 Implicit reference conversions // public static bool ImplicitReferenceConversionExists (TypeSpec expr_type, TypeSpec target_type) { if (target_type.IsStruct) return false; // from the null type to any reference-type. if (expr_type == InternalType.NullLiteral) return true; if (expr_type.IsGenericParameter) return ImplicitTypeParameterConversion (null, (TypeParameterSpec) expr_type, target_type) != 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)){ return !TypeManager.IsValueType (expr_type); } } // // Implicit reference conversions (no-boxing) to object or dynamic // if (target_type.BuiltinType == BuiltinTypeSpec.Type.Object || target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { switch (expr_type.Kind) { case MemberKind.Class: case MemberKind.Interface: case MemberKind.Delegate: case MemberKind.ArrayType: return true; } return expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; } if (expr_type == target_type || TypeSpec.IsBaseClass (expr_type, target_type, true)) { if (TypeManager.IsGenericParameter (expr_type)) return false; if (TypeManager.IsValueType (expr_type)) return false; // Array type variance conversion //if (target_type.IsArray != expr_type.IsArray) // return false; return true; } var expr_type_array = expr_type as ArrayContainer; if (expr_type_array != null) { var target_type_array = target_type as ArrayContainer; // from an array-type S to an array-type of type T if (target_type_array != null && expr_type_array.Rank == target_type_array.Rank) { // // Both SE and TE are reference-types // TypeSpec expr_element_type = expr_type_array.Element; if (!TypeManager.IsReferenceType (expr_element_type)) return false; TypeSpec target_element_type = target_type_array.Element; if (!TypeManager.IsReferenceType (target_element_type)) return false; // // An implicit reference conversion exists from SE to TE // return ImplicitReferenceConversionExists (expr_element_type, target_element_type); } // from an array-type to System.Array if (target_type.BuiltinType == BuiltinTypeSpec.Type.Array) return true; // from an array-type of type T to IList<T> if (ArrayToIList (expr_type_array, target_type, false)) return true; return false; } if (TypeSpecComparer.IsEqual (expr_type, target_type)) return true; if (TypeSpecComparer.Variant.IsEqual (expr_type, target_type)) return true; // from any interface type S to interface-type T. if (expr_type.IsInterface && target_type.IsInterface) { return expr_type.ImplementsInterface (target_type, true); } // from any delegate type to System.Delegate if (target_type.BuiltinType == BuiltinTypeSpec.Type.Delegate && (expr_type.BuiltinType == BuiltinTypeSpec.Type.Delegate || expr_type.IsDelegate)) return true; return false; }
public override bool Resolve(BlockContext ec) { expr = expr.Resolve (ec); if (expr == null) return false; expr_type = expr.Type; if (!expr_type.ImplementsInterface (TypeManager.idisposable_type) && Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) { if (expr_type != InternalType.Dynamic) { Using.Error_IsNotConvertibleToIDisposable (ec, expr); return false; } expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.idisposable_type, loc); expr_type = expr.Type; } local_copy = new TemporaryVariable (expr_type, loc); local_copy.Resolve (ec); ec.StartFlowBranching (this); bool ok = Statement.Resolve (ec); ec.EndFlowBranching (); ok &= base.Resolve (ec); if (TypeManager.void_dispose_void == null) { TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes); } return ok; }
public override bool Resolve(BlockContext ec) { enumerator_type = TypeManager.ienumerator_type; bool is_dynamic = expr.Type == InternalType.Dynamic; if (is_dynamic) expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc); if (!ProbeCollectionType (ec, expr.Type)) { Error_Enumerator (ec); return false; } VarExpr ve = var_type as VarExpr; if (ve != null) { // Infer implicitly typed local variable from foreach enumerable type var_type = new TypeExpression ( is_dynamic ? InternalType.Dynamic : get_current.Type, var_type.Location); } var_type = var_type.ResolveAsTypeTerminal (ec, false); if (var_type == null) return false; enumerator = new TemporaryVariable (enumerator_type, loc); enumerator.Resolve (ec); init = new Invocation (get_enumerator, null); init = init.Resolve (ec); if (init == null) return false; Expression move_next_expr; { var mi = new List<MemberSpec> (1) { move_next }; MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc); mg.InstanceExpression = enumerator; move_next_expr = new Invocation (mg, null); } get_current.InstanceExpression = enumerator; Statement block = new CollectionForeachStatement ( var_type.Type, variable, get_current, statement, loc); loop = new While (new BooleanExpression (move_next_expr), block, loc); bool implements_idisposable = enumerator_type.ImplementsInterface (TypeManager.idisposable_type); if (implements_idisposable || !enumerator_type.IsSealed) { wrapper = new DisposableWrapper (this, implements_idisposable); } else { wrapper = new NonDisposableWrapper (this); } return wrapper.Resolve (ec); }