public static Expression ImplicitTypeParameterConversion (Expression expr, TypeParameterSpec expr_type, TypeSpec target_type) { // // From T to a type parameter U, provided T depends on U // if (target_type.IsGenericParameter) { if (expr_type.TypeArguments != null && expr_type.HasDependencyOn (target_type)) { if (expr == null) return EmptyExpression.Null; if (expr_type.IsReferenceType && !((TypeParameterSpec) target_type).IsReferenceType) return new BoxedCast (expr, target_type); return new ClassCast (expr, target_type); } return null; } // // LAMESPEC: From T to dynamic type because it's like T to object // if (target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { if (expr == null) return EmptyExpression.Null; if (expr_type.IsReferenceType) return new ClassCast (expr, target_type); return new BoxedCast (expr, target_type); } // // From T to its effective base class C // From T to any base class of C (it cannot contain dynamic or be of dynamic type) // From T to any interface implemented by C // var base_type = expr_type.GetEffectiveBase (); if (base_type == target_type || TypeSpec.IsBaseClass (base_type, target_type, false) || base_type.ImplementsInterface (target_type, true)) { if (expr == null) return EmptyExpression.Null; if (expr_type.IsReferenceType) return new ClassCast (expr, target_type); return new BoxedCast (expr, target_type); } if (target_type.IsInterface && expr_type.IsConvertibleToInterface (target_type)) { if (expr == null) return EmptyExpression.Null; if (expr_type.IsReferenceType) return new ClassCast (expr, target_type); return new BoxedCast (expr, target_type); } return null; }
public TypeParameterInflator(TypeSpec type, TypeParameterSpec[] tparams, TypeSpec[] targs) { if (tparams.Length != targs.Length) throw new ArgumentException ("Invalid arguments"); this.tparams = tparams; this.targs = targs; this.type = type; }
public HoistedStoreyClass (DeclSpace parent, MemberName name, TypeParameter[] tparams, Modifiers mod) : base (parent, name, mod | Modifiers.PRIVATE) { if (tparams != null) { type_params = new TypeParameter[tparams.Length]; var src = new TypeParameterSpec[tparams.Length]; var dst = new TypeParameterSpec[tparams.Length]; for (int i = 0; i < type_params.Length; ++i) { type_params[i] = tparams[i].CreateHoistedCopy (this, spec); src[i] = tparams[i].Type; dst[i] = type_params[i].Type; } // A copy is not enough, inflate any type parameter constraints // using a new type parameters var inflator = new TypeParameterInflator (null, src, dst); for (int i = 0; i < type_params.Length; ++i) { src[i].InflateConstraints (inflator, dst[i]); } } }
public ImportedGenericMethodDefinition (MethodInfo provider, AParametersCollection parameters, TypeParameterSpec[] tparams) : base (provider, parameters) { this.tparams = tparams; }
static Expression ExplicitTypeParameterConversionToT (Expression source, TypeSpec source_type, TypeParameterSpec target_type) { // // From the effective base class C of T to T and from any base class of C to T // var effective = target_type.GetEffectiveBase (); if (TypeSpecComparer.IsEqual (effective, source_type) || TypeSpec.IsBaseClass (effective, source_type, false)) return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); return null; }
public TypeParameter (TypeParameterSpec spec, DeclSpace parent, TypeSpec parentSpec, MemberName name, Attributes attrs) : base (parent, name, attrs) { this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) { BaseType = spec.BaseType, InterfacesDefined = spec.InterfacesDefined, TypeArguments = spec.TypeArguments }; }
TypeParameterSpec CreateTypeParameter (MetaType type, TypeSpec declaringType) { Variance variance; switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) { case GenericParameterAttributes.Covariant: variance = Variance.Covariant; break; case GenericParameterAttributes.Contravariant: variance = Variance.Contravariant; break; default: variance = Variance.None; break; } SpecialConstraint special = SpecialConstraint.None; var import_special = type.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask; if ((import_special & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) { special |= SpecialConstraint.Struct; } else if ((import_special & GenericParameterAttributes.DefaultConstructorConstraint) != 0) { special = SpecialConstraint.Constructor; } if ((import_special & GenericParameterAttributes.ReferenceTypeConstraint) != 0) { special |= SpecialConstraint.Class; } TypeParameterSpec spec; var def = new ImportedTypeParameterDefinition (type, this); if (type.DeclaringMethod != null) { spec = new TypeParameterSpec (type.GenericParameterPosition, def, special, variance, type); } else { spec = new TypeParameterSpec (declaringType, type.GenericParameterPosition, def, special, variance, type); } return spec; }
public ImportedGenericMethodDefinition (MethodInfo provider, TypeSpec type, AParametersCollection parameters, TypeParameterSpec[] tparams, MetadataImporter importer) : base (provider, type, parameters, importer) { this.tparams = tparams; }
// // Constraints have to match by definition but not position, used by // partial classes or methods // public bool HasSameConstraintsDefinition (TypeParameterSpec other) { if (spec != other.spec) return false; if (BaseType != other.BaseType) return false; if (!TypeSpecComparer.Override.IsSame (InterfacesDefined, other.InterfacesDefined)) return false; if (!TypeSpecComparer.Override.IsSame (targs, other.targs)) return false; return true; }
public TypeParameter (DeclSpace parent, int index, MemberName name, Constraints constraints, Attributes attrs, Variance variance) : base (parent, name, attrs) { this.constraints = constraints; // this.variance = variance; this.spec = new TypeParameterSpec (null, index, this, SpecialConstraint.None, variance, null); }
static void CheckConversion (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc) { var expr = new EmptyExpression (atype); if (!Convert.ImplicitStandardConversionExists (expr, ttype)) { mc.Compiler.Report.SymbolRelatedToPreviousError (tparam); if (TypeManager.IsValueType (atype)) { mc.Compiler.Report.Error (315, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing conversion from `{0}' to `{3}'", atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); } else if (atype.IsGenericParameter) { mc.Compiler.Report.Error (314, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing or type parameter conversion from `{0}' to `{3}'", atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); } else { mc.Compiler.Report.Error (311, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no implicit reference conversion from `{0}' to `{3}'", atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ()); } } }
static bool CheckConstraint (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc) { // // First, check the `class' and `struct' constraints. // if (tparam.HasSpecialClass && !TypeManager.IsReferenceType (atype)) { mc.Compiler.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}'", TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ()); return false; } if (tparam.HasSpecialStruct && (!TypeManager.IsValueType (atype) || TypeManager.IsNullableType (atype))) { mc.Compiler.Report.Error (453, loc, "The type `{0}' must be a non-nullable value type in order to use it as type parameter `{1}' in the generic type or method `{2}'", TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ()); return false; } // // The class constraint comes next. // if (tparam.HasTypeConstraint) { CheckConversion (mc, context, atype, tparam, tparam.BaseType, loc); } // // Now, check the interfaces and type parameters constraints // if (tparam.Interfaces != null) { if (TypeManager.IsNullableType (atype)) { mc.Compiler.Report.Error (313, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' never satisfies interface constraint", atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ()); } else { foreach (TypeSpec iface in tparam.Interfaces) { CheckConversion (mc, context, atype, tparam, iface, loc); } } } // // Finally, check the constructor constraint. // if (!tparam.HasSpecialConstructor) return true; if (!HasDefaultConstructor (atype)) { mc.Compiler.Report.SymbolRelatedToPreviousError (atype); mc.Compiler.Report.Error (310, loc, "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'", TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ()); return false; } return true; }
/// <summary> /// Check the constraints; we're called from ResolveAsTypeTerminal() /// after fully resolving the constructed type. /// </summary> public static bool CheckAll (IMemberContext mc, MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc) { for (int i = 0; i < tparams.Length; i++) { if (!CheckConstraint (mc, context, targs [i], tparams [i], loc)) return false; } return true; }
public TypeParameterSpec Mutate (TypeParameterSpec tp) { for (int i = 0; i < mvar.Length; ++i) { if (mvar[i].Type == tp) return var[i].Type; } return tp; }
public TypeSpec Inflate (TypeParameterSpec tp) { for (int i = 0; i < tparams.Length; ++i) if (tparams [i] == tp) return targs[i]; // This can happen when inflating nested types // without type arguments specified return tp; }
TypeParameterSpec CreateTypeParameter (MetaType type, TypeSpec declaringType) { Variance variance; switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) { case GenericParameterAttributes.Covariant: variance = Variance.Covariant; break; case GenericParameterAttributes.Contravariant: variance = Variance.Contravariant; break; default: variance = Variance.None; break; } SpecialConstraint special = SpecialConstraint.None; var import_special = type.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask; if ((import_special & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) { special |= SpecialConstraint.Struct; } else if ((import_special & GenericParameterAttributes.DefaultConstructorConstraint) != 0) { special = SpecialConstraint.Constructor; } if ((import_special & GenericParameterAttributes.ReferenceTypeConstraint) != 0) { special |= SpecialConstraint.Class; } TypeParameterSpec spec; var def = new ImportedTypeParameterDefinition (type); if (type.DeclaringMethod != null) spec = new TypeParameterSpec (type.GenericParameterPosition, def, special, variance, type); else spec = new TypeParameterSpec (declaringType, type.GenericParameterPosition, def, special, variance, type); // Add it now, so any constraint can reference it and get same instance import_cache.Add (type, spec); var constraints = type.GetGenericParameterConstraints (); List<TypeSpec> tparams = null; foreach (var ct in constraints) { if (ct.IsGenericParameter) { if (tparams == null) tparams = new List<TypeSpec> (); tparams.Add (CreateType (ct)); continue; } if (ct.IsClass) { spec.BaseType = CreateType (ct); continue; } spec.AddInterface (CreateType (ct)); } if (spec.BaseType == null) spec.BaseType = TypeManager.object_type; if (tparams != null) spec.TypeArguments = tparams.ToArray (); return spec; }
void ImportTypeParameterTypeConstraints (TypeParameterSpec spec, MetaType type) { var constraints = type.GetGenericParameterConstraints (); List<TypeSpec> tparams = null; foreach (var ct in constraints) { if (ct.IsGenericParameter) { if (tparams == null) tparams = new List<TypeSpec> (); tparams.Add (CreateType (ct)); continue; } if (!IsMissingType (ct) && ct.IsClass) { spec.BaseType = CreateType (ct); continue; } spec.AddInterface (CreateType (ct)); } if (spec.BaseType == null) spec.BaseType = module.Compiler.BuiltinTypes.Object; if (tparams != null) spec.TypeArguments = tparams.ToArray (); }
// // Constraints have to match by using same set of types, used by // implicit interface implementation // public bool HasSameConstraintsImplementation (TypeParameterSpec other) { if (spec != other.spec) return false; // // It can be same base type or inflated type parameter // // interface I<T> { void Foo<U> where U : T; } // class A : I<int> { void Foo<X> where X : int {} } // bool found; if (!TypeSpecComparer.Override.IsEqual (BaseType, other.BaseType)) { if (other.targs == null) return false; found = false; foreach (var otarg in other.targs) { if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) { found = true; break; } } if (!found) return false; } // Check interfaces implementation -> definition if (InterfacesDefined != null) { foreach (var iface in InterfacesDefined) { found = false; if (other.InterfacesDefined != null) { foreach (var oiface in other.InterfacesDefined) { if (TypeSpecComparer.Override.IsEqual (iface, oiface)) { found = true; break; } } } if (found) continue; if (other.targs != null) { foreach (var otarg in other.targs) { if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) { found = true; break; } } } if (!found) return false; } } // Check interfaces implementation <- definition if (other.InterfacesDefined != null) { if (InterfacesDefined == null) return false; foreach (var oiface in other.InterfacesDefined) { found = false; foreach (var iface in InterfacesDefined) { if (TypeSpecComparer.Override.IsEqual (iface, oiface)) { found = true; break; } } if (!found) return false; } } // Check type parameters implementation -> definition if (targs != null) { if (other.targs == null) return false; foreach (var targ in targs) { found = false; foreach (var otarg in other.targs) { if (TypeSpecComparer.Override.IsEqual (targ, otarg)) { found = true; break; } } if (!found) return false; } } // Check type parameters implementation <- definition if (other.targs != null) { foreach (var otarg in other.targs) { // Ignore inflated type arguments, were checked above if (!otarg.IsGenericParameter) continue; if (targs == null) return false; found = false; foreach (var targ in targs) { if (TypeSpecComparer.Override.IsEqual (targ, otarg)) { found = true; break; } } if (!found) return false; } } return true; }
TypeParameterSpec[] CreateGenericParameters (int first, MetaType[] tparams) { var tspec = new TypeParameterSpec[tparams.Length - first]; for (int pos = first; pos < tparams.Length; ++pos) { var type = tparams[pos]; int index = pos - first; tspec[index] = (TypeParameterSpec) CreateType (type, new DynamicTypeReader (), false); } return tspec; }
public static TypeParameterSpec[] InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec[] tparams) { TypeParameterSpec[] constraints = null; for (int i = 0; i < tparams.Length; ++i) { var tp = tparams[i]; if (tp.HasTypeConstraint || tp.Interfaces != null || tp.TypeArguments != null) { if (constraints == null) { constraints = new TypeParameterSpec[tparams.Length]; Array.Copy (tparams, constraints, constraints.Length); } constraints[i] = (TypeParameterSpec) constraints[i].InflateMember (inflator); } } if (constraints == null) constraints = tparams; return constraints; }
public HoistedStoreyClass (TypeDefinition parent, MemberName name, TypeParameters tparams, Modifiers mods, MemberKind kind) : base (parent, name, mods | Modifiers.PRIVATE, kind) { if (tparams != null) { var type_params = name.TypeParameters; var src = new TypeParameterSpec[tparams.Count]; var dst = new TypeParameterSpec[tparams.Count]; for (int i = 0; i < tparams.Count; ++i) { type_params[i] = tparams[i].CreateHoistedCopy (spec); src[i] = tparams[i].Type; dst[i] = type_params[i].Type; } // A copy is not enough, inflate any type parameter constraints // using a new type parameters var inflator = new TypeParameterInflator (this, null, src, dst); for (int i = 0; i < tparams.Count; ++i) { src[i].InflateConstraints (inflator, dst[i]); } mutator = new TypeParameterMutator (tparams, type_params); } }
public void InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec tps) { tps.BaseType = inflator.Inflate (BaseType); if (ifaces != null) { tps.ifaces = new List<TypeSpec> (ifaces.Count); for (int i = 0; i < ifaces.Count; ++i) tps.ifaces.Add (inflator.Inflate (ifaces[i])); } if (targs != null) { tps.targs = new TypeSpec[targs.Length]; for (int i = 0; i < targs.Length; ++i) tps.targs[i] = inflator.Inflate (targs[i]); } }