bool CheckConflictingInheritedConstraint (TypeSpec ba, TypeSpec bb, IMemberContext context, Location loc)
{
- if (!TypeManager.IsSubclassOf (ba, bb) && !TypeManager.IsSubclassOf (bb, ba)) {
+ if (!TypeSpec.IsBaseClass (ba, bb, false) && !TypeSpec.IsBaseClass (bb, ba, false)) {
context.Compiler.Report.Error (455, loc,
"Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
tparam.Value,
Constraints constraints;
GenericTypeParameterBuilder builder;
-// Variance variance;
TypeParameterSpec spec;
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);
}
+ public TypeParameter (TypeParameterSpec spec, DeclSpace parent, TypeSpec parentSpec, MemberName name, Attributes attrs)
+ : base (parent, name, attrs)
+ {
+ this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) {
+ BaseType = spec.BaseType,
+ InterfacesDefined = spec.InterfacesDefined,
+ TypeArguments = spec.TypeArguments
+ };
+ }
+
#region Properties
public override AttributeTargets AttributeTargets {
if (constraints != null)
return spec.HasSameConstraintsDefinition (tp.Type);
- constraints = new_constraints;
+ // 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;
}
constraints.CheckGenericConstraints (this);
}
- public TypeParameter CreateHoistedCopy (TypeSpec declaringType)
+ public TypeParameter CreateHoistedCopy (TypeContainer declaringType, TypeSpec declaringSpec)
{
- 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
- }
- };
+ return new TypeParameter (spec, declaringType, declaringSpec, MemberName, null);
}
public override bool Define ()
return MemberName.Name;
}
- public MemberCache LoadMembers (TypeSpec declaringType)
+ public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
{
throw new NotSupportedException ("Not supported for compiled definition");
}
if (constraints != null)
return constraints.Resolve (context, this);
- spec.BaseType = TypeManager.object_type;
+ if (spec.BaseType == null)
+ spec.BaseType = TypeManager.object_type;
+
return true;
}
// class A : I<int> { void Foo<X> where X : int {} }
//
bool found;
- if (BaseType != other.BaseType) {
+ if (!TypeSpecComparer.Override.IsEqual (BaseType, other.BaseType)) {
if (other.targs == null)
return false;
return constraints;
}
- public override MemberSpec InflateMember (TypeParameterInflator inflator)
+ public void InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec tps)
{
- var tps = (TypeParameterSpec) MemberwiseClone ();
tps.BaseType = inflator.Inflate (BaseType);
if (ifaces != null) {
- tps.ifaces = new TypeSpec[ifaces.Count];
+ tps.ifaces = new List<TypeSpec> (ifaces.Count);
for (int i = 0; i < ifaces.Count; ++i)
- tps.ifaces[i] = inflator.Inflate (ifaces[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 MemberSpec InflateMember (TypeParameterInflator inflator)
+ {
+ var tps = (TypeParameterSpec) MemberwiseClone ();
+ InflateConstraints (inflator, tps);
return tps;
}
}
}
+ public bool IsConvertibleToInterface (TypeSpec iface)
+ {
+ if (Interfaces != null) {
+ foreach (var t in Interfaces) {
+ if (t == iface)
+ return true;
+ }
+ }
+
+ if (TypeArguments != null) {
+ foreach (var t in TypeArguments) {
+ if (((TypeParameterSpec) t).IsConvertibleToInterface (iface))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public override TypeSpec Mutate (TypeParameterMutator mutator)
{
return mutator.Mutate (this);
// 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);
+ ts = MemberCache.FindNestedType (parent, ts.Name, ts.Arity);
//
// Handle the tricky case where parent shares local type arguments
}
// Inflate generic type
- if (ts.IsGeneric)
+ if (ts.Arity > 0)
return InflateTypeParameters (ts);
return ts;
if (tparams [i] == tp)
return targs[i];
- // CECIL: This can happen when inflating nested types
+ // This can happen when inflating nested types
// without type arguments specified
return tp;
}
this.var = var;
}
+ #region Properties
+
+ public TypeParameter[] MethodTypeParameters {
+ get {
+ return mvar;
+ }
+ }
+
+ #endregion
+
+ public static TypeSpec GetMemberDeclaringType (TypeSpec type)
+ {
+ if (type is InflatedTypeSpec) {
+ if (type.DeclaringType == null)
+ return type.GetDefinition ();
+
+ var parent = GetMemberDeclaringType (type.DeclaringType);
+ type = MemberCache.GetMember<TypeSpec> (parent, type);
+ }
+
+ return type;
+ }
+
public TypeSpec Mutate (TypeSpec ts)
{
TypeSpec value;
return value;
}
- public FieldInfo Mutate (FieldSpec fs)
- {
- // TODO:
- return fs.GetMetaInfo ();
- }
-
public TypeParameterSpec Mutate (TypeParameterSpec tp)
{
for (int i = 0; i < mvar.Length; ++i) {
}
}
- public override MemberCache MemberCacheTypes {
- get {
- if (cache == null)
- InitializeMemberCache (true);
-
- return cache;
- }
- }
-
//
// Types used to inflate the generic type
//
if (TypeManager.IsNullableType (open_type))
return targs[0].GetSignatureForError () + "?";
- if (MemberDefinition is AnonymousTypeClass)
- return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
-
return base.GetSignatureForError ();
}
protected override void InitializeMemberCache (bool onlyTypes)
{
if (cache == null)
- cache = new MemberCache (open_type.MemberCache);
+ cache = new MemberCache (onlyTypes ? open_type.MemberCacheTypes : open_type.MemberCache);
TypeParameterSpec[] tparams_full;
TypeSpec[] targs_full = targs;
// inflated because are not yet available in membercache
//
if ((state & StateFlags.PendingMemberCacheMembers) == 0) {
- open_type.MemberCache.InflateTypes (cache, inflator);
+ open_type.MemberCacheTypes.InflateTypes (cache, inflator);
//
// Inflate any implemented interfaces
public override bool Resolve (IMemberContext ec)
{
- // should not be called
- throw new NotSupportedException ();
+ // Nothing to be resolved
+ return true;
}
}
//
// Checks the constraints of open generic type against type
- // arguments. Has to be called onafter all members are defined
+ // arguments. Has to be called after all members have been defined
//
public bool CheckConstraints (IMemberContext ec)
{
if (constraints == null)
return true;
- return ConstraintChecker.CheckAll (open_type, args.Arguments, constraints, loc, ec.Compiler.Report);
+ return new ConstraintChecker(ec).CheckAll (open_type, args.Arguments, constraints, loc);
}
public override bool CheckAccessLevel (IMemberContext mc)
static bool HasDynamicArguments (TypeSpec[] args)
{
- foreach (var item in args) {
+ for (int i = 0; i < args.Length; ++i) {
+ var item = args[i];
+
if (item == InternalType.Dynamic)
return true;
if (TypeManager.IsGenericType (item))
return HasDynamicArguments (TypeManager.GetTypeArguments (item));
+
+ if (item.IsArray) {
+ while (item.IsArray) {
+ item = ((ArrayContainer) item).Element;
+ }
+
+ if (item == InternalType.Dynamic)
+ return true;
+ }
}
return false;
}
}
- static class ConstraintChecker
+ //
+ // Generic type with unbound type arguments, used for typeof (G<,,>)
+ //
+ class GenericOpenTypeExpr : TypeExpr
{
- /// <summary>
- /// Check the constraints; we're called from ResolveAsTypeTerminal()
- /// after fully resolving the constructed type.
- /// </summary>
- public static bool CheckAll (MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc, Report report)
+ public GenericOpenTypeExpr (TypeSpec type, /*UnboundTypeArguments args,*/ Location loc)
+ {
+ this.type = type.GetDefinition ();
+ this.loc = loc;
+ }
+
+ protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
+ {
+ return this;
+ }
+ }
+
+ struct ConstraintChecker
+ {
+ IMemberContext mc;
+ bool ignore_inferred_dynamic;
+
+ public ConstraintChecker (IMemberContext ctx)
+ {
+ this.mc = ctx;
+ ignore_inferred_dynamic = false;
+ }
+
+ #region Properties
+
+ public bool IgnoreInferredDynamic {
+ get {
+ return ignore_inferred_dynamic;
+ }
+ set {
+ ignore_inferred_dynamic = value;
+ }
+ }
+
+ #endregion
+
+ //
+ // Checks all type arguments againts type parameters constraints
+ // NOTE: It can run in probing mode when `mc' is null
+ //
+ public bool CheckAll (MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc)
{
for (int i = 0; i < tparams.Length; i++) {
- if (!CheckConstraint (context, targs [i], tparams [i], loc, report))
+ if (ignore_inferred_dynamic && targs[i] == InternalType.Dynamic)
+ continue;
+
+ if (!CheckConstraint (context, targs [i], tparams [i], loc))
return false;
}
return true;
}
- static bool CheckConstraint (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc, Report report)
+ bool CheckConstraint (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc)
{
//
// 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 ());
+ if (mc != null) {
+ mc.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 ());
+ }
+
return false;
}
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 ());
+ if (mc != null) {
+ mc.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 ());
+ }
+
return false;
}
+ bool ok = true;
+
//
- // The class constraint comes next.
+ // Check the class constraint
//
if (tparam.HasTypeConstraint) {
- CheckConversion (context, atype, tparam, tparam.BaseType, loc, report);
+ if (!CheckConversion (mc, context, atype, tparam, tparam.BaseType, loc)) {
+ if (mc == null)
+ return false;
+
+ ok = false;
+ }
}
//
- // Now, check the interfaces and type parameters constraints
+ // Check the interfaces constraints
//
if (tparam.Interfaces != null) {
if (TypeManager.IsNullableType (atype)) {
- report.Error (313, loc,
+ if (mc == null)
+ return false;
+
+ mc.Compiler.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 ());
+ ok = false;
} else {
foreach (TypeSpec iface in tparam.Interfaces) {
- CheckConversion (context, atype, tparam, iface, loc, report);
+ if (!CheckConversion (mc, context, atype, tparam, iface, loc)) {
+ if (mc == null)
+ return false;
+
+ ok = false;
+ }
+ }
+ }
+ }
+
+ //
+ // Check the type parameter constraint
+ //
+ if (tparam.TypeArguments != null) {
+ foreach (var ta in tparam.TypeArguments) {
+ if (!CheckConversion (mc, context, atype, tparam, ta, loc)) {
+ if (mc == null)
+ return false;
+
+ ok = false;
}
}
}
// Finally, check the constructor constraint.
//
if (!tparam.HasSpecialConstructor)
- return true;
+ return ok;
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 ());
+ if (mc != null) {
+ mc.Compiler.Report.SymbolRelatedToPreviousError (atype);
+ mc.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 ());
+ }
return false;
}
- return true;
+ return ok;
+ }
+
+ static bool HasDynamicTypeArgument (TypeSpec[] targs)
+ {
+ for (int i = 0; i < targs.Length; ++i) {
+ var targ = targs [i];
+ if (targ == InternalType.Dynamic)
+ return true;
+
+ if (HasDynamicTypeArgument (targ.TypeArguments))
+ return true;
+ }
+
+ return false;
}
- static void CheckConversion (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc, Report report)
+ bool CheckConversion (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc)
{
var expr = new EmptyExpression (atype);
- if (!Convert.ImplicitStandardConversionExists (expr, ttype)) {
- report.SymbolRelatedToPreviousError (tparam);
+ if (Convert.ImplicitStandardConversionExists (expr, ttype))
+ return true;
+
+ //
+ // When partial/full type inference finds a dynamic type argument delay
+ // the constraint check to runtime, it can succeed for real underlying
+ // dynamic type
+ //
+ if (ignore_inferred_dynamic && HasDynamicTypeArgument (ttype.TypeArguments))
+ return true;
+
+ if (mc != null) {
+ mc.Compiler.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}'",
+ mc.Compiler.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}'",
+ mc.Compiler.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}'",
+ mc.Compiler.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 ());
}
}
+
+ return false;
}
- static bool HasDefaultConstructor (TypeSpec atype)
+ bool HasDefaultConstructor (TypeSpec atype)
{
var tp = atype as TypeParameterSpec;
if (tp != null) {
{
TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations ();
string[] snames = new string [names.Length];
+ var block = m.Block;
for (int i = 0; i < names.Length; i++) {
string type_argument_name = names[i].Name;
- 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");
+ if (block == null) {
+ int idx = parameters.GetParameterIndexByName (type_argument_name);
+ if (idx >= 0) {
+ var b = m.Block;
+ if (b == null)
+ b = new ToplevelBlock (Compiler, Location);
+
+ b.Error_AlreadyDeclaredTypeParameter (type_argument_name, parameters[i].Location);
+ }
+ } else {
+ INamedBlockVariable variable = null;
+ block.GetLocalName (type_argument_name, m.Block, ref variable);
+ if (variable != null)
+ variable.Block.Error_AlreadyDeclaredTypeParameter (type_argument_name, variable.Location);
}
-
+
snames[i] = type_argument_name;
}
return Variance.None;
}
-
- /// <summary>
- /// 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.
- /// </summary>
- 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 (i_args.Length == 0)
- return 0;
-
- method = method.MakeGenericMethod (i_args);
- return 0;
- }
- }
-
- 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;
- }
-
- public static ATypeInference CreateInstance (Arguments arguments)
- {
- return new TypeInference (arguments);
- }
-
- public virtual int InferenceScore {
- get {
- return int.MaxValue;
- }
- }
-
- public abstract TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method);
}
//
// Implements C# type inference
//
- class TypeInference : ATypeInference
+ class TypeInference
{
//
// Tracks successful rate of type inference
//
int score = int.MaxValue;
+ readonly Arguments arguments;
+ readonly int arg_count;
public TypeInference (Arguments arguments)
- : base (arguments)
{
+ this.arguments = arguments;
+ if (arguments != null)
+ arg_count = arguments.Count;
}
- public override int InferenceScore {
+ public int InferenceScore {
get {
return score;
}
}
- public override TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method)
+ public TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method)
{
var method_generic_args = method.GenericDefinition.TypeParameters;
TypeInferenceContext context = new TypeInferenceContext (method_generic_args);
Upper = 2
}
- class BoundInfo
+ class BoundInfo : IEquatable<BoundInfo>
{
public readonly TypeSpec Type;
public readonly BoundKind Kind;
return Type.GetHashCode ();
}
- public override bool Equals (object obj)
+ #region IEquatable<BoundInfo> Members
+
+ public bool Equals (BoundInfo other)
{
- BoundInfo a = (BoundInfo) obj;
- return Type == a.Type && Kind == a.Kind;
+ return Type == other.Type && Kind == other.Kind;
}
+
+ #endregion
}
readonly TypeSpec[] unfixed_types;
var a = bounds [index];
if (a == null) {
- a = new List<BoundInfo> ();
+ a = new List<BoundInfo> (2);
+ a.Add (bound);
bounds [index] = a;
- } else {
- if (a.Contains (bound))
- return;
+ return;
}
- //
- // SPEC: does not cover type inference using constraints
- //
- //if (TypeManager.IsGenericParameter (t)) {
- // GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
- // if (constraints != null) {
- // //if (constraints.EffectiveBaseClass != null)
- // // t = constraints.EffectiveBaseClass;
- // }
- //}
+ if (a.Contains (bound))
+ return;
+
a.Add (bound);
}
}
if (bound.Kind == BoundKind.Exact || cbound.Kind == BoundKind.Exact) {
- if (cbound.Kind != BoundKind.Exact) {
+ if (cbound.Kind == BoundKind.Lower) {
if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) {
break;
}
continue;
}
+ if (cbound.Kind == BoundKind.Upper) {
+ if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
+ break;
+ }
+
+ continue;
+ }
if (bound.Kind != BoundKind.Exact) {
if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
}
if (bound.Kind == BoundKind.Lower) {
- if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) {
- break;
+ if (cbound.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;
+ }
+
+ bound = cbound;
}
- } else {
+
+ continue;
+ }
+
+ if (bound.Kind == BoundKind.Upper) {
if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
break;
}
+ } else {
+ throw new NotImplementedException ("variance conversion");
}
}
if (cii != candidates_count)
continue;
- if (best_candidate != null && best_candidate != bound.Type)
- return false;
+ //
+ // We already have the best candidate, break if thet are different
+ //
+ // Dynamic is never ambiguous as we prefer dynamic over other best candidate types
+ //
+ if (best_candidate != null) {
+
+ if (best_candidate == InternalType.Dynamic)
+ continue;
+
+ if (bound.Type != InternalType.Dynamic && best_candidate != bound.Type)
+ return false;
+ }
best_candidate = bound.Type;
}
}
//
- // 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 TypeSpec InflateGenericArgument (TypeSpec parameter)
{
var tp = parameter as TypeParameterSpec;
if (tp != null) {
//
- // Inflate method generic argument (MVAR) only
+ // Type inference work on generic arguments (MVAR) only
//
if (!tp.IsMethodOwned)
return parameter;
- return fixed_types [tp.DeclaredPosition];
+ return fixed_types [tp.DeclaredPosition] ?? parameter;
}
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) {
- inflated_targs[ii] = InflateGenericArgument (gt.TypeArguments [ii]);
+ var inflated = InflateGenericArgument (gt.TypeArguments [ii]);
+ if (inflated == null)
+ return null;
+
+ inflated_targs[ii] = inflated;
}
return gt.GetDefinition ().MakeGenericType (inflated_targs);
//
if (unique_candidate_targs != null) {
TypeSpec[] second_unique_candidate_targs = TypeManager.GetTypeArguments (u_candidate);
- if (TypeSpecComparer.Default.Equals (unique_candidate_targs, second_unique_candidate_targs)) {
+ if (TypeSpecComparer.Equals (unique_candidate_targs, second_unique_candidate_targs)) {
unique_candidate_targs = second_unique_candidate_targs;
continue;
}
// 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];
+ }
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;
- Arguments args = DelegateCreation.CreateDelegateMethodArguments (invoke.Parameters, e.Location);
- mg = mg.OverloadResolve (ec, ref args, true, e.Location);
+ Arguments args = DelegateCreation.CreateDelegateMethodArguments (invoke.Parameters, param_types, e.Location);
+ mg = mg.OverloadResolve (ec, ref args, null, OverloadResolver.Restrictions.CovariantDelegate | OverloadResolver.Restrictions.ProbingOnly);
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;
}
//