X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mcs%2Fmcs%2Fgeneric.cs;h=11a913a4f6d0362f46cfce7fe0415e7b3411d4e7;hb=d660494ca016170ecf2204473ba6847c430a3b21;hp=0f05ee2d4698b6f70f976e494e9b077edb075f7b;hpb=409ebb6a2ee08734c182bb9a90d54f9a55c6a20b;p=mono.git diff --git a/mcs/mcs/generic.cs b/mcs/mcs/generic.cs index 0f05ee2d469..11a913a4f6d 100644 --- a/mcs/mcs/generic.cs +++ b/mcs/mcs/generic.cs @@ -14,2130 +14,2138 @@ using System; using System.Reflection; using System.Reflection.Emit; using System.Globalization; -using System.Collections; +using System.Collections.Generic; using System.Text; -using System.Text.RegularExpressions; +using System.Linq; namespace Mono.CSharp { + public enum Variance + { + // + // Don't add or modify internal values, they are used as -/+ calculation signs + // + None = 0, + Covariant = 1, + Contravariant = -1 + } - /// - /// Abstract base class for type parameter constraints. - /// The type parameter can come from a generic type definition or from reflection. - /// - public abstract class GenericConstraints { - public abstract string TypeParameter { - get; - } - - public abstract GenericParameterAttributes Attributes { - get; - } - - public bool HasConstructorConstraint { - get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; } - } - - public bool HasReferenceTypeConstraint { - get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; } - } + [Flags] + public enum SpecialConstraint + { + None = 0, + Constructor = 1 << 2, + Class = 1 << 3, + Struct = 1 << 4 + } - public bool HasValueTypeConstraint { - get { return (Attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0; } + public class SpecialContraintExpr : FullNamedExpression + { + public SpecialContraintExpr (SpecialConstraint constraint, Location loc) + { + this.loc = loc; + this.Constraint = constraint; } - public virtual bool HasClassConstraint { - get { return ClassConstraint != null; } - } + public SpecialConstraint Constraint { get; private set; } - public abstract Type ClassConstraint { - get; + protected override Expression DoResolve (ResolveContext rc) + { + throw new NotImplementedException (); } + } - public abstract Type[] InterfaceConstraints { - get; + // + // A set of parsed constraints for a type parameter + // + public class Constraints + { + SimpleMemberName tparam; + List constraints; + Location loc; + bool resolved; + bool resolving; + + public Constraints (SimpleMemberName tparam, List constraints, Location loc) + { + this.tparam = tparam; + this.constraints = constraints; + this.loc = loc; } - public abstract Type EffectiveBaseClass { - get; - } + #region Properties - // - // Returns whether the type parameter is "known to be a reference type". - // - public virtual bool IsReferenceType { + public Location Location { get { - if (HasReferenceTypeConstraint) - return true; - if (HasValueTypeConstraint) - return false; - - if (ClassConstraint != null) { - if (ClassConstraint.IsValueType) - return false; - - if (ClassConstraint != TypeManager.object_type) - return true; - } - - foreach (Type t in InterfaceConstraints) { - if (!t.IsGenericParameter) - continue; - - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t); - if ((gc != null) && gc.IsReferenceType) - return true; - } - - return false; + return loc; } } - // - // Returns whether the type parameter is "known to be a value type". - // - public virtual bool IsValueType { + public SimpleMemberName TypeParameter { get { - if (HasValueTypeConstraint) - return true; - if (HasReferenceTypeConstraint) - return false; - - if (ClassConstraint != null) { - if (!ClassConstraint.IsValueType) - return false; - - if (ClassConstraint != TypeManager.value_type) - return true; - } - - foreach (Type t in InterfaceConstraints) { - if (!t.IsGenericParameter) - continue; - - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t); - if ((gc != null) && gc.IsValueType) - return true; - } - - return false; + return tparam; } } - } - public enum SpecialConstraint - { - Constructor, - ReferenceType, - ValueType - } + #endregion - /// - /// Tracks the constraints for a type parameter from a generic type definition. - /// - public class Constraints : GenericConstraints { - string name; - ArrayList constraints; - Location loc; - - // - // name is the identifier, constraints is an arraylist of - // Expressions (with types) or `true' for the constructor constraint. - // - public Constraints (string name, ArrayList constraints, - Location loc) + bool CheckConflictingInheritedConstraint (TypeSpec ba, TypeSpec bb, IMemberContext context, Location loc) { - this.name = name; - this.constraints = constraints; - this.loc = loc; - } - - public override string TypeParameter { - get { - return name; + if (!TypeManager.IsSubclassOf (ba, bb) && !TypeManager.IsSubclassOf (bb, ba)) { + context.Compiler.Report.Error (455, loc, + "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'", + tparam.Value, + ba.GetSignatureForError (), bb.GetSignatureForError ()); + return false; } + + return true; } - public Constraints Clone () + public void CheckGenericConstraints (IMemberContext context) { - return new Constraints (name, constraints, loc); + foreach (var c in constraints) { + var ge = c as GenericTypeExpr; + if (ge != null) + ge.CheckConstraints (context); + } } - GenericParameterAttributes attrs; - TypeExpr class_constraint; - ArrayList iface_constraints; - ArrayList type_param_constraints; - int num_constraints; - Type class_constraint_type; - Type[] iface_constraint_types; - Type effective_base_type; - bool resolved; - bool resolved_types; - - /// - /// Resolve the constraints - but only resolve things into Expression's, not - /// into actual types. - /// - public bool Resolve (IResolveContext ec) + // + // Resolve the constraints types with only possible early checks, return + // value `false' is reserved for recursive failure + // + public bool Resolve (IMemberContext context, TypeParameter tp) { if (resolved) return true; - iface_constraints = new ArrayList (2); // TODO: Too expensive allocation - type_param_constraints = new ArrayList (); - - foreach (object obj in constraints) { - if (HasConstructorConstraint) { - Report.Error (401, loc, - "The new() constraint must be the last constraint specified"); - return false; - } + if (resolving) + return false; - if (obj is SpecialConstraint) { - SpecialConstraint sc = (SpecialConstraint) obj; + resolving = true; + var spec = tp.Type; + List tparam_types = null; + bool iface_found = false; - if (sc == SpecialConstraint.Constructor) { - if (!HasValueTypeConstraint) { - attrs |= GenericParameterAttributes.DefaultConstructorConstraint; - continue; - } + spec.BaseType = TypeManager.object_type; - Report.Error (451, loc, "The `new()' constraint " + - "cannot be used with the `struct' constraint"); - return false; - } + for (int i = 0; i < constraints.Count; ++i) { + var constraint = constraints[i]; - if ((num_constraints > 0) || HasReferenceTypeConstraint || HasValueTypeConstraint) { - Report.Error (449, loc, "The `class' or `struct' " + - "constraint must be the first constraint specified"); - return false; - } + if (constraint is SpecialContraintExpr) { + spec.SpecialConstraint |= ((SpecialContraintExpr) constraint).Constraint; + if (spec.HasSpecialStruct) + spec.BaseType = TypeManager.value_type; - if (sc == SpecialConstraint.ReferenceType) - attrs |= GenericParameterAttributes.ReferenceTypeConstraint; - else - attrs |= GenericParameterAttributes.NotNullableValueTypeConstraint; + // Set to null as it does not have a type + constraints[i] = null; continue; } - int errors = Report.Errors; - FullNamedExpression fn = ((Expression) obj).ResolveAsTypeStep (ec, false); - - if (fn == null) { - if (errors != Report.Errors) - return false; + var type_expr = constraints[i] = constraint.ResolveAsTypeTerminal (context, false); + if (type_expr == null) + continue; - NamespaceEntry.Error_NamespaceNotFound (loc, ((Expression)obj).GetSignatureForError ()); - return false; + var gexpr = type_expr as GenericTypeExpr; + if (gexpr != null && gexpr.HasDynamicArguments ()) { + context.Compiler.Report.Error (1968, constraint.Location, + "A constraint cannot be the dynamic type `{0}'", gexpr.GetSignatureForError ()); + continue; } - TypeExpr expr; - GenericTypeExpr cexpr = fn as GenericTypeExpr; - if (cexpr != null) { - expr = cexpr.ResolveAsBaseTerminal (ec, false); - } else - expr = ((Expression) obj).ResolveAsTypeTerminal (ec, false); - - if ((expr == null) || (expr.Type == null)) - return false; + var type = type_expr.Type; - if (!ec.GenericDeclContainer.IsAccessibleAs (fn.Type)) { - Report.SymbolRelatedToPreviousError (fn.Type); - Report.Error (703, loc, + if (!context.CurrentMemberDefinition.IsAccessibleAs (type)) { + context.Compiler.Report.SymbolRelatedToPreviousError (type); + context.Compiler.Report.Error (703, loc, "Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'", - fn.GetSignatureForError (), ec.GenericDeclContainer.GetSignatureForError ()); - return false; + type.GetSignatureForError (), context.GetSignatureForError ()); } - 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 || iface_constraints.Count != 0) { - Report.Error (406, loc, - "The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list", - expr.GetSignatureForError ()); - return false; - } else if (HasReferenceTypeConstraint || HasValueTypeConstraint) { - Report.Error (450, loc, "`{0}': cannot specify both " + - "a constraint class and the `class' " + - "or `struct' constraint", expr.GetSignatureForError ()); - return false; - } else - class_constraint = expr; + if (type.IsInterface) { + if (!spec.AddInterface (type)) { + context.Compiler.Report.Error (405, constraint.Location, + "Duplicate constraint `{0}' for type parameter `{1}'", type.GetSignatureForError (), tparam.Value); + } + + iface_found = true; + continue; + } - num_constraints++; - } - ArrayList list = new ArrayList (); - foreach (TypeExpr iface_constraint in iface_constraints) { - foreach (Type type in list) { - if (!type.Equals (iface_constraint.Type)) + var constraint_tp = type as TypeParameterSpec; + if (constraint_tp != null) { + if (tparam_types == null) { + tparam_types = new List (2); + } else if (tparam_types.Contains (constraint_tp)) { + context.Compiler.Report.Error (405, constraint.Location, + "Duplicate constraint `{0}' for type parameter `{1}'", type.GetSignatureForError (), tparam.Value); continue; + } - Report.Error (405, loc, - "Duplicate constraint `{0}' for type " + - "parameter `{1}'.", iface_constraint.GetSignatureForError (), - name); - return false; - } + // + // Checks whether each generic method parameter constraint type + // is valid with respect to T + // + if (tp.IsMethodTypeParameter) { + TypeManager.CheckTypeVariance (type, Variance.Contravariant, context); + } - list.Add (iface_constraint.Type); - } + var tp_def = constraint_tp.MemberDefinition as TypeParameter; + if (tp_def != null && !tp_def.ResolveConstraints (context)) { + context.Compiler.Report.Error (454, constraint.Location, + "Circular constraint dependency involving `{0}' and `{1}'", + constraint_tp.GetSignatureForError (), tp.GetSignatureForError ()); + continue; + } + + // + // Checks whether there are no conflicts between type parameter constraints + // + // class Foo + // where T : A + // where U : B, T + // + // A and B are not convertible and only 1 class constraint is allowed + // + if (constraint_tp.HasTypeConstraint) { + if (spec.HasTypeConstraint || spec.HasSpecialStruct) { + if (!CheckConflictingInheritedConstraint (spec.BaseType, constraint_tp.BaseType, context, constraint.Location)) + continue; + } else { + for (int ii = 0; ii < tparam_types.Count; ++ii) { + if (!tparam_types[ii].HasTypeConstraint) + continue; + + if (!CheckConflictingInheritedConstraint (tparam_types[ii].BaseType, constraint_tp.BaseType, context, constraint.Location)) + break; + } + } + } - foreach (TypeParameterExpr expr in type_param_constraints) { - foreach (Type type in list) { - if (!type.Equals (expr.Type)) + if (constraint_tp.HasSpecialStruct) { + context.Compiler.Report.Error (456, constraint.Location, + "Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'", + constraint_tp.GetSignatureForError (), tp.GetSignatureForError ()); continue; + } - Report.Error (405, loc, - "Duplicate constraint `{0}' for type " + - "parameter `{1}'.", expr.GetSignatureForError (), name); - return false; + tparam_types.Add (constraint_tp); + continue; } - list.Add (expr.Type); - } + if (iface_found || spec.HasTypeConstraint) { + context.Compiler.Report.Error (406, constraint.Location, + "The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list", + type.GetSignatureForError ()); + } - iface_constraint_types = new Type [list.Count]; - list.CopyTo (iface_constraint_types, 0); + if (spec.HasSpecialStruct || spec.HasSpecialClass) { + context.Compiler.Report.Error (450, type_expr.Location, + "`{0}': cannot specify both a constraint class and the `class' or `struct' constraint", + type.GetSignatureForError ()); + } - if (class_constraint != null) { - class_constraint_type = class_constraint.Type; - if (class_constraint_type == null) - return false; + if (type == InternalType.Dynamic) { + context.Compiler.Report.Error (1967, constraint.Location, "A constraint cannot be the dynamic type"); + continue; + } - if (class_constraint_type.IsSealed) { - if (class_constraint_type.IsAbstract) - { - Report.Error (717, loc, "`{0}' is not a valid constraint. Static classes cannot be used as constraints", - TypeManager.CSharpName (class_constraint_type)); - } - else - { - Report.Error (701, loc, "`{0}' is not a valid constraint. A constraint must be an interface, " + - "a non-sealed class or a type parameter", TypeManager.CSharpName(class_constraint_type)); - } - return false; + if (type.IsSealed || !type.IsClass) { + context.Compiler.Report.Error (701, loc, + "`{0}' is not a valid constraint. A constraint must be an interface, a non-sealed class or a type parameter", + TypeManager.CSharpName (type)); + continue; } - 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) || - class_constraint_type == TypeManager.multicast_delegate_type) { - Report.Error (702, loc, - "A constraint cannot be special class `{0}'", - TypeManager.CSharpName (class_constraint_type)); - return false; + if (type.IsStatic) { + context.Compiler.Report.Error (717, constraint.Location, + "`{0}' is not a valid constraint. Static classes cannot be used as constraints", + type.GetSignatureForError ()); + } else if (type == TypeManager.array_type || type == TypeManager.delegate_type || + type == TypeManager.enum_type || type == TypeManager.value_type || + type == TypeManager.object_type || type == TypeManager.multicast_delegate_type) { + context.Compiler.Report.Error (702, constraint.Location, + "A constraint cannot be special class `{0}'", type.GetSignatureForError ()); + continue; } - } - if (class_constraint_type != null) - effective_base_type = class_constraint_type; - else if (HasValueTypeConstraint) - effective_base_type = TypeManager.value_type; - else - effective_base_type = TypeManager.object_type; + spec.BaseType = type; + } - if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) - attrs |= GenericParameterAttributes.DefaultConstructorConstraint; + if (tparam_types != null) + spec.TypeArguments = tparam_types.ToArray (); + resolving = false; resolved = true; return true; } - bool CheckTypeParameterConstraints (TypeParameter tparam, ref TypeExpr prevConstraint, ArrayList seen) + public void VerifyClsCompliance (Report report) { - seen.Add (tparam); - - Constraints constraints = tparam.Constraints; - if (constraints == null) - return true; - - if (constraints.HasValueTypeConstraint) { - 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; - } - - // - // Checks whether there are no conflicts between type parameter constraints - // - // class Foo - // where T : A - // where U : A, B // A and B are not convertible - // - if (constraints.HasClassConstraint) { - if (prevConstraint != null) { - Type t2 = constraints.ClassConstraint; - TypeExpr e2 = constraints.class_constraint; - - if (!Convert.ImplicitReferenceConversionExists (prevConstraint, t2) && - !Convert.ImplicitReferenceConversionExists (e2, prevConstraint.Type)) { - Report.Error (455, loc, - "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'", - name, TypeManager.CSharpName (prevConstraint.Type), TypeManager.CSharpName (t2)); - return false; - } - } - - prevConstraint = constraints.class_constraint; - } - - if (constraints.type_param_constraints == null) - return true; + foreach (var c in constraints) + { + if (c == null) + continue; - 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.GetSignatureForError ()); - return false; + if (!c.Type.IsCLSCompliant ()) { + report.SymbolRelatedToPreviousError (c.Type); + report.Warning (3024, 1, loc, "Constraint type `{0}' is not CLS-compliant", + c.Type.GetSignatureForError ()); } - - if (!CheckTypeParameterConstraints (expr.TypeParameter, ref prevConstraint, seen)) - return false; } - - return true; } + } - /// - /// Resolve the constraints into actual types. - /// - public bool ResolveTypes (IResolveContext ec) - { - if (resolved_types) - return true; - - resolved_types = true; - - foreach (object obj in constraints) { - GenericTypeExpr cexpr = obj as GenericTypeExpr; - if (cexpr == null) - continue; + // + // A type parameter for a generic type or generic method definition + // + public class TypeParameter : MemberCore, ITypeDefinition + { + static readonly string[] attribute_target = new string [] { "type parameter" }; + + Constraints constraints; + GenericTypeParameterBuilder builder; +// Variance variance; + TypeParameterSpec spec; - if (!cexpr.CheckConstraints (ec)) - return false; - } + 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); + } - if (type_param_constraints.Count != 0) { - ArrayList seen = new ArrayList (); - TypeExpr prev_constraint = class_constraint; - foreach (TypeParameterExpr expr in type_param_constraints) { - if (!CheckTypeParameterConstraints (expr.TypeParameter, ref prev_constraint, seen)) - return false; - seen.Clear (); - } - } + #region Properties - for (int i = 0; i < iface_constraints.Count; ++i) { - TypeExpr iface_constraint = (TypeExpr) iface_constraints [i]; - iface_constraint = iface_constraint.ResolveAsTypeTerminal (ec, false); - if (iface_constraint == null) - return false; - iface_constraints [i] = iface_constraint; + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.GenericParameter; } + } - if (class_constraint != null) { - class_constraint = class_constraint.ResolveAsTypeTerminal (ec, false); - if (class_constraint == null) - return false; + public override string DocCommentHeader { + get { + throw new InvalidOperationException ( + "Unexpected attempt to get doc comment from " + this.GetType ()); } - - return true; } - public override GenericParameterAttributes Attributes { - get { return attrs; } + public bool IsMethodTypeParameter { + get { + return spec.IsMethodOwned; + } } - public override bool HasClassConstraint { - get { return class_constraint != null; } + public string Namespace { + get { + return null; + } } - public override Type ClassConstraint { - get { return class_constraint_type; } + public TypeParameterSpec Type { + get { + return spec; + } } - public override Type[] InterfaceConstraints { - get { return iface_constraint_types; } + public int TypeParametersCount { + get { + return 0; + } } - public override Type EffectiveBaseClass { - get { return effective_base_type; } + public TypeParameterSpec[] TypeParameters { + get { + return null; + } } - public bool IsSubclassOf (Type t) - { - if ((class_constraint_type != null) && - class_constraint_type.IsSubclassOf (t)) - return true; - - if (iface_constraint_types == null) - return false; - - foreach (Type iface in iface_constraint_types) { - if (TypeManager.IsSubclassOf (iface, t)) - return true; + public override string[] ValidAttributeTargets { + get { + return attribute_target; } - - return false; } - public Location Location { + public Variance Variance { get { - return loc; + return spec.Variance; } } - /// - /// This is used when we're implementing a generic interface method. - /// Each method type parameter in implementing method must have the same - /// constraints than the corresponding type parameter in the interface - /// method. To do that, we're called on each of the implementing method's - /// type parameters. - /// - public bool AreEqual (GenericConstraints gc) - { - if (gc.Attributes != attrs) - return false; + #endregion - if (HasClassConstraint != gc.HasClassConstraint) - return false; - if (HasClassConstraint && !TypeManager.IsEqual (gc.ClassConstraint, ClassConstraint)) - return false; + // + // This is called for each part of a partial generic type definition. + // + // If partial type parameters constraints are not null and we don't + // already have constraints they become our constraints. If we already + // have constraints, we must check that they're the same. + // + public bool AddPartialConstraints (TypeContainer part, TypeParameter tp) + { + if (builder == null) + throw new InvalidOperationException (); - int gc_icount = gc.InterfaceConstraints != null ? - gc.InterfaceConstraints.Length : 0; - int icount = InterfaceConstraints != null ? - InterfaceConstraints.Length : 0; + var new_constraints = tp.constraints; + if (new_constraints == null) + return true; - if (gc_icount != icount) + // TODO: could create spec only + //tp.Define (null, -1, part.Definition); + tp.spec.DeclaringType = part.Definition; + if (!tp.ResolveConstraints (part)) return false; - for (int i = 0; i < gc.InterfaceConstraints.Length; ++i) { - Type iface = gc.InterfaceConstraints [i]; - if (iface.IsGenericType) - iface = iface.GetGenericTypeDefinition (); - - bool ok = false; - for (int ii = 0; i < InterfaceConstraints.Length; ++ii) { - Type check = InterfaceConstraints [ii]; - if (check.IsGenericType) - check = check.GetGenericTypeDefinition (); - - if (TypeManager.IsEqual (iface, check)) { - ok = true; - break; - } - } - - if (!ok) - return false; - } + if (constraints != null) + return spec.HasSameConstraintsDefinition (tp.Type); + // Copy constraint from resolved part to partial container + spec.SpecialConstraint = tp.spec.SpecialConstraint; + spec.InterfacesDefined = tp.spec.InterfacesDefined; + spec.TypeArguments = tp.spec.TypeArguments; + spec.BaseType = tp.spec.BaseType; + return true; } - public void VerifyClsCompliance () + public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) { - if (class_constraint_type != null && !AttributeTester.IsClsCompliant (class_constraint_type)) - Warning_ConstrainIsNotClsCompliant (class_constraint_type, class_constraint.Location); + builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata); + } - if (iface_constraint_types != null) { - for (int i = 0; i < iface_constraint_types.Length; ++i) { - if (!AttributeTester.IsClsCompliant (iface_constraint_types [i])) - Warning_ConstrainIsNotClsCompliant (iface_constraint_types [i], - ((TypeExpr)iface_constraints [i]).Location); + public void CheckGenericConstraints () + { + if (constraints != null) + constraints.CheckGenericConstraints (this); + } + + public TypeParameter CreateHoistedCopy (TypeSpec declaringType) + { + return new TypeParameter (Parent, spec.DeclaredPosition, MemberName, constraints, null, spec.Variance) { + spec = new TypeParameterSpec (declaringType, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) { + BaseType = spec.BaseType, + InterfacesDefined = spec.InterfacesDefined, + TypeArguments = spec.TypeArguments } - } + }; } - void Warning_ConstrainIsNotClsCompliant (Type t, Location loc) + public override bool Define () { - Report.SymbolRelatedToPreviousError (t); - Report.Warning (3024, 1, loc, "Constraint type `{0}' is not CLS-compliant", - TypeManager.CSharpName (t)); + return true; } - } - /// - /// A type parameter from a generic type definition. - /// - public class TypeParameter : MemberCore, IMemberContainer - { - static readonly string[] attribute_target = new string [] { "type parameter" }; - - DeclSpace decl; - GenericConstraints gc; - Constraints constraints; - GenericTypeParameterBuilder type; - MemberCache member_cache; + // + // This is the first method which is called during the resolving + // process; we're called immediately after creating the type parameters + // with SRE (by calling `DefineGenericParameters()' on the TypeBuilder / + // MethodBuilder). + // + public void Define (GenericTypeParameterBuilder type, TypeSpec declaringType) + { + if (builder != null) + throw new InternalErrorException (); + + this.builder = type; + spec.DeclaringType = declaringType; + spec.SetMetaInfo (type); + } - public TypeParameter (DeclSpace parent, DeclSpace decl, string name, - Constraints constraints, Attributes attrs, Location loc) - : base (parent, new MemberName (name, loc), attrs) + public void EmitConstraints (GenericTypeParameterBuilder builder) { - this.decl = decl; - this.constraints = constraints; + var attr = GenericParameterAttributes.None; + if (spec.Variance == Variance.Contravariant) + attr |= GenericParameterAttributes.Contravariant; + else if (spec.Variance == Variance.Covariant) + attr |= GenericParameterAttributes.Covariant; + + if (spec.HasSpecialClass) + attr |= GenericParameterAttributes.ReferenceTypeConstraint; + else if (spec.HasSpecialStruct) + attr |= GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint; + + if (spec.HasSpecialConstructor) + attr |= GenericParameterAttributes.DefaultConstructorConstraint; + + if (spec.BaseType != TypeManager.object_type) + builder.SetBaseTypeConstraint (spec.BaseType.GetMetaInfo ()); + + if (spec.InterfacesDefined != null) + builder.SetInterfaceConstraints (spec.InterfacesDefined.Select (l => l.GetMetaInfo ()).ToArray ()); + + if (spec.TypeArguments != null) + builder.SetInterfaceConstraints (spec.TypeArguments.Select (l => l.GetMetaInfo ()).ToArray ()); + + builder.SetGenericParameterAttributes (attr); + } + + public override void Emit () + { + EmitConstraints (builder); + + if (OptAttributes != null) + OptAttributes.Emit (); + + base.Emit (); } - public GenericConstraints GenericConstraints { - get { return gc != null ? gc : constraints; } + public void ErrorInvalidVariance (IMemberContext mc, Variance expected) + { + Report.SymbolRelatedToPreviousError (mc.CurrentMemberDefinition); + string input_variance = Variance == Variance.Contravariant ? "contravariant" : "covariant"; + string gtype_variance; + switch (expected) { + case Variance.Contravariant: gtype_variance = "contravariantly"; break; + case Variance.Covariant: gtype_variance = "covariantly"; break; + default: gtype_variance = "invariantly"; break; + } + + Delegate d = mc as Delegate; + string parameters = d != null ? d.Parameters.GetSignatureForError () : ""; + + Report.Error (1961, Location, + "The {2} type parameter `{0}' must be {3} valid on `{1}{4}'", + GetSignatureForError (), mc.GetSignatureForError (), input_variance, gtype_variance, parameters); } - public Constraints Constraints { - get { return constraints; } + public TypeSpec GetAttributeCoClass () + { + return null; } - public DeclSpace DeclSpace { - get { return decl; } + public string GetAttributeDefaultMember () + { + throw new NotSupportedException (); } - public Type Type { - get { return type; } + public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa) + { + throw new NotSupportedException (); } - /// - /// This is the first method which is called during the resolving - /// process; we're called immediately after creating the type parameters - /// with SRE (by calling `DefineGenericParameters()' on the TypeBuilder / - /// MethodBuilder). - /// - /// We're either called from TypeContainer.DefineType() or from - /// GenericMethod.Define() (called from Method.Define()). - /// - public void Define (GenericTypeParameterBuilder type) + public override string GetSignatureForError () { - if (this.type != null) - throw new InvalidOperationException (); + return MemberName.Name; + } - this.type = type; - TypeManager.AddTypeParameter (type, this); + public MemberCache LoadMembers (TypeSpec declaringType) + { + throw new NotSupportedException ("Not supported for compiled definition"); } - /// - /// This is the second method which is called during the resolving - /// process - in case of class type parameters, we're called from - /// TypeContainer.ResolveType() - after it resolved the class'es - /// base class and interfaces. For method type parameters, we're - /// called immediately after Define(). - /// - /// We're just resolving the constraints into expressions here, we - /// don't resolve them into actual types. - /// - /// Note that in the special case of partial generic classes, we may be - /// called _before_ Define() and we may also be called multiple types. - /// - public bool Resolve (DeclSpace ds) + // + // Resolves all type parameter constraints + // + public bool ResolveConstraints (IMemberContext context) { - if (constraints != null) { - if (!constraints.Resolve (ds)) { - constraints = null; - return false; - } - } + if (constraints != null) + return constraints.Resolve (context, this); + spec.BaseType = TypeManager.object_type; return true; } - /// - /// This is the third method which is called during the resolving - /// process. We're called immediately after calling DefineConstraints() - /// on all of the current class'es type parameters. - /// - /// Our job is to resolve the constraints to actual types. - /// - /// Note that we may have circular dependencies on type parameters - this - /// is why Resolve() and ResolveType() are separate. - /// - public bool ResolveType (IResolveContext ec) + public static TypeParameter FindTypeParameter (TypeParameter[] tparams, string name) { - if (constraints != null) { - if (!constraints.ResolveTypes (ec)) { - constraints = null; - return false; - } + foreach (var tp in tparams) { + if (tp.Name == name) + return tp; } - return true; + return null; } - /// - /// This is the fourth and last method which is called during the resolving - /// process. We're called after everything is fully resolved and actually - /// register the constraints with SRE and the TypeManager. - /// - public bool DefineType (IResolveContext ec) + public override bool IsClsComplianceRequired () { - return DefineType (ec, null, null, false); + return false; } - /// - /// This is the fith and last method which is called during the resolving - /// process. We're called after everything is fully resolved and actually - /// register the constraints with SRE and the TypeManager. - /// - /// The `builder', `implementing' and `is_override' arguments are only - /// applicable to method type parameters. - /// - public bool DefineType (IResolveContext ec, MethodBuilder builder, - MethodInfo implementing, bool is_override) + public new void VerifyClsCompliance () { - if (!ResolveType (ec)) - return false; + if (constraints != null) + constraints.VerifyClsCompliance (Report); + } + } - if (implementing != null) { - if (is_override && (constraints != null)) { - Report.Error (460, Location, - "`{0}': Cannot specify constraints for overrides or explicit interface implementation methods", - TypeManager.CSharpSignature (builder)); - return false; - } + [System.Diagnostics.DebuggerDisplay ("{DisplayDebugInfo()}")] + public class TypeParameterSpec : TypeSpec + { + public static readonly new TypeParameterSpec[] EmptyTypes = new TypeParameterSpec[0]; - MethodBase mb = TypeManager.DropGenericMethodArguments (implementing); + Variance variance; + SpecialConstraint spec; + readonly int tp_pos; + TypeSpec[] targs; + TypeSpec[] ifaces_defined; - int pos = type.GenericParameterPosition; - Type mparam = mb.GetGenericArguments () [pos]; - GenericConstraints temp_gc = ReflectionConstraints.GetConstraints (mparam); + // + // Creates type owned type parameter + // + public TypeParameterSpec (TypeSpec declaringType, int index, ITypeDefinition definition, SpecialConstraint spec, Variance variance, Type info) + : base (MemberKind.TypeParameter, declaringType, definition, info, Modifiers.PUBLIC) + { + this.variance = variance; + this.spec = spec; + state &= ~StateFlags.Obsolete_Undetected; + tp_pos = index; + } - if (temp_gc != null) - gc = new InflatedConstraints (temp_gc, implementing.DeclaringType); - else if (constraints != null) - gc = new InflatedConstraints (constraints, implementing.DeclaringType); + // + // Creates method owned type parameter + // + public TypeParameterSpec (int index, ITypeDefinition definition, SpecialConstraint spec, Variance variance, Type info) + : this (null, index, definition, spec, variance, info) + { + } - bool ok = true; - if (constraints != null) { - if (temp_gc == null) - ok = false; - else if (!constraints.AreEqual (gc)) - ok = false; - } else { - if (!is_override && (temp_gc != null)) - ok = false; - } + #region Properties - if (!ok) { - Report.SymbolRelatedToPreviousError (implementing); - - Report.Error ( - 425, Location, "The constraints for type " + - "parameter `{0}' of method `{1}' must match " + - "the constraints for type parameter `{2}' " + - "of interface method `{3}'. Consider using " + - "an explicit interface implementation instead", - Name, TypeManager.CSharpSignature (builder), - TypeManager.CSharpName (mparam), TypeManager.CSharpSignature (mb)); - return false; - } - } else if (DeclSpace is CompilerGeneratedClass) { - TypeParameter[] tparams = DeclSpace.TypeParameters; - Type[] types = new Type [tparams.Length]; - for (int i = 0; i < tparams.Length; i++) - types [i] = tparams [i].Type; - - if (constraints != null) - gc = new InflatedConstraints (constraints, types); - } else { - gc = (GenericConstraints) constraints; + public int DeclaredPosition { + get { + return tp_pos; } + } - if (gc == null) - return true; - - if (gc.HasClassConstraint || gc.HasValueTypeConstraint) - type.SetBaseTypeConstraint (gc.EffectiveBaseClass); + public bool HasSpecialConstructor { + get { + return (spec & SpecialConstraint.Constructor) != 0; + } + } - type.SetInterfaceConstraints (gc.InterfaceConstraints); - type.SetGenericParameterAttributes (gc.Attributes); - TypeManager.RegisterBuilder (type, gc.InterfaceConstraints); + public bool HasSpecialClass { + get { + return (spec & SpecialConstraint.Class) != 0; + } + } - return true; + public bool HasSpecialStruct { + get { + return (spec & SpecialConstraint.Struct) != 0; + } } - /// - /// This is called for each part of a partial generic type definition. - /// - /// If `new_constraints' is not null and we don't already have constraints, - /// they become our constraints. If we already have constraints, we must - /// check that they're the same. - /// con - /// - public bool UpdateConstraints (IResolveContext ec, Constraints new_constraints) - { - if (type == null) - throw new InvalidOperationException (); + public bool HasTypeConstraint { + get { + return BaseType != TypeManager.object_type && BaseType != TypeManager.value_type; + } + } - if (new_constraints == null) - return true; + public override IList Interfaces { + get { + if ((state & StateFlags.InterfacesExpanded) == 0) { + if (ifaces != null) { + for (int i = 0; i < ifaces.Count; ++i ) { + var iface_type = ifaces[i]; + if (iface_type.Interfaces != null) { + if (ifaces_defined == null) + ifaces_defined = ifaces.ToArray (); + + for (int ii = 0; ii < iface_type.Interfaces.Count; ++ii) { + var ii_iface_type = iface_type.Interfaces [ii]; + + AddInterface (ii_iface_type); + } + } + } + } - if (!new_constraints.Resolve (ec)) - return false; - if (!new_constraints.ResolveTypes (ec)) - return false; + if (ifaces_defined == null && ifaces != null) + ifaces_defined = ifaces.ToArray (); - if (constraints != null) - return constraints.AreEqual (new_constraints); + state |= StateFlags.InterfacesExpanded; + } - constraints = new_constraints; - return true; + return ifaces; + } } - public override void Emit () - { - if (OptAttributes != null) - OptAttributes.Emit (); + // + // Unexpanded interfaces list + // + public TypeSpec[] InterfacesDefined { + get { + if (ifaces_defined == null && ifaces != null) + ifaces_defined = ifaces.ToArray (); - base.Emit (); + return ifaces_defined; + } + set { + ifaces_defined = value; + } } - public override string DocCommentHeader { + public bool IsConstrained { get { - throw new InvalidOperationException ( - "Unexpected attempt to get doc comment from " + this.GetType () + "."); + return spec != SpecialConstraint.None || ifaces != null || targs != null || HasTypeConstraint; } } // - // MemberContainer + // Returns whether the type parameter is "known to be a reference type" // + public bool IsReferenceType { + get { + return (spec & SpecialConstraint.Class) != 0 || HasTypeConstraint; + } + } - public override bool Define () - { - return true; + public bool IsValueType { // TODO: Do I need this ? + get { + // TODO MemberCache: probably wrong + return HasSpecialStruct; + } } - public override void ApplyAttributeBuilder (Attribute a, - CustomAttributeBuilder cb) - { - type.SetCustomAttribute (cb); + public override string Name { + get { + return definition.Name; + } } - public override AttributeTargets AttributeTargets { + public bool IsMethodOwned { get { - return AttributeTargets.GenericParameter; + return DeclaringType == null; } } - public override string[] ValidAttributeTargets { + public SpecialConstraint SpecialConstraint { get { - return attribute_target; + return spec; + } + set { + spec = value; } } // - // IMemberContainer + // Types used to inflate the generic type // - - string IMemberContainer.Name { - get { return Name; } + public new TypeSpec[] TypeArguments { + get { + return targs; + } + set { + targs = value; + } } - MemberCache IMemberContainer.BaseCache { + public Variance Variance { get { - if (gc == null) - return null; - - if (gc.EffectiveBaseClass.BaseType == null) - return null; - - return TypeManager.LookupMemberCache (gc.EffectiveBaseClass.BaseType); + return variance; } } - bool IMemberContainer.IsInterface { - get { return false; } - } + #endregion - MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf) + public string DisplayDebugInfo () { - throw new NotSupportedException (); + var s = GetSignatureForError (); + return IsMethodOwned ? s + "!!" : s + "!"; } - public MemberCache MemberCache { - get { - if (member_cache != null) - return member_cache; - - if (gc == null) - return null; + // + // Finds effective base class + // + public TypeSpec GetEffectiveBase () + { + if (HasSpecialStruct) { + return TypeManager.value_type; + } - Type[] ifaces = TypeManager.ExpandInterfaces (gc.InterfaceConstraints); - member_cache = new MemberCache (this, gc.EffectiveBaseClass, ifaces); + if (BaseType != null && targs == null) + return BaseType; - return member_cache; + var types = targs; + if (HasTypeConstraint) { + Array.Resize (ref types, types.Length + 1); + types[types.Length - 1] = BaseType; } + + if (types != null) + return Convert.FindMostEncompassedType (types.Select (l => l.BaseType)); + + return TypeManager.object_type; } - public MemberList FindMembers (MemberTypes mt, BindingFlags bf, - MemberFilter filter, object criteria) + public override string GetSignatureForError () { - if (gc == null) - return MemberList.Empty; - - ArrayList members = new ArrayList (); + return Name; + } - if (gc.HasClassConstraint) { - MemberList list = TypeManager.FindMembers ( - gc.ClassConstraint, mt, bf, filter, criteria); + // + // 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; - members.AddRange (list); - } + if (BaseType != other.BaseType) + return false; - Type[] ifaces = TypeManager.ExpandInterfaces (gc.InterfaceConstraints); - foreach (Type t in ifaces) { - MemberList list = TypeManager.FindMembers ( - t, mt, bf, filter, criteria); + if (!TypeSpecComparer.Override.IsSame (InterfacesDefined, other.InterfacesDefined)) + return false; - members.AddRange (list); - } + if (!TypeSpecComparer.Override.IsSame (targs, other.targs)) + return false; - return new MemberList (members); + return true; } - public bool IsSubclassOf (Type t) + // + // Constraints have to match by using same set of types, used by + // implicit interface implementation + // + public bool HasSameConstraintsImplementation (TypeParameterSpec other) { - if (type.Equals (t)) - return true; - - if (constraints != null) - return constraints.IsSubclassOf (t); + if (spec != other.spec) + return false; - return false; - } + // + // It can be same base type or inflated type parameter + // + // interface I { void Foo where U : T; } + // class A : I { void Foo where X : int {} } + // + bool found; + if (BaseType != other.BaseType) { + if (other.targs == null) + return false; - public static string GetSignatureForError (TypeParameter[] tp) - { - if (tp == null || tp.Length == 0) - return ""; + found = false; + foreach (var otarg in other.targs) { + if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) { + found = true; + break; + } + } - StringBuilder sb = new StringBuilder ("<"); - for (int i = 0; i < tp.Length; ++i) { - if (i > 0) - sb.Append (","); - sb.Append (tp[i].GetSignatureForError ()); + if (!found) + return false; } - sb.Append ('>'); - return sb.ToString (); - } - public void InflateConstraints (Type declaring) - { - if (constraints != null) - gc = new InflatedConstraints (constraints, declaring); - } - - public override bool IsClsComplianceRequired () - { - 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; + } + } + } - protected class InflatedConstraints : GenericConstraints - { - GenericConstraints gc; - Type base_type; - Type class_constraint; - Type[] iface_constraints; - Type[] dargs; + if (found) + continue; - public InflatedConstraints (GenericConstraints gc, Type declaring) - : this (gc, TypeManager.GetTypeArguments (declaring)) - { } + if (other.targs != null) { + foreach (var otarg in other.targs) { + if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) { + found = true; + break; + } + } + } - public InflatedConstraints (GenericConstraints gc, Type[] dargs) - { - this.gc = gc; - this.dargs = dargs; - - ArrayList list = new ArrayList (); - if (gc.HasClassConstraint) - list.Add (inflate (gc.ClassConstraint)); - foreach (Type iface in gc.InterfaceConstraints) - list.Add (inflate (iface)); - - bool has_class_constr = false; - if (list.Count > 0) { - Type first = (Type) list [0]; - has_class_constr = !first.IsGenericParameter && !first.IsInterface; + if (!found) + return false; } + } - if ((list.Count > 0) && has_class_constr) { - class_constraint = (Type) list [0]; - iface_constraints = new Type [list.Count - 1]; - list.CopyTo (1, iface_constraints, 0, list.Count - 1); - } else { - iface_constraints = new Type [list.Count]; - list.CopyTo (iface_constraints, 0); - } + // 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 (HasValueTypeConstraint) - base_type = TypeManager.value_type; - else if (class_constraint != null) - base_type = class_constraint; - else - base_type = TypeManager.object_type; + if (!found) + return false; + } } - Type inflate (Type t) - { - if (t == null) - return null; - if (t.IsGenericParameter) - return t.GenericParameterPosition < dargs.Length ? dargs [t.GenericParameterPosition] : t; - if (t.IsGenericType) { - Type[] args = t.GetGenericArguments (); - Type[] inflated = new Type [args.Length]; + // Check type parameters implementation -> definition + if (targs != null) { + if (other.targs == null) + return false; - for (int i = 0; i < args.Length; i++) - inflated [i] = inflate (args [i]); + foreach (var targ in targs) { + found = false; + foreach (var otarg in other.targs) { + if (TypeSpecComparer.Override.IsEqual (targ, otarg)) { + found = true; + break; + } + } - t = t.GetGenericTypeDefinition (); - t = t.MakeGenericType (inflated); + if (!found) + return false; } - - return t; } - public override string TypeParameter { - get { return gc.TypeParameter; } - } + // 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; - public override GenericParameterAttributes Attributes { - get { return gc.Attributes; } - } + if (targs == null) + return false; - public override Type ClassConstraint { - get { return class_constraint; } - } + found = false; + foreach (var targ in targs) { + if (TypeSpecComparer.Override.IsEqual (targ, otarg)) { + found = true; + break; + } + } - public override Type EffectiveBaseClass { - get { return base_type; } + if (!found) + return false; + } } - public override Type[] InterfaceConstraints { - get { return iface_constraints; } - } + return true; } - } - /// - /// A TypeExpr which already resolved to a type parameter. - /// - public class TypeParameterExpr : TypeExpr { - TypeParameter type_parameter; + public static TypeParameterSpec[] InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec[] tparams) + { + TypeParameterSpec[] constraints = null; - public TypeParameter TypeParameter { - get { - return type_parameter; + 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); + } } - } - - public TypeParameterExpr (TypeParameter type_parameter, Location loc) - { - this.type_parameter = type_parameter; - this.loc = loc; - } - - protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec) - { - throw new NotSupportedException (); + + if (constraints == null) + constraints = tparams; + + return constraints; } - public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent) + public override MemberSpec InflateMember (TypeParameterInflator inflator) { - type = type_parameter.Type; - eclass = ExprClass.TypeParameter; - return this; - } + var tps = (TypeParameterSpec) MemberwiseClone (); + tps.BaseType = inflator.Inflate (BaseType); + if (ifaces != null) { + tps.ifaces = new List (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]); + } - public override bool IsInterface { - get { return false; } + return tps; } - public override bool CheckAccessLevel (DeclSpace ds) + // + // Populates type parameter members using type parameter constraints + // The trick here is to be called late enough but not too late to + // populate member cache with all members from other types + // + protected override void InitializeMemberCache (bool onlyTypes) { - return true; + cache = new MemberCache (); + if (ifaces != null) { + foreach (var iface_type in Interfaces) { + cache.AddInterface (iface_type); + } + } } - } - // - // Tracks the type arguments when instantiating a generic type. It's used - // by both type arguments and type parameters - // - public class TypeArguments { - ArrayList args; - Type[] atypes; - - public TypeArguments () + public bool IsConvertibleToInterface (TypeSpec iface) { - args = new ArrayList (); - } + if (Interfaces != null) { + foreach (var t in Interfaces) { + if (t == iface) + return true; + } + } - public TypeArguments (params FullNamedExpression[] types) - { - this.args = new ArrayList (types); + if (TypeArguments != null) { + foreach (var t in TypeArguments) { + if (((TypeParameterSpec) t).IsConvertibleToInterface (iface)) + return true; + } + } + + return false; } - public void Add (FullNamedExpression type) + public override TypeSpec Mutate (TypeParameterMutator mutator) { - args.Add (type); + return mutator.Mutate (this); } + } + + public struct TypeParameterInflator + { + readonly TypeSpec type; + readonly TypeParameterSpec[] tparams; + readonly TypeSpec[] targs; - public void Add (TypeArguments new_args) + public TypeParameterInflator (TypeParameterInflator nested, TypeSpec type) + : this (type, nested.tparams, nested.targs) { - args.AddRange (new_args.args); } - // TODO: Should be deleted - public TypeParameterName[] GetDeclarations () + public TypeParameterInflator (TypeSpec type, TypeParameterSpec[] tparams, TypeSpec[] targs) { - return (TypeParameterName[]) args.ToArray (typeof (TypeParameterName)); - } + if (tparams.Length != targs.Length) + throw new ArgumentException ("Invalid arguments"); - /// - /// We may only be used after Resolve() is called and return the fully - /// resolved types. - /// - public Type[] Arguments { - get { - return atypes; - } + this.tparams = tparams; + this.targs = targs; + this.type = type; } - public int Count { + // + // Type parameters to inflate + // + public TypeParameterSpec[] TypeParameters { get { - return args.Count; + return tparams; } } - public string GetSignatureForError() + public TypeSpec Inflate (TypeSpec ts) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < Count; ++i) - { - Expression expr = (Expression)args [i]; - sb.Append(expr.GetSignatureForError()); - if (i + 1 < Count) - sb.Append(','); - } - return sb.ToString(); - } + var tp = ts as TypeParameterSpec; + if (tp != null) + return Inflate (tp); - /// - /// Resolve the type arguments. - /// - public bool Resolve (IResolveContext ec) - { - if (atypes != null) - return true; + var ac = ts as ArrayContainer; + if (ac != null) { + var et = Inflate (ac.Element); + if (et != ac.Element) + return ArrayContainer.MakeType (et, ac.Rank); - int count = args.Count; - bool ok = true; + return ac; + } - atypes = new Type [count]; + // + // When inflating a nested type, inflate its parent first + // in case it's using same type parameters (was inflated within the type) + // + if (ts.IsNested) { + var parent = Inflate (ts.DeclaringType); + if (ts.DeclaringType != parent) { + // + // Keep the inflated type arguments + // + var targs = ts.TypeArguments; - for (int i = 0; i < count; i++){ - TypeExpr te = ((FullNamedExpression) args[i]).ResolveAsTypeTerminal (ec, false); - if (te == null) { - ok = false; - continue; - } + // + // Parent was inflated, find the same type on inflated type + // to use same cache for nested types on same generic parent + // + // TODO: Should use BindingRestriction.DeclaredOnly or GetMember + ts = MemberCache.FindNestedType (parent, ts.Name, targs.Length); - atypes[i] = te.Type; + // + // Handle the tricky case where parent shares local type arguments + // which means inflating inflated type + // + // class Test { + // public static Nested Foo () { return null; } + // + // public class Nested {} + // } + // + // return type of Test.Foo() has to be Test.Nested + // + if (targs.Length > 0) { + var inflated_targs = new TypeSpec [targs.Length]; + for (var i = 0; i < targs.Length; ++i) + inflated_targs[i] = Inflate (targs[i]); - if (te.Type.IsSealed && te.Type.IsAbstract) { - Report.Error (718, te.Location, "`{0}': static classes cannot be used as generic arguments", - te.GetSignatureForError ()); - ok = false; - } + ts = ts.MakeGenericType (inflated_targs); + } - if (te.Type.IsPointer || TypeManager.IsSpecialType (te.Type)) { - Report.Error (306, te.Location, - "The type `{0}' may not be used as a type argument", - te.GetSignatureForError ()); - ok = false; + return ts; } } - return ok; - } - public TypeArguments Clone () - { - TypeArguments copy = new TypeArguments (); - foreach (Expression ta in args) - copy.args.Add (ta); + // Inflate generic type + if (ts.Arity > 0) + return InflateTypeParameters (ts); - return copy; + return ts; } - } - - public class TypeParameterName : SimpleName - { - Attributes attributes; - public TypeParameterName (string name, Attributes attrs, Location loc) - : base (name, loc) + public TypeSpec Inflate (TypeParameterSpec tp) { - attributes = attrs; - } + for (int i = 0; i < tparams.Length; ++i) + if (tparams [i] == tp) + return targs[i]; - public Attributes OptAttributes { - get { - return attributes; - } + // This can happen when inflating nested types + // without type arguments specified + return tp; } - } - /// - /// A reference expression to generic type - /// - class GenericTypeExpr : TypeExpr - { - TypeArguments args; - Type[] gen_params; // TODO: Waiting for constrains check cleanup - Type open_type; - - // - // Should be carefully used only with defined generic containers. Type parameters - // can be used as type arguments in this case. // - // TODO: This could be GenericTypeExpr specialization + // Inflates generic types // - public GenericTypeExpr (DeclSpace gType, Location l) + TypeSpec InflateTypeParameters (TypeSpec type) { - open_type = gType.TypeBuilder.GetGenericTypeDefinition (); + var targs = new TypeSpec[type.Arity]; + var i = 0; - args = new TypeArguments (); - foreach (TypeParameter type_param in gType.TypeParameters) - args.Add (new TypeParameterExpr (type_param, l)); + var gti = type as InflatedTypeSpec; - this.loc = l; - } + // + // Inflating using outside type arguments, var v = new Foo (), class Foo {} + // + if (gti != null) { + for (; i < targs.Length; ++i) + targs[i] = Inflate (gti.TypeArguments[i]); - /// - /// Instantiate the generic type `t' with the type arguments `args'. - /// Use this constructor if you already know the fully resolved - /// generic type. - /// - public GenericTypeExpr (Type t, TypeArguments args, Location l) - { - open_type = t.GetGenericTypeDefinition (); + return gti.GetDefinition ().MakeGenericType (targs); + } - loc = l; - this.args = args; - } + // + // Inflating parent using inside type arguments, class Foo { ITest foo; } + // + var args = type.MemberDefinition.TypeParameters; + foreach (var ds_tp in args) + targs[i++] = Inflate (ds_tp); - public TypeArguments TypeArguments { - get { return args; } + return type.MakeGenericType (targs); } - public override string GetSignatureForError () - { - return TypeManager.CSharpName (type); + public TypeSpec TypeInstance { + get { return type; } } + } - protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec) - { - if (eclass != ExprClass.Invalid) - return this; - - if (!args.Resolve (ec)) - return null; + // + // Before emitting any code we have to change all MVAR references to VAR + // when the method is of generic type and has hoisted variables + // + public class TypeParameterMutator + { + TypeParameter[] mvar; + TypeParameter[] var; + Dictionary mutated_typespec = new Dictionary (); - gen_params = open_type.GetGenericArguments (); - Type[] atypes = args.Arguments; - - if (atypes.Length != gen_params.Length) { - Namespace.Error_InvalidNumberOfTypeArguments (open_type, loc); - return null; - } + public TypeParameterMutator (TypeParameter[] mvar, TypeParameter[] var) + { + if (mvar.Length != var.Length) + throw new ArgumentException (); - // - // Now bind the parameters - // - type = open_type.MakeGenericType (atypes); - eclass = ExprClass.Type; - return this; + this.mvar = mvar; + this.var = var; } - /// - /// Check the constraints; we're called from ResolveAsTypeTerminal() - /// after fully resolving the constructed type. - /// - public bool CheckConstraints (IResolveContext ec) + public TypeSpec Mutate (TypeSpec ts) { - return ConstraintChecker.CheckConstraints (ec, open_type, gen_params, args.Arguments, loc); + TypeSpec value; + if (mutated_typespec.TryGetValue (ts, out value)) + return value; + + value = ts.Mutate (this); + mutated_typespec.Add (ts, value); + return value; } - public override bool CheckAccessLevel (DeclSpace ds) + public FieldInfo Mutate (FieldSpec fs) { - return ds.CheckAccessLevel (open_type); + // TODO: + return fs.GetMetaInfo (); } - public override bool AsAccessible (DeclSpace ds) + public TypeParameterSpec Mutate (TypeParameterSpec tp) { - foreach (Type t in args.Arguments) { - if (!ds.IsAccessibleAs (t)) - return false; + for (int i = 0; i < mvar.Length; ++i) { + if (mvar[i].Type == tp) + return var[i].Type; } - return ds.IsAccessibleAs (open_type); + return tp; } - public override bool IsClass { - get { return open_type.IsClass; } - } + public TypeSpec[] Mutate (TypeSpec[] targs) + { + TypeSpec[] mutated = new TypeSpec[targs.Length]; + bool changed = false; + for (int i = 0; i < targs.Length; ++i) { + mutated[i] = Mutate (targs[i]); + changed |= targs[i] != mutated[i]; + } - public override bool IsValueType { - get { return open_type.IsValueType; } + return changed ? mutated : targs; } + } - public override bool IsInterface { - get { return open_type.IsInterface; } + /// + /// A TypeExpr which already resolved to a type parameter. + /// + public class TypeParameterExpr : TypeExpr { + + public TypeParameterExpr (TypeParameter type_parameter, Location loc) + { + this.type = type_parameter.Type; + this.eclass = ExprClass.TypeParameter; + this.loc = loc; } - public override bool IsSealed { - get { return open_type.IsSealed; } + protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec) + { + throw new NotSupportedException (); } - public override bool Equals (object obj) + public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent) { - GenericTypeExpr cobj = obj as GenericTypeExpr; - if (cobj == null) - return false; - - if ((type == null) || (cobj.type == null)) - return false; - - return type == cobj.type; + return this; } - public override int GetHashCode () + public override bool CheckAccessLevel (IMemberContext ds) { - return base.GetHashCode (); + return true; } } - public abstract class ConstraintChecker + public class InflatedTypeSpec : TypeSpec { - protected readonly Type[] gen_params; - protected readonly Type[] atypes; - protected readonly Location loc; + TypeSpec[] targs; + TypeParameterSpec[] constraints; + readonly TypeSpec open_type; - protected ConstraintChecker (Type[] gen_params, Type[] atypes, Location loc) + public InflatedTypeSpec (TypeSpec openType, TypeSpec declaringType, TypeSpec[] targs) + : base (openType.Kind, declaringType, openType.MemberDefinition, null, openType.Modifiers) { - this.gen_params = gen_params; - this.atypes = atypes; - this.loc = loc; + if (targs == null) + throw new ArgumentNullException ("targs"); + +// this.state = openType.state; + this.open_type = openType; + this.targs = targs; } - /// - /// Check the constraints; we're called from ResolveAsTypeTerminal() - /// after fully resolving the constructed type. - /// - public bool CheckConstraints (IResolveContext ec) - { - for (int i = 0; i < gen_params.Length; i++) { - if (!CheckConstraints (ec, i)) - return false; - } + #region Properties - return true; - } + public override TypeSpec BaseType { + get { + if (cache == null || (state & StateFlags.PendingBaseTypeInflate) != 0) + InitializeMemberCache (true); - protected bool CheckConstraints (IResolveContext ec, int index) - { - Type atype = atypes [index]; - Type ptype = gen_params [index]; + return base.BaseType; + } + } - if (atype == ptype) - return true; + // + // Inflated type parameters with constraints array, mapping with type arguments is based on index + // + public TypeParameterSpec[] Constraints { + get { + if (constraints == null) { + var inflator = new TypeParameterInflator (this, MemberDefinition.TypeParameters, targs); + constraints = TypeParameterSpec.InflateConstraints (inflator, MemberDefinition.TypeParameters); + } - Expression aexpr = new EmptyExpression (atype); + return constraints; + } + } - GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype); - if (gc == null) - return true; + public override IList Interfaces { + get { + if (cache == null) + InitializeMemberCache (true); - bool is_class, is_struct; - if (atype.IsGenericParameter) { - GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype); - if (agc != null) { - if (agc is Constraints) - ((Constraints) agc).Resolve (ec); - is_class = agc.IsReferenceType; - is_struct = agc.IsValueType; - } else { - is_class = is_struct = false; - } - } else { -#if MS_COMPATIBLE - is_class = false; - if (!atype.IsGenericType) -#endif - is_class = atype.IsClass || atype.IsInterface; - is_struct = atype.IsValueType && !TypeManager.IsNullableType (atype); + return base.Interfaces; } + } - // - // First, check the `class' and `struct' constraints. - // - if (gc.HasReferenceTypeConstraint && !is_class) { - 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), - TypeManager.CSharpName (ptype), - GetSignatureForError ()); - return false; - } else if (gc.HasValueTypeConstraint && !is_struct) { - 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), - TypeManager.CSharpName (ptype), - GetSignatureForError ()); - return false; + public override MemberCache MemberCacheTypes { + get { + if (cache == null) + InitializeMemberCache (true); + + return cache; } + } - // - // The class constraint comes next. - // - if (gc.HasClassConstraint) { - if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint)) - return false; + // + // Types used to inflate the generic type + // + public override TypeSpec[] TypeArguments { + get { + return targs; } + } + #endregion + + Type CreateMetaInfo (TypeParameterMutator mutator) + { // - // Now, check the interface constraints. + // Converts nested type arguments into right order + // Foo.Bar => string, bool, int // - if (gc.InterfaceConstraints != null) { - foreach (Type it in gc.InterfaceConstraints) { - if (!CheckConstraint (ec, ptype, aexpr, it)) - return false; + var all = new List (); + TypeSpec type = this; + TypeSpec definition = type; + do { + if (type.GetDefinition().IsGeneric) { + all.InsertRange (0, + type.TypeArguments != TypeSpec.EmptyTypes ? + type.TypeArguments.Select (l => l.GetMetaInfo ()) : + type.MemberDefinition.TypeParameters.Select (l => l.GetMetaInfo ())); } - } - // - // Finally, check the constructor constraint. - // + definition = definition.GetDefinition (); + type = type.DeclaringType; + } while (type != null); - if (!gc.HasConstructorConstraint) - return true; + return definition.GetMetaInfo ().MakeGenericType (all.ToArray ()); + } - if (TypeManager.IsBuiltinType (atype) || atype.IsValueType) - return true; + public override ObsoleteAttribute GetAttributeObsolete () + { + return open_type.GetAttributeObsolete (); + } - if (HasDefaultConstructor (atype)) + protected override bool IsNotCLSCompliant () + { + if (base.IsNotCLSCompliant ()) return true; - Report_SymbolRelatedToPreviousError (); - Report.SymbolRelatedToPreviousError (atype); - 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), - TypeManager.CSharpName (ptype), - GetSignatureForError ()); + foreach (var ta in TypeArguments) { + if (ta.MemberDefinition.IsNotCLSCompliant ()) + return true; + } + return false; } - protected bool CheckConstraint (IResolveContext ec, Type ptype, Expression expr, - Type ctype) + public override TypeSpec GetDefinition () { - if (TypeManager.HasGenericArguments (ctype)) { - Type[] types = TypeManager.GetTypeArguments (ctype); - - TypeArguments new_args = new TypeArguments (); + return open_type; + } - for (int i = 0; i < types.Length; i++) { - Type t = types [i]; + public override Type GetMetaInfo () + { + if (info == null) + info = CreateMetaInfo (null); - if (t.IsGenericParameter) { - int pos = t.GenericParameterPosition; - t = atypes [pos]; - } - new_args.Add (new TypeExpression (t, loc)); - } + return info; + } - TypeExpr ct = new GenericTypeExpr (ctype, new_args, loc); - if (ct.ResolveAsTypeStep (ec, false) == null) - return false; - ctype = ct.Type; - } else if (ctype.IsGenericParameter) { - int pos = ctype.GenericParameterPosition; - ctype = atypes [pos]; - } - - if (Convert.ImplicitStandardConversionExists (expr, ctype)) - return true; + public override string GetSignatureForError () + { + if (TypeManager.IsNullableType (open_type)) + return targs[0].GetSignatureForError () + "?"; - Report_SymbolRelatedToPreviousError (); - Report.SymbolRelatedToPreviousError (expr.Type); + if (MemberDefinition is AnonymousTypeClass) + return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError (); - if (TypeManager.IsNullableType (expr.Type) && ctype.IsInterface) { - 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 of type `{3}'", - TypeManager.CSharpName (expr.Type), TypeManager.CSharpName (ptype), - GetSignatureForError (), TypeManager.CSharpName (ctype)); - } else { - 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}'", - TypeManager.CSharpName (expr.Type), TypeManager.CSharpName (ctype), - TypeManager.CSharpName (ptype), GetSignatureForError ()); - } - return false; + return base.GetSignatureForError (); } - static bool HasDefaultConstructor (Type atype) + protected override string GetTypeNameSignature () { - TypeParameter tparam = TypeManager.LookupTypeParameter (atype); - if (tparam != null) { - if (tparam.GenericConstraints == null) - return false; - - return tparam.GenericConstraints.HasConstructorConstraint || - tparam.GenericConstraints.HasValueTypeConstraint; - } - - if (atype.IsAbstract) - return false; + if (targs.Length == 0 || MemberDefinition is AnonymousTypeClass) + return null; - again: - atype = TypeManager.DropGenericTypeArguments (atype); - if (atype is TypeBuilder) { - TypeContainer tc = TypeManager.LookupTypeContainer (atype); - if (tc.InstanceConstructors == null) { - atype = atype.BaseType; - goto again; - } + return "<" + TypeManager.CSharpName (targs) + ">"; + } - foreach (Constructor c in tc.InstanceConstructors) { - if ((c.ModFlags & Modifiers.PUBLIC) == 0) - continue; - if ((c.Parameters.FixedParameters != null) && - (c.Parameters.FixedParameters.Length != 0)) - continue; - if (c.Parameters.HasArglist || c.Parameters.HasParams) - continue; + protected override void InitializeMemberCache (bool onlyTypes) + { + if (cache == null) + cache = new MemberCache (open_type.MemberCache); - return true; + TypeParameterSpec[] tparams_full; + TypeSpec[] targs_full = targs; + if (IsNested) { + // + // Special case is needed when we are inflating an open type (nested type definition) + // on inflated parent. Consider following case + // + // Foo.Bar => Foo.Bar + // + // Any later inflation of Foo.Bar has to also inflate T if used inside Bar + // + List merged_targs = null; + List merged_tparams = null; + + var type = DeclaringType; + + do { + if (type.TypeArguments.Length > 0) { + if (merged_targs == null) { + merged_targs = new List (); + merged_tparams = new List (); + if (targs.Length > 0) { + merged_targs.AddRange (targs); + merged_tparams.AddRange (open_type.MemberDefinition.TypeParameters); + } + } + merged_tparams.AddRange (type.MemberDefinition.TypeParameters); + merged_targs.AddRange (type.TypeArguments); + } + type = type.DeclaringType; + } while (type != null); + + if (merged_targs != null) { + // Type arguments are not in the right order but it should not matter in this case + targs_full = merged_targs.ToArray (); + tparams_full = merged_tparams.ToArray (); + } else if (targs.Length == 0) { + tparams_full = TypeParameterSpec.EmptyTypes; + } else { + tparams_full = open_type.MemberDefinition.TypeParameters; } + } else if (targs.Length == 0) { + tparams_full = TypeParameterSpec.EmptyTypes; + } else { + tparams_full = open_type.MemberDefinition.TypeParameters; } - MemberInfo [] list = TypeManager.MemberLookup (null, null, atype, MemberTypes.Constructor, - BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, - ConstructorInfo.ConstructorName, null); - - if (list == null) - return false; + var inflator = new TypeParameterInflator (this, tparams_full, targs_full); - foreach (MethodBase mb in list) { - AParametersCollection pd = TypeManager.GetParameterData (mb); - if (pd.Count == 0) - return true; - } + // + // Two stage inflate due to possible nested types recursive + // references + // + // class A { + // B b; + // class B { + // T Value; + // } + // } + // + // When resolving type of `b' members of `B' cannot be + // inflated because are not yet available in membercache + // + if ((state & StateFlags.PendingMemberCacheMembers) == 0) { + open_type.MemberCache.InflateTypes (cache, inflator); - return false; - } + // + // Inflate any implemented interfaces + // + if (open_type.Interfaces != null) { + ifaces = new List (open_type.Interfaces.Count); + foreach (var iface in open_type.Interfaces) { + var iface_inflated = inflator.Inflate (iface); + AddInterface (iface_inflated); + } + } - protected abstract string GetSignatureForError (); - protected abstract void Report_SymbolRelatedToPreviousError (); + // + // Handles the tricky case of recursive nested base generic type + // + // class A : Base.Nested> { + // class Nested {} + // } + // + // When inflating A. base type is not yet known, secondary + // inflation is required (not common case) once base scope + // is known + // + if (open_type.BaseType == null) { + if (IsClass) + state |= StateFlags.PendingBaseTypeInflate; + } else { + BaseType = inflator.Inflate (open_type.BaseType); + } + } else if ((state & StateFlags.PendingBaseTypeInflate) != 0) { + BaseType = inflator.Inflate (open_type.BaseType); + state &= ~StateFlags.PendingBaseTypeInflate; + } - public static bool CheckConstraints (EmitContext ec, MethodBase definition, - MethodBase instantiated, Location loc) - { - MethodConstraintChecker checker = new MethodConstraintChecker ( - definition, definition.GetGenericArguments (), - instantiated.GetGenericArguments (), loc); + if (onlyTypes) { + state |= StateFlags.PendingMemberCacheMembers; + return; + } - return checker.CheckConstraints (ec); - } + var tc = open_type.MemberDefinition as TypeContainer; + if (tc != null && !tc.HasMembersDefined) + throw new InternalErrorException ("Inflating MemberCache with undefined members"); - public static bool CheckConstraints (IResolveContext ec, Type gt, Type[] gen_params, - Type[] atypes, Location loc) - { - TypeConstraintChecker checker = new TypeConstraintChecker ( - gt, gen_params, atypes, loc); + if ((state & StateFlags.PendingBaseTypeInflate) != 0) { + BaseType = inflator.Inflate (open_type.BaseType); + state &= ~StateFlags.PendingBaseTypeInflate; + } - return checker.CheckConstraints (ec); + state &= ~StateFlags.PendingMemberCacheMembers; + open_type.MemberCache.InflateMembers (cache, open_type, inflator); } - protected class MethodConstraintChecker : ConstraintChecker + public override TypeSpec Mutate (TypeParameterMutator mutator) { - MethodBase definition; + var targs = TypeArguments; + if (targs != null) + targs = mutator.Mutate (targs); - public MethodConstraintChecker (MethodBase definition, Type[] gen_params, - Type[] atypes, Location loc) - : base (gen_params, atypes, loc) - { - this.definition = definition; - } + var decl = DeclaringType; + if (IsNested && DeclaringType.IsGenericOrParentIsGeneric) + decl = mutator.Mutate (decl); - protected override string GetSignatureForError () - { - return TypeManager.CSharpSignature (definition); - } - - protected override void Report_SymbolRelatedToPreviousError () - { - Report.SymbolRelatedToPreviousError (definition); - } - } + if (targs == TypeArguments && decl == DeclaringType) + return this; - protected class TypeConstraintChecker : ConstraintChecker - { - Type gt; + var mutated = (InflatedTypeSpec) MemberwiseClone (); + if (decl != DeclaringType) { + // Gets back MethodInfo in case of metaInfo was inflated + //mutated.info = MemberCache.GetMember (DeclaringType.GetDefinition (), this).info; - public TypeConstraintChecker (Type gt, Type[] gen_params, Type[] atypes, - Location loc) - : base (gen_params, atypes, loc) - { - this.gt = gt; + mutated.declaringType = decl; + mutated.state |= StateFlags.PendingMetaInflate; } - protected override string GetSignatureForError () - { - return TypeManager.CSharpName (gt); + if (targs != null) { + mutated.targs = targs; + mutated.info = null; } - protected override void Report_SymbolRelatedToPreviousError () - { - Report.SymbolRelatedToPreviousError (gt); - } + return mutated; } } - /// - /// A generic method definition. - /// - public class GenericMethod : DeclSpace + + // + // Tracks the type arguments when instantiating a generic type. It's used + // by both type arguments and type parameters + // + public class TypeArguments { - FullNamedExpression return_type; - Parameters parameters; + List args; + TypeSpec[] atypes; - public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name, - FullNamedExpression return_type, Parameters parameters) - : base (ns, parent, name, null) + public TypeArguments (params FullNamedExpression[] types) { - this.return_type = return_type; - this.parameters = parameters; + this.args = new List (types); } - public override TypeBuilder DefineType () + public void Add (FullNamedExpression type) { - throw new Exception (); + args.Add (type); } - public override bool Define () + // TODO: Kill this monster + public TypeParameterName[] GetDeclarations () { - for (int i = 0; i < TypeParameters.Length; i++) - if (!TypeParameters [i].Resolve (this)) - return false; - - return true; + return args.ConvertAll (i => (TypeParameterName) i).ToArray (); } /// - /// Define and resolve the type parameters. - /// We're called from Method.Define(). + /// We may only be used after Resolve() is called and return the fully + /// resolved types. /// - public bool Define (MethodBuilder mb) - { - TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations (); - string[] snames = new string [names.Length]; - for (int i = 0; i < names.Length; i++) { - string type_argument_name = names[i].Name; - Parameter p = parameters.GetParameterByName (type_argument_name); - if (p != null) { - Error_ParameterNameCollision (p.Location, type_argument_name, "method parameter"); - return false; - } - - snames[i] = type_argument_name; + // TODO: Not needed, just return type from resolve + public TypeSpec[] Arguments { + get { + return atypes; } + } - GenericTypeParameterBuilder[] gen_params = mb.DefineGenericParameters (snames); - for (int i = 0; i < TypeParameters.Length; i++) - TypeParameters [i].Define (gen_params [i]); + public int Count { + get { + return args.Count; + } + } - if (!Define ()) + public virtual bool IsEmpty { + get { return false; - - for (int i = 0; i < TypeParameters.Length; i++) { - if (!TypeParameters [i].ResolveType (this)) - return false; } - - return true; } - internal static void Error_ParameterNameCollision (Location loc, string name, string collisionWith) + public string GetSignatureForError() { - Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'", - name, collisionWith); + StringBuilder sb = new StringBuilder (); + for (int i = 0; i < Count; ++i) { + var expr = args[i]; + if (expr != null) + sb.Append (expr.GetSignatureForError ()); + + if (i + 1 < Count) + sb.Append (','); + } + + return sb.ToString (); } /// - /// We're called from MethodData.Define() after creating the MethodBuilder. + /// Resolve the type arguments. /// - public bool DefineType (EmitContext ec, MethodBuilder mb, - MethodInfo implementing, bool is_override) + public virtual bool Resolve (IMemberContext ec) { - for (int i = 0; i < TypeParameters.Length; i++) - if (!TypeParameters [i].DefineType ( - ec, mb, implementing, is_override)) - return false; + if (atypes != null) + return atypes.Length != 0; + + int count = args.Count; + bool ok = true; + + atypes = new TypeSpec [count]; + + for (int i = 0; i < count; i++){ + TypeExpr te = args[i].ResolveAsTypeTerminal (ec, false); + if (te == null) { + ok = false; + continue; + } - bool ok = parameters.Resolve (ec); + atypes[i] = te.Type; - if ((return_type != null) && (return_type.ResolveAsTypeTerminal (ec, false) == null)) - ok = false; + if (te.Type.IsStatic) { + ec.Compiler.Report.Error (718, te.Location, "`{0}': static classes cannot be used as generic arguments", + te.GetSignatureForError ()); + ok = false; + } + + if (te.Type.IsPointer || TypeManager.IsSpecialType (te.Type)) { + ec.Compiler.Report.Error (306, te.Location, + "The type `{0}' may not be used as a type argument", + te.GetSignatureForError ()); + ok = false; + } + } + + if (!ok) + atypes = TypeSpec.EmptyTypes; return ok; } - public void EmitAttributes () + public TypeArguments Clone () { - for (int i = 0; i < TypeParameters.Length; i++) - TypeParameters [i].Emit (); + TypeArguments copy = new TypeArguments (); + foreach (var ta in args) + copy.args.Add (ta); - if (OptAttributes != null) - OptAttributes.Emit (); + return copy; } + } - public override MemberList FindMembers (MemberTypes mt, BindingFlags bf, - MemberFilter filter, object criteria) + public class UnboundTypeArguments : TypeArguments + { + public UnboundTypeArguments (int arity) + : base (new FullNamedExpression[arity]) { - throw new Exception (); - } + } - public override MemberCache MemberCache { + public override bool IsEmpty { get { - return null; + return true; } } - public override AttributeTargets AttributeTargets { - get { - return AttributeTargets.Method | AttributeTargets.ReturnValue; - } + public override bool Resolve (IMemberContext ec) + { + // should not be called + throw new NotSupportedException (); } + } - public override string DocCommentHeader { - get { return "M:"; } + public class TypeParameterName : SimpleName + { + Attributes attributes; + Variance variance; + + public TypeParameterName (string name, Attributes attrs, Location loc) + : this (name, attrs, Variance.None, loc) + { } - public new void VerifyClsCompliance () + public TypeParameterName (string name, Attributes attrs, Variance variance, Location loc) + : base (name, loc) { - foreach (TypeParameter tp in TypeParameters) { - if (tp.Constraints == null) - continue; + attributes = attrs; + this.variance = variance; + } + + public Attributes OptAttributes { + get { + return attributes; + } + } - tp.Constraints.VerifyClsCompliance (); + public Variance Variance { + get { + return variance; } } } - public partial class TypeManager + // + // A type expression of generic type with type arguments + // + class GenericTypeExpr : TypeExpr { - static public Type activator_type; - - public static TypeContainer LookupGenericTypeContainer (Type t) + TypeArguments args; + TypeSpec open_type; + bool constraints_checked; + + /// + /// Instantiate the generic type `t' with the type arguments `args'. + /// Use this constructor if you already know the fully resolved + /// generic type. + /// + public GenericTypeExpr (TypeSpec open_type, TypeArguments args, Location l) { - t = DropGenericTypeArguments (t); - return LookupTypeContainer (t); + this.open_type = open_type; + loc = l; + this.args = args; } - /// - /// Check whether `a' and `b' may become equal generic types. - /// The algorithm to do that is a little bit complicated. - /// - public static bool MayBecomeEqualGenericTypes (Type a, Type b, Type[] class_inferred, - Type[] method_inferred) + public TypeArguments TypeArguments { + get { return args; } + } + + public override string GetSignatureForError () { - if (a.IsGenericParameter) { - // - // If a is an array of a's type, they may never - // become equal. - // - while (b.IsArray) { - b = b.GetElementType (); - if (a.Equals (b)) - return false; - } + return TypeManager.CSharpName (type); + } - // - // If b is a generic parameter or an actual type, - // they may become equal: - // - // class X : I, I - // class X : I, I - // - if (b.IsGenericParameter || !b.IsGenericType) { - int pos = a.GenericParameterPosition; - Type[] args = a.DeclaringMethod != null ? method_inferred : class_inferred; - if (args [pos] == null) { - args [pos] = b; - return true; - } + protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec) + { + if (!args.Resolve (ec)) + return null; - return args [pos] == a; - } + TypeSpec[] atypes = args.Arguments; - // - // We're now comparing a type parameter with a - // generic instance. They may become equal unless - // the type parameter appears anywhere in the - // generic instance: - // - // class X : I, I> - // -> error because you could instanciate it as - // X,int> - // - // class X : I, I> -> ok - // + // + // Now bind the parameters + // + type = open_type.MakeGenericType (atypes); - Type[] bargs = GetTypeArguments (b); - for (int i = 0; i < bargs.Length; i++) { - if (a.Equals (bargs [i])) - return false; - } + // + // Check constraints when context is not method/base type + // + if (!ec.HasUnresolvedConstraints) + CheckConstraints (ec); + return this; + } + + // + // Checks the constraints of open generic type against type + // arguments. Has to be called onafter all members are defined + // + public bool CheckConstraints (IMemberContext ec) + { + if (constraints_checked) return true; - } - if (b.IsGenericParameter) - return MayBecomeEqualGenericTypes (b, a, class_inferred, method_inferred); + constraints_checked = true; - // - // At this point, neither a nor b are a type parameter. - // - // If one of them is a generic instance, let - // MayBecomeEqualGenericInstances() compare them (if the - // other one is not a generic instance, they can never - // become equal). - // + var gtype = (InflatedTypeSpec) type; + var constraints = gtype.Constraints; + if (constraints == null) + return true; - if (a.IsGenericType || b.IsGenericType) - return MayBecomeEqualGenericInstances (a, b, class_inferred, method_inferred); + return ConstraintChecker.CheckAll (open_type, args.Arguments, constraints, loc, ec.Compiler.Report); + } + + public override bool CheckAccessLevel (IMemberContext mc) + { + DeclSpace c = mc.CurrentMemberDefinition as DeclSpace; + if (c == null) + c = mc.CurrentMemberDefinition.Parent; - // - // If both of them are arrays. - // + return c.CheckAccessLevel (open_type); + } - if (a.IsArray && b.IsArray) { - if (a.GetArrayRank () != b.GetArrayRank ()) - return false; - - a = a.GetElementType (); - b = b.GetElementType (); + public bool HasDynamicArguments () + { + return HasDynamicArguments (args.Arguments); + } - return MayBecomeEqualGenericTypes (a, b, class_inferred, method_inferred); - } + static bool HasDynamicArguments (TypeSpec[] args) + { + foreach (var item in args) { + if (item == InternalType.Dynamic) + return true; - // - // Ok, two ordinary types. - // + if (TypeManager.IsGenericType (item)) + return HasDynamicArguments (TypeManager.GetTypeArguments (item)); + } - return a.Equals (b); + return false; } - // - // Checks whether two generic instances may become equal for some - // particular instantiation (26.3.1). - // - public static bool MayBecomeEqualGenericInstances (Type a, Type b, - Type[] class_inferred, - Type[] method_inferred) + public override bool Equals (object obj) { - if (!a.IsGenericType || !b.IsGenericType) + GenericTypeExpr cobj = obj as GenericTypeExpr; + if (cobj == null) return false; - if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ()) + + if ((type == null) || (cobj.type == null)) return false; - return MayBecomeEqualGenericInstances ( - GetTypeArguments (a), GetTypeArguments (b), class_inferred, method_inferred); + return type == cobj.type; } - public static bool MayBecomeEqualGenericInstances (Type[] aargs, Type[] bargs, - Type[] class_inferred, - Type[] method_inferred) + public override int GetHashCode () { - if (aargs.Length != bargs.Length) - return false; + return base.GetHashCode (); + } + } - for (int i = 0; i < aargs.Length; i++) { - if (!MayBecomeEqualGenericTypes (aargs [i], bargs [i], class_inferred, method_inferred)) + static class ConstraintChecker + { + /// + /// Check the constraints; we're called from ResolveAsTypeTerminal() + /// after fully resolving the constructed type. + /// + public static bool CheckAll (MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc, Report report) + { + for (int i = 0; i < tparams.Length; i++) { + if (!CheckConstraint (context, targs [i], tparams [i], loc, report)) return false; } return true; } - /// - /// Type inference. Try to infer the type arguments from `method', - /// which is invoked with the arguments `arguments'. This is used - /// when resolving an Invocation or a DelegateInvocation and the user - /// did not explicitly specify type arguments. - /// - public static int InferTypeArguments (EmitContext ec, - ArrayList arguments, - ref MethodBase method) + static bool CheckConstraint (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc, Report report) { - ATypeInference ti = ATypeInference.CreateInstance (arguments); - Type[] i_args = ti.InferMethodArguments (ec, method); - if (i_args == null) - return ti.InferenceScore; + // + // First, check the `class' and `struct' constraints. + // + if (tparam.HasSpecialClass && !TypeManager.IsReferenceType (atype)) { + 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 (i_args.Length == 0) - return 0; + if (tparam.HasSpecialStruct && (!TypeManager.IsValueType (atype) || TypeManager.IsNullableType (atype))) { + 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 (context, atype, tparam, tparam.BaseType, loc, report); + } + + // + // Now, check the interfaces and type parameters constraints + // + if (tparam.Interfaces != null) { + if (TypeManager.IsNullableType (atype)) { + 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 (context, atype, tparam, iface, loc, report); + } + } + } + + // + // Finally, check the constructor constraint. + // + if (!tparam.HasSpecialConstructor) + return true; + + if (!HasDefaultConstructor (atype)) { + report.SymbolRelatedToPreviousError (atype); + 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; + } + + static void CheckConversion (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc, Report report) + { + var expr = new EmptyExpression (atype); + if (!Convert.ImplicitStandardConversionExists (expr, ttype)) { + report.SymbolRelatedToPreviousError (tparam); + if (TypeManager.IsValueType (atype)) { + 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) { + 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 { + 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 HasDefaultConstructor (TypeSpec atype) + { + var tp = atype as TypeParameterSpec; + if (tp != null) { + return tp.HasSpecialConstructor || tp.HasSpecialStruct; + } + + if (atype.IsStruct || atype.IsEnum) + return true; + + if (atype.IsAbstract) + return false; - method = ((MethodInfo) method).MakeGenericMethod (i_args); - return 0; - } + var tdef = atype.GetDefinition (); - /// - /// Type inference. - /// - public static bool InferTypeArguments (AParametersCollection apd, - ref MethodBase method) - { - if (!TypeManager.IsGenericMethod (method)) - return true; + // + // In some circumstances MemberCache is not yet populated and members + // cannot be defined yet (recursive type new constraints) + // + // class A where T : B, new () {} + // class B where T : A, new () {} + // + var tc = tdef.MemberDefinition as Class; + if (tc != null) { + if (tc.InstanceConstructors == null) { + // Default ctor will be generated later + return true; + } + + foreach (var c in tc.InstanceConstructors) { + if (c.ParameterInfo.IsEmpty) { + if ((c.ModFlags & Modifiers.PUBLIC) != 0) + return true; + } + } - ATypeInference ti = ATypeInference.CreateInstance (ArrayList.Adapter (apd.Types)); - Type[] i_args = ti.InferDelegateArguments (method); - if (i_args == null) return false; + } - method = ((MethodInfo) method).MakeGenericMethod (i_args); - return true; + var found = MemberCache.FindMember (tdef, + MemberFilter.Constructor (ParametersCompiled.EmptyReadOnlyParameters), + BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly); + + return found != null && (found.Modifiers & Modifiers.PUBLIC) != 0; } } - abstract class ATypeInference + /// + /// A generic method definition. + /// + public class GenericMethod : DeclSpace { - protected readonly ArrayList arguments; - protected readonly int arg_count; + ParametersCompiled parameters; - protected ATypeInference (ArrayList arguments) + public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name, + FullNamedExpression return_type, ParametersCompiled parameters) + : base (ns, parent, name, null) { - this.arguments = arguments; - if (arguments != null) - arg_count = arguments.Count; + this.parameters = parameters; } - public static ATypeInference CreateInstance (ArrayList arguments) + public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name, TypeParameter[] tparams, + FullNamedExpression return_type, ParametersCompiled parameters) + : this (ns, parent, name, return_type, parameters) { - if (RootContext.Version == LanguageVersion.ISO_2) - return new TypeInferenceV2 (arguments); - - return new TypeInferenceV3 (arguments); + this.type_params = tparams; } - public virtual int InferenceScore { + public override TypeParameter[] CurrentTypeParameters { get { - return int.MaxValue; + return base.type_params; } } - public abstract Type[] InferMethodArguments (EmitContext ec, MethodBase method); - public abstract Type[] InferDelegateArguments (MethodBase method); - } - - // - // Implements C# 2.0 type inference - // - class TypeInferenceV2 : ATypeInference - { - public TypeInferenceV2 (ArrayList arguments) - : base (arguments) + public override TypeBuilder DefineType () { + throw new Exception (); } - public override Type[] InferDelegateArguments (MethodBase method) + public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) { - AParametersCollection pd = TypeManager.GetParameterData (method); - if (arg_count != pd.Count) - return null; - - Type[] method_args = method.GetGenericArguments (); - Type[] inferred_types = new Type[method_args.Length]; - - Type[] param_types = new Type[pd.Count]; - Type[] arg_types = (Type[])arguments.ToArray (typeof (Type)); - - for (int i = 0; i < arg_count; i++) { - param_types[i] = pd.Types [i]; - } - - if (!InferTypeArguments (param_types, arg_types, inferred_types)) - return null; - - return inferred_types; + throw new NotSupportedException (); } - public override Type[] InferMethodArguments (EmitContext ec, MethodBase method) + public override bool Define () { - AParametersCollection pd = TypeManager.GetParameterData (method); - Type[] method_generic_args = method.GetGenericArguments (); - Type [] inferred_types = new Type [method_generic_args.Length]; - Type[] arg_types = new Type [pd.Count]; - - int a_count = arg_types.Length; - if (pd.HasParams) - --a_count; + throw new NotSupportedException (); + } - for (int i = 0; i < a_count; i++) { - Argument a = (Argument) arguments[i]; - if (a.Expr is NullLiteral || a.Expr is MethodGroupExpr || a.Expr is AnonymousMethodExpression) - continue; + /// + /// Define and resolve the type parameters. + /// We're called from Method.Define(). + /// + public bool Define (MethodOrOperator m) + { + TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations (); + string[] snames = new string [names.Length]; + for (int i = 0; i < names.Length; i++) { + string type_argument_name = names[i].Name; + int idx = parameters.GetParameterIndexByName (type_argument_name); - if (!TypeInferenceV2.UnifyType (pd.Types [i], a.Type, inferred_types)) - return null; - } + if (idx >= 0) { + var b = m.Block; + if (b == null) + b = new ToplevelBlock (Compiler, Location); - if (pd.HasParams) { - Type element_type = TypeManager.GetElementType (pd.Types [a_count]); - for (int i = a_count; i < arg_count; i++) { - Argument a = (Argument) arguments [i]; - if (a.Expr is NullLiteral || a.Expr is MethodGroupExpr || a.Expr is AnonymousMethodExpression) - continue; + b.Error_AlreadyDeclaredTypeParameter (parameters [i].Location, + type_argument_name, "method parameter"); + } - if (!TypeInferenceV2.UnifyType (element_type, a.Type, inferred_types)) - return null; + if (m.Block != null) { + var ikv = m.Block.GetKnownVariable (type_argument_name); + if (ikv != null) + ikv.Block.Error_AlreadyDeclaredTypeParameter (ikv.Location, type_argument_name, "local variable"); } + + snames[i] = type_argument_name; } - for (int i = 0; i < inferred_types.Length; i++) - if (inferred_types [i] == null) - return null; + GenericTypeParameterBuilder[] gen_params = m.MethodBuilder.DefineGenericParameters (snames); + for (int i = 0; i < TypeParameters.Length; i++) + TypeParameters [i].Define (gen_params [i], null); - return inferred_types; + return true; } - static bool InferTypeArguments (Type[] param_types, Type[] arg_types, - Type[] inferred_types) + public void EmitAttributes () { - for (int i = 0; i < arg_types.Length; i++) { - if (arg_types[i] == null) - continue; - - if (!UnifyType (param_types[i], arg_types[i], inferred_types)) - return false; - } - - for (int i = 0; i < inferred_types.Length; ++i) - if (inferred_types[i] == null) - return false; - - return true; + if (OptAttributes != null) + OptAttributes.Emit (); } - public static bool UnifyType (Type pt, Type at, Type[] inferred) + public override string GetSignatureForError () { - if (pt.IsGenericParameter) { - if (pt.DeclaringMethod == null) - return pt == at; - - int pos = pt.GenericParameterPosition; - - if (inferred [pos] == null) - inferred [pos] = at; + return base.GetSignatureForError () + parameters.GetSignatureForError (); + } - return inferred [pos] == at; + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Method | AttributeTargets.ReturnValue; } + } - if (!pt.ContainsGenericParameters) { - if (at.ContainsGenericParameters) - return UnifyType (at, pt, inferred); - else - return true; - } + public override string DocCommentHeader { + get { return "M:"; } + } - if (at.IsArray) { - if (pt.IsArray) { - if (at.GetArrayRank () != pt.GetArrayRank ()) - return false; + public new void VerifyClsCompliance () + { + foreach (TypeParameter tp in TypeParameters) { + tp.VerifyClsCompliance (); + } + } + } - return UnifyType (pt.GetElementType (), at.GetElementType (), inferred); + public partial class TypeManager + { + public static Variance CheckTypeVariance (TypeSpec t, Variance expected, IMemberContext member) + { + var tp = t as TypeParameterSpec; + if (tp != null) { + Variance v = tp.Variance; + if (expected == Variance.None && v != expected || + expected == Variance.Covariant && v == Variance.Contravariant || + expected == Variance.Contravariant && v == Variance.Covariant) { + ((TypeParameter)tp.MemberDefinition).ErrorInvalidVariance (member, expected); } - if (!pt.IsGenericType) - return false; - - Type gt = pt.GetGenericTypeDefinition (); - if ((gt != TypeManager.generic_ilist_type) && (gt != TypeManager.generic_icollection_type) && - (gt != TypeManager.generic_ienumerable_type)) - return false; - - Type[] args = TypeManager.GetTypeArguments (pt); - return UnifyType (args[0], at.GetElementType (), inferred); + return expected; } - if (pt.IsArray) { - if (!at.IsArray || - (pt.GetArrayRank () != at.GetArrayRank ())) - return false; + if (t.TypeArguments.Length > 0) { + var targs_definition = t.MemberDefinition.TypeParameters; + TypeSpec[] targs = GetTypeArguments (t); + for (int i = 0; i < targs.Length; ++i) { + Variance v = targs_definition[i].Variance; + CheckTypeVariance (targs[i], (Variance) ((int)v * (int)expected), member); + } - return UnifyType (pt.GetElementType (), at.GetElementType (), inferred); + return expected; } - if (pt.IsByRef && at.IsByRef) - return UnifyType (pt.GetElementType (), at.GetElementType (), inferred); - ArrayList list = new ArrayList (); - if (at.IsGenericType) - list.Add (at); - for (Type bt = at.BaseType; bt != null; bt = bt.BaseType) - list.Add (bt); + if (t.IsArray) + return CheckTypeVariance (GetElementType (t), expected, member); - list.AddRange (TypeManager.GetInterfaces (at)); + return Variance.None; + } - foreach (Type type in list) { - if (!type.IsGenericType) - continue; + /// + /// Type inference. Try to infer the type arguments from `method', + /// which is invoked with the arguments `arguments'. This is used + /// when resolving an Invocation or a DelegateInvocation and the user + /// did not explicitly specify type arguments. + /// + public static int InferTypeArguments (ResolveContext ec, Arguments arguments, ref MethodSpec method) + { + ATypeInference ti = ATypeInference.CreateInstance (arguments); + TypeSpec[] i_args = ti.InferMethodArguments (ec, method); + if (i_args == null) + return ti.InferenceScore; - if (TypeManager.DropGenericTypeArguments (pt) != TypeManager.DropGenericTypeArguments (type)) - continue; + if (i_args.Length == 0) + return 0; - if (!UnifyTypes (pt.GetGenericArguments (), type.GetGenericArguments (), inferred)) - return false; - } + method = method.MakeGenericMethod (i_args); + return 0; + } + } - return true; + abstract class ATypeInference + { + protected readonly Arguments arguments; + protected readonly int arg_count; + + protected ATypeInference (Arguments arguments) + { + this.arguments = arguments; + if (arguments != null) + arg_count = arguments.Count; } - static bool UnifyTypes (Type[] pts, Type[] ats, Type[] inferred) + public static ATypeInference CreateInstance (Arguments arguments) { - for (int i = 0; i < ats.Length; i++) { - if (!UnifyType (pts [i], ats [i], inferred)) - return false; + return new TypeInference (arguments); + } + + public virtual int InferenceScore { + get { + return int.MaxValue; } - return true; } + + public abstract TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method); } // - // Implements C# 3.0 type inference + // Implements C# type inference // - class TypeInferenceV3 : ATypeInference + class TypeInference : ATypeInference { // // Tracks successful rate of type inference // int score = int.MaxValue; - public TypeInferenceV3 (ArrayList arguments) + public TypeInference (Arguments arguments) : base (arguments) { } @@ -2148,39 +2156,14 @@ namespace Mono.CSharp { } } - public override Type[] InferDelegateArguments (MethodBase method) - { - AParametersCollection pd = TypeManager.GetParameterData (method); - if (arg_count != pd.Count) - return null; - - Type[] d_gargs = method.GetGenericArguments (); - TypeInferenceContext context = new TypeInferenceContext (d_gargs); - - // A lower-bound inference is made from each argument type Uj of D - // to the corresponding parameter type Tj of M - for (int i = 0; i < arg_count; ++i) { - Type t = pd.Types [i]; - if (!t.IsGenericParameter) - continue; - - context.LowerBoundInference ((Type)arguments[i], t); - } - - if (!context.FixAllTypes ()) - return null; - - return context.InferredTypeArguments; - } - - public override Type[] InferMethodArguments (EmitContext ec, MethodBase method) + public override TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method) { - Type[] method_generic_args = method.GetGenericArguments (); + var method_generic_args = method.GenericDefinition.TypeParameters; TypeInferenceContext context = new TypeInferenceContext (method_generic_args); if (!context.UnfixedVariableExists) - return Type.EmptyTypes; + return TypeSpec.EmptyTypes; - AParametersCollection pd = TypeManager.GetParameterData (method); + AParametersCollection pd = method.Parameters; if (!InferInPhases (ec, context, pd)) return null; @@ -2190,7 +2173,7 @@ namespace Mono.CSharp { // // Implements method type arguments inference // - bool InferInPhases (EmitContext ec, TypeInferenceContext tic, AParametersCollection methodParameters) + bool InferInPhases (ResolveContext ec, TypeInferenceContext tic, AParametersCollection methodParameters) { int params_arguments_start; if (methodParameters.HasParams) { @@ -2199,14 +2182,16 @@ namespace Mono.CSharp { params_arguments_start = arg_count; } - Type [] ptypes = methodParameters.Types; + TypeSpec [] ptypes = methodParameters.Types; // // The first inference phase // - Type method_parameter = null; + TypeSpec method_parameter = null; for (int i = 0; i < arg_count; i++) { - Argument a = (Argument) arguments [i]; + Argument a = arguments [i]; + if (a == null) + continue; if (i < params_arguments_start) { method_parameter = methodParameters.Types [i]; @@ -2216,7 +2201,7 @@ namespace Mono.CSharp { else method_parameter = TypeManager.GetElementType (methodParameters.Types [params_arguments_start]); - ptypes = (Type[]) ptypes.Clone (); + ptypes = (TypeSpec[]) ptypes.Clone (); ptypes [i] = method_parameter; } @@ -2226,13 +2211,23 @@ namespace Mono.CSharp { // AnonymousMethodExpression am = a.Expr as AnonymousMethodExpression; if (am != null) { - if (am.ExplicitTypeInference (tic, method_parameter)) + if (am.ExplicitTypeInference (ec, tic, method_parameter)) --score; continue; } - if (a.Expr is NullLiteral) + if (a.IsByRef) { + score -= tic.ExactInference (a.Type, method_parameter); + continue; + } + + if (a.Expr.Type == InternalType.Null) + continue; + + if (TypeManager.IsValueType (method_parameter)) { + score -= tic.LowerBoundInference (a.Type, method_parameter); continue; + } // // Otherwise an output type inference is made @@ -2245,16 +2240,16 @@ namespace Mono.CSharp { // we don't need to call it in cycle // bool fixed_any = false; - if (!tic.FixIndependentTypeArguments (ptypes, ref fixed_any)) + if (!tic.FixIndependentTypeArguments (ec, ptypes, ref fixed_any)) return false; return DoSecondPhase (ec, tic, ptypes, !fixed_any); } - bool DoSecondPhase (EmitContext ec, TypeInferenceContext tic, Type[] methodParameters, bool fixDependent) + bool DoSecondPhase (ResolveContext ec, TypeInferenceContext tic, TypeSpec[] methodParameters, bool fixDependent) { bool fixed_any = false; - if (fixDependent && !tic.FixDependentTypes (ref fixed_any)) + if (fixDependent && !tic.FixDependentTypes (ec, ref fixed_any)) return false; // If no further unfixed type variables exist, type inference succeeds @@ -2270,26 +2265,20 @@ namespace Mono.CSharp { for (int i = 0; i < arg_count; i++) { // Align params arguments - Type t_i = methodParameters [i >= methodParameters.Length ? methodParameters.Length - 1: i]; + TypeSpec t_i = methodParameters [i >= methodParameters.Length ? methodParameters.Length - 1: i]; if (!TypeManager.IsDelegateType (t_i)) { - if (TypeManager.DropGenericTypeArguments (t_i) != TypeManager.expression_type) + if (t_i.GetDefinition () != TypeManager.expression_type) continue; - t_i = t_i.GetGenericArguments () [0]; + t_i = TypeManager.GetTypeArguments (t_i) [0]; } - MethodInfo mi = Delegate.GetInvokeMethod (t_i, t_i); - Type rtype = mi.ReturnType; + var mi = Delegate.GetInvokeMethod (ec.Compiler, t_i); + TypeSpec rtype = mi.ReturnType; -#if MS_COMPATIBLE - // Blablabla, because reflection does not work with dynamic types - Type[] g_args = t_i.GetGenericArguments (); - rtype = g_args[rtype.GenericParameterPosition]; -#endif - - if (tic.IsReturnTypeNonDependent (mi, rtype)) - score -= tic.OutputTypeInference (ec, ((Argument) arguments [i]).Expr, t_i); + if (tic.IsReturnTypeNonDependent (ec, mi, rtype)) + score -= tic.OutputTypeInference (ec, arguments [i].Expr, t_i); } @@ -2299,22 +2288,53 @@ namespace Mono.CSharp { public class TypeInferenceContext { - readonly Type[] unfixed_types; - readonly Type[] fixed_types; - readonly ArrayList[] bounds; + enum BoundKind + { + Exact = 0, + Lower = 1, + Upper = 2 + } + + class BoundInfo + { + public readonly TypeSpec Type; + public readonly BoundKind Kind; + + public BoundInfo (TypeSpec type, BoundKind kind) + { + this.Type = type; + this.Kind = kind; + } + + public override int GetHashCode () + { + return Type.GetHashCode (); + } + + public override bool Equals (object obj) + { + BoundInfo a = (BoundInfo) obj; + return Type == a.Type && Kind == a.Kind; + } + } + + readonly TypeSpec[] unfixed_types; + readonly TypeSpec[] fixed_types; + readonly List[] bounds; bool failed; - - public TypeInferenceContext (Type[] typeArguments) + + // TODO MemberCache: Could it be TypeParameterSpec[] ?? + public TypeInferenceContext (TypeSpec[] typeArguments) { if (typeArguments.Length == 0) throw new ArgumentException ("Empty generic arguments"); - fixed_types = new Type [typeArguments.Length]; + fixed_types = new TypeSpec [typeArguments.Length]; for (int i = 0; i < typeArguments.Length; ++i) { if (typeArguments [i].IsGenericParameter) { if (bounds == null) { - bounds = new ArrayList [typeArguments.Length]; - unfixed_types = new Type [typeArguments.Length]; + bounds = new List [typeArguments.Length]; + unfixed_types = new TypeSpec [typeArguments.Length]; } unfixed_types [i] = typeArguments [i]; } else { @@ -2323,26 +2343,43 @@ namespace Mono.CSharp { } } - public Type[] InferredTypeArguments { + // + // Used together with AddCommonTypeBound fo implement + // 7.4.2.13 Finding the best common type of a set of expressions + // + public TypeInferenceContext () + { + fixed_types = new TypeSpec [1]; + unfixed_types = new TypeSpec [1]; + unfixed_types[0] = InternalType.Arglist; // it can be any internal type + bounds = new List [1]; + } + + public TypeSpec[] InferredTypeArguments { get { return fixed_types; } } - void AddToBounds (Type t, int index) + public void AddCommonTypeBound (TypeSpec type) + { + AddToBounds (new BoundInfo (type, BoundKind.Lower), 0); + } + + void AddToBounds (BoundInfo bound, int index) { // // Some types cannot be used as type arguments // - if (t == TypeManager.void_type || t.IsPointer) + if (bound.Type == TypeManager.void_type || bound.Type.IsPointer) return; - ArrayList a = bounds [index]; + var a = bounds [index]; if (a == null) { - a = new ArrayList (); + a = new List (); bounds [index] = a; } else { - if (a.Contains (t)) + if (a.Contains (bound)) return; } @@ -2356,20 +2393,20 @@ namespace Mono.CSharp { // // t = constraints.EffectiveBaseClass; // } //} - a.Add (t); + a.Add (bound); } - bool AllTypesAreFixed (Type[] types) + bool AllTypesAreFixed (TypeSpec[] types) { - foreach (Type t in types) { + foreach (TypeSpec t in types) { if (t.IsGenericParameter) { if (!IsFixed (t)) return false; continue; } - if (t.IsGenericType) - return AllTypesAreFixed (t.GetGenericArguments ()); + if (TypeManager.IsGenericType (t)) + return AllTypesAreFixed (TypeManager.GetTypeArguments (t)); } return true; @@ -2378,26 +2415,27 @@ namespace Mono.CSharp { // // 26.3.3.8 Exact Inference // - public int ExactInference (Type u, Type v) + public int ExactInference (TypeSpec u, TypeSpec v) { // If V is an array type if (v.IsArray) { if (!u.IsArray) return 0; - if (u.GetArrayRank () != v.GetArrayRank ()) + // TODO MemberCache: GetMetaInfo () + if (u.GetMetaInfo ().GetArrayRank () != v.GetMetaInfo ().GetArrayRank ()) return 0; return ExactInference (TypeManager.GetElementType (u), TypeManager.GetElementType (v)); } // If V is constructed type and U is constructed type - if (v.IsGenericType && !v.IsGenericTypeDefinition) { - if (!u.IsGenericType) + if (TypeManager.IsGenericType (v)) { + if (!TypeManager.IsGenericType (u)) return 0; - Type [] ga_u = u.GetGenericArguments (); - Type [] ga_v = v.GetGenericArguments (); + TypeSpec [] ga_u = TypeManager.GetTypeArguments (u); + TypeSpec [] ga_v = TypeManager.GetTypeArguments (v); if (ga_u.Length != ga_v.Length) return 0; @@ -2413,14 +2451,14 @@ namespace Mono.CSharp { if (pos == -1) return 0; - AddToBounds (u, pos); + AddToBounds (new BoundInfo (u, BoundKind.Exact), pos); return 1; } - public bool FixAllTypes () + public bool FixAllTypes (ResolveContext ec) { for (int i = 0; i < unfixed_types.Length; ++i) { - if (!FixType (i)) + if (!FixType (ec, i)) return false; } return true; @@ -2431,7 +2469,7 @@ namespace Mono.CSharp { // a, There is at least one type variable Xj that depends on Xi // b, Xi has a non-empty set of bounds // - public bool FixDependentTypes (ref bool fixed_any) + public bool FixDependentTypes (ResolveContext ec, ref bool fixed_any) { for (int i = 0; i < unfixed_types.Length; ++i) { if (unfixed_types[i] == null) @@ -2440,7 +2478,7 @@ namespace Mono.CSharp { if (bounds[i] == null) continue; - if (!FixType (i)) + if (!FixType (ec, i)) return false; fixed_any = true; @@ -2452,43 +2490,37 @@ namespace Mono.CSharp { // // All unfixed type variables Xi which depend on no Xj are fixed // - public bool FixIndependentTypeArguments (Type[] methodParameters, ref bool fixed_any) + public bool FixIndependentTypeArguments (ResolveContext ec, TypeSpec[] methodParameters, ref bool fixed_any) { - ArrayList types_to_fix = new ArrayList (unfixed_types); + var types_to_fix = new List (unfixed_types); for (int i = 0; i < methodParameters.Length; ++i) { - Type t = methodParameters[i]; - if (t.IsGenericParameter) - continue; + TypeSpec t = methodParameters[i]; if (!TypeManager.IsDelegateType (t)) { - if (TypeManager.DropGenericTypeArguments (t) != TypeManager.expression_type) + if (TypeManager.expression_type == null || t.MemberDefinition != TypeManager.expression_type.MemberDefinition) continue; - t = t.GetGenericArguments () [0]; + t = TypeManager.GetTypeArguments (t) [0]; } - MethodInfo invoke = Delegate.GetInvokeMethod (t, t); - Type rtype = invoke.ReturnType; - if (!rtype.IsGenericParameter && !rtype.IsGenericType) + if (t.IsGenericParameter) + continue; + + var invoke = Delegate.GetInvokeMethod (ec.Compiler, t); + TypeSpec rtype = invoke.ReturnType; + if (!rtype.IsGenericParameter && !TypeManager.IsGenericType (rtype)) continue; -#if MS_COMPATIBLE - // Blablabla, because reflection does not work with dynamic types - if (rtype.IsGenericParameter) { - Type [] g_args = t.GetGenericArguments (); - rtype = g_args [rtype.GenericParameterPosition]; - } -#endif // Remove dependent types, they cannot be fixed yet RemoveDependentTypes (types_to_fix, rtype); } - foreach (Type t in types_to_fix) { + foreach (TypeSpec t in types_to_fix) { if (t == null) continue; int idx = IsUnfixed (t); - if (idx >= 0 && !FixType (idx)) { + if (idx >= 0 && !FixType (ec, idx)) { return false; } } @@ -2500,7 +2532,7 @@ namespace Mono.CSharp { // // 26.3.3.10 Fixing // - public bool FixType (int i) + public bool FixType (ResolveContext ec, int i) { // It's already fixed if (unfixed_types[i] == null) @@ -2509,13 +2541,17 @@ namespace Mono.CSharp { if (failed) return false; - ArrayList candidates = (ArrayList)bounds [i]; + var candidates = bounds [i]; if (candidates == null) return false; if (candidates.Count == 1) { unfixed_types[i] = null; - fixed_types[i] = (Type)candidates[0]; + TypeSpec t = candidates[0].Type; + if (t == InternalType.Null) + return false; + + fixed_types [i] = t; return true; } @@ -2524,28 +2560,64 @@ namespace Mono.CSharp { // a standard implicit conversion to all the other // candidate types. // - Type best_candidate = null; + TypeSpec best_candidate = null; int cii; int candidates_count = candidates.Count; for (int ci = 0; ci < candidates_count; ++ci) { - Type candidate = (Type)candidates [ci]; + BoundInfo bound = candidates [ci]; for (cii = 0; cii < candidates_count; ++cii) { if (cii == ci) continue; - if (!Convert.ImplicitConversionExists (null, - new TypeExpression ((Type)candidates [cii], Location.Null), candidate)) { + BoundInfo cbound = candidates[cii]; + + // Same type parameters with different bounds + if (cbound.Type == bound.Type) { + if (bound.Kind != BoundKind.Exact) + bound = cbound; + + continue; + } + + if (bound.Kind == BoundKind.Exact || cbound.Kind == BoundKind.Exact) { + if (cbound.Kind != BoundKind.Exact) { + if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) { + break; + } + + continue; + } + + if (bound.Kind != BoundKind.Exact) { + if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) { + break; + } + + bound = cbound; + continue; + } + break; } + + if (bound.Kind == BoundKind.Lower) { + if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) { + break; + } + } else { + if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) { + break; + } + } } if (cii != candidates_count) continue; - if (best_candidate != null) + if (best_candidate != null && best_candidate != bound.Type) return false; - best_candidate = candidate; + best_candidate = bound.Type; } if (best_candidate == null) @@ -2557,26 +2629,34 @@ namespace Mono.CSharp { } // - // Uses inferred types to inflate delegate type argument + // Uses inferred or partially infered types to inflate delegate type argument. Returns + // null when type parameter was not yet inferres // - public Type InflateGenericArgument (Type parameter) + public TypeSpec InflateGenericArgument (TypeSpec parameter) { - if (parameter.IsGenericParameter) { + var tp = parameter as TypeParameterSpec; + if (tp != null) { // - // Inflate method generic argument (MVAR) only + // Type inference work on generic arguments (MVAR) only // - if (parameter.DeclaringMethod == null) + if (!tp.IsMethodOwned) return parameter; - return fixed_types [parameter.GenericParameterPosition]; + return fixed_types [tp.DeclaredPosition] ?? parameter; } - if (parameter.IsGenericType) { - Type [] parameter_targs = parameter.GetGenericArguments (); - for (int ii = 0; ii < parameter_targs.Length; ++ii) { - parameter_targs [ii] = InflateGenericArgument (parameter_targs [ii]); + var gt = parameter as InflatedTypeSpec; + if (gt != null) { + var inflated_targs = new TypeSpec [gt.TypeArguments.Length]; + for (int ii = 0; ii < inflated_targs.Length; ++ii) { + var inflated = InflateGenericArgument (gt.TypeArguments [ii]); + if (inflated == null) + return null; + + inflated_targs[ii] = inflated; } - return parameter.GetGenericTypeDefinition ().MakeGenericType (parameter_targs); + + return gt.GetDefinition ().MakeGenericType (inflated_targs); } return parameter; @@ -2586,18 +2666,18 @@ namespace Mono.CSharp { // Tests whether all delegate input arguments are fixed and generic output type // requires output type inference // - public bool IsReturnTypeNonDependent (MethodInfo invoke, Type returnType) + public bool IsReturnTypeNonDependent (ResolveContext ec, MethodSpec invoke, TypeSpec returnType) { if (returnType.IsGenericParameter) { if (IsFixed (returnType)) return false; - } else if (returnType.IsGenericType) { + } else if (TypeManager.IsGenericType (returnType)) { if (TypeManager.IsDelegateType (returnType)) { - invoke = Delegate.GetInvokeMethod (returnType, returnType); - return IsReturnTypeNonDependent (invoke, invoke.ReturnType); + invoke = Delegate.GetInvokeMethod (ec.Compiler, returnType); + return IsReturnTypeNonDependent (ec, invoke, invoke.ReturnType); } - Type[] g_args = returnType.GetGenericArguments (); + TypeSpec[] g_args = TypeManager.GetTypeArguments (returnType); // At least one unfixed return type has to exist if (AllTypesAreFixed (g_args)) @@ -2607,16 +2687,16 @@ namespace Mono.CSharp { } // All generic input arguments have to be fixed - AParametersCollection d_parameters = TypeManager.GetParameterData (invoke); + AParametersCollection d_parameters = invoke.Parameters; return AllTypesAreFixed (d_parameters.Types); } - bool IsFixed (Type type) + bool IsFixed (TypeSpec type) { return IsUnfixed (type) == -1; } - int IsUnfixed (Type type) + int IsUnfixed (TypeSpec type) { if (!type.IsGenericParameter) return -1; @@ -2633,92 +2713,89 @@ namespace Mono.CSharp { // // 26.3.3.9 Lower-bound Inference // - public int LowerBoundInference (Type u, Type v) + public int LowerBoundInference (TypeSpec u, TypeSpec v) + { + return LowerBoundInference (u, v, false); + } + + // + // Lower-bound (false) or Upper-bound (true) inference based on inversed argument + // + int LowerBoundInference (TypeSpec u, TypeSpec v, bool inversed) { // If V is one of the unfixed type arguments int pos = IsUnfixed (v); if (pos != -1) { - AddToBounds (u, pos); + AddToBounds (new BoundInfo (u, inversed ? BoundKind.Upper : BoundKind.Lower), pos); return 1; } // If U is an array type - if (u.IsArray) { - int u_dim = u.GetArrayRank (); - Type v_e; - Type u_e = TypeManager.GetElementType (u); - - if (v.IsArray) { - if (u_dim != v.GetArrayRank ()) + var u_ac = u as ArrayContainer; + if (u_ac != null) { + var v_ac = v as ArrayContainer; + if (v_ac != null) { + if (u_ac.Rank != v_ac.Rank) return 0; - v_e = TypeManager.GetElementType (v); - - if (u.IsByRef) { - return LowerBoundInference (u_e, v_e); - } + if (TypeManager.IsValueType (u_ac.Element)) + return ExactInference (u_ac.Element, v_ac.Element); - return ExactInference (u_e, v_e); + return LowerBoundInference (u_ac.Element, v_ac.Element, inversed); } - if (u_dim != 1) + if (u_ac.Rank != 1) return 0; - if (v.IsGenericType) { - Type g_v = v.GetGenericTypeDefinition (); - if ((g_v != TypeManager.generic_ilist_type) && (g_v != TypeManager.generic_icollection_type) && - (g_v != TypeManager.generic_ienumerable_type)) + if (TypeManager.IsGenericType (v)) { + TypeSpec g_v = v.GetDefinition (); + if (g_v != TypeManager.generic_ilist_type && + g_v != TypeManager.generic_icollection_type && + g_v != TypeManager.generic_ienumerable_type) return 0; - v_e = TypeManager.GetTypeArguments (v)[0]; + var v_i = TypeManager.GetTypeArguments (v) [0]; + if (TypeManager.IsValueType (u_ac.Element)) + return ExactInference (u_ac.Element, v_i); - if (u.IsByRef) { - return LowerBoundInference (u_e, v_e); - } - - return ExactInference (u_e, v_e); + return LowerBoundInference (u_ac.Element, v_i); } - } else if (v.IsGenericType && !v.IsGenericTypeDefinition) { + } else if (TypeManager.IsGenericType (v)) { // - // if V is a constructed type C and there is a unique set of types U1..Uk - // such that a standard implicit conversion exists from U to C then an exact - // inference is made from each Ui for the corresponding Vi + // if V is a constructed type C and there is a unique type C + // such that U is identical to, inherits from (directly or indirectly), + // or implements (directly or indirectly) C // - ArrayList u_candidates = new ArrayList (); - if (u.IsGenericType) - u_candidates.Add (u); + var u_candidates = new List (); + var open_v = v.MemberDefinition; - for (Type t = u.BaseType; t != null; t = t.BaseType) { - if (t.IsGenericType && !t.IsGenericTypeDefinition) + for (TypeSpec t = u; t != null; t = t.BaseType) { + if (open_v == t.MemberDefinition) u_candidates.Add (t); - } - - // TODO: Implement GetGenericInterfaces only and remove - // the if from foreach - u_candidates.AddRange (TypeManager.GetInterfaces (u)); - Type open_v = v.GetGenericTypeDefinition (); - Type [] unique_candidate_targs = null; - Type [] ga_v = v.GetGenericArguments (); - foreach (Type u_candidate in u_candidates) { - if (!u_candidate.IsGenericType || u_candidate.IsGenericTypeDefinition) - continue; - - if (TypeManager.DropGenericTypeArguments (u_candidate) != open_v) - continue; + if (t.Interfaces != null) { + foreach (var iface in t.Interfaces) { + if (open_v == iface.MemberDefinition) + u_candidates.Add (iface); + } + } + } + TypeSpec [] unique_candidate_targs = null; + TypeSpec[] ga_v = TypeManager.GetTypeArguments (v); + foreach (TypeSpec u_candidate in u_candidates) { // - // The unique set of types U1..Uk means that if we have an interface C, - // class U: C, C then no type inference is made when inferring - // from U to C because T could be int or long + // The unique set of types U1..Uk means that if we have an interface I, + // class U : I, I then no type inference is made when inferring + // type I by applying type U because T could be int or long // if (unique_candidate_targs != null) { - Type[] second_unique_candidate_targs = u_candidate.GetGenericArguments (); - if (TypeManager.IsEqual (unique_candidate_targs, second_unique_candidate_targs)) { + TypeSpec[] second_unique_candidate_targs = TypeManager.GetTypeArguments (u_candidate); + if (TypeSpecComparer.Default.Equals (unique_candidate_targs, second_unique_candidate_targs)) { unique_candidate_targs = second_unique_candidate_targs; continue; } - + // // This should always cause type inference failure // @@ -2726,14 +2803,27 @@ namespace Mono.CSharp { return 1; } - unique_candidate_targs = u_candidate.GetGenericArguments (); + unique_candidate_targs = TypeManager.GetTypeArguments (u_candidate); } if (unique_candidate_targs != null) { + var ga_open_v = open_v.TypeParameters; int score = 0; - for (int i = 0; i < unique_candidate_targs.Length; ++i) - if (ExactInference (unique_candidate_targs [i], ga_v [i]) == 0) - ++score; + for (int i = 0; i < unique_candidate_targs.Length; ++i) { + Variance variance = ga_open_v [i].Variance; + + TypeSpec u_i = unique_candidate_targs [i]; + if (variance == Variance.None || TypeManager.IsValueType (u_i)) { + if (ExactInference (u_i, ga_v [i]) == 0) + ++score; + } else { + bool upper_bound = (variance == Variance.Contravariant && !inversed) || + (variance == Variance.Covariant && inversed); + + if (LowerBoundInference (u_i, ga_v [i], upper_bound) == 0) + ++score; + } + } return score; } } @@ -2744,25 +2834,20 @@ namespace Mono.CSharp { // // 26.3.3.6 Output Type Inference // - public int OutputTypeInference (EmitContext ec, Expression e, Type t) + public int OutputTypeInference (ResolveContext ec, Expression e, TypeSpec t) { // If e is a lambda or anonymous method with inferred return type AnonymousMethodExpression ame = e as AnonymousMethodExpression; if (ame != null) { - Type rt = ame.InferReturnType (ec, this, t); - MethodInfo invoke = Delegate.GetInvokeMethod (t, t); + TypeSpec rt = ame.InferReturnType (ec, this, t); + var invoke = Delegate.GetInvokeMethod (ec.Compiler, t); if (rt == null) { - AParametersCollection pd = TypeManager.GetParameterData (invoke); + AParametersCollection pd = invoke.Parameters; return ame.Parameters.Count == pd.Count ? 1 : 0; } - Type rtype = invoke.ReturnType; -#if MS_COMPATIBLE - // Blablabla, because reflection does not work with dynamic types - Type [] g_args = t.GetGenericArguments (); - rtype = g_args [rtype.GenericParameterPosition]; -#endif + TypeSpec rtype = invoke.ReturnType; return LowerBoundInference (rt, rtype) + 1; } @@ -2773,30 +2858,39 @@ namespace Mono.CSharp { // then a lower-bound inference is made from U for Tb. // if (e is MethodGroupExpr) { - // TODO: Or expression tree - if (!TypeManager.IsDelegateType (t)) - return 0; + if (!TypeManager.IsDelegateType (t)) { + if (TypeManager.expression_type == null || t.MemberDefinition != TypeManager.expression_type.MemberDefinition) + return 0; + + t = TypeManager.GetTypeArguments (t)[0]; + } - MethodInfo invoke = Delegate.GetInvokeMethod (t, t); - Type rtype = invoke.ReturnType; -#if MS_COMPATIBLE - // Blablabla, because reflection does not work with dynamic types - Type [] g_args = t.GetGenericArguments (); - rtype = g_args [rtype.GenericParameterPosition]; -#endif + var invoke = Delegate.GetInvokeMethod (ec.Compiler, t); + TypeSpec rtype = invoke.ReturnType; - if (!TypeManager.IsGenericType (rtype)) + if (!rtype.IsGenericParameter && !TypeManager.IsGenericType (rtype)) return 0; + // LAMESPEC: Standard does not specify that all methodgroup arguments + // has to be fixed but it does not specify how to do recursive type inference + // either. We choose the simple option and infer return type only + // if all delegate generic arguments are fixed. + TypeSpec[] param_types = new TypeSpec [invoke.Parameters.Count]; + for (int i = 0; i < param_types.Length; ++i) { + var inflated = InflateGenericArgument (invoke.Parameters.Types[i]); + if (inflated == null) + return 0; + + param_types[i] = inflated; + } + MethodGroupExpr mg = (MethodGroupExpr) e; - ArrayList args = DelegateCreation.CreateDelegateMethodArguments (invoke, e.Location); + Arguments args = DelegateCreation.CreateDelegateMethodArguments (invoke.Parameters, param_types, e.Location); mg = mg.OverloadResolve (ec, ref args, true, e.Location); if (mg == null) return 0; - // TODO: What should happen when return type is of generic type ? - throw new NotImplementedException (); -// return LowerBoundInference (null, rtype) + 1; + return LowerBoundInference (mg.BestCandidate.ReturnType, rtype) + 1; } // @@ -2806,15 +2900,16 @@ namespace Mono.CSharp { return LowerBoundInference (e.Type, t) * 2; } - static void RemoveDependentTypes (ArrayList types, Type returnType) + void RemoveDependentTypes (List types, TypeSpec returnType) { - if (returnType.IsGenericParameter) { - types [returnType.GenericParameterPosition] = null; + int idx = IsUnfixed (returnType); + if (idx >= 0) { + types [idx] = null; return; } - if (returnType.IsGenericType) { - foreach (Type t in returnType.GetGenericArguments ()) { + if (TypeManager.IsGenericType (returnType)) { + foreach (TypeSpec t in TypeManager.GetTypeArguments (returnType)) { RemoveDependentTypes (types, t); } } @@ -2825,7 +2920,7 @@ namespace Mono.CSharp { if (unfixed_types == null) return false; - foreach (Type ut in unfixed_types) + foreach (TypeSpec ut in unfixed_types) if (ut != null) return true; return false;