if (resolved)
return true;
- iface_constraints = new ArrayList ();
+ iface_constraints = new ArrayList (2); // TODO: Too expensive allocation
type_param_constraints = new ArrayList ();
foreach (object obj in constraints) {
type_param_constraints.Add (expr);
else if (expr.IsInterface)
iface_constraints.Add (expr);
- else if (class_constraint != null) {
+ else if (class_constraint != null || iface_constraints.Count != 0) {
Report.Error (406, loc,
- "`{0}': the class constraint for `{1}' " +
- "must come before any other constraints.",
- expr.GetSignatureForError (), name);
+ "The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list",
+ expr.GetSignatureForError ());
return false;
} else if (HasReferenceTypeConstraint || HasValueTypeConstraint) {
Report.Error (450, loc, "`{0}': cannot specify both " +
else
effective_base_type = TypeManager.object_type;
+ if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
+ attrs |= GenericParameterAttributes.DefaultConstructorConstraint;
+
resolved = true;
return true;
}
- bool CheckTypeParameterConstraints (TypeParameter tparam, Hashtable seen)
+ bool CheckTypeParameterConstraints (TypeParameter tparam, ref TypeExpr prevConstraint, ArrayList seen)
{
- seen.Add (tparam, true);
+ seen.Add (tparam);
Constraints constraints = tparam.Constraints;
if (constraints == null)
return true;
if (constraints.HasValueTypeConstraint) {
- Report.Error (456, loc, "Type parameter `{0}' has " +
- "the `struct' constraint, so it cannot " +
- "be used as a constraint for `{1}'",
- tparam.Name, name);
+ Report.Error (456, loc,
+ "Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'",
+ tparam.Name, name);
return false;
}
+ //
+ // Checks whether there are no conflicts between type parameter constraints
+ //
+ // class Foo<T, U>
+ // where T : A
+ // where U : A, B // A and B are not convertible
+ //
+ if (constraints.HasClassConstraint) {
+ if (prevConstraint != null) {
+ Type t2 = constraints.ClassConstraint;
+ TypeExpr e2 = constraints.class_constraint;
+
+ if (!Convert.ImplicitReferenceConversionExists (prevConstraint, t2) &&
+ !Convert.ImplicitReferenceConversionExists (e2, prevConstraint.Type)) {
+ Report.Error (455, loc,
+ "Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
+ name, TypeManager.CSharpName (prevConstraint.Type), TypeManager.CSharpName (t2));
+ return false;
+ }
+ }
+
+ prevConstraint = constraints.class_constraint;
+ }
+
if (constraints.type_param_constraints == null)
return true;
return false;
}
- if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
+ if (!CheckTypeParameterConstraints (expr.TypeParameter, ref prevConstraint, seen))
return false;
}
return false;
}
- foreach (TypeParameterExpr expr in type_param_constraints) {
- Hashtable seen = new Hashtable ();
- if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
- return false;
+ if (type_param_constraints.Count != 0) {
+ ArrayList seen = new ArrayList ();
+ TypeExpr prev_constraint = class_constraint;
+ foreach (TypeParameterExpr expr in type_param_constraints) {
+ if (!CheckTypeParameterConstraints (expr.TypeParameter, ref prev_constraint, seen))
+ return false;
+ seen.Clear ();
+ }
}
for (int i = 0; i < iface_constraints.Count; ++i) {
return true;
}
- /// <summary>
- /// Check whether there are no conflicts in our type parameter constraints.
- ///
- /// This is an example:
- ///
- /// class Foo<T,U>
- /// where T : class
- /// where U : T, struct
- /// </summary>
- public bool CheckDependencies ()
- {
- foreach (TypeParameterExpr expr in type_param_constraints) {
- if (!CheckDependencies (expr.TypeParameter))
- return false;
- }
-
- return true;
- }
-
- bool CheckDependencies (TypeParameter tparam)
- {
- Constraints constraints = tparam.Constraints;
- if (constraints == null)
- return true;
-
- if (HasValueTypeConstraint && constraints.HasClassConstraint) {
- Report.Error (455, loc, "Type parameter `{0}' inherits " +
- "conflicting constraints `{1}' and `{2}'",
- name, TypeManager.CSharpName (constraints.ClassConstraint),
- "System.ValueType");
- return false;
- }
-
- if (HasClassConstraint && constraints.HasClassConstraint) {
- Type t1 = ClassConstraint;
- TypeExpr e1 = class_constraint;
- Type t2 = constraints.ClassConstraint;
- TypeExpr e2 = constraints.class_constraint;
-
- if (!Convert.ImplicitReferenceConversionExists (e1, t2) &&
- !Convert.ImplicitReferenceConversionExists (e2, t1)) {
- Report.Error (455, loc,
- "Type parameter `{0}' inherits " +
- "conflicting constraints `{1}' and `{2}'",
- name, TypeManager.CSharpName (t1), TypeManager.CSharpName (t2));
- return false;
- }
- }
-
- if (constraints.type_param_constraints == null)
- return true;
-
- foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
- if (!CheckDependencies (expr.TypeParameter))
- return false;
- }
-
- return true;
- }
-
public override GenericParameterAttributes Attributes {
get { return attrs; }
}
/// method. To do that, we're called on each of the implementing method's
/// type parameters.
/// </summary>
- public bool CheckInterfaceMethod (GenericConstraints gc)
+ public bool AreEqual (GenericConstraints gc)
{
if (gc.Attributes != attrs)
return false;
if (constraints != null) {
if (temp_gc == null)
ok = false;
- else if (!constraints.CheckInterfaceMethod (gc))
+ else if (!constraints.AreEqual (gc))
ok = false;
} else {
if (!is_override && (temp_gc != null))
if (gc == null)
return true;
- if (gc.HasClassConstraint)
- type.SetBaseTypeConstraint (gc.ClassConstraint);
+ if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
+ type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
type.SetInterfaceConstraints (gc.InterfaceConstraints);
type.SetGenericParameterAttributes (gc.Attributes);
return true;
}
- /// <summary>
- /// Check whether there are no conflicts in our type parameter constraints.
- ///
- /// This is an example:
- ///
- /// class Foo<T,U>
- /// where T : class
- /// where U : T, struct
- /// </summary>
- public bool CheckDependencies ()
- {
- if (constraints != null)
- return constraints.CheckDependencies ();
-
- return true;
- }
-
/// <summary>
/// This is called for each part of a partial generic type definition.
///
return false;
if (constraints != null)
- return constraints.CheckInterfaceMethod (new_constraints);
+ return constraints.AreEqual (new_constraints);
constraints = new_constraints;
return true;
if (t == null)
return null;
if (t.IsGenericParameter)
- return dargs [t.GenericParameterPosition];
+ return t.GenericParameterPosition < dargs.Length ? dargs [t.GenericParameterPosition] : t;
if (t.IsGenericType) {
Type[] args = t.GetGenericArguments ();
Type[] inflated = new Type [args.Length];
protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
{
- type = type_parameter.Type;
+ throw new NotSupportedException ();
+ }
+ public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
+ {
+ type = type_parameter.Type;
+ eclass = ExprClass.TypeParameter;
return this;
}
Type[] atypes;
int dimension;
bool has_type_args;
- bool created;
public TypeArguments (Location loc)
{
public void Add (Expression type)
{
- if (created)
- throw new InvalidOperationException ();
-
args.Add (type);
}
public void Add (TypeArguments new_args)
{
- if (created)
- throw new InvalidOperationException ();
-
args.AddRange (new_args.args);
}
return false;
}
- if (te.Type.IsPointer) {
- Report.Error (306, Location, "The type `{0}' may not be used " +
- "as a type argument", TypeManager.CSharpName (te.Type));
+ if (te.Type.IsPointer || TypeManager.IsSpecialType (te.Type)) {
+ Report.Error (306, Location,
+ "The type `{0}' may not be used as a type argument",
+ TypeManager.CSharpName (te.Type));
return false;
}
public override string GetSignatureForError ()
{
- return TypeManager.RemoveGenericArity (gt.FullName) + "<" + args.GetSignatureForError () + ">";
+ return TypeManager.CSharpName (type);
}
protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
if (Convert.ImplicitStandardConversionExists (expr, ctype))
return true;
- Error_TypeMustBeConvertible (expr.Type, ctype, ptype);
+ Report_SymbolRelatedToPreviousError ();
+ Report.SymbolRelatedToPreviousError (expr.Type);
+
+ if (TypeManager.IsNullableType (expr.Type) && ctype.IsInterface) {
+ Report.Error (313, loc,
+ "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. " +
+ "The nullable type `{0}' never satisfies interface constraint of type `{3}'",
+ TypeManager.CSharpName (expr.Type), TypeManager.CSharpName (ptype),
+ GetSignatureForError (), TypeManager.CSharpName (ctype));
+ } else {
+ Report.Error (309, loc,
+ "The type `{0}' must be convertible to `{1}' in order to " +
+ "use it as parameter `{2}' in the generic type or method `{3}'",
+ TypeManager.CSharpName (expr.Type), TypeManager.CSharpName (ctype),
+ TypeManager.CSharpName (ptype), GetSignatureForError ());
+ }
return false;
}
- bool HasDefaultConstructor (Type atype)
+ static bool HasDefaultConstructor (Type atype)
{
+ TypeParameter tparam = TypeManager.LookupTypeParameter (atype);
+ if (tparam != null) {
+ if (tparam.GenericConstraints == null)
+ return false;
+
+ return tparam.GenericConstraints.HasConstructorConstraint ||
+ tparam.GenericConstraints.HasValueTypeConstraint;
+ }
+
if (atype.IsAbstract)
return false;
}
}
- TypeParameter tparam = TypeManager.LookupTypeParameter (atype);
- if (tparam != null) {
- if (tparam.GenericConstraints == null)
- return false;
-
- return tparam.GenericConstraints.HasConstructorConstraint ||
- tparam.GenericConstraints.HasValueTypeConstraint;
- }
-
MemberInfo [] list = TypeManager.MemberLookup (null, null, atype, MemberTypes.Constructor,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
ConstructorInfo.ConstructorName, null);
return false;
foreach (MethodBase mb in list) {
- ParameterData pd = TypeManager.GetParameterData (mb);
+ AParametersCollection pd = TypeManager.GetParameterData (mb);
if (pd.Count == 0)
return true;
}
protected abstract string GetSignatureForError ();
protected abstract void Report_SymbolRelatedToPreviousError ();
- void Error_TypeMustBeConvertible (Type atype, Type gc, Type ptype)
- {
- Report_SymbolRelatedToPreviousError ();
- Report.SymbolRelatedToPreviousError (atype);
- Report.Error (309, loc,
- "The type `{0}' must be convertible to `{1}' in order to " +
- "use it as parameter `{2}' in the generic type or method `{3}'",
- TypeManager.CSharpName (atype), TypeManager.CSharpName (gc),
- TypeManager.CSharpName (ptype), GetSignatureForError ());
- }
-
public static bool CheckConstraints (EmitContext ec, MethodBase definition,
MethodBase instantiated, Location loc)
{
/// Define and resolve the type parameters.
/// We're called from Method.Define().
/// </summary>
- public bool Define (MethodBuilder mb, ToplevelBlock block)
+ public bool Define (MethodBuilder mb)
{
TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations ();
string[] snames = new string [names.Length];
ec, mb, implementing, is_override))
return false;
- bool ok = true;
- foreach (Parameter p in parameters.FixedParameters){
- if (!p.Resolve (ec))
- ok = false;
- }
+ bool ok = parameters.Resolve (ec);
+
if ((return_type != null) && (return_type.ResolveAsTypeTerminal (ec, false) == null))
ok = false;
OptAttributes.Emit ();
}
- public override bool DefineMembers ()
- {
- return true;
- }
-
public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
MemberFilter filter, object criteria)
{
public partial class TypeManager
{
+ static public Type activator_type;
+
public static TypeContainer LookupGenericTypeContainer (Type t)
{
t = DropGenericTypeArguments (t);
/// <summary>
/// Type inference.
/// </summary>
- public static bool InferTypeArguments (ParameterData apd,
+ public static bool InferTypeArguments (AParametersCollection apd,
ref MethodBase method)
{
if (!TypeManager.IsGenericMethod (method))
public override Type[] InferDelegateArguments (MethodBase method)
{
- ParameterData pd = TypeManager.GetParameterData (method);
+ AParametersCollection pd = TypeManager.GetParameterData (method);
if (arg_count != pd.Count)
return null;
Type[] arg_types = (Type[])arguments.ToArray (typeof (Type));
for (int i = 0; i < arg_count; i++) {
- param_types[i] = pd.ParameterType (i);
+ param_types[i] = pd.Types [i];
}
if (!InferTypeArguments (param_types, arg_types, inferred_types))
public override Type[] InferMethodArguments (EmitContext ec, MethodBase method)
{
- ParameterData pd = TypeManager.GetParameterData (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];
if (a.Expr is NullLiteral || a.Expr is MethodGroupExpr || a.Expr is AnonymousMethodExpression)
continue;
- if (!TypeInferenceV2.UnifyType (pd.ParameterType (i), a.Type, inferred_types))
+ if (!TypeInferenceV2.UnifyType (pd.Types [i], a.Type, inferred_types))
return null;
}
if (pd.HasParams) {
- Type element_type = TypeManager.GetElementType (pd.ParameterType (a_count));
+ 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)
public override Type[] InferDelegateArguments (MethodBase method)
{
- ParameterData pd = TypeManager.GetParameterData (method);
+ AParametersCollection pd = TypeManager.GetParameterData (method);
if (arg_count != pd.Count)
return null;
if (!context.UnfixedVariableExists)
return Type.EmptyTypes;
- ParameterData pd = TypeManager.GetParameterData (method);
+ AParametersCollection pd = TypeManager.GetParameterData (method);
if (!InferInPhases (ec, context, pd))
return null;
//
// Implements method type arguments inference
//
- bool InferInPhases (EmitContext ec, TypeInferenceContext tic, ParameterData methodParameters)
+ bool InferInPhases (EmitContext ec, TypeInferenceContext tic, AParametersCollection methodParameters)
{
int params_arguments_start;
if (methodParameters.HasParams) {
} else {
params_arguments_start = arg_count;
}
+
+ Type [] ptypes = methodParameters.Types;
//
// The first inference phase
method_parameter = methodParameters.Types [params_arguments_start];
else
method_parameter = TypeManager.GetElementType (methodParameters.Types [params_arguments_start]);
+
+ ptypes = (Type[]) ptypes.Clone ();
+ ptypes [i] = method_parameter;
}
//
continue;
}
- if (a.Expr.Type == TypeManager.null_type)
+ if (a.Expr is NullLiteral)
continue;
//
// we don't need to call it in cycle
//
bool fixed_any = false;
- if (!tic.FixIndependentTypeArguments (methodParameters, ref fixed_any))
+ if (!tic.FixIndependentTypeArguments (ptypes, ref fixed_any))
return false;
- return DoSecondPhase (ec, tic, methodParameters, !fixed_any);
+ return DoSecondPhase (ec, tic, ptypes, !fixed_any);
}
- bool DoSecondPhase (EmitContext ec, TypeInferenceContext tic, ParameterData methodParameters, bool fixDependent)
+ bool DoSecondPhase (EmitContext ec, TypeInferenceContext tic, Type[] methodParameters, bool fixDependent)
{
bool fixed_any = false;
- if (fixDependent && !tic.FixDependentTypes (methodParameters, ref fixed_any))
+ if (fixDependent && !tic.FixDependentTypes (ref fixed_any))
return false;
// If no further unfixed type variables exist, type inference succeeds
// contain unfixed type variables but the input types do not,
// an output type inference is made
for (int i = 0; i < arg_count; i++) {
- Type t_i = methodParameters.ParameterType (i);
+
+ // Align params arguments
+ Type t_i = methodParameters [i >= methodParameters.Length ? methodParameters.Length - 1: i];
+
if (!TypeManager.IsDelegateType (t_i)) {
if (TypeManager.DropGenericTypeArguments (t_i) != TypeManager.expression_type)
continue;
readonly Type[] unfixed_types;
readonly Type[] fixed_types;
readonly ArrayList[] bounds;
+ bool failed;
public TypeInferenceContext (Type[] typeArguments)
{
void AddToBounds (Type t, int index)
{
+ //
+ // Some types cannot be used as type arguments
+ //
+ if (t == TypeManager.void_type || t.IsPointer)
+ return;
+
ArrayList a = bounds [index];
if (a == null) {
a = new ArrayList ();
//
// 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 (TypeManager.IsGenericParameter (t)) {
+ // GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
+ // if (constraints != null) {
+ // //if (constraints.EffectiveBaseClass != null)
+ // // t = constraints.EffectiveBaseClass;
+ // }
+ //}
a.Add (t);
}
// 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 (ParameterData methodParameters, ref bool fixed_any)
+ public bool FixDependentTypes (ref bool fixed_any)
{
for (int i = 0; i < unfixed_types.Length; ++i) {
if (unfixed_types[i] == null)
//
// All unfixed type variables Xi which depend on no Xj are fixed
//
- public bool FixIndependentTypeArguments (ParameterData methodParameters, ref bool fixed_any)
+ public bool FixIndependentTypeArguments (Type[] methodParameters, ref bool fixed_any)
{
ArrayList types_to_fix = new ArrayList (unfixed_types);
- for (int i = 0; i < methodParameters.Types.Length; ++i) {
- Type t = methodParameters.Types [i];
+ for (int i = 0; i < methodParameters.Length; ++i) {
+ Type t = methodParameters[i];
if (t.IsGenericParameter)
continue;
if (unfixed_types[i] == null)
throw new InternalErrorException ("Type argument has been already fixed");
+ if (failed)
+ return false;
+
ArrayList candidates = (ArrayList)bounds [i];
if (candidates == null)
return false;
//
public Type InflateGenericArgument (Type parameter)
{
- if (parameter.IsGenericParameter)
+ if (parameter.IsGenericParameter) {
+ //
+ // Inflate method generic argument (MVAR) only
+ //
+ if (parameter.DeclaringMethod == null)
+ return parameter;
+
return fixed_types [parameter.GenericParameterPosition];
+ }
if (parameter.IsGenericType) {
Type [] parameter_targs = parameter.GetGenericArguments ();
}
// All generic input arguments have to be fixed
- ParameterData d_parameters = TypeManager.GetParameterData (invoke);
+ AParametersCollection d_parameters = TypeManager.GetParameterData (invoke);
return AllTypesAreFixed (d_parameters.Types);
}
//
public int LowerBoundInference (Type u, Type v)
{
- // Remove ref, out modifiers
- if (v.IsByRef)
- v = v.GetElementType ();
-
// If V is one of the unfixed type arguments
int pos = IsUnfixed (v);
if (pos != -1) {
u_candidates.AddRange (TypeManager.GetInterfaces (u));
Type open_v = v.GetGenericTypeDefinition ();
- int score = 0;
+ Type [] unique_candidate_targs = null;
+ Type [] ga_v = v.GetGenericArguments ();
foreach (Type u_candidate in u_candidates) {
if (!u_candidate.IsGenericType || u_candidate.IsGenericTypeDefinition)
continue;
if (TypeManager.DropGenericTypeArguments (u_candidate) != open_v)
continue;
- Type [] ga_u = u_candidate.GetGenericArguments ();
- Type [] ga_v = v.GetGenericArguments ();
- bool all_exact = true;
- for (int i = 0; i < ga_u.Length; ++i)
- if (ExactInference (ga_u [i], ga_v [i]) == 0)
- all_exact = false;
+ //
+ // 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
+ //
+ if (unique_candidate_targs != null) {
+ Type[] second_unique_candidate_targs = u_candidate.GetGenericArguments ();
+ if (TypeManager.IsEqual (unique_candidate_targs, second_unique_candidate_targs)) {
+ unique_candidate_targs = second_unique_candidate_targs;
+ continue;
+ }
+
+ //
+ // This should always cause type inference failure
+ //
+ failed = true;
+ return 1;
+ }
- if (all_exact && score == 0)
- ++score;
+ unique_candidate_targs = u_candidate.GetGenericArguments ();
+ }
+
+ if (unique_candidate_targs != null) {
+ int score = 0;
+ for (int i = 0; i < unique_candidate_targs.Length; ++i)
+ if (ExactInference (unique_candidate_targs [i], ga_v [i]) == 0)
+ ++score;
+ return score;
}
- return score;
}
return 0;
MethodInfo invoke = Delegate.GetInvokeMethod (t, t);
if (rt == null) {
- ParameterData pd = TypeManager.GetParameterData (invoke);
+ AParametersCollection pd = TypeManager.GetParameterData (invoke);
return ame.Parameters.Count == pd.Count ? 1 : 0;
}
return LowerBoundInference (rt, rtype) + 1;
}
+ //
+ // if E is a method group and T is a delegate type or expression tree type
+ // return type Tb with parameter types T1..Tk and return type Tb, and overload
+ // resolution of E with the types T1..Tk yields a single method with return type U,
+ // 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;
MethodInfo invoke = Delegate.GetInvokeMethod (t, t);
Type rtype = invoke.ReturnType;
+#if MS_COMPATIBLE
+ // Blablabla, because reflection does not work with dynamic types
+ Type [] g_args = t.GetGenericArguments ();
+ rtype = g_args [rtype.GenericParameterPosition];
+#endif
+
if (!TypeManager.IsGenericType (rtype))
return 0;
-
+
+ MethodGroupExpr mg = (MethodGroupExpr) e;
+ ArrayList args = DelegateCreation.CreateDelegateMethodArguments (invoke, e.Location);
+ mg = mg.OverloadResolve (ec, ref args, true, e.Location);
+ if (mg == null)
+ return 0;
+
+ // TODO: What should happen when return type is of generic type ?
throw new NotImplementedException ();
+// return LowerBoundInference (null, rtype) + 1;
}
//