X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fgeneric.cs;h=5a94fa821e122ef8e194dc523a162a63d23438d8;hb=9076dfdec8582c59a2c683da9943496514f8d2dd;hp=961457711363c9e810ef924c9da8d0e29983d695;hpb=27c1676ab986d2cedecd712acd750350ced565a3;p=mono.git diff --git a/mcs/gmcs/generic.cs b/mcs/gmcs/generic.cs index 96145771136..5a94fa821e1 100644 --- a/mcs/gmcs/generic.cs +++ b/mcs/gmcs/generic.cs @@ -15,6 +15,13 @@ using System.Text; namespace Mono.CSharp { + public enum SpecialConstraint + { + Constructor, + ReferenceType, + ValueType + } + // // Tracks the constraints for a type parameter // @@ -42,11 +49,14 @@ namespace Mono.CSharp { } bool has_ctor_constraint; + bool has_reference_type; + bool has_value_type; TypeExpr class_constraint; ArrayList iface_constraints; - TypeExpr[] constraint_types; + ArrayList type_param_constraints; int num_constraints, first_constraint; - Type[] types; + Type class_constraint_type; + Type[] iface_constraint_types; public bool HasConstructorConstraint { get { return has_ctor_constraint; } @@ -55,6 +65,7 @@ namespace Mono.CSharp { public bool Resolve (DeclSpace ds) { iface_constraints = new ArrayList (); + type_param_constraints = new ArrayList (); foreach (object obj in constraints) { if (has_ctor_constraint) { @@ -63,8 +74,34 @@ namespace Mono.CSharp { return false; } - if (obj is bool) { - has_ctor_constraint = true; + if (obj is SpecialConstraint) { + SpecialConstraint sc = (SpecialConstraint) obj; + + if (sc == SpecialConstraint.Constructor) { + if (!has_value_type) { + has_ctor_constraint = true; + continue; + } + + Report.Error ( + 451, loc, "The new () constraint " + + "cannot be used with the `struct' " + + "constraint."); + return false; + } + + if ((num_constraints > 0) || has_reference_type || + has_value_type) { + Report.Error (449, loc, + "The `class' or `struct' " + + "constraint must be first"); + return false; + } + + if (sc == SpecialConstraint.ReferenceType) + has_reference_type = true; + else + has_value_type = true; continue; } @@ -72,14 +109,10 @@ namespace Mono.CSharp { if (expr == null) return false; - if (expr is TypeParameterExpr) { - Report.Error (700, loc, - "`{0}': naked type parameters cannot " + - "be used as bounds", expr.Name); - return false; - } - - if (expr.IsInterface) + TypeParameterExpr texpr = expr as TypeParameterExpr; + if (texpr != null) + type_param_constraints.Add (expr); + else if (expr.IsInterface) iface_constraints.Add (expr); else if (class_constraint != null) { Report.Error (406, loc, @@ -87,88 +120,230 @@ namespace Mono.CSharp { "must come before any other constraints.", expr.Name, name); return false; + } else if (has_reference_type || has_value_type) { + Report.Error (450, loc, "`{0}': cannot specify both " + + "a constraint class and the `class' " + + "or `struct' constraint.", expr.Name); + return false; } else class_constraint = expr; num_constraints++; } - constraint_types = new TypeExpr [num_constraints]; - if (class_constraint != null) - constraint_types [first_constraint++] = class_constraint; - iface_constraints.CopyTo (constraint_types, first_constraint); + return true; + } + + bool CheckTypeParameterConstraints (TypeParameter tparam, Hashtable seen) + { + seen.Add (tparam, true); + + Constraints constraints = tparam.Constraints; + if (constraints == null) + return true; + + if (constraints.IsValueType) { + Report.Error (456, loc, "Type parameter `{0}' has " + + "the `struct' constraint, so it cannot " + + "be used as a constraint for `{1}'", + tparam.Name, name); + return false; + } + + if (constraints.type_param_constraints == null) + return true; + + foreach (TypeParameterExpr expr in constraints.type_param_constraints) { + if (seen.Contains (expr.TypeParameter)) { + Report.Error (454, loc, "Circular constraint " + + "dependency involving `{0}' and `{1}'", + tparam.Name, expr.Name); + return false; + } + + if (!CheckTypeParameterConstraints (expr.TypeParameter, seen)) + return false; + } return true; } - public Type[] ResolveTypes (EmitContext ec) + public bool ResolveTypes (EmitContext ec) { - types = new Type [constraint_types.Length]; + foreach (TypeParameterExpr expr in type_param_constraints) { + Hashtable seen = new Hashtable (); + if (!CheckTypeParameterConstraints (expr.TypeParameter, seen)) + return false; + } - for (int i = 0; i < constraint_types.Length; i++) { - types [i] = constraint_types [i].ResolveType (ec); - if (types [i] == null) - return null; + ArrayList list = new ArrayList (); + + foreach (TypeExpr iface_constraint in iface_constraints) { + Type resolved = iface_constraint.ResolveType (ec); + if (resolved == null) + return false; - for (int j = first_constraint; j < i; j++) { - if (!types [j].Equals (types [i])) + foreach (TypeExpr texpr in list) { + if (!texpr.Equals (resolved)) continue; Report.Error (405, loc, "Duplicate constraint `{0}' for type " + - "parameter `{1}'.", types [i], name); - return null; + "parameter `{1}'.", resolved, name); + return false; } + + list.Add (resolved); } + foreach (TypeParameterExpr expr in type_param_constraints) { + Type resolved = expr.ResolveType (ec); + if (resolved == null) + return false; + + foreach (TypeExpr texpr in list) { + if (!texpr.Equals (resolved)) + continue; + + Report.Error (405, loc, + "Duplicate constraint `{0}' for type " + + "parameter `{1}'.", resolved, name); + return false; + } + + list.Add (resolved); + } + + iface_constraint_types = new Type [list.Count]; + list.CopyTo (iface_constraint_types, 0); + if (class_constraint != null) { - if (types [0].IsSealed) { + class_constraint_type = class_constraint.ResolveType (ec); + if (class_constraint_type == null) + return false; + + if (class_constraint_type.IsSealed) { Report.Error (701, loc, "`{0}' is not a valid bound. Bounds " + "must be interfaces or non sealed " + - "classes", types [0]); - return null; + "classes", class_constraint_type); + return false; } - if ((types [0] == TypeManager.array_type) || - (types [0] == TypeManager.delegate_type) || - (types [0] == TypeManager.enum_type) || - (types [0] == TypeManager.value_type) || - (types [0] == TypeManager.object_type)) { + if ((class_constraint_type == TypeManager.array_type) || + (class_constraint_type == TypeManager.delegate_type) || + (class_constraint_type == TypeManager.enum_type) || + (class_constraint_type == TypeManager.value_type) || + (class_constraint_type == TypeManager.object_type)) { Report.Error (702, loc, "Bound cannot be special class `{0}'", - types [0]); - return null; + class_constraint_type); + return false; } } - return types; + if (has_reference_type) + class_constraint_type = TypeManager.object_type; + else if (has_value_type) + class_constraint_type = TypeManager.value_type; + + return true; } - bool GenericConstraints.HasConstructor { - get { - return has_ctor_constraint; + public bool CheckDependencies (EmitContext ec) + { + foreach (TypeParameterExpr expr in type_param_constraints) { + if (!CheckDependencies (expr.TypeParameter, ec)) + return false; } + + return true; } - Type[] GenericConstraints.Types { - get { - if (types == null) - throw new InvalidOperationException (); + bool CheckDependencies (TypeParameter tparam, EmitContext ec) + { + Constraints constraints = tparam.Constraints; + if (constraints == null) + return true; - return types; + if (IsValueType && constraints.HasClassConstraint) { + Report.Error (455, loc, "Type parameter `{0}' inherits " + + "conflicting constraints `{1}' and `{2}'", + name, constraints.ClassConstraint, + "System.ValueType"); + return false; } + + if (HasClassConstraint && constraints.HasClassConstraint) { + Type t1 = ClassConstraint; + TypeExpr e1 = class_constraint; + Type t2 = constraints.ClassConstraint; + TypeExpr e2 = constraints.class_constraint; + + if (!Convert.ImplicitReferenceConversionExists (e1, t2) && + !Convert.ImplicitReferenceConversionExists (e2, t1)) { + Report.Error (455, loc, + "Type parameter `{0}' inherits " + + "conflicting constraints `{1}' and `{2}'", + name, t1, t2); + return false; + } + } + + if (constraints.type_param_constraints == null) + return true; + + foreach (TypeParameterExpr expr in constraints.type_param_constraints) { + if (!CheckDependencies (expr.TypeParameter, ec)) + return false; + } + + return true; + } + + public void Define (GenericTypeParameterBuilder type) + { + if (has_ctor_constraint) + type.Mono_SetConstructorConstraint (); + if (has_reference_type) + type.Mono_SetReferenceTypeConstraint (); + else if (has_value_type) + type.Mono_SetValueTypeConstraint (); + } + + bool GenericConstraints.HasConstructor { + get { return has_ctor_constraint; } + } + + bool GenericConstraints.IsReferenceType { + get { return has_reference_type; } + } + + public bool IsValueType { + get { return has_value_type; } + } + + public bool HasClassConstraint { + get { return class_constraint_type != null; } + } + + public Type ClassConstraint { + get { return class_constraint_type; } + } + + Type[] GenericConstraints.InterfaceConstraints { + get { return iface_constraint_types; } } } // // This type represents a generic type parameter // - public class TypeParameter { + public class TypeParameter : IMemberContainer { string name; Constraints constraints; Location loc; - Type type; + GenericTypeParameterBuilder type; public TypeParameter (string name, Constraints constraints, Location loc) { @@ -218,52 +393,87 @@ namespace Mono.CSharp { return true; } - public Type Define (TypeBuilder tb) - { - type = tb.DefineGenericParameter (name); - TypeManager.AddTypeParameter (type, this); - return type; - } - - public Type DefineMethod (MethodBuilder mb) + public void Define (GenericTypeParameterBuilder type) { - type = mb.DefineGenericParameter (name); + this.type = type; + Type[] ifaces = null; + if (constraints != null) + constraints.Define (type); TypeManager.AddTypeParameter (type, this); - return type; } - public bool DefineType (EmitContext ec, TypeBuilder tb) + public bool DefineType (EmitContext ec) { - int index = type.GenericParameterPosition; - if (constraints == null) - tb.SetGenericParameterConstraints (index, new Type [0], false); - else { - Type[] types = constraints.ResolveTypes (ec); - if (types == null) + if (constraints != null) { + if (!constraints.ResolveTypes (ec)) return false; - tb.SetGenericParameterConstraints ( - index, types, constraints.HasConstructorConstraint); + GenericConstraints gc = (GenericConstraints) constraints; + + if (gc.HasClassConstraint) + type.SetBaseTypeConstraint (gc.ClassConstraint); + + type.SetInterfaceConstraints (gc.InterfaceConstraints); + TypeManager.RegisterBuilder (type, gc.InterfaceConstraints); } return true; } - public bool DefineType (EmitContext ec, MethodBuilder mb) + public bool CheckDependencies (EmitContext ec) + { + if (constraints != null) + return constraints.CheckDependencies (ec); + + return true; + } + + // + // IMemberContainer + // + + IMemberContainer IMemberContainer.ParentContainer { + get { return null; } + } + + bool IMemberContainer.IsInterface { + get { return true; } + } + + MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf) + { + return FindMembers (mt, bf, null, null); + } + + MemberCache IMemberContainer.MemberCache { + get { return null; } + } + + public MemberList FindMembers (MemberTypes mt, BindingFlags bf, + MemberFilter filter, object criteria) { - int index = type.GenericParameterPosition; if (constraints == null) - mb.SetGenericParameterConstraints (index, new Type [0], false); - else { - Type[] types = constraints.ResolveTypes (ec); - if (types == null) - return false; + return MemberList.Empty; + + ArrayList members = new ArrayList (); - mb.SetGenericParameterConstraints ( - index, types, constraints.HasConstructorConstraint); + GenericConstraints gc = (GenericConstraints) constraints; + + if (gc.HasClassConstraint) { + MemberList list = TypeManager.FindMembers ( + gc.ClassConstraint, mt, bf, filter, criteria); + + members.AddRange (list); } - return true; + foreach (Type t in gc.InterfaceConstraints) { + MemberList list = TypeManager.FindMembers ( + t, mt, bf, filter, criteria); + + members.AddRange (list); + } + + return new MemberList (members); } public override string ToString () @@ -305,6 +515,10 @@ namespace Mono.CSharp { return this; } + public override bool IsInterface { + get { return false; } + } + public void Error_CannotUseAsUnmanagedType (Location loc) { Report.Error (-203, loc, "Can not use type parameter as unamanged type"); @@ -315,6 +529,7 @@ namespace Mono.CSharp { public readonly Location Location; ArrayList args; Type[] atypes; + int dimension; bool has_type_args; bool created; @@ -324,6 +539,12 @@ namespace Mono.CSharp { this.Location = loc; } + public TypeArguments (int dimension, Location loc) + { + this.dimension = dimension; + this.Location = loc; + } + public void Add (Expression type) { if (created) @@ -371,7 +592,16 @@ namespace Mono.CSharp { public int Count { get { - return args.Count; + if (dimension > 0) + return dimension; + else + return args.Count; + } + } + + public bool IsUnbound { + get { + return dimension > 0; } } @@ -379,12 +609,13 @@ namespace Mono.CSharp { { StringBuilder s = new StringBuilder (); - int count = args.Count; + int count = Count; for (int i = 0; i < count; i++){ // // FIXME: Use TypeManager.CSharpname once we have the type // - s.Append (args [i].ToString ()); + if (args != null) + s.Append (args [i].ToString ()); if (i+1 < count) s.Append (","); } @@ -398,7 +629,7 @@ namespace Mono.CSharp { bool ok = true; atypes = new Type [count]; - + for (int i = 0; i < count; i++){ TypeExpr te = ds.ResolveTypeExpr ( (Expression) args [i], false, Location); @@ -429,7 +660,7 @@ namespace Mono.CSharp { public ConstructedType (string name, TypeArguments args, Location l) { loc = l; - this.name = name + "!" + args.Count; + this.name = MemberName.MakeName (name, args.Count); this.args = args; eclass = ExprClass.Type; @@ -501,6 +732,32 @@ namespace Mono.CSharp { } } + protected bool CheckConstraint (EmitContext ec, Type ptype, Expression expr, + Type ctype) + { + if (TypeManager.HasGenericArguments (ctype)) { + Type[] types = TypeManager.GetTypeArguments (ctype); + + TypeArguments new_args = new TypeArguments (loc); + + for (int i = 0; i < types.Length; i++) { + Type t = types [i]; + + if (t.IsGenericParameter) { + int pos = t.GenericParameterPosition; + t = args.Arguments [pos]; + } + new_args.Add (new TypeExpression (t, loc)); + } + + ctype = new ConstructedType (ctype, new_args, loc).ResolveType (ec); + if (ctype == null) + return false; + } + + return Convert.ImplicitStandardConversionExists (expr, ctype); + } + protected bool CheckConstraints (EmitContext ec, int index) { Type atype = atypes [index]; @@ -511,13 +768,36 @@ namespace Mono.CSharp { Expression aexpr = new EmptyExpression (atype); + Type parent = ptype.BaseType; + // - // First, check the class constraint. + // 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; + } + } - Type parent = ptype.BaseType; + // + // The class constraint comes next. + // if ((parent != null) && (parent != TypeManager.object_type)) { - if (!Convert.ImplicitStandardConversionExists (aexpr, parent)) { + if (!CheckConstraint (ec, ptype, aexpr, parent)) { Report.Error (309, loc, "The type `{0}' must be " + "convertible to `{1}' in order to " + "use it as parameter `{2}' in the " + @@ -530,8 +810,14 @@ namespace Mono.CSharp { // // Now, check the interface constraints. // - foreach (Type itype in ptype.GetInterfaces ()) { - if (!Convert.ImplicitStandardConversionExists (aexpr, itype)) { + foreach (Type it in TypeManager.GetInterfaces (ptype)) { + Type itype; + if (it.IsGenericParameter) + itype = atypes [it.GenericParameterPosition]; + else + itype = it; + + if (!CheckConstraint (ec, ptype, aexpr, itype)) { Report.Error (309, loc, "The type `{0}' must be " + "convertible to `{1}' in order to " + "use it as parameter `{2}' in the " + @@ -656,15 +942,9 @@ namespace Mono.CSharp { return type; } - public Expression GetMemberAccess (EmitContext ec) + public Expression GetSimpleName (EmitContext ec) { - TypeExpr current; - if (ec.TypeContainer.CurrentType != null) - current = ec.TypeContainer.CurrentType; - else - current = new TypeExpression (ec.ContainerType, loc); - - return new MemberAccess (current, Basename, args, loc); + return new SimpleName (Basename, args, loc); } public override bool CheckAccessLevel (DeclSpace ds) @@ -697,12 +977,6 @@ namespace Mono.CSharp { get { return false; } } - public override TypeExpr[] GetInterfaces () - { - TypeExpr[] ifaces = TypeManager.GetInterfaces (gt); - return ifaces; - } - public override bool Equals (object obj) { ConstructedType cobj = obj as ConstructedType; @@ -717,7 +991,7 @@ namespace Mono.CSharp { public string Basename { get { - int pos = name.LastIndexOf ('!'); + int pos = name.LastIndexOf ('`'); if (pos >= 0) return name.Substring (0, pos); else @@ -735,8 +1009,8 @@ namespace Mono.CSharp { public class GenericMethod : DeclSpace { public GenericMethod (NamespaceEntry ns, TypeContainer parent, - MemberName name, Attributes attrs, Location l) - : base (ns, parent, name, attrs, l) + MemberName name, Location l) + : base (ns, parent, name, null, l) { } public override TypeBuilder DefineType () @@ -744,23 +1018,25 @@ namespace Mono.CSharp { throw new Exception (); } - public override bool Define (TypeContainer parent) + public override bool Define () { for (int i = 0; i < TypeParameters.Length; i++) - if (!TypeParameters [i].Resolve (parent)) + if (!TypeParameters [i].Resolve (Parent)) return false; return true; } - public bool Define (TypeContainer parent, MethodBuilder mb) + public bool Define (MethodBuilder mb) { - if (!Define (parent)) + if (!Define ()) return false; - Type[] gen_params = new Type [TypeParameters.Length]; + GenericTypeParameterBuilder[] gen_params; + string[] names = MemberName.TypeArguments.GetDeclarations (); + gen_params = mb.DefineGenericParameters (names); for (int i = 0; i < TypeParameters.Length; i++) - gen_params [i] = TypeParameters [i].DefineMethod (mb); + TypeParameters [i].Define (gen_params [i]); return true; } @@ -768,7 +1044,7 @@ namespace Mono.CSharp { public bool DefineType (EmitContext ec, MethodBuilder mb) { for (int i = 0; i < TypeParameters.Length; i++) - if (!TypeParameters [i].DefineType (ec, mb)) + if (!TypeParameters [i].DefineType (ec)) return false; return true; @@ -790,6 +1066,22 @@ namespace Mono.CSharp { throw new Exception (); } } + + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + { + // FIXME + } + + protected override void VerifyObsoleteAttribute() + { + // FIXME + } + + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Method | AttributeTargets.ReturnValue; + } + } } public class DefaultValueExpression : Expression