#endif
namespace Mono.CSharp {
+ public class VarianceDecl
+ {
+ public VarianceDecl (Variance variance, Location loc)
+ {
+ this.Variance = variance;
+ this.Location = loc;
+ }
+
+ public Variance Variance { get; private set; }
+ public Location Location { get; private set; }
+
+ public static Variance CheckTypeVariance (TypeSpec t, Variance expected, IMemberContext member)
+ {
+ var tp = t as TypeParameterSpec;
+ if (tp != null) {
+ var 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);
+ }
+
+ return expected;
+ }
+
+ if (t.TypeArguments.Length > 0) {
+ var targs_definition = t.MemberDefinition.TypeParameters;
+ TypeSpec[] targs = TypeManager.GetTypeArguments (t);
+ for (int i = 0; i < targs.Length; ++i) {
+ var v = targs_definition[i].Variance;
+ CheckTypeVariance (targs[i], (Variance) ((int) v * (int) expected), member);
+ }
+
+ return expected;
+ }
+
+ var ac = t as ArrayContainer;
+ if (ac != null)
+ return CheckTypeVariance (ac.Element, expected, member);
+
+ return Variance.None;
+ }
+ }
+
public enum Variance
{
//
//
public class Constraints
{
- SimpleMemberName tparam;
- List<FullNamedExpression> constraints;
- Location loc;
+ readonly SimpleMemberName tparam;
+ readonly List<FullNamedExpression> constraints;
+ readonly Location loc;
bool resolved;
bool resolving;
// is valid with respect to T
//
if (tp.IsMethodTypeParameter) {
- TypeManager.CheckTypeVariance (type, Variance.Contravariant, context);
+ VarianceDecl.CheckTypeVariance (type, Variance.Contravariant, context);
}
var tp_def = constraint_tp.MemberDefinition as TypeParameter;
if (type.IsSealed || !type.IsClass) {
context.Module.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));
+ type.GetSignatureForError ());
continue;
}
//
public class TypeParameter : MemberCore, ITypeDefinition
{
- static readonly string[] attribute_target = new string [] { "type parameter" };
+ static readonly string[] attribute_target = { "type parameter" };
Constraints constraints;
GenericTypeParameterBuilder builder;
- TypeParameterSpec spec;
+ readonly TypeParameterSpec spec;
- public TypeParameter (int index, MemberName name, Constraints constraints, Attributes attrs, Variance variance)
+ public TypeParameter (int index, MemberName name, Constraints constraints, Attributes attrs, Variance Variance)
: base (null, name, attrs)
{
this.constraints = constraints;
- this.spec = new TypeParameterSpec (null, index, this, SpecialConstraint.None, variance, null);
+ this.spec = new TypeParameterSpec (null, index, this, SpecialConstraint.None, Variance, null);
}
//
// Used by parser
//
- public TypeParameter (MemberName name, Attributes attrs, Variance variance)
+ public TypeParameter (MemberName name, Attributes attrs, VarianceDecl variance)
: base (null, name, attrs)
{
- this.spec = new TypeParameterSpec (null, -1, this, SpecialConstraint.None, variance, null);
+ var var = variance == null ? Variance.None : variance.Variance;
+ this.spec = new TypeParameterSpec (null, -1, this, SpecialConstraint.None, var, null);
+ this.VarianceDecl = variance;
}
-
+
public TypeParameter (TypeParameterSpec spec, TypeSpec parentSpec, MemberName name, Attributes attrs)
: base (null, name, attrs)
{
TypeArguments = spec.TypeArguments
};
}
-
+
#region Properties
public override AttributeTargets AttributeTargets {
}
}
+ public VarianceDecl VarianceDecl { get; private set; }
+
#endregion
//
//
// 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.
+ // have constraints, we must check that they're same.
//
public bool AddPartialConstraints (TypeDefinition part, TypeParameter tp)
{
// Copy constraint from resolved part to partial container
spec.SpecialConstraint = tp.spec.SpecialConstraint;
- spec.Interfaces = tp.spec.Interfaces;
+ spec.InterfacesDefined = tp.spec.InterfacesDefined;
spec.TypeArguments = tp.spec.TypeArguments;
spec.BaseType = tp.spec.BaseType;
// with SRE (by calling `DefineGenericParameters()' on the TypeBuilder /
// MethodBuilder).
//
- public void Define (GenericTypeParameterBuilder type, TypeSpec declaringType, TypeContainer parent)
+ public void Create (TypeSpec declaringType, TypeContainer parent)
{
if (builder != null)
throw new InternalErrorException ();
// Needed to get compiler reference
this.Parent = parent;
- this.builder = type;
spec.DeclaringType = declaringType;
+ }
+
+ public void Define (GenericTypeParameterBuilder type)
+ {
+ this.builder = type;
spec.SetMetaInfo (type);
}
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 ());
+ if (spec.TypeArguments != null) {
+ var meta_constraints = new List<MetaType> (spec.TypeArguments.Length);
+ foreach (var c in spec.TypeArguments) {
+ //
+ // Inflated type parameters can collide with special constraint types, don't
+ // emit any such type parameter.
+ //
+ if (c.BuiltinType == BuiltinTypeSpec.Type.Object || c.BuiltinType == BuiltinTypeSpec.Type.ValueType)
+ continue;
+
+ meta_constraints.Add (c.GetMetaInfo ());
+ }
+
+ builder.SetInterfaceConstraints (meta_constraints.ToArray ());
+ }
builder.SetGenericParameterAttributes (attr);
}
}
}
}
+ } else if (ifaces_defined == null) {
+ ifaces_defined = ifaces == null ? TypeSpec.EmptyTypes : ifaces.ToArray ();
}
//
}
}
- if (ifaces_defined == null)
- ifaces_defined = ifaces == null ? TypeSpec.EmptyTypes : ifaces.ToArray ();
-
state |= StateFlags.InterfacesExpanded;
}
public TypeSpec[] InterfacesDefined {
get {
if (ifaces_defined == null) {
- if (ifaces == null)
- return null;
-
- ifaces_defined = ifaces.ToArray ();
+ ifaces_defined = ifaces == null ? TypeSpec.EmptyTypes : ifaces.ToArray ();
}
return ifaces_defined.Length == 0 ? null : ifaces_defined;
tps.ifaces_defined = new TypeSpec[defined.Length];
for (int i = 0; i < defined.Length; ++i)
tps.ifaces_defined [i] = inflator.Inflate (defined[i]);
+ } else if (ifaces_defined == TypeSpec.EmptyTypes) {
+ tps.ifaces_defined = TypeSpec.EmptyTypes;
}
var ifaces = Interfaces;
tps.ifaces = new List<TypeSpec> (ifaces.Count);
for (int i = 0; i < ifaces.Count; ++i)
tps.ifaces.Add (inflator.Inflate (ifaces[i]));
+ tps.state |= StateFlags.InterfacesExpanded;
}
if (targs != null) {
public override MemberSpec InflateMember (TypeParameterInflator inflator)
{
var tps = (TypeParameterSpec) MemberwiseClone ();
+#if DEBUG
+ tps.ID += 1000000;
+#endif
+
InflateConstraints (inflator, tps);
return tps;
}
return ac;
}
+ if (type.Kind == MemberKind.MissingType)
+ return type;
+
//
// When inflating a nested type, inflate its parent first
// in case it's using same type parameters (was inflated within the type)
{
readonly TypeParameters mvar;
readonly TypeParameters var;
+ readonly TypeParameterSpec[] src;
Dictionary<TypeSpec, TypeSpec> mutated_typespec;
public TypeParameterMutator (TypeParameters mvar, TypeParameters var)
this.var = var;
}
+ public TypeParameterMutator (TypeParameterSpec[] srcVar, TypeParameters destVar)
+ {
+ if (srcVar.Length != destVar.Count)
+ throw new ArgumentException ();
+
+ this.src = srcVar;
+ this.var = destVar;
+ }
+
#region Properties
public TypeParameters MethodTypeParameters {
public TypeParameterSpec Mutate (TypeParameterSpec tp)
{
- for (int i = 0; i < mvar.Count; ++i) {
- if (mvar[i].Type == tp)
- return var[i].Type;
+ if (mvar != null) {
+ for (int i = 0; i < mvar.Count; ++i) {
+ if (mvar[i].Type == tp)
+ return var[i].Type;
+ }
+ } else {
+ for (int i = 0; i < src.Length; ++i) {
+ if (src[i] == tp)
+ return var[i].Type;
+ }
}
return tp;
}
}
- public override bool IsGenericIterateInterface {
+ public override bool IsArrayGenericInterface {
get {
return (open_type.state & StateFlags.GenericIterateInterface) != 0;
}
return false;
}
- TypeParameterInflator CreateLocalInflator (IModuleContext context)
+ public TypeParameterInflator CreateLocalInflator (IModuleContext context)
{
TypeParameterSpec[] tparams_full;
TypeSpec[] targs_full = targs;
return new TypeParameterInflator (context, this, tparams_full, targs_full);
}
- MetaType CreateMetaInfo (TypeParameterMutator mutator)
+ MetaType CreateMetaInfo ()
{
//
// Converts nested type arguments into right order
public override MetaType GetMetaInfo ()
{
if (info == null)
- info = CreateMetaInfo (null);
+ info = CreateMetaInfo ();
return info;
}
names.AddRange (tparams.names);
}
- public void Define (GenericTypeParameterBuilder[] buiders, TypeSpec declaringType, int parentOffset, TypeContainer parent)
+ public void Create (TypeSpec declaringType, int parentOffset, TypeContainer parent)
{
types = new TypeParameterSpec[Count];
for (int i = 0; i < types.Length; ++i) {
var tp = names[i];
- tp.Define (buiders[i + parentOffset], declaringType, parent);
+ tp.Create (declaringType, parent);
types[i] = tp.Type;
types[i].DeclaredPosition = i + parentOffset;
}
}
+ public void Define (GenericTypeParameterBuilder[] builders)
+ {
+ for (int i = 0; i < types.Length; ++i) {
+ var tp = names[i];
+ tp.Define (builders [types [i].DeclaredPosition]);
+ }
+ }
+
public TypeParameter this[int index] {
get {
return names [index];
return sb.ToString ();
}
+
+ public void CheckPartialConstraints (Method part)
+ {
+ var partTypeParameters = part.CurrentTypeParameters;
+
+ for (int i = 0; i < Count; i++) {
+ var tp_a = names[i];
+ var tp_b = partTypeParameters [i];
+ if (tp_a.Constraints == null) {
+ if (tp_b.Constraints == null)
+ continue;
+ } else if (tp_b.Constraints != null && tp_a.Type.HasSameConstraintsDefinition (tp_b.Type)) {
+ continue;
+ }
+
+ part.Compiler.Report.SymbolRelatedToPreviousError (this[i].CurrentMemberDefinition.Location, "");
+ part.Compiler.Report.Error (761, part.Location,
+ "Partial method declarations of `{0}' have inconsistent constraints for type parameter `{1}'",
+ part.GetSignatureForError (), partTypeParameters[i].GetSignatureForError ());
+ }
+ }
+
+ public void UpdateConstraints (TypeDefinition part)
+ {
+ var partTypeParameters = part.MemberName.TypeParameters;
+
+ for (int i = 0; i < Count; i++) {
+ var tp = names [i];
+ if (tp.AddPartialConstraints (part, partTypeParameters [i]))
+ continue;
+
+ part.Compiler.Report.SymbolRelatedToPreviousError (this[i].CurrentMemberDefinition);
+ part.Compiler.Report.Error (265, part.Location,
+ "Partial declarations of `{0}' have inconsistent constraints for type parameter `{1}'",
+ part.GetSignatureForError (), tp.GetSignatureForError ());
+ }
+ }
+
public void VerifyClsCompliance ()
{
foreach (var tp in names) {
public override string GetSignatureForError ()
{
- return TypeManager.CSharpName (type);
+ return type.GetSignatureForError ();
}
public override TypeSpec ResolveAsType (IMemberContext mc)
if (mc != null) {
mc.Module.Compiler.Report.Error (452, loc,
"The type `{0}' must be a reference type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
- TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+ atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ());
}
return false;
if (mc != null) {
mc.Module.Compiler.Report.Error (453, loc,
"The type `{0}' must be a non-nullable value type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
- TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+ atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ());
}
return false;
//
// Check the interfaces constraints
//
- if (tparam.Interfaces != null) {
- foreach (TypeSpec iface in tparam.Interfaces) {
+ if (tparam.InterfacesDefined != null) {
+ foreach (TypeSpec iface in tparam.InterfacesDefined) {
if (!CheckConversion (mc, context, atype, tparam, iface, loc)) {
if (mc == null)
return false;
mc.Module.Compiler.Report.SymbolRelatedToPreviousError (atype);
mc.Module.Compiler.Report.Error (310, loc,
"The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'",
- TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+ atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ());
}
return false;
}
}
}
- 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);
- }
-
- return expected;
- }
-
- 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 expected;
- }
-
- if (t.IsArray)
- return CheckTypeVariance (GetElementType (t), expected, member);
-
- return Variance.None;
- }
- }
-
//
// Implements C# type inference
//
//
AnonymousMethodExpression am = a.Expr as AnonymousMethodExpression;
if (am != null) {
- if (am.ExplicitTypeInference (ec, tic, method_parameter))
+ if (am.ExplicitTypeInference (tic, method_parameter))
--score;
continue;
}
var mi = Delegate.GetInvokeMethod (t_i);
TypeSpec rtype = mi.ReturnType;
- if (tic.IsReturnTypeNonDependent (ec, mi, rtype)) {
+ if (tic.IsReturnTypeNonDependent (mi, rtype)) {
// It can be null for default arguments
if (arguments[i] == null)
continue;
public void AddCommonTypeBound (TypeSpec type)
{
- AddToBounds (new BoundInfo (type, BoundKind.Lower), 0);
+ AddToBounds (new BoundInfo (type, BoundKind.Lower), 0, false);
+ }
+
+ public void AddCommonTypeBoundAsync (TypeSpec type)
+ {
+ AddToBounds (new BoundInfo (type, BoundKind.Lower), 0, true);
}
- void AddToBounds (BoundInfo bound, int index)
+ void AddToBounds (BoundInfo bound, int index, bool voidAllowed)
{
//
// Some types cannot be used as type arguments
//
- if (bound.Type.Kind == MemberKind.Void || bound.Type.IsPointer || bound.Type.IsSpecialRuntimeType ||
+ if ((bound.Type.Kind == MemberKind.Void && !voidAllowed) || bound.Type.IsPointer || bound.Type.IsSpecialRuntimeType ||
bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod)
return;
if (pos == -1)
return 0;
- AddToBounds (new BoundInfo (u, BoundKind.Exact), pos);
+ AddToBounds (new BoundInfo (u, BoundKind.Exact), pos, false);
return 1;
}
}
//
- // Determines a unique type from which there is
- // a standard implicit conversion to all the other
- // candidate types.
+ // The set of candidate types Uj starts out as the set of
+ // all types in the set of bounds for Xi
//
- TypeSpec best_candidate = null;
- int cii;
- int candidates_count = candidates.Count;
- for (int ci = 0; ci < candidates_count; ++ci) {
- BoundInfo bound = candidates [ci];
- for (cii = 0; cii < candidates_count; ++cii) {
- if (cii == ci)
- continue;
+ var applicable = new bool [candidates.Count];
+ for (int ci = 0; ci < applicable.Length; ++ci)
+ applicable [ci] = true;
+
+ for (int ci = 0; ci < applicable.Length; ++ci) {
+ var bound = candidates [ci];
+ int cii = 0;
+
+ switch (bound.Kind) {
+ case BoundKind.Exact:
+ for (; cii != applicable.Length; ++cii) {
+ if (ci == cii)
+ continue;
- BoundInfo cbound = candidates[cii];
-
- // Same type parameters with different bounds
- if (cbound.Type == bound.Type) {
- if (bound.Kind != BoundKind.Exact)
- bound = cbound;
+ if (!applicable[cii])
+ break;
- continue;
+ //
+ // For each exact bound U of Xi all types Uj which are not identical
+ // to U are removed from the candidate set
+ //
+ if (candidates [cii].Type != bound.Type)
+ applicable[cii] = false;
}
- if (bound.Kind == BoundKind.Exact || cbound.Kind == BoundKind.Exact) {
- if (cbound.Kind == BoundKind.Lower) {
- if (!Convert.ImplicitConversionExists (ec, cbound.GetTypeExpression (), bound.Type)) {
- break;
- }
-
+ break;
+ case BoundKind.Lower:
+ for (; cii != applicable.Length; ++cii) {
+ if (ci == cii)
continue;
- }
- if (cbound.Kind == BoundKind.Upper) {
- if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), cbound.Type)) {
- break;
- }
- continue;
+ if (!applicable[cii])
+ break;
+
+ //
+ // For each lower bound U of Xi all types Uj to which there is not an implicit conversion
+ // from U are removed from the candidate set
+ //
+ if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), candidates [cii].Type)) {
+ applicable[cii] = false;
}
-
- if (bound.Kind != BoundKind.Exact) {
- if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), cbound.Type)) {
- break;
- }
+ }
+
+ break;
- bound = cbound;
+ case BoundKind.Upper:
+ for (; cii != applicable.Length; ++cii) {
+ if (ci == cii)
continue;
- }
-
- break;
+
+ if (!applicable[cii])
+ break;
+
+ //
+ // For each upper bound U of Xi all types Uj from which there is not an implicit conversion
+ // to U are removed from the candidate set
+ //
+ if (!Convert.ImplicitConversionExists (ec, candidates[cii].GetTypeExpression (), bound.Type))
+ applicable[cii] = false;
}
- if (bound.Kind == BoundKind.Lower) {
- if (cbound.Kind == BoundKind.Lower) {
- if (!Convert.ImplicitConversionExists (ec, cbound.GetTypeExpression (), bound.Type)) {
- break;
- }
- } else {
- if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), cbound.Type)) {
- break;
- }
+ break;
+ }
+ }
- bound = cbound;
- }
+ TypeSpec best_candidate = null;
+ for (int ci = 0; ci < applicable.Length; ++ci) {
+ if (!applicable[ci])
+ continue;
+
+ var bound = candidates [ci];
+ if (bound.Type == best_candidate)
+ continue;
+ int cii = 0;
+ for (; cii < applicable.Length; ++cii) {
+ if (ci == cii)
continue;
- }
- if (bound.Kind == BoundKind.Upper) {
- if (!Convert.ImplicitConversionExists (ec, bound.GetTypeExpression (), cbound.Type)) {
- break;
- }
- } else {
- throw new NotImplementedException ("variance conversion");
- }
+ if (!applicable[cii])
+ continue;
+
+ if (!Convert.ImplicitConversionExists (ec, candidates[cii].GetTypeExpression (), bound.Type))
+ break;
}
- if (cii != candidates_count)
+ if (cii != applicable.Length)
continue;
//
- // We already have the best candidate, break if thet are different
+ // We already have the best candidate, break if it's different (non-unique)
//
// Dynamic is never ambiguous as we prefer dynamic over other best candidate types
//
// Tests whether all delegate input arguments are fixed and generic output type
// requires output type inference
//
- public bool IsReturnTypeNonDependent (ResolveContext ec, MethodSpec invoke, TypeSpec returnType)
+ public bool IsReturnTypeNonDependent (MethodSpec invoke, TypeSpec returnType)
{
+ AParametersCollection d_parameters = invoke.Parameters;
+
+ if (d_parameters.IsEmpty)
+ return true;
+
while (returnType.IsArray)
returnType = ((ArrayContainer) returnType).Element;
if (IsFixed (returnType))
return false;
} else if (TypeManager.IsGenericType (returnType)) {
- if (returnType.IsDelegate) {
- invoke = Delegate.GetInvokeMethod (returnType);
- return IsReturnTypeNonDependent (ec, invoke, invoke.ReturnType);
- }
-
TypeSpec[] g_args = TypeManager.GetTypeArguments (returnType);
// At least one unfixed return type has to exist
}
// All generic input arguments have to be fixed
- AParametersCollection d_parameters = invoke.Parameters;
return AllTypesAreFixed (d_parameters.Types);
}
-
+
bool IsFixed (TypeSpec type)
{
return IsUnfixed (type) == -1;
// If V is one of the unfixed type arguments
int pos = IsUnfixed (v);
if (pos != -1) {
- AddToBounds (new BoundInfo (u, inversed ? BoundKind.Upper : BoundKind.Lower), pos);
+ AddToBounds (new BoundInfo (u, inversed ? BoundKind.Upper : BoundKind.Lower), pos, false);
return 1;
}
return LowerBoundInference (u_ac.Element, v_ac.Element, inversed);
}
- if (u_ac.Rank != 1 || !v.IsGenericIterateInterface)
+ if (u_ac.Rank != 1 || !v.IsArrayGenericInterface)
return 0;
var v_i = TypeManager.GetTypeArguments (v) [0];
var invoke = Delegate.GetInvokeMethod (t);
TypeSpec rtype = invoke.ReturnType;
- if (!rtype.IsGenericParameter && !TypeManager.IsGenericType (rtype))
+ if (!IsReturnTypeNonDependent (invoke, rtype))
return 0;
// LAMESPEC: Standard does not specify that all methodgroup arguments
if (inflated == null)
return 0;
- if (IsUnfixed (inflated) >= 0)
- return 0;
-
param_types[i] = inflated;
}
MethodGroupExpr mg = (MethodGroupExpr) e;
- Arguments args = DelegateCreation.CreateDelegateMethodArguments (invoke.Parameters, param_types, e.Location);
+ Arguments args = DelegateCreation.CreateDelegateMethodArguments (ec, invoke.Parameters, param_types, e.Location);
mg = mg.OverloadResolve (ec, ref args, null, OverloadResolver.Restrictions.CovariantDelegate | OverloadResolver.Restrictions.ProbingOnly);
if (mg == null)
return 0;