}
}
+ public enum Variance
+ {
+ None,
+ Covariant,
+ Contravariant
+ }
+
public enum SpecialConstraint
{
Constructor,
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.decl = decl;
this.constraints = constraints;
+ this.variance = variance;
+ if (variance != Variance.None && !(decl is Interface) && !(decl is Delegate)) {
+ Report.Error (-36, loc, "Generic variance can only be used with interfaces and delegates");
+ }
}
public GenericConstraints GenericConstraints {
get { return decl; }
}
+ public Variance Variance {
+ get { return variance; }
+ }
+
public Type Type {
get { return type; }
}
gc = (GenericConstraints) constraints;
}
- if (gc == null)
- return true;
+ SetConstraints (type);
+ return true;
+ }
- if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
- type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
+ public void SetConstraints (GenericTypeParameterBuilder type)
+ {
+ GenericParameterAttributes attr = GenericParameterAttributes.None;
+ if (variance == Variance.Contravariant)
+ attr |= GenericParameterAttributes.Contravariant;
+ else if (variance == Variance.Covariant)
+ attr |= GenericParameterAttributes.Covariant;
- type.SetInterfaceConstraints (gc.InterfaceConstraints);
- type.SetGenericParameterAttributes (gc.Attributes);
- TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
+ if (gc != null) {
+ if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
+ type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
- return true;
+ attr |= gc.Attributes;
+ type.SetInterfaceConstraints (gc.InterfaceConstraints);
+ TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
+ }
+
+ type.SetGenericParameterAttributes (attr);
}
/// <summary>
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>
return ConstraintChecker.CheckConstraints (ec, open_type, gen_params, args.Arguments, loc);
}
+ static bool IsVariant (Type type)
+ {
+ return (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) != 0;
+ }
+
+ static bool IsCovariant (Type type)
+ {
+ return (type.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0;
+ }
+
+ static bool IsContravariant (Type type)
+ {
+ return (type.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0;
+ }
+
+ public bool VerifyVariantTypeParameters ()
+ {
+ for (int i = 0; i < args.Count; i++) {
+ Type argument = args.Arguments[i];
+ if (argument.IsGenericParameter && IsVariant (argument)) {
+ if (IsContravariant (argument) && !IsContravariant (gen_params[i])) {
+ Report.Error (-34, loc, "Contravariant type parameters can only be used " +
+ "as type arguments in contravariant positions");
+ return false;
+ }
+ else if (IsCovariant (argument) && !IsCovariant (gen_params[i])) {
+ Report.Error (-35, loc, "Covariant type parameters can only be used " +
+ "as type arguments in covariant positions");
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+
public override bool CheckAccessLevel (DeclSpace ds)
{
return ds.CheckAccessLevel (open_type);
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;