+2004-09-28 Martin Baulig <martin@ximian.com>
+
+ * generic.cs
+ (GenericConstraints.EffectiveBaseClass): New public property.
+ (TypeParameter.GenericConstraints): New public property.
+ (ConstructedType.CheckConstraints): Improved.
+
+ * convert.cs (Convert.TypeParam_EffectiveBaseType): New private method.
+ (Convert.TypeParameterConversion): New private method; use this in
+ ImplicitReferenceConversion() and ImplicitReferenceConversionExists()
+ for all conversions related to type parameters.
+
2004-09-24 Martin Baulig <martin@ximian.com>
* convert.cs (Convert.ImplicitReferenceConversion): Added implicit
return true;
}
+ static Type TypeParam_EffectiveBaseType (Type t)
+ {
+ GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
+ if (gc == null)
+ return TypeManager.object_type;
+
+ return TypeParam_EffectiveBaseType (gc);
+ }
+
+ static Type TypeParam_EffectiveBaseType (GenericConstraints gc)
+ {
+ ArrayList list = new ArrayList ();
+ list.Add (gc.EffectiveBaseClass);
+ foreach (Type t in gc.InterfaceConstraints) {
+ if (!t.IsGenericParameter)
+ continue;
+
+ GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
+ if (new_gc != null)
+ list.Add (TypeParam_EffectiveBaseType (new_gc));
+ }
+ return FindMostEncompassedType (list);
+ }
+
+ static Expression TypeParameterConversion (Expression expr, bool is_reference, Type target_type)
+ {
+ if (is_reference)
+ return new EmptyCast (expr, target_type);
+ else
+ return new BoxedCast (expr, target_type);
+ }
+
+ static Expression ImplicitTypeParameterConversion (Expression expr, Type target_type)
+ {
+ Type expr_type = expr.Type;
+
+ GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
+
+ if (gc == null) {
+ if (target_type == TypeManager.object_type)
+ return new BoxedCast (expr);
+
+ return null;
+ }
+
+ // We're converting from a type parameter which is known to be a reference type.
+ bool is_reference = gc.IsReferenceType;
+ Type base_type = TypeParam_EffectiveBaseType (gc);
+
+ if (TypeManager.IsSubclassOf (base_type, target_type))
+ return TypeParameterConversion (expr, is_reference, target_type);
+
+ if (target_type.IsInterface) {
+ if (TypeManager.ImplementsInterface (base_type, target_type))
+ return TypeParameterConversion (expr, is_reference, target_type);
+
+ foreach (Type t in gc.InterfaceConstraints) {
+ if (TypeManager.IsSubclassOf (t, target_type))
+ return TypeParameterConversion (expr, is_reference, target_type);
+ }
+ }
+
+ foreach (Type t in gc.InterfaceConstraints) {
+ if (!t.IsGenericParameter)
+ continue;
+ if (TypeManager.IsSubclassOf (t, target_type))
+ return TypeParameterConversion (expr, is_reference, target_type);
+ }
+
+ return null;
+ }
+
static EmptyExpression MyEmptyExpr;
static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
{
if (expr_type == TypeManager.void_type)
return null;
+ if (expr_type.IsGenericParameter)
+ return ImplicitTypeParameterConversion (expr, target_type);
+
//
// notice that it is possible to write "ValueType v = 1", the ValueType here
// is an abstract class, and not really a value type, so we apply the same rules.
if (TypeManager.IsEqualGenericType (expr_type, target_type))
return new EmptyCast (expr, target_type);
- if (expr_type.IsGenericParameter) {
- GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
-
- // We're converting from a type parameter which is known to be a reference type.
- if ((gc != null) && gc.IsReferenceType) {
- if (gc.HasClassConstraint && gc.ClassConstraint.IsSubclassOf (target_type))
- return new EmptyCast (expr, target_type);
-
- if (target_type.IsInterface) {
- foreach (Type t in gc.InterfaceConstraints) {
- if (TypeManager.ImplementsInterface (t, target_type))
- return new EmptyCast (expr, target_type);
- }
- }
- }
- }
-
return null;
}
{
Type expr_type = expr.Type;
+ if (expr_type.IsGenericParameter)
+ return ImplicitTypeParameterConversion (expr, target_type) != null;
+
//
// This is the boxed case.
//
if (TypeManager.IsEqualGenericType (expr_type, target_type))
return true;
- if (expr_type.IsGenericParameter) {
- GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
-
- // We're converting from a type parameter which is known to be a reference type.
- if ((gc != null) && gc.IsReferenceType) {
- if (gc.HasClassConstraint && gc.ClassConstraint.IsSubclassOf (target_type))
- return true;
-
- if (target_type.IsInterface) {
- foreach (Type t in gc.InterfaceConstraints) {
- if (TypeManager.ImplementsInterface (t, target_type))
- return true;
- }
- }
- }
- }
-
return false;
}
get { return (Attributes & GenericParameterAttributes.ValueTypeConstraint) != 0; }
}
- public bool HasClassConstraint {
+ public virtual bool HasClassConstraint {
get { return ClassConstraint != null; }
}
get;
}
+ public abstract Type EffectiveBaseClass {
+ get;
+ }
+
// <summary>
// Returns whether the type parameter is "known to be a reference type".
// </summary>
int num_constraints, first_constraint;
Type class_constraint_type;
Type[] iface_constraint_types;
+ Type effective_base_type;
public bool Resolve (DeclSpace ds)
{
}
}
- if (HasReferenceTypeConstraint)
- class_constraint_type = TypeManager.object_type;
+ if (class_constraint_type != null)
+ effective_base_type = class_constraint_type;
else if (HasValueTypeConstraint)
- class_constraint_type = TypeManager.value_type;
+ effective_base_type = TypeManager.value_type;
+ else
+ effective_base_type = TypeManager.object_type;
return true;
}
get { return attrs; }
}
+ public override bool HasClassConstraint {
+ get { return class_constraint != null; }
+ }
+
public override Type ClassConstraint {
get { return class_constraint_type; }
}
get { return iface_constraint_types; }
}
+ public override Type EffectiveBaseClass {
+ get { return effective_base_type; }
+ }
+
internal bool IsSubclassOf (Type t)
{
if ((class_constraint_type != null) &&
if (gc.Attributes != attrs)
return false;
+ if (HasClassConstraint != gc.HasClassConstraint)
+ return false;
if (HasClassConstraint && !gc.ClassConstraint.Equals (ClassConstraint))
return false;
//
public class TypeParameter : MemberCore, IMemberContainer {
string name;
+ GenericConstraints gc;
Constraints constraints;
Location loc;
GenericTypeParameterBuilder type;
this.loc = loc;
}
+ public GenericConstraints GenericConstraints {
+ get {
+ return gc != null ? gc : constraints;
+ }
+ }
+
public Constraints Constraints {
get {
return constraints;
public bool DefineType (EmitContext ec, MethodBuilder builder,
MethodInfo implementing, bool is_override)
{
- GenericConstraints gc;
-
if (implementing != null) {
if (is_override && (constraints != null)) {
Report.Error (
Expression aexpr = new EmptyExpression (atype);
- Type parent = ptype.BaseType;
+ GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype);
+ if (gc == null)
+ return true;
//
// First, check the `class' and `struct' constraints.
//
- if (parent == TypeManager.object_type) {
- if (!atype.IsClass) {
- Report.Error (452, loc, "The type `{0}' must be " +
- "a reference type in order to use it " +
- "as type parameter `{1}' in the " +
- "generic type or method `{2}'.",
- atype, ptype, DeclarationName);
- return false;
- }
- } else if (parent == TypeManager.value_type) {
- if (!atype.IsValueType) {
- Report.Error (453, loc, "The type `{0}' must be " +
- "a value type in order to use it " +
- "as type parameter `{1}' in the " +
- "generic type or method `{2}'.",
- atype, ptype, DeclarationName);
- return false;
- }
+ if (gc.HasReferenceTypeConstraint && !atype.IsClass) {
+ Report.Error (452, loc, "The type `{0}' must be " +
+ "a reference type in order to use it " +
+ "as type parameter `{1}' in the " +
+ "generic type or method `{2}'.",
+ atype, ptype, DeclarationName);
+ return false;
+ } else if (gc.HasValueTypeConstraint && !atype.IsValueType) {
+ Report.Error (453, loc, "The type `{0}' must be " +
+ "a value type in order to use it " +
+ "as type parameter `{1}' in the " +
+ "generic type or method `{2}'.",
+ atype, ptype, DeclarationName);
+ return false;
}
//
// The class constraint comes next.
//
- if ((parent != null) && (parent != TypeManager.object_type)) {
- if (!CheckConstraint (ec, ptype, aexpr, parent)) {
+ if (gc.HasClassConstraint) {
+ if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint)) {
Report.Error (309, loc, "The type `{0}' must be " +
"convertible to `{1}' in order to " +
"use it as parameter `{2}' in the " +
"generic type or method `{3}'",
- atype, parent, ptype, DeclarationName);
+ atype, gc.ClassConstraint, ptype, DeclarationName);
return false;
}
}
//
// Now, check the interface constraints.
//
- foreach (Type it in TypeManager.GetInterfaces (ptype)) {
+ foreach (Type it in gc.InterfaceConstraints) {
Type itype;
if (it.IsGenericParameter)
itype = atypes [it.GenericParameterPosition];
// Finally, check the constructor constraint.
//
- if (!TypeManager.HasConstructorConstraint (ptype))
+ if (!gc.HasConstructorConstraint)
return true;
if (TypeManager.IsBuiltinType (atype))
public class ReflectionConstraints : GenericConstraints
{
GenericParameterAttributes attrs;
+ Type base_type;
Type class_constraint;
Type[] iface_constraints;
} else
iface_constraints = constraints;
attrs = t.GenericParameterAttributes;
+
+ if (HasValueTypeConstraint)
+ base_type = TypeManager.value_type;
+ else if (class_constraint != null)
+ base_type = class_constraint;
+ else
+ base_type = TypeManager.object_type;
}
public override GenericParameterAttributes Attributes {
get { return class_constraint; }
}
+ public override Type EffectiveBaseClass {
+ get { return base_type; }
+ }
+
public override Type[] InterfaceConstraints {
get { return iface_constraints; }
}
TypeParameter tparam = LookupTypeParameter (t);
if (tparam != null)
- return tparam.Constraints;
+ return tparam.GenericConstraints;
return new ReflectionConstraints (t);
}