return false;
if (ClassConstraint != null) {
- if (!ClassConstraint.IsValueType)
+ if (!TypeManager.IsValueType (ClassConstraint))
return false;
if (ClassConstraint != TypeManager.value_type)
}
}
+ public class ReflectionConstraints : GenericConstraints
+ {
+ GenericParameterAttributes attrs;
+ Type base_type;
+ Type class_constraint;
+ Type[] iface_constraints;
+ string name;
+
+ public static GenericConstraints GetConstraints (Type t)
+ {
+ Type[] constraints = t.GetGenericParameterConstraints ();
+ GenericParameterAttributes attrs = t.GenericParameterAttributes;
+ if (constraints.Length == 0 && attrs == GenericParameterAttributes.None)
+ return null;
+ return new ReflectionConstraints (t.Name, constraints, attrs);
+ }
+
+ private ReflectionConstraints (string name, Type[] constraints, GenericParameterAttributes attrs)
+ {
+ this.name = name;
+ this.attrs = attrs;
+
+ if ((constraints.Length > 0) && !constraints[0].IsInterface) {
+ class_constraint = constraints[0];
+ iface_constraints = new Type[constraints.Length - 1];
+ Array.Copy (constraints, 1, iface_constraints, 0, constraints.Length - 1);
+ } else
+ iface_constraints = constraints;
+
+ if (HasValueTypeConstraint)
+ base_type = TypeManager.value_type;
+ else if (class_constraint != null)
+ base_type = class_constraint;
+ else
+ base_type = TypeManager.object_type;
+ }
+
+ public override string TypeParameter
+ {
+ get { return name; }
+ }
+
+ public override GenericParameterAttributes Attributes
+ {
+ get { return attrs; }
+ }
+
+ public override Type ClassConstraint
+ {
+ get { return class_constraint; }
+ }
+
+ public override Type EffectiveBaseClass
+ {
+ get { return base_type; }
+ }
+
+ public override Type[] InterfaceConstraints
+ {
+ get { return iface_constraints; }
+ }
+ }
+
+ public enum Variance
+ {
+ //
+ // Don't add or modify internal values, they are used as -/+ calculation signs
+ //
+ None = 0,
+ Covariant = 1,
+ Contravariant = -1
+ }
+
public enum SpecialConstraint
{
Constructor,
/// Resolve the constraints - but only resolve things into Expression's, not
/// into actual types.
/// </summary>
- public bool Resolve (IResolveContext ec)
+ public bool Resolve (MemberCore ec, TypeParameter tp, Report Report)
{
if (resolved)
return true;
+ if (ec == null)
+ return false;
+
iface_constraints = new ArrayList (2); // TODO: Too expensive allocation
type_param_constraints = new ArrayList ();
if (errors != Report.Errors)
return false;
- NamespaceEntry.Error_NamespaceNotFound (loc, ((Expression)obj).GetSignatureForError ());
+ NamespaceEntry.Error_NamespaceNotFound (loc, ((Expression)obj).GetSignatureForError (), Report);
return false;
}
TypeExpr expr;
- ConstructedType cexpr = fn as ConstructedType;
+ GenericTypeExpr cexpr = fn as GenericTypeExpr;
if (cexpr != null) {
- if (!cexpr.ResolveConstructedType (ec))
- return false;
-
- expr = cexpr;
+ expr = cexpr.ResolveAsBaseTerminal (ec, false);
} else
expr = ((Expression) obj).ResolveAsTypeTerminal (ec, false);
if ((expr == null) || (expr.Type == null))
return false;
- if (!ec.GenericDeclContainer.IsAccessibleAs (fn.Type)) {
+ if (!ec.IsAccessibleAs (fn.Type)) {
Report.SymbolRelatedToPreviousError (fn.Type);
Report.Error (703, loc,
"Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'",
- fn.GetSignatureForError (), ec.GenericDeclContainer.GetSignatureForError ());
+ fn.GetSignatureForError (), ec.GetSignatureForError ());
return false;
}
- TypeParameterExpr texpr = expr as TypeParameterExpr;
- if (texpr != null)
+ if (TypeManager.IsGenericParameter (expr.Type))
type_param_constraints.Add (expr);
else if (expr.IsInterface)
iface_constraints.Add (expr);
} else
class_constraint = expr;
+
+ //
+ // Checks whether each generic method parameter constraint type
+ // is valid with respect to T
+ //
+ if (tp != null && tp.Type.DeclaringMethod != null) {
+ TypeManager.CheckTypeVariance (expr.Type, Variance.Contravariant, ec as MemberCore);
+ }
+
num_constraints++;
}
list.Add (iface_constraint.Type);
}
- foreach (TypeParameterExpr expr in type_param_constraints) {
+ foreach (TypeExpr expr in type_param_constraints) {
foreach (Type type in list) {
if (!type.Equals (expr.Type))
continue;
TypeManager.CSharpName (class_constraint_type));
return false;
}
+
+ if (TypeManager.IsDynamicType (class_constraint_type)) {
+ Report.Error (1967, loc, "A constraint cannot be the dynamic type");
+ return false;
+ }
}
if (class_constraint_type != null)
return true;
}
- bool CheckTypeParameterConstraints (TypeParameter tparam, ref TypeExpr prevConstraint, ArrayList seen)
+ bool CheckTypeParameterConstraints (Type tparam, ref TypeExpr prevConstraint, ArrayList seen, Report Report)
{
seen.Add (tparam);
- Constraints constraints = tparam.Constraints;
+ Constraints constraints = TypeManager.LookupTypeParameter (tparam).Constraints;
if (constraints == null)
return true;
if (constraints.type_param_constraints == null)
return true;
- foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
- if (seen.Contains (expr.TypeParameter)) {
+ foreach (TypeExpr expr in constraints.type_param_constraints) {
+ if (seen.Contains (expr.Type)) {
Report.Error (454, loc, "Circular constraint " +
"dependency involving `{0}' and `{1}'",
tparam.Name, expr.GetSignatureForError ());
return false;
}
- if (!CheckTypeParameterConstraints (expr.TypeParameter, ref prevConstraint, seen))
+ if (!CheckTypeParameterConstraints (expr.Type, ref prevConstraint, seen, Report))
return false;
}
/// <summary>
/// Resolve the constraints into actual types.
/// </summary>
- public bool ResolveTypes (IResolveContext ec)
+ public bool ResolveTypes (IMemberContext ec, Report r)
{
if (resolved_types)
return true;
resolved_types = true;
foreach (object obj in constraints) {
- ConstructedType cexpr = obj as ConstructedType;
+ GenericTypeExpr cexpr = obj as GenericTypeExpr;
if (cexpr == null)
continue;
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))
+ foreach (TypeExpr expr in type_param_constraints) {
+ if (!CheckTypeParameterConstraints (expr.Type, ref prev_constraint, seen, r))
return false;
seen.Clear ();
}
iface = iface.GetGenericTypeDefinition ();
bool ok = false;
- for (int ii = 0; i < InterfaceConstraints.Length; ++ii) {
+ for (int ii = 0; ii < InterfaceConstraints.Length; ii++) {
Type check = InterfaceConstraints [ii];
if (check.IsGenericType)
check = check.GetGenericTypeDefinition ();
return true;
}
- public void VerifyClsCompliance ()
+ public void VerifyClsCompliance (Report r)
{
if (class_constraint_type != null && !AttributeTester.IsClsCompliant (class_constraint_type))
- Warning_ConstrainIsNotClsCompliant (class_constraint_type, class_constraint.Location);
+ Warning_ConstrainIsNotClsCompliant (class_constraint_type, class_constraint.Location, r);
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);
+ ((TypeExpr)iface_constraints [i]).Location, r);
}
}
}
- void Warning_ConstrainIsNotClsCompliant (Type t, Location loc)
+ void Warning_ConstrainIsNotClsCompliant (Type t, Location loc, Report Report)
{
Report.SymbolRelatedToPreviousError (t);
Report.Warning (3024, 1, loc, "Constraint type `{0}' is not CLS-compliant",
{
static readonly string[] attribute_target = new string [] { "type parameter" };
- string name;
DeclSpace decl;
GenericConstraints gc;
Constraints constraints;
GenericTypeParameterBuilder type;
MemberCache member_cache;
+ Variance variance;
public TypeParameter (DeclSpace parent, DeclSpace decl, string name,
- Constraints constraints, Attributes attrs, Location loc)
+ Constraints constraints, Attributes attrs, Variance variance, Location loc)
: base (parent, new MemberName (name, loc), attrs)
{
- this.name = name;
this.decl = decl;
this.constraints = constraints;
+ this.variance = variance;
}
public GenericConstraints GenericConstraints {
get { return decl; }
}
+ public Variance Variance {
+ get { return variance; }
+ }
+
public Type Type {
get { return type; }
}
TypeManager.AddTypeParameter (type, this);
}
+ public void ErrorInvalidVariance (IMemberContext mc, Variance expected)
+ {
+// TODO: Report.SymbolRelatedToPreviousError (mc);
+ 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);
+ }
+
/// <summary>
/// This is the second method which is called during the resolving
/// process - in case of class type parameters, we're called from
public bool Resolve (DeclSpace ds)
{
if (constraints != null) {
- if (!constraints.Resolve (ds)) {
+ if (!constraints.Resolve (ds, this, Report)) {
constraints = null;
return false;
}
/// Note that we may have circular dependencies on type parameters - this
/// is why Resolve() and ResolveType() are separate.
/// </summary>
- public bool ResolveType (IResolveContext ec)
+ public bool ResolveType (IMemberContext ec)
{
if (constraints != null) {
- if (!constraints.ResolveTypes (ec)) {
+ if (!constraints.ResolveTypes (ec, Report)) {
constraints = null;
return false;
}
/// process. We're called after everything is fully resolved and actually
/// register the constraints with SRE and the TypeManager.
/// </summary>
- public bool DefineType (IResolveContext ec)
+ public bool DefineType (IMemberContext ec)
{
return DefineType (ec, null, null, false);
}
/// The `builder', `implementing' and `is_override' arguments are only
/// applicable to method type parameters.
/// </summary>
- public bool DefineType (IResolveContext ec, MethodBuilder builder,
+ public bool DefineType (IMemberContext ec, MethodBuilder builder,
MethodInfo implementing, bool is_override)
{
if (!ResolveType (ec))
gc = (GenericConstraints) constraints;
}
- if (gc == null)
- return true;
+ SetConstraints (type);
+ return true;
+ }
- if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
- type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
+ public static TypeParameter FindTypeParameter (TypeParameter[] tparams, string name)
+ {
+ foreach (var tp in tparams) {
+ if (tp.Name == name)
+ return tp;
+ }
- type.SetInterfaceConstraints (gc.InterfaceConstraints);
- type.SetGenericParameterAttributes (gc.Attributes);
- TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
+ return null;
+ }
- return true;
+ public void SetConstraints (GenericTypeParameterBuilder type)
+ {
+ GenericParameterAttributes attr = GenericParameterAttributes.None;
+ if (variance == Variance.Contravariant)
+ attr |= GenericParameterAttributes.Contravariant;
+ else if (variance == Variance.Covariant)
+ attr |= GenericParameterAttributes.Covariant;
+
+ if (gc != null) {
+ if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
+ type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
+
+ attr |= gc.Attributes;
+ type.SetInterfaceConstraints (gc.InterfaceConstraints);
+ TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
+ }
+
+ type.SetGenericParameterAttributes (attr);
}
/// <summary>
/// check that they're the same.
/// con
/// </summary>
- public bool UpdateConstraints (IResolveContext ec, Constraints new_constraints)
+ public bool UpdateConstraints (MemberCore ec, Constraints new_constraints)
{
if (type == null)
throw new InvalidOperationException ();
if (new_constraints == null)
return true;
- if (!new_constraints.Resolve (ec))
+ if (!new_constraints.Resolve (ec, this, Report))
return false;
- if (!new_constraints.ResolveTypes (ec))
+ if (!new_constraints.ResolveTypes (ec, Report))
return false;
if (constraints != null)
return true;
}
- public override void ApplyAttributeBuilder (Attribute a,
- CustomAttributeBuilder cb)
+ public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
{
type.SetCustomAttribute (cb);
}
return false;
}
- public override string ToString ()
- {
- return "TypeParameter[" + name + "]";
- }
-
- public static string GetSignatureForError (TypeParameter[] tp)
- {
- if (tp == null || tp.Length == 0)
- return "";
-
- StringBuilder sb = new StringBuilder ("<");
- for (int i = 0; i < tp.Length; ++i) {
- if (i > 0)
- sb.Append (",");
- sb.Append (tp[i].GetSignatureForError ());
- }
- sb.Append ('>');
- return sb.ToString ();
- }
-
public void InflateConstraints (Type declaring)
{
if (constraints != null)
/// A TypeExpr which already resolved to a type parameter.
/// </summary>
public class TypeParameterExpr : TypeExpr {
- TypeParameter type_parameter;
-
- public TypeParameter TypeParameter {
- get {
- return type_parameter;
- }
- }
public TypeParameterExpr (TypeParameter type_parameter, Location loc)
{
- this.type_parameter = type_parameter;
+ this.type = type_parameter.Type;
+ this.eclass = ExprClass.TypeParameter;
this.loc = loc;
}
- protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
+ protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
{
throw new NotSupportedException ();
}
- public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
+ public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
{
- type = type_parameter.Type;
- eclass = ExprClass.TypeParameter;
return this;
}
get { return false; }
}
- public override bool CheckAccessLevel (DeclSpace ds)
+ public override bool CheckAccessLevel (IMemberContext ds)
{
return true;
}
}
- /// <summary>
- /// Tracks the type arguments when instantiating a generic type. We're used in
- /// ConstructedType.
- /// </summary>
+ //
+ // Tracks the type arguments when instantiating a generic type. It's used
+ // by both type arguments and type parameters
+ //
public class TypeArguments {
- public readonly Location Location;
ArrayList args;
Type[] atypes;
- int dimension;
- bool has_type_args;
- public TypeArguments (Location loc)
+ public TypeArguments ()
{
args = new ArrayList ();
- this.Location = loc;
}
- public TypeArguments (Location loc, params Expression[] types)
+ public TypeArguments (params FullNamedExpression[] types)
{
- this.Location = loc;
this.args = new ArrayList (types);
}
-
- public TypeArguments (int dimension, Location loc)
- {
- this.dimension = dimension;
- this.Location = loc;
- }
- public void Add (Expression type)
+ public void Add (FullNamedExpression type)
{
args.Add (type);
}
args.AddRange (new_args.args);
}
- /// <summary>
- /// We're used during the parsing process: the parser can't distinguish
- /// between type parameters and type arguments. Because of that, the
- /// parser creates a `MemberName' with `TypeArguments' for both cases and
- /// in case of a generic type definition, we call GetDeclarations().
- /// </summary>
+ // TODO: Should be deleted
public TypeParameterName[] GetDeclarations ()
{
- TypeParameterName[] ret = new TypeParameterName [args.Count];
- for (int i = 0; i < args.Count; i++) {
- TypeParameterName name = args [i] as TypeParameterName;
- if (name != null) {
- ret [i] = name;
- continue;
- }
- SimpleName sn = args [i] as SimpleName;
- if (sn != null && !sn.HasTypeArguments) {
- ret [i] = new TypeParameterName (sn.Name, null, sn.Location);
- continue;
- }
-
- Expression expr = (Expression) args [i];
- // TODO: Wrong location
- Report.Error (81, Location, "Type parameter declaration must be an identifier not a type");
- ret [i] = new TypeParameterName (expr.GetSignatureForError (), null, expr.Location);
- }
- return ret;
+ return (TypeParameterName[]) args.ToArray (typeof (TypeParameterName));
}
/// <summary>
}
}
- public bool HasTypeArguments {
- get {
- return has_type_args;
- }
- }
-
public int Count {
get {
- if (dimension > 0)
- return dimension;
- else
- return args.Count;
- }
- }
-
- public bool IsUnbound {
- get {
- return dimension > 0;
+ return args.Count;
}
}
- public override string ToString ()
- {
- StringBuilder s = new StringBuilder ();
-
- int count = Count;
- for (int i = 0; i < count; i++){
- //
- // FIXME: Use TypeManager.CSharpname once we have the type
- //
- if (args != null)
- s.Append (args [i].ToString ());
- if (i+1 < count)
- s.Append (",");
- }
- return s.ToString ();
- }
-
public string GetSignatureForError()
{
StringBuilder sb = new StringBuilder();
/// <summary>
/// Resolve the type arguments.
/// </summary>
- public bool Resolve (IResolveContext ec)
+ public bool Resolve (IMemberContext ec)
{
+ if (atypes != null)
+ return atypes.Length != 0;
+
int count = args.Count;
bool ok = true;
atypes = new Type [count];
for (int i = 0; i < count; i++){
- TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec, false);
+ TypeExpr te = ((FullNamedExpression) args[i]).ResolveAsTypeTerminal (ec, false);
if (te == null) {
ok = false;
continue;
}
atypes[i] = te.Type;
- if (te.Type.IsGenericParameter) {
- if (te is TypeParameterExpr)
- has_type_args = true;
- continue;
- }
if (te.Type.IsSealed && te.Type.IsAbstract) {
- Report.Error (718, Location, "`{0}': static classes cannot be used as generic arguments",
+ ec.Compiler.Report.Error (718, te.Location, "`{0}': static classes cannot be used as generic arguments",
te.GetSignatureForError ());
- return false;
+ ok = false;
}
if (te.Type.IsPointer || TypeManager.IsSpecialType (te.Type)) {
- Report.Error (306, Location,
+ ec.Compiler.Report.Error (306, te.Location,
"The type `{0}' may not be used as a type argument",
- TypeManager.CSharpName (te.Type));
- return false;
- }
-
- if (te.Type == TypeManager.void_type) {
- Expression.Error_VoidInvalidInTheContext (Location);
- return false;
+ te.GetSignatureForError ());
+ ok = false;
}
}
+
+ if (!ok)
+ atypes = Type.EmptyTypes;
+
return ok;
}
public TypeArguments Clone ()
{
- TypeArguments copy = new TypeArguments (Location);
+ TypeArguments copy = new TypeArguments ();
foreach (Expression ta in args)
copy.args.Add (ta);
public class TypeParameterName : SimpleName
{
Attributes attributes;
+ Variance variance;
public TypeParameterName (string name, Attributes attrs, Location loc)
+ : this (name, attrs, Variance.None, loc)
+ {
+ }
+
+ public TypeParameterName (string name, Attributes attrs, Variance variance, Location loc)
: base (name, loc)
{
attributes = attrs;
+ this.variance = variance;
}
public Attributes OptAttributes {
return attributes;
}
}
+
+ public Variance Variance {
+ get {
+ return variance;
+ }
+ }
}
/// <summary>
- /// An instantiation of a generic type.
+ /// A reference expression to generic type
/// </summary>
- public class ConstructedType : TypeExpr {
- FullNamedExpression name;
+ class GenericTypeExpr : TypeExpr
+ {
TypeArguments args;
- Type[] gen_params, atypes;
- Type gt;
-
- /// <summary>
- /// Instantiate the generic type `fname' with the type arguments `args'.
- /// </summary>
- public ConstructedType (FullNamedExpression fname, TypeArguments args, Location l)
- {
- loc = l;
- this.name = fname;
- this.args = args;
+ Type[] gen_params; // TODO: Waiting for constrains check cleanup
+ Type open_type;
- eclass = ExprClass.Type;
- }
-
- /// <summary>
- /// This is used to construct the `this' type inside a generic type definition.
- /// </summary>
- public ConstructedType (Type t, TypeParameter[] type_params, Location l)
+ //
+ // 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
+ //
+ public GenericTypeExpr (DeclSpace gType, Location l)
{
- gt = t.GetGenericTypeDefinition ();
+ open_type = gType.TypeBuilder.GetGenericTypeDefinition ();
- args = new TypeArguments (l);
- foreach (TypeParameter type_param in type_params)
+ args = new TypeArguments ();
+ foreach (TypeParameter type_param in gType.TypeParameters)
args.Add (new TypeParameterExpr (type_param, l));
this.loc = l;
- this.name = new TypeExpression (gt, l);
- eclass = ExprClass.Type;
}
/// <summary>
/// Use this constructor if you already know the fully resolved
/// generic type.
/// </summary>
- public ConstructedType (Type t, TypeArguments args, Location l)
- : this ((FullNamedExpression)null, args, l)
+ public GenericTypeExpr (Type t, TypeArguments args, Location l)
{
- gt = t.GetGenericTypeDefinition ();
- this.name = new TypeExpression (gt, l);
+ open_type = t.GetGenericTypeDefinition ();
+
+ loc = l;
+ this.args = args;
}
public TypeArguments TypeArguments {
return TypeManager.CSharpName (type);
}
- protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
- {
- if (!ResolveConstructedType (ec))
- return null;
-
- return this;
- }
-
- /// <summary>
- /// Check the constraints; we're called from ResolveAsTypeTerminal()
- /// after fully resolving the constructed type.
- /// </summary>
- public bool CheckConstraints (IResolveContext ec)
- {
- return ConstraintChecker.CheckConstraints (ec, gt, gen_params, atypes, loc);
- }
-
- /// <summary>
- /// Resolve the constructed type, but don't check the constraints.
- /// </summary>
- public bool ResolveConstructedType (IResolveContext ec)
+ protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
{
- if (type != null)
- return true;
- // If we already know the fully resolved generic type.
- if (gt != null)
- return DoResolveType (ec);
+ if (eclass != ExprClass.Invalid)
+ return this;
- int num_args;
- Type t = name.Type;
-
- if (t == null) {
- Report.Error (246, loc, "Cannot find type `{0}'<...>", GetSignatureForError ());
- return false;
- }
-
- num_args = TypeManager.GetNumberOfTypeArguments (t);
- if (num_args == 0) {
- Report.Error (308, loc,
- "The non-generic type `{0}' cannot " +
- "be used with type arguments.",
- TypeManager.CSharpName (t));
- return false;
- }
-
- gt = t.GetGenericTypeDefinition ();
- return DoResolveType (ec);
- }
-
- bool DoResolveType (IResolveContext ec)
- {
- //
- // Resolve the arguments.
- //
- if (args.Resolve (ec) == false)
- return false;
+ eclass = ExprClass.Type;
- gen_params = gt.GetGenericArguments ();
- atypes = args.Arguments;
+ if (!args.Resolve (ec))
+ return null;
+ gen_params = open_type.GetGenericArguments ();
+ Type[] atypes = args.Arguments;
+
if (atypes.Length != gen_params.Length) {
- Report.Error (305, loc,
- "Using the generic type `{0}' " +
- "requires {1} type arguments",
- TypeManager.CSharpName (gt),
- gen_params.Length.ToString ());
- return false;
+ Namespace.Error_InvalidNumberOfTypeArguments (open_type, loc);
+ return null;
}
//
- // Now bind the parameters.
+ // Now bind the parameters
//
- type = gt.MakeGenericType (atypes);
- return true;
- }
-
- public Expression GetSimpleName (EmitContext ec)
- {
+ type = open_type.MakeGenericType (atypes);
return this;
}
- public override bool CheckAccessLevel (DeclSpace ds)
+ /// <summary>
+ /// Check the constraints; we're called from ResolveAsTypeTerminal()
+ /// after fully resolving the constructed type.
+ /// </summary>
+ public bool CheckConstraints (IMemberContext ec)
{
- return ds.CheckAccessLevel (gt);
+ return ConstraintChecker.CheckConstraints (ec, open_type, gen_params, args.Arguments, loc);
}
-
- public override bool AsAccessible (DeclSpace ds)
+
+ public override bool CheckAccessLevel (IMemberContext mc)
{
- foreach (Type t in atypes) {
- if (!ds.IsAccessibleAs (t))
- return false;
- }
-
- return ds.IsAccessibleAs (gt);
+ return mc.CurrentTypeDefinition.CheckAccessLevel (open_type);
}
public override bool IsClass {
- get { return gt.IsClass; }
+ get { return open_type.IsClass; }
}
public override bool IsValueType {
- get { return gt.IsValueType; }
+ get { return TypeManager.IsStruct (open_type); }
}
public override bool IsInterface {
- get { return gt.IsInterface; }
+ get { return open_type.IsInterface; }
}
public override bool IsSealed {
- get { return gt.IsSealed; }
+ get { return open_type.IsSealed; }
}
public override bool Equals (object obj)
{
- ConstructedType cobj = obj as ConstructedType;
+ GenericTypeExpr cobj = obj as GenericTypeExpr;
if (cobj == null)
return false;
protected readonly Type[] gen_params;
protected readonly Type[] atypes;
protected readonly Location loc;
+ protected Report Report;
- protected ConstraintChecker (Type[] gen_params, Type[] atypes, Location loc)
+ protected ConstraintChecker (Type[] gen_params, Type[] atypes, Location loc, Report r)
{
this.gen_params = gen_params;
this.atypes = atypes;
this.loc = loc;
+ this.Report = r;
}
/// <summary>
/// Check the constraints; we're called from ResolveAsTypeTerminal()
/// after fully resolving the constructed type.
/// </summary>
- public bool CheckConstraints (IResolveContext ec)
+ public bool CheckConstraints (IMemberContext ec)
{
for (int i = 0; i < gen_params.Length; i++) {
if (!CheckConstraints (ec, i))
return true;
}
- protected bool CheckConstraints (IResolveContext ec, int index)
+ protected bool CheckConstraints (IMemberContext ec, int index)
{
Type atype = atypes [index];
Type ptype = gen_params [index];
if (atype.IsGenericParameter) {
GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype);
if (agc != null) {
- if (agc is Constraints)
- ((Constraints) agc).Resolve (ec);
+ if (agc is Constraints) {
+ // FIXME: No constraints can be resolved here, we are in
+ // completely wrong/different context. This path is hit
+ // when resolving base type of unresolved generic type
+ // with constraints. We are waiting with CheckConsttraints
+ // after type-definition but not in this case
+ if (!((Constraints) agc).Resolve (null, null, Report))
+ return true;
+ }
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);
+ is_class = TypeManager.IsReferenceType (atype);
+ is_struct = TypeManager.IsValueType (atype) && !TypeManager.IsNullableType (atype);
}
//
if (!gc.HasConstructorConstraint)
return true;
- if (TypeManager.IsBuiltinType (atype) || atype.IsValueType)
+ if (TypeManager.IsValueType (atype))
return true;
if (HasDefaultConstructor (atype))
return false;
}
- protected bool CheckConstraint (IResolveContext ec, Type ptype, Expression expr,
+ protected bool CheckConstraint (IMemberContext ec, Type ptype, Expression expr,
Type ctype)
{
+ //
+ // All this is needed because we don't have
+ // real inflated type hierarchy
+ //
if (TypeManager.HasGenericArguments (ctype)) {
Type[] types = TypeManager.GetTypeArguments (ctype);
- TypeArguments new_args = new TypeArguments (loc);
+ TypeArguments new_args = new TypeArguments ();
for (int i = 0; i < types.Length; i++) {
- Type t = types [i];
+ Type t = TypeManager.TypeToCoreType (types [i]);
if (t.IsGenericParameter) {
int pos = t.GenericParameterPosition;
- t = atypes [pos];
+ if (t.DeclaringMethod == null && this is MethodConstraintChecker) {
+ Type parent = ((MethodConstraintChecker) this).declaring_type;
+ t = parent.GetGenericArguments ()[pos];
+ } else {
+ t = atypes [pos];
+ }
}
new_args.Add (new TypeExpression (t, loc));
}
- TypeExpr ct = new ConstructedType (ctype, new_args, loc);
+ 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 (ctype.DeclaringMethod == null) {
+ // FIXME: Implement
+ return true;
+ } else {
+ ctype = atypes [pos];
+ }
}
if (Convert.ImplicitStandardConversionExists (expr, ctype))
protected abstract string GetSignatureForError ();
protected abstract void Report_SymbolRelatedToPreviousError ();
- public static bool CheckConstraints (EmitContext ec, MethodBase definition,
+ public static bool CheckConstraints (IMemberContext ec, MethodBase definition,
MethodBase instantiated, Location loc)
{
MethodConstraintChecker checker = new MethodConstraintChecker (
- definition, definition.GetGenericArguments (),
- instantiated.GetGenericArguments (), loc);
+ definition, instantiated.DeclaringType, definition.GetGenericArguments (),
+ instantiated.GetGenericArguments (), loc, ec.Compiler.Report);
return checker.CheckConstraints (ec);
}
- public static bool CheckConstraints (IResolveContext ec, Type gt, Type[] gen_params,
+ public static bool CheckConstraints (IMemberContext ec, Type gt, Type[] gen_params,
Type[] atypes, Location loc)
{
TypeConstraintChecker checker = new TypeConstraintChecker (
- gt, gen_params, atypes, loc);
+ gt, gen_params, atypes, loc, ec.Compiler.Report);
return checker.CheckConstraints (ec);
}
protected class MethodConstraintChecker : ConstraintChecker
{
MethodBase definition;
+ public Type declaring_type;
- public MethodConstraintChecker (MethodBase definition, Type[] gen_params,
- Type[] atypes, Location loc)
- : base (gen_params, atypes, loc)
+ public MethodConstraintChecker (MethodBase definition, Type declaringType, Type[] gen_params,
+ Type[] atypes, Location loc, Report r)
+ : base (gen_params, atypes, loc, r)
{
+ this.declaring_type = declaringType;
this.definition = definition;
}
Type gt;
public TypeConstraintChecker (Type gt, Type[] gen_params, Type[] atypes,
- Location loc)
- : base (gen_params, atypes, loc)
+ Location loc, Report r)
+ : base (gen_params, atypes, loc, r)
{
this.gt = gt;
}
public class GenericMethod : DeclSpace
{
FullNamedExpression return_type;
- Parameters parameters;
+ ParametersCompiled parameters;
public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name,
- FullNamedExpression return_type, Parameters parameters)
+ FullNamedExpression return_type, ParametersCompiled parameters)
: base (ns, parent, name, null)
{
this.return_type = return_type;
this.parameters = parameters;
}
+ public override TypeContainer CurrentTypeDefinition {
+ get {
+ return Parent.CurrentTypeDefinition;
+ }
+ }
+
+ public override TypeParameter[] CurrentTypeParameters {
+ get {
+ return base.type_params;
+ }
+ }
+
public override TypeBuilder DefineType ()
{
throw new Exception ();
/// Define and resolve the type parameters.
/// We're called from Method.Define().
/// </summary>
- public bool Define (MethodBuilder mb)
+ 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;
- Parameter p = parameters.GetParameterByName (type_argument_name);
- if (p != null) {
- Error_ParameterNameCollision (p.Location, type_argument_name, "method parameter");
- return false;
+ int idx = parameters.GetParameterIndexByName (type_argument_name);
+ if (idx >= 0) {
+ Block b = m.Block;
+ if (b == null)
+ b = new Block (null);
+
+ b.Error_AlreadyDeclaredTypeParameter (Report, parameters [i].Location,
+ type_argument_name, "method parameter");
}
snames[i] = type_argument_name;
}
- GenericTypeParameterBuilder[] gen_params = mb.DefineGenericParameters (snames);
+ GenericTypeParameterBuilder[] gen_params = m.MethodBuilder.DefineGenericParameters (snames);
for (int i = 0; i < TypeParameters.Length; i++)
TypeParameters [i].Define (gen_params [i]);
return true;
}
- internal static void Error_ParameterNameCollision (Location loc, string name, string collisionWith)
- {
- Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
- name, collisionWith);
- }
-
/// <summary>
/// We're called from MethodData.Define() after creating the MethodBuilder.
/// </summary>
- public bool DefineType (EmitContext ec, MethodBuilder mb,
+ public bool DefineType (IMemberContext ec, MethodBuilder mb,
MethodInfo implementing, bool is_override)
{
for (int i = 0; i < TypeParameters.Length; i++)
MemberFilter filter, object criteria)
{
throw new Exception ();
- }
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return base.GetSignatureForError () + parameters.GetSignatureForError ();
+ }
public override MemberCache MemberCache {
get {
if (tp.Constraints == null)
continue;
- tp.Constraints.VerifyClsCompliance ();
+ tp.Constraints.VerifyClsCompliance (Report);
}
}
}
return LookupTypeContainer (t);
}
+ public static Variance GetTypeParameterVariance (Type type)
+ {
+ TypeParameter tparam = LookupTypeParameter (type);
+ if (tparam != null)
+ return tparam.Variance;
+
+ switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) {
+ case GenericParameterAttributes.Covariant:
+ return Variance.Covariant;
+ case GenericParameterAttributes.Contravariant:
+ return Variance.Contravariant;
+ default:
+ return Variance.None;
+ }
+ }
+
+ public static Variance CheckTypeVariance (Type t, Variance expected, IMemberContext member)
+ {
+ TypeParameter tp = LookupTypeParameter (t);
+ 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)
+ tp.ErrorInvalidVariance (member, expected);
+
+ return expected;
+ }
+
+ if (t.IsGenericType) {
+ Type[] targs_definition = GetTypeArguments (DropGenericTypeArguments (t));
+ Type[] targs = GetTypeArguments (t);
+ for (int i = 0; i < targs_definition.Length; ++i) {
+ Variance v = GetTypeParameterVariance (targs_definition[i]);
+ CheckTypeVariance (targs[i], (Variance) ((int)v * (int)expected), member);
+ }
+
+ return expected;
+ }
+
+ if (t.IsArray)
+ return CheckTypeVariance (GetElementType (t), expected, member);
+
+ return Variance.None;
+ }
+
+ public static bool IsVariantOf (Type type1, Type type2)
+ {
+ if (!type1.IsGenericType || !type2.IsGenericType)
+ return false;
+
+ Type generic_target_type = DropGenericTypeArguments (type2);
+ if (DropGenericTypeArguments (type1) != generic_target_type)
+ return false;
+
+ Type[] t1 = GetTypeArguments (type1);
+ Type[] t2 = GetTypeArguments (type2);
+ Type[] targs_definition = GetTypeArguments (generic_target_type);
+ for (int i = 0; i < targs_definition.Length; ++i) {
+ Variance v = GetTypeParameterVariance (targs_definition [i]);
+ if (v == Variance.None) {
+ if (t1[i] == t2[i])
+ continue;
+ return false;
+ }
+
+ if (v == Variance.Covariant) {
+ if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t1 [i]), t2 [i]))
+ return false;
+ } else if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t2[i]), t1[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/// <summary>
/// Check whether `a' and `b' may become equal generic types.
/// The algorithm to do that is a little bit complicated.
// become equal.
//
while (b.IsArray) {
- b = b.GetElementType ();
+ b = GetElementType (b);
if (a.Equals (b))
return false;
}
if (a.GetArrayRank () != b.GetArrayRank ())
return false;
- a = a.GetElementType ();
- b = b.GetElementType ();
+ a = GetElementType (a);
+ b = GetElementType (b);
return MayBecomeEqualGenericTypes (a, b, class_inferred, method_inferred);
}
/// when resolving an Invocation or a DelegateInvocation and the user
/// did not explicitly specify type arguments.
/// </summary>
- public static int InferTypeArguments (EmitContext ec,
- ArrayList arguments,
- ref MethodBase method)
+ public static int InferTypeArguments (ResolveContext ec, Arguments arguments, ref MethodBase method)
{
ATypeInference ti = ATypeInference.CreateInstance (arguments);
Type[] i_args = ti.InferMethodArguments (ec, method);
return 0;
}
- /// <summary>
- /// Type inference.
- /// </summary>
- public static bool InferTypeArguments (AParametersCollection apd,
- ref MethodBase method)
+/*
+ public static bool InferTypeArguments (ResolveContext ec, AParametersCollection param, ref MethodBase method)
{
if (!TypeManager.IsGenericMethod (method))
return true;
- ATypeInference ti = ATypeInference.CreateInstance (ArrayList.Adapter (apd.Types));
- Type[] i_args = ti.InferDelegateArguments (method);
+ ATypeInference ti = ATypeInference.CreateInstance (DelegateCreation.CreateDelegateMethodArguments (param, Location.Null));
+ Type[] i_args = ti.InferDelegateArguments (ec, method);
if (i_args == null)
return false;
method = ((MethodInfo) method).MakeGenericMethod (i_args);
return true;
}
+*/
}
abstract class ATypeInference
{
- protected readonly ArrayList arguments;
+ protected readonly Arguments arguments;
protected readonly int arg_count;
- protected ATypeInference (ArrayList arguments)
+ protected ATypeInference (Arguments arguments)
{
this.arguments = arguments;
if (arguments != null)
arg_count = arguments.Count;
}
- public static ATypeInference CreateInstance (ArrayList arguments)
+ public static ATypeInference CreateInstance (Arguments arguments)
{
- if (RootContext.Version == LanguageVersion.ISO_2)
- return new TypeInferenceV2 (arguments);
-
- return new TypeInferenceV3 (arguments);
+ return new TypeInference (arguments);
}
public virtual int InferenceScore {
}
}
- 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 Type[] InferDelegateArguments (MethodBase method)
- {
- 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;
- }
-
- public override Type[] InferMethodArguments (EmitContext ec, MethodBase method)
- {
- 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;
-
- 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;
-
- if (!TypeInferenceV2.UnifyType (pd.Types [i], a.Type, inferred_types))
- return null;
- }
-
- 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;
-
- if (!TypeInferenceV2.UnifyType (element_type, a.Type, inferred_types))
- return null;
- }
- }
-
- for (int i = 0; i < inferred_types.Length; i++)
- if (inferred_types [i] == null)
- return null;
-
- return inferred_types;
- }
-
- static bool InferTypeArguments (Type[] param_types, Type[] arg_types,
- Type[] inferred_types)
- {
- 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;
- }
-
- public static bool UnifyType (Type pt, Type at, Type[] inferred)
- {
- if (pt.IsGenericParameter) {
- if (pt.DeclaringMethod == null)
- return pt == at;
-
- int pos = pt.GenericParameterPosition;
-
- if (inferred [pos] == null)
- inferred [pos] = at;
-
- return inferred [pos] == at;
- }
-
- if (!pt.ContainsGenericParameters) {
- if (at.ContainsGenericParameters)
- return UnifyType (at, pt, inferred);
- else
- return true;
- }
-
- if (at.IsArray) {
- if (pt.IsArray) {
- if (at.GetArrayRank () != pt.GetArrayRank ())
- return false;
-
- return UnifyType (pt.GetElementType (), at.GetElementType (), inferred);
- }
-
- 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);
- }
-
- if (pt.IsArray) {
- if (!at.IsArray ||
- (pt.GetArrayRank () != at.GetArrayRank ()))
- return false;
-
- return UnifyType (pt.GetElementType (), at.GetElementType (), inferred);
- }
-
- 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);
-
- list.AddRange (TypeManager.GetInterfaces (at));
-
- foreach (Type type in list) {
- if (!type.IsGenericType)
- continue;
-
- if (TypeManager.DropGenericTypeArguments (pt) != TypeManager.DropGenericTypeArguments (type))
- continue;
-
- if (!UnifyTypes (pt.GetGenericArguments (), type.GetGenericArguments (), inferred))
- return false;
- }
-
- return true;
- }
-
- static bool UnifyTypes (Type[] pts, Type[] ats, Type[] inferred)
- {
- for (int i = 0; i < ats.Length; i++) {
- if (!UnifyType (pts [i], ats [i], inferred))
- return false;
- }
- return true;
- }
+ public abstract Type[] InferMethodArguments (ResolveContext ec, MethodBase method);
+// public abstract Type[] InferDelegateArguments (ResolveContext ec, MethodBase 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)
{
}
}
}
- public override Type[] InferDelegateArguments (MethodBase method)
+/*
+ public override Type[] InferDelegateArguments (ResolveContext ec, MethodBase method)
{
AParametersCollection pd = TypeManager.GetParameterData (method);
if (arg_count != pd.Count)
if (!t.IsGenericParameter)
continue;
- context.LowerBoundInference ((Type)arguments[i], t);
+ context.LowerBoundInference (arguments [i].Expr.Type, t);
}
- if (!context.FixAllTypes ())
+ if (!context.FixAllTypes (ec))
return null;
return context.InferredTypeArguments;
}
-
- public override Type[] InferMethodArguments (EmitContext ec, MethodBase method)
+*/
+ public override Type[] InferMethodArguments (ResolveContext ec, MethodBase method)
{
Type[] method_generic_args = method.GetGenericArguments ();
TypeInferenceContext context = new TypeInferenceContext (method_generic_args);
//
// 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) {
//
Type 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];
//
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 == TypeManager.null_type)
continue;
+ if (TypeManager.IsValueType (method_parameter)) {
+ score -= tic.LowerBoundInference (a.Type, method_parameter);
+ continue;
+ }
+
//
// Otherwise an output type inference is made
//
// 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, Type[] 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
t_i = t_i.GetGenericArguments () [0];
}
- MethodInfo mi = Delegate.GetInvokeMethod (t_i, t_i);
+ MethodInfo mi = Delegate.GetInvokeMethod (ec.Compiler, t_i, t_i);
Type rtype = mi.ReturnType;
#if MS_COMPATIBLE
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);
}
public class TypeInferenceContext
{
+ enum BoundKind
+ {
+ Exact = 0,
+ Lower = 1,
+ Upper = 2
+ }
+
+ class BoundInfo
+ {
+ public readonly Type Type;
+ public readonly BoundKind Kind;
+
+ public BoundInfo (Type 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 Type[] unfixed_types;
readonly Type[] fixed_types;
readonly ArrayList[] bounds;
}
}
+ //
+ // 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 Type [1];
+ unfixed_types = new Type [1];
+ unfixed_types[0] = InternalType.Arglist; // it can be any internal type
+ bounds = new ArrayList [1];
+ }
+
public Type[] InferredTypeArguments {
get {
return fixed_types;
}
}
- void AddToBounds (Type t, int index)
+ public void AddCommonTypeBound (Type 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];
a = new ArrayList ();
bounds [index] = a;
} else {
- if (a.Contains (t))
+ if (a.Contains (bound))
return;
}
// // t = constraints.EffectiveBaseClass;
// }
//}
- a.Add (t);
+ a.Add (bound);
}
bool AllTypesAreFixed (Type[] types)
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;
// 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)
if (bounds[i] == null)
continue;
- if (!FixType (i))
+ if (!FixType (ec, i))
return false;
fixed_any = true;
//
// 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, Type[] methodParameters, ref bool fixed_any)
{
ArrayList types_to_fix = new ArrayList (unfixed_types);
for (int i = 0; i < methodParameters.Length; ++i) {
Type t = methodParameters[i];
- if (t.IsGenericParameter)
- continue;
if (!TypeManager.IsDelegateType (t)) {
if (TypeManager.DropGenericTypeArguments (t) != TypeManager.expression_type)
t = t.GetGenericArguments () [0];
}
- MethodInfo invoke = Delegate.GetInvokeMethod (t, t);
+ if (t.IsGenericParameter)
+ continue;
+
+ MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, t, t);
Type rtype = invoke.ReturnType;
if (!rtype.IsGenericParameter && !rtype.IsGenericType)
continue;
continue;
int idx = IsUnfixed (t);
- if (idx >= 0 && !FixType (idx)) {
+ if (idx >= 0 && !FixType (ec, idx)) {
return false;
}
}
//
// 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)
if (candidates.Count == 1) {
unfixed_types[i] = null;
- fixed_types[i] = (Type)candidates[0];
+ Type t = ((BoundInfo) candidates[0]).Type;
+ if (t == TypeManager.null_type)
+ return false;
+
+ fixed_types [i] = t;
return true;
}
int cii;
int candidates_count = candidates.Count;
for (int ci = 0; ci < candidates_count; ++ci) {
- Type candidate = (Type)candidates [ci];
+ BoundInfo bound = (BoundInfo)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 = (BoundInfo) 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)
// 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, MethodInfo invoke, Type returnType)
{
if (returnType.IsGenericParameter) {
if (IsFixed (returnType))
return false;
} else if (returnType.IsGenericType) {
if (TypeManager.IsDelegateType (returnType)) {
- invoke = Delegate.GetInvokeMethod (returnType, returnType);
- return IsReturnTypeNonDependent (invoke, invoke.ReturnType);
+ invoke = Delegate.GetInvokeMethod (ec.Compiler, returnType, returnType);
+ return IsReturnTypeNonDependent (ec, invoke, invoke.ReturnType);
}
Type[] g_args = returnType.GetGenericArguments ();
// 26.3.3.9 Lower-bound Inference
//
public int LowerBoundInference (Type u, Type v)
+ {
+ return LowerBoundInference (u, v, false);
+ }
+
+ //
+ // Lower-bound (false) or Upper-bound (true) inference based on inversed argument
+ //
+ int LowerBoundInference (Type u, Type 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);
+ Type v_i;
+ Type u_i = TypeManager.GetElementType (u);
if (v.IsArray) {
if (u_dim != v.GetArrayRank ())
return 0;
- v_e = TypeManager.GetElementType (v);
+ v_i = TypeManager.GetElementType (v);
- if (u.IsByRef) {
- return LowerBoundInference (u_e, v_e);
- }
+ if (TypeManager.IsValueType (u_i))
+ return ExactInference (u_i, v_i);
- return ExactInference (u_e, v_e);
+ return LowerBoundInference (u_i, v_i, inversed);
}
if (u_dim != 1)
(g_v != TypeManager.generic_ienumerable_type))
return 0;
- v_e = TypeManager.GetTypeArguments (v)[0];
+ v_i = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (v) [0]);
+ if (TypeManager.IsValueType (u_i))
+ return ExactInference (u_i, v_i);
- if (u.IsByRef) {
- return LowerBoundInference (u_e, v_e);
- }
-
- return ExactInference (u_e, v_e);
+ return LowerBoundInference (u_i, v_i);
}
} else if (v.IsGenericType && !v.IsGenericTypeDefinition) {
//
- // if V is a constructed type C<V1..Vk> and there is a unique set of types U1..Uk
- // such that a standard implicit conversion exists from U to C<U1..Uk> then an exact
- // inference is made from each Ui for the corresponding Vi
+ // if V is a constructed type C<V1..Vk> and there is a unique type C<U1..Uk>
+ // such that U is identical to, inherits from (directly or indirectly),
+ // or implements (directly or indirectly) C<U1..Uk>
//
ArrayList u_candidates = new ArrayList ();
if (u.IsGenericType)
continue;
//
- // The unique set of types U1..Uk means that if we have an interface C<T>,
- // class U: C<int>, C<long> then no type inference is made when inferring
- // from U to C<T> because T could be int or long
+ // The unique set of types U1..Uk means that if we have an interface I<T>,
+ // class U : I<int>, I<long> then no type inference is made when inferring
+ // type I<T> by applying type U because T could be int or long
//
if (unique_candidate_targs != null) {
Type[] second_unique_candidate_targs = u_candidate.GetGenericArguments ();
unique_candidate_targs = second_unique_candidate_targs;
continue;
}
-
+
//
// This should always cause type inference failure
//
}
if (unique_candidate_targs != null) {
+ Type[] ga_open_v = open_v.GetGenericArguments ();
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 = TypeManager.GetTypeParameterVariance (ga_open_v [i]);
+
+ Type 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;
}
}
//
// 26.3.3.6 Output Type Inference
//
- public int OutputTypeInference (EmitContext ec, Expression e, Type t)
+ public int OutputTypeInference (ResolveContext ec, Expression e, Type 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);
+ MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, t, t);
if (rt == null) {
AParametersCollection pd = TypeManager.GetParameterData (invoke);
if (!TypeManager.IsDelegateType (t))
return 0;
- MethodInfo invoke = Delegate.GetInvokeMethod (t, t);
+ MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, t, t);
Type rtype = invoke.ReturnType;
#if MS_COMPATIBLE
// Blablabla, because reflection does not work with dynamic types
return 0;
MethodGroupExpr mg = (MethodGroupExpr) e;
- ArrayList args = DelegateCreation.CreateDelegateMethodArguments (invoke, e.Location);
+ Arguments args = DelegateCreation.CreateDelegateMethodArguments (TypeManager.GetParameterData (invoke), e.Location);
mg = mg.OverloadResolve (ec, ref args, true, e.Location);
if (mg == null)
return 0;
return LowerBoundInference (e.Type, t) * 2;
}
- static void RemoveDependentTypes (ArrayList types, Type returnType)
+ void RemoveDependentTypes (ArrayList types, Type returnType)
{
- if (returnType.IsGenericParameter) {
- types [returnType.GenericParameterPosition] = null;
+ int idx = IsUnfixed (returnType);
+ if (idx >= 0) {
+ types [idx] = null;
return;
}