// Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@gmail.com)
//
-// Licensed under the terms of the GNU GPL
+// Dual licensed under the terms of the MIT X11 or GNU GPL
//
-// (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
-// (C) 2004 Novell, Inc
+// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
+// Copyright 2004-2008 Novell, Inc
//
using System;
using System.Reflection;
}
}
+ public enum Variance
+ {
+ None,
+ Covariant,
+ Contravariant
+ }
+
public enum SpecialConstraint
{
Constructor,
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) {
}
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;
- // TODO: It's aleady done in ResolveAsBaseTerminal
- if (!ec.GenericDeclContainer.AsAccessible (fn.Type, ec.GenericDeclContainer.ModFlags)) {
+ if (!ec.GenericDeclContainer.IsAccessibleAs (fn.Type)) {
Report.SymbolRelatedToPreviousError (fn.Type);
Report.Error (703, loc,
"Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'",
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.Name, 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;
if (seen.Contains (expr.TypeParameter)) {
Report.Error (454, loc, "Circular constraint " +
"dependency involving `{0}' and `{1}'",
- tparam.Name, expr.Name);
+ tparam.Name, expr.GetSignatureForError ());
return false;
}
- if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
+ if (!CheckTypeParameterConstraints (expr.TypeParameter, ref prevConstraint, seen))
return false;
}
resolved_types = true;
foreach (object obj in constraints) {
- ConstructedType cexpr = obj as ConstructedType;
+ GenericTypeExpr cexpr = obj as GenericTypeExpr;
if (cexpr == null)
continue;
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;
/// </summary>
public class TypeParameter : MemberCore, IMemberContainer
{
- string name;
+ static readonly string[] attribute_target = new string [] { "type parameter" };
+
DeclSpace decl;
GenericConstraints gc;
Constraints constraints;
- Location loc;
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.loc = loc;
+ 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; }
}
if (implementing != null) {
if (is_override && (constraints != null)) {
- Report.Error (460, loc,
+ Report.Error (460, Location,
"`{0}': Cannot specify constraints for overrides or explicit interface implementation methods",
TypeManager.CSharpSignature (builder));
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))
Report.SymbolRelatedToPreviousError (implementing);
Report.Error (
- 425, loc, "The constraints for type " +
+ 425, Location, "The constraints for type " +
"parameter `{0}' of method `{1}' must match " +
"the constraints for type parameter `{2}' " +
"of interface method `{3}'. Consider using " +
gc = (GenericConstraints) constraints;
}
- if (gc == null)
- return true;
-
- if (gc.HasClassConstraint)
- type.SetBaseTypeConstraint (gc.ClassConstraint);
-
- type.SetInterfaceConstraints (gc.InterfaceConstraints);
- type.SetGenericParameterAttributes (gc.Attributes);
- TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
-
+ SetConstraints (type);
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 ()
+ public void SetConstraints (GenericTypeParameterBuilder type)
{
- if (constraints != null)
- return constraints.CheckDependencies ();
+ GenericParameterAttributes attr = GenericParameterAttributes.None;
+ if (variance == Variance.Contravariant)
+ attr |= GenericParameterAttributes.Contravariant;
+ else if (variance == Variance.Covariant)
+ attr |= GenericParameterAttributes.Covariant;
- return true;
+ 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>
return false;
if (constraints != null)
- return constraints.CheckInterfaceMethod (new_constraints);
+ return constraints.AreEqual (new_constraints);
constraints = new_constraints;
return true;
public override AttributeTargets AttributeTargets {
get {
- return (AttributeTargets) AttributeTargets.GenericParameter;
+ return AttributeTargets.GenericParameter;
}
}
public override string[] ValidAttributeTargets {
get {
- return new string [] { "type parameter" };
+ return attribute_target;
}
}
MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
{
- return FindMembers (mt, bf, null, null);
+ throw new NotSupportedException ();
}
public MemberCache MemberCache {
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)
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];
public class TypeParameterExpr : TypeExpr {
TypeParameter type_parameter;
- public override string Name {
- get {
- return type_parameter.Name;
- }
- }
-
- public override string FullName {
- get {
- return type_parameter.Name;
- }
- }
-
public TypeParameter TypeParameter {
get {
return type_parameter;
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;
}
{
return true;
}
-
- public void Error_CannotUseAsUnmanagedType (Location loc)
- {
- Report.Error (-203, loc, "Can not use type parameter as unmanaged type");
- }
}
- /// <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;
- bool created;
- 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)
{
- if (created)
- throw new InvalidOperationException ();
-
args.Add (type);
}
public void Add (TypeArguments new_args)
{
- if (created)
- throw new InvalidOperationException ();
-
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) {
- ret [i] = new TypeParameterName (sn.Name, null, sn.Location);
- continue;
- }
-
- Report.Error (81, Location, "Type parameter declaration " +
- "must be an identifier not a type");
- return null;
- }
- 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;
- }
- }
-
- 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 args.Count;
}
- return s.ToString ();
}
public string GetSignatureForError()
/// </summary>
public bool Resolve (IResolveContext 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",
+ Report.Error (718, te.Location, "`{0}': static classes cannot be used as generic arguments",
te.GetSignatureForError ());
- 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));
- return false;
+ ok = false;
}
- if (te.Type == TypeManager.void_type) {
- Expression.Error_VoidInvalidInTheContext (Location);
- return false;
+ if (te.Type.IsPointer || TypeManager.IsSpecialType (te.Type)) {
+ Report.Error (306, te.Location,
+ "The type `{0}' may not be used as a type argument",
+ 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 {
- string full_name;
- 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;
-
- eclass = ExprClass.Type;
- full_name = name + "<" + args.ToString () + ">";
- }
-
- protected ConstructedType (TypeArguments args, Location l)
- {
- loc = l;
- this.args = args;
-
- eclass = ExprClass.Type;
- }
+ Type[] gen_params; // TODO: Waiting for constrains check cleanup
+ Type open_type;
- protected ConstructedType (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)
{
- loc = l;
+ 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));
- 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)
- : this (type_params, l)
- {
- gt = t.GetGenericTypeDefinition ();
-
- this.name = new TypeExpression (gt, l);
- full_name = gt.FullName + "<" + args.ToString () + ">";
+ this.loc = l;
}
/// <summary>
/// Use this constructor if you already know the fully resolved
/// generic type.
/// </summary>
- public ConstructedType (Type t, TypeArguments args, Location l)
- : this (args, l)
+ public GenericTypeExpr (Type t, TypeArguments args, Location l)
{
- gt = t.GetGenericTypeDefinition ();
+ open_type = t.GetGenericTypeDefinition ();
- this.name = new TypeExpression (gt, l);
- full_name = gt.FullName + "<" + args.ToString () + ">";
+ loc = l;
+ this.args = args;
}
public TypeArguments TypeArguments {
public override string GetSignatureForError ()
{
- return TypeManager.RemoveGenericArity (gt.FullName) + "<" + args.GetSignatureForError () + ">";
+ return TypeManager.CSharpName (type);
}
protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
{
- if (!ResolveConstructedType (ec))
+ if (eclass != ExprClass.Invalid)
+ return this;
+
+ eclass = ExprClass.Type;
+
+ if (!args.Resolve (ec))
+ return null;
+
+ gen_params = open_type.GetGenericArguments ();
+ Type[] atypes = args.Arguments;
+
+ if (atypes.Length != gen_params.Length) {
+ Namespace.Error_InvalidNumberOfTypeArguments (open_type, loc);
return null;
+ }
+ //
+ // Now bind the parameters
+ //
+ type = open_type.MakeGenericType (atypes);
return this;
}
/// </summary>
public bool CheckConstraints (IResolveContext ec)
{
- return ConstraintChecker.CheckConstraints (ec, gt, gen_params, atypes, loc);
+ return ConstraintChecker.CheckConstraints (ec, open_type, gen_params, args.Arguments, loc);
}
- /// <summary>
- /// Resolve the constructed type, but don't check the constraints.
- /// </summary>
- public bool ResolveConstructedType (IResolveContext ec)
+ static bool IsVariant (Type type)
{
- if (type != null)
- return true;
- // If we already know the fully resolved generic type.
- if (gt != null)
- return DoResolveType (ec);
-
- int num_args;
- Type t = name.Type;
-
- if (t == null) {
- Report.Error (246, loc, "Cannot find type `{0}'<...>", Name);
- 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);
+ return (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) != 0;
}
-
- bool DoResolveType (IResolveContext ec)
+
+ static bool IsCovariant (Type type)
{
- //
- // Resolve the arguments.
- //
- if (args.Resolve (ec) == false)
- return false;
-
- gen_params = gt.GetGenericArguments ();
- 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;
- }
-
- //
- // Now bind the parameters.
- //
- type = gt.MakeGenericType (atypes);
- return true;
+ return (type.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0;
}
-
- public Expression GetSimpleName (EmitContext ec)
+
+ static bool IsContravariant (Type type)
{
- return this;
+ 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 (gt);
+ return ds.CheckAccessLevel (open_type);
}
- public override bool AsAccessible (DeclSpace ds, int flags)
+ public override bool AsAccessible (DeclSpace ds)
{
- foreach (Type t in atypes) {
- if (!ds.AsAccessible (t, flags))
+ foreach (Type t in args.Arguments) {
+ if (!ds.IsAccessibleAs (t))
return false;
}
- return ds.AsAccessible (gt, flags);
+ return ds.IsAccessibleAs (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;
{
return base.GetHashCode ();
}
-
- public override string Name {
- get {
- return full_name;
- }
- }
-
- public override string FullName {
- get {
- return full_name;
- }
- }
}
public abstract class ConstraintChecker
if (!atype.IsGenericType)
#endif
is_class = atype.IsClass || atype.IsInterface;
- is_struct = atype.IsValueType && !TypeManager.IsNullableType (atype);
+ is_struct = TypeManager.IsValueType (atype) && !TypeManager.IsNullableType (atype);
}
//
if (!gc.HasConstructorConstraint)
return true;
- if (TypeManager.IsBuiltinType (atype) || atype.IsValueType)
+ if (TypeManager.IsBuiltinType (atype) || TypeManager.IsValueType (atype))
return true;
if (HasDefaultConstructor (atype))
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];
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))
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)
{
- if (atype.IsAbstract)
- return false;
-
- again:
- atype = TypeManager.DropGenericTypeArguments (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;
+
+ again:
+ atype = TypeManager.DropGenericTypeArguments (atype);
if (atype is TypeBuilder) {
TypeContainer tc = TypeManager.LookupTypeContainer (atype);
if (tc.InstanceConstructors == null) {
}
}
- TypeParameter tparam = TypeManager.LookupTypeParameter (atype);
- if (tparam != null) {
- if (tparam.GenericConstraints == null)
- return false;
-
- return tparam.GenericConstraints.HasConstructorConstraint ||
- tparam.GenericConstraints.HasValueTypeConstraint;
- }
-
- MemberList list = TypeManager.FindMembers (
- atype, MemberTypes.Constructor,
- BindingFlags.Public | BindingFlags.Instance |
- BindingFlags.DeclaredOnly, null, null);
+ MemberInfo [] list = TypeManager.MemberLookup (null, null, atype, MemberTypes.Constructor,
+ BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
+ ConstructorInfo.ConstructorName, null);
- if (atype.IsAbstract || (list == null))
+ if (list == null)
return false;
foreach (MethodBase mb in list) {
- ParameterData pd = TypeManager.GetParameterData (mb);
- if ((pd.Count == 0) && mb.IsPublic && !mb.IsStatic)
+ 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)
{
/// </summary>
public class GenericMethod : DeclSpace
{
- Expression return_type;
- Parameters parameters;
+ FullNamedExpression return_type;
+ ParametersCompiled parameters;
public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name,
- Expression return_type, Parameters parameters)
+ FullNamedExpression return_type, ParametersCompiled parameters)
: base (ns, parent, name, null)
{
this.return_type = return_type;
/// Define and resolve the type parameters.
/// We're called from Method.Define().
/// </summary>
- public bool Define (MethodBuilder mb, ToplevelBlock block)
+ 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 (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>
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 class NullableType : TypeExpr
- {
- Expression underlying;
-
- public NullableType (Expression underlying, Location l)
- {
- this.underlying = underlying;
- loc = l;
-
- eclass = ExprClass.Type;
- }
-
- public NullableType (Type type, Location loc)
- : this (new TypeExpression (type, loc), loc)
- { }
-
- public override string Name {
- get { return underlying.ToString () + "?"; }
- }
-
- public override string FullName {
- get { return underlying.ToString () + "?"; }
- }
-
- protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
- {
- TypeArguments args = new TypeArguments (loc);
- args.Add (underlying);
-
- ConstructedType ctype = new ConstructedType (TypeManager.generic_nullable_type, args, loc);
- return ctype.ResolveAsTypeTerminal (ec, false);
- }
- }
-
public partial class TypeManager
{
- //
- // A list of core types that the compiler requires or uses
- //
static public Type activator_type;
- static public Type generic_ilist_type;
- static public Type generic_icollection_type;
- static public Type generic_ienumerator_type;
- static public Type generic_ienumerable_type;
- static public Type generic_nullable_type;
-
- //
- // These methods are called by code generated by the compiler
- //
- static public MethodInfo activator_create_instance;
-
- static void InitGenericCoreTypes ()
- {
- activator_type = CoreLookupType ("System", "Activator");
-
- generic_ilist_type = CoreLookupType (
- "System.Collections.Generic", "IList", 1);
- generic_icollection_type = CoreLookupType (
- "System.Collections.Generic", "ICollection", 1);
- generic_ienumerator_type = CoreLookupType (
- "System.Collections.Generic", "IEnumerator", 1);
- generic_ienumerable_type = CoreLookupType (
- "System.Collections.Generic", "IEnumerable", 1);
- generic_nullable_type = CoreLookupType (
- "System", "Nullable", 1);
- }
-
- static void InitGenericCodeHelpers ()
- {
- // Activator
- activator_create_instance = GetMethod (
- activator_type, "CreateInstance", Type.EmptyTypes);
- }
-
- static Type CoreLookupType (string ns, string name, int arity)
- {
- return CoreLookupType (ns, MemberName.MakeName (name, arity));
- }
-
+
public static TypeContainer LookupGenericTypeContainer (Type t)
{
t = DropGenericTypeArguments (t);
// 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);
}
/// <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)
if (at.GetArrayRank () != pt.GetArrayRank ())
return false;
- return UnifyType (pt.GetElementType (), at.GetElementType (), inferred);
+ return UnifyType (TypeManager.GetElementType (pt), TypeManager.GetElementType (at), inferred);
}
if (!pt.IsGenericType)
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) {
- params_arguments_start = arg_count - methodParameters.Count - 1;
+ params_arguments_start = methodParameters.Count - 1;
} else {
params_arguments_start = arg_count;
}
+
+ Type [] ptypes = methodParameters.Types;
//
// The first inference phase
//
Type method_parameter = null;
for (int i = 0; i < arg_count; i++) {
+ Argument a = (Argument) arguments [i];
+
if (i < params_arguments_start) {
method_parameter = methodParameters.Types [i];
} else if (i == params_arguments_start) {
- method_parameter = TypeManager.GetElementType (methodParameters.Types [params_arguments_start]);
- }
+ if (arg_count == params_arguments_start + 1 && TypeManager.HasElementType (a.Type))
+ method_parameter = methodParameters.Types [params_arguments_start];
+ else
+ method_parameter = TypeManager.GetElementType (methodParameters.Types [params_arguments_start]);
- Argument a = (Argument) arguments[i];
+ ptypes = (Type[]) ptypes.Clone ();
+ ptypes [i] = method_parameter;
+ }
//
// When a lambda expression, an anonymous method
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);
- if (!TypeManager.IsDelegateType (t_i))
- continue;
+
+ // 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;
+
+ t_i = t_i.GetGenericArguments () [0];
+ }
MethodInfo mi = Delegate.GetInvokeMethod (t_i, t_i);
Type rtype = mi.ReturnType;
readonly Type[] unfixed_types;
readonly Type[] fixed_types;
readonly ArrayList[] bounds;
+ bool failed;
public TypeInferenceContext (Type[] typeArguments)
{
void AddToBounds (Type t, int index)
{
- ArrayList a = bounds[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 ();
- a.Add (t);
- bounds[index] = a;
- return;
+ bounds [index] = a;
+ } else {
+ if (a.Contains (t))
+ return;
}
- if (a.Contains (t))
- 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;
+ // }
+ //}
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);
- foreach (Type t in methodParameters.Types) {
+ for (int i = 0; i < methodParameters.Length; ++i) {
+ Type t = methodParameters[i];
if (t.IsGenericParameter)
continue;
- if (!TypeManager.IsDelegateType (t))
- continue;
+ if (!TypeManager.IsDelegateType (t)) {
+ if (TypeManager.DropGenericTypeArguments (t) != TypeManager.expression_type)
+ continue;
+
+ t = t.GetGenericArguments () [0];
+ }
MethodInfo invoke = Delegate.GetInvokeMethod (t, t);
Type rtype = invoke.ReturnType;
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;
return true;
}
- // TODO: Review, I think it is still wrong
+ //
+ // Determines a unique type from which there is
+ // a standard implicit conversion to all the other
+ // candidate types.
+ //
Type best_candidate = null;
- for (int ci = 0; ci < candidates.Count; ++ci) {
- TypeExpr candidate = new TypeExpression ((Type)candidates[ci], Location.Null);
- bool failed = false;
- for (int cii = 0; cii < candidates.Count; ++cii) {
+ int cii;
+ int candidates_count = candidates.Count;
+ for (int ci = 0; ci < candidates_count; ++ci) {
+ Type candidate = (Type)candidates [ci];
+ for (cii = 0; cii < candidates_count; ++cii) {
if (cii == ci)
continue;
- if (!Convert.ImplicitStandardConversionExists (candidate, (Type)candidates[cii])) {
- failed = true;
+ if (!Convert.ImplicitConversionExists (null,
+ new TypeExpression ((Type)candidates [cii], Location.Null), candidate)) {
+ break;
}
}
- if (failed)
+ if (cii != candidates_count)
continue;
if (best_candidate != null)
return false;
- best_candidate = candidate.Type;
+ best_candidate = candidate;
}
if (best_candidate == null)
//
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) {
+ AddToBounds (u, pos);
+ return 1;
+ }
// If U is an array type
if (u.IsArray) {
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 ();
}
- return score;
- }
- // If V is one of the unfixed type arguments
- int pos = IsUnfixed (v);
- if (pos == -1)
- return 0;
+ 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;
+ }
+ }
- AddToBounds (u, pos);
- return 1;
+ 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;
}
//
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;
}
}
}
}
-
- public abstract class Nullable
- {
- public sealed class NullableInfo
- {
- public readonly Type Type;
- public readonly Type UnderlyingType;
- public readonly MethodInfo HasValue;
- public readonly MethodInfo Value;
- public readonly ConstructorInfo Constructor;
-
- public NullableInfo (Type type)
- {
- Type = type;
- UnderlyingType = TypeManager.GetTypeArguments (type) [0];
-
- PropertyInfo has_value_pi = TypeManager.GetProperty (type, "HasValue");
- PropertyInfo value_pi = TypeManager.GetProperty (type, "Value");
-
- HasValue = has_value_pi.GetGetMethod (false);
- Value = value_pi.GetGetMethod (false);
- Constructor = type.GetConstructor (new Type[] { UnderlyingType });
- }
- }
-
- public class HasValue : Expression
- {
- Expression expr;
- NullableInfo info;
-
- private HasValue (Expression expr)
- {
- this.expr = expr;
- }
-
- public static Expression Create (Expression expr, EmitContext ec)
- {
- return new HasValue (expr).Resolve (ec);
- }
-
- public override void Emit (EmitContext ec)
- {
- ((IMemoryLocation) expr).AddressOf (ec, AddressOp.LoadStore);
- ec.ig.EmitCall (OpCodes.Call, info.HasValue, null);
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- this.info = new NullableInfo (expr.Type);
-
- type = TypeManager.bool_type;
- eclass = expr.eclass;
- return this;
- }
- }
-
- public class Unwrap : Expression, IMemoryLocation, IAssignMethod
- {
- Expression expr;
- NullableInfo info;
-
- LocalTemporary temp;
- bool has_temp;
-
- protected Unwrap (Expression expr)
- {
- this.expr = expr;
- this.loc = expr.Location;
- }
-
- public static Unwrap Create (Expression expr, EmitContext ec)
- {
- return new Unwrap (expr).Resolve (ec) as Unwrap;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- expr = expr.Resolve (ec);
- if (expr == null)
- return null;
-
- temp = new LocalTemporary (expr.Type);
-
- info = new NullableInfo (expr.Type);
- type = info.UnderlyingType;
- eclass = expr.eclass;
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- AddressOf (ec, AddressOp.LoadStore);
- ec.ig.EmitCall (OpCodes.Call, info.Value, null);
- }
-
- public void EmitCheck (EmitContext ec)
- {
- AddressOf (ec, AddressOp.LoadStore);
- ec.ig.EmitCall (OpCodes.Call, info.HasValue, null);
- }
-
- public void Store (EmitContext ec)
- {
- create_temp (ec);
- }
-
- void create_temp (EmitContext ec)
- {
- if ((temp != null) && !has_temp) {
- expr.Emit (ec);
- temp.Store (ec);
- has_temp = true;
- }
- }
-
- public void AddressOf (EmitContext ec, AddressOp mode)
- {
- create_temp (ec);
- if (temp != null)
- temp.AddressOf (ec, AddressOp.LoadStore);
- else
- ((IMemoryLocation) expr).AddressOf (ec, AddressOp.LoadStore);
- }
-
- public void Emit (EmitContext ec, bool leave_copy)
- {
- create_temp (ec);
- if (leave_copy) {
- if (temp != null)
- temp.Emit (ec);
- else
- expr.Emit (ec);
- }
-
- Emit (ec);
- }
-
- public void EmitAssign (EmitContext ec, Expression source,
- bool leave_copy, bool prepare_for_load)
- {
- InternalWrap wrap = new InternalWrap (source, info, loc);
- ((IAssignMethod) expr).EmitAssign (ec, wrap, leave_copy, false);
- }
-
- protected class InternalWrap : Expression
- {
- public Expression expr;
- public NullableInfo info;
-
- public InternalWrap (Expression expr, NullableInfo info, Location loc)
- {
- this.expr = expr;
- this.info = info;
- this.loc = loc;
-
- type = info.Type;
- eclass = ExprClass.Value;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- expr.Emit (ec);
- ec.ig.Emit (OpCodes.Newobj, info.Constructor);
- }
- }
- }
-
- public class Wrap : Expression
- {
- Expression expr;
- NullableInfo info;
-
- protected Wrap (Expression expr)
- {
- this.expr = expr;
- this.loc = expr.Location;
- }
-
- public static Wrap Create (Expression expr, EmitContext ec)
- {
- return new Wrap (expr).Resolve (ec) as Wrap;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- expr = expr.Resolve (ec);
- if (expr == null)
- return null;
-
- TypeExpr target_type = new NullableType (expr.Type, loc);
- target_type = target_type.ResolveAsTypeTerminal (ec, false);
- if (target_type == null)
- return null;
-
- type = target_type.Type;
- info = new NullableInfo (type);
- eclass = ExprClass.Value;
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- expr.Emit (ec);
- ec.ig.Emit (OpCodes.Newobj, info.Constructor);
- }
- }
-
- public class NullableLiteral : NullLiteral, IMemoryLocation {
- public NullableLiteral (Type target_type, Location loc)
- : base (loc)
- {
- this.type = target_type;
-
- eclass = ExprClass.Value;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- LocalTemporary value_target = new LocalTemporary (type);
-
- value_target.AddressOf (ec, AddressOp.Store);
- ec.ig.Emit (OpCodes.Initobj, type);
- value_target.Emit (ec);
- }
-
- public void AddressOf (EmitContext ec, AddressOp Mode)
- {
- LocalTemporary value_target = new LocalTemporary (type);
-
- value_target.AddressOf (ec, AddressOp.Store);
- ec.ig.Emit (OpCodes.Initobj, type);
- ((IMemoryLocation) value_target).AddressOf (ec, Mode);
- }
- }
-
- public abstract class Lifted : Expression, IMemoryLocation
- {
- Expression expr, underlying, wrap, null_value;
- Unwrap unwrap;
-
- protected Lifted (Expression expr, Location loc)
- {
- this.expr = expr;
- this.loc = loc;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- expr = expr.Resolve (ec);
- if (expr == null)
- return null;
-
- unwrap = Unwrap.Create (expr, ec);
- if (unwrap == null)
- return null;
-
- underlying = ResolveUnderlying (unwrap, ec);
- if (underlying == null)
- return null;
-
- wrap = Wrap.Create (underlying, ec);
- if (wrap == null)
- return null;
-
- null_value = new NullableLiteral (wrap.Type, loc).Resolve (ec);
- if (null_value == null)
- return null;
-
- type = wrap.Type;
- eclass = ExprClass.Value;
- return this;
- }
-
- protected abstract Expression ResolveUnderlying (Expression unwrap, EmitContext ec);
-
- public override void Emit (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
- Label is_null_label = ig.DefineLabel ();
- Label end_label = ig.DefineLabel ();
-
- unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, is_null_label);
-
- wrap.Emit (ec);
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (is_null_label);
- null_value.Emit (ec);
-
- ig.MarkLabel (end_label);
- }
-
- public void AddressOf (EmitContext ec, AddressOp mode)
- {
- unwrap.AddressOf (ec, mode);
- }
- }
-
- public class LiftedConversion : Lifted
- {
- public readonly bool IsUser;
- public readonly bool IsExplicit;
- public readonly Type TargetType;
-
- public LiftedConversion (Expression expr, Type target_type, bool is_user,
- bool is_explicit, Location loc)
- : base (expr, loc)
- {
- this.IsUser = is_user;
- this.IsExplicit = is_explicit;
- this.TargetType = target_type;
- }
-
- protected override Expression ResolveUnderlying (Expression unwrap, EmitContext ec)
- {
- Type type = TypeManager.GetTypeArguments (TargetType) [0];
-
- if (IsUser) {
- return Convert.UserDefinedConversion (ec, unwrap, type, loc, IsExplicit);
- } else {
- if (IsExplicit)
- return Convert.ExplicitConversion (ec, unwrap, type, loc);
- else
- return Convert.ImplicitConversion (ec, unwrap, type, loc);
- }
- }
- }
-
- public class LiftedUnaryOperator : Lifted
- {
- public readonly Unary.Operator Oper;
-
- public LiftedUnaryOperator (Unary.Operator op, Expression expr, Location loc)
- : base (expr, loc)
- {
- this.Oper = op;
- }
-
- protected override Expression ResolveUnderlying (Expression unwrap, EmitContext ec)
- {
- return new Unary (Oper, unwrap, loc);
- }
- }
-
- public class LiftedConditional : Lifted
- {
- Expression true_expr, false_expr;
-
- public LiftedConditional (Expression expr, Expression true_expr, Expression false_expr,
- Location loc)
- : base (expr, loc)
- {
- this.true_expr = true_expr;
- this.false_expr = false_expr;
- }
-
- protected override Expression ResolveUnderlying (Expression unwrap, EmitContext ec)
- {
- return new Conditional (unwrap, true_expr, false_expr);
- }
- }
-
- public class LiftedBinaryOperator : Binary
- {
- Expression underlying, null_value, bool_wrap;
- Unwrap left_unwrap, right_unwrap;
- bool is_equality, is_comparision, is_boolean;
-
- public LiftedBinaryOperator (Binary.Operator op, Expression left, Expression right,
- Location loc)
- : base (op, left, right)
- {
- this.loc = loc;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- if ((Oper == Binary.Operator.LogicalAnd) ||
- (Oper == Binary.Operator.LogicalOr)) {
- Error_OperatorCannotBeApplied ();
- return null;
- }
-
- if (TypeManager.IsNullableType (left.Type)) {
- left = left_unwrap = Unwrap.Create (left, ec);
- if (left == null)
- return null;
- }
-
- if (TypeManager.IsNullableType (right.Type)) {
- right = right_unwrap = Unwrap.Create (right, ec);
- if (right == null)
- return null;
- }
-
- if (((Oper == Binary.Operator.BitwiseAnd) || (Oper == Binary.Operator.BitwiseOr)) &&
- ((left.Type == TypeManager.bool_type) && (right.Type == TypeManager.bool_type))) {
- Expression empty = new EmptyExpression (TypeManager.bool_type);
- bool_wrap = Wrap.Create (empty, ec);
- null_value = new NullableLiteral (bool_wrap.Type, loc).Resolve (ec);
-
- type = bool_wrap.Type;
- is_boolean = true;
- } else if ((Oper == Binary.Operator.Equality) || (Oper == Binary.Operator.Inequality)) {
- if (!(left is NullLiteral) && !(right is NullLiteral)) {
- underlying = new Binary (Oper, left, right).Resolve (ec);
- if (underlying == null)
- return null;
- }
-
- type = TypeManager.bool_type;
- is_equality = true;
- } else if ((Oper == Binary.Operator.LessThan) ||
- (Oper == Binary.Operator.GreaterThan) ||
- (Oper == Binary.Operator.LessThanOrEqual) ||
- (Oper == Binary.Operator.GreaterThanOrEqual)) {
- underlying = new Binary (Oper, left, right).Resolve (ec);
- if (underlying == null)
- return null;
-
- type = TypeManager.bool_type;
- is_comparision = true;
- } else {
- underlying = new Binary (Oper, left, right).Resolve (ec);
- if (underlying == null)
- return null;
-
- underlying = Wrap.Create (underlying, ec);
- if (underlying == null)
- return null;
-
- type = underlying.Type;
- null_value = new NullableLiteral (type, loc).Resolve (ec);
- }
-
- eclass = ExprClass.Value;
- return this;
- }
-
- void EmitBoolean (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- Label left_is_null_label = ig.DefineLabel ();
- Label right_is_null_label = ig.DefineLabel ();
- Label is_null_label = ig.DefineLabel ();
- Label wrap_label = ig.DefineLabel ();
- Label end_label = ig.DefineLabel ();
-
- if (left_unwrap != null) {
- left_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, left_is_null_label);
- }
-
- left.Emit (ec);
- ig.Emit (OpCodes.Dup);
- if ((Oper == Binary.Operator.BitwiseOr) || (Oper == Binary.Operator.LogicalOr))
- ig.Emit (OpCodes.Brtrue, wrap_label);
- else
- ig.Emit (OpCodes.Brfalse, wrap_label);
-
- if (right_unwrap != null) {
- right_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, right_is_null_label);
- }
-
- if ((Oper == Binary.Operator.LogicalAnd) || (Oper == Binary.Operator.LogicalOr))
- ig.Emit (OpCodes.Pop);
-
- right.Emit (ec);
- if (Oper == Binary.Operator.BitwiseOr)
- ig.Emit (OpCodes.Or);
- else if (Oper == Binary.Operator.BitwiseAnd)
- ig.Emit (OpCodes.And);
- ig.Emit (OpCodes.Br, wrap_label);
-
- ig.MarkLabel (left_is_null_label);
- if (right_unwrap != null) {
- right_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, is_null_label);
- }
-
- right.Emit (ec);
- ig.Emit (OpCodes.Dup);
- if ((Oper == Binary.Operator.BitwiseOr) || (Oper == Binary.Operator.LogicalOr))
- ig.Emit (OpCodes.Brtrue, wrap_label);
- else
- ig.Emit (OpCodes.Brfalse, wrap_label);
-
- ig.MarkLabel (right_is_null_label);
- ig.Emit (OpCodes.Pop);
- ig.MarkLabel (is_null_label);
- null_value.Emit (ec);
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (wrap_label);
- ig.Emit (OpCodes.Nop);
- bool_wrap.Emit (ec);
- ig.Emit (OpCodes.Nop);
-
- ig.MarkLabel (end_label);
- }
-
- void EmitEquality (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- // Given 'X? x;' for any value type X: 'x != null' is the same as 'x.HasValue'
- if (left is NullLiteral) {
- if (right_unwrap == null)
- throw new InternalErrorException ();
- right_unwrap.EmitCheck (ec);
- if (Oper == Binary.Operator.Equality) {
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Ceq);
- }
- return;
- }
-
- if (right is NullLiteral) {
- if (left_unwrap == null)
- throw new InternalErrorException ();
- left_unwrap.EmitCheck (ec);
- if (Oper == Binary.Operator.Equality) {
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Ceq);
- }
- return;
- }
-
- Label both_have_value_label = ig.DefineLabel ();
- Label end_label = ig.DefineLabel ();
-
- if (left_unwrap != null && right_unwrap != null) {
- Label dissimilar_label = ig.DefineLabel ();
-
- left_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Dup);
- right_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Bne_Un, dissimilar_label);
-
- ig.Emit (OpCodes.Brtrue, both_have_value_label);
-
- // both are null
- if (Oper == Binary.Operator.Equality)
- ig.Emit (OpCodes.Ldc_I4_1);
- else
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (dissimilar_label);
- ig.Emit (OpCodes.Pop);
- } else if (left_unwrap != null) {
- left_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brtrue, both_have_value_label);
- } else if (right_unwrap != null) {
- right_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brtrue, both_have_value_label);
- } else {
- throw new InternalErrorException ("shouldn't get here");
- }
-
- // one is null while the other isn't
- if (Oper == Binary.Operator.Equality)
- ig.Emit (OpCodes.Ldc_I4_0);
- else
- ig.Emit (OpCodes.Ldc_I4_1);
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (both_have_value_label);
- underlying.Emit (ec);
-
- ig.MarkLabel (end_label);
- }
-
- void EmitComparision (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- Label is_null_label = ig.DefineLabel ();
- Label end_label = ig.DefineLabel ();
-
- if (left_unwrap != null) {
- left_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, is_null_label);
- }
-
- if (right_unwrap != null) {
- right_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, is_null_label);
- }
-
- underlying.Emit (ec);
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (is_null_label);
- ig.Emit (OpCodes.Ldc_I4_0);
-
- ig.MarkLabel (end_label);
- }
-
- public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
- {
- Emit (ec);
- ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
- }
-
- public override void Emit (EmitContext ec)
- {
- if (left_unwrap != null)
- left_unwrap.Store (ec);
- if (right_unwrap != null)
- right_unwrap.Store (ec);
-
- if (is_boolean) {
- EmitBoolean (ec);
- return;
- } else if (is_equality) {
- EmitEquality (ec);
- return;
- } else if (is_comparision) {
- EmitComparision (ec);
- return;
- }
-
- ILGenerator ig = ec.ig;
-
- Label is_null_label = ig.DefineLabel ();
- Label end_label = ig.DefineLabel ();
-
- if (left_unwrap != null) {
- left_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, is_null_label);
- }
-
- if (right_unwrap != null) {
- right_unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, is_null_label);
- }
-
- underlying.Emit (ec);
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (is_null_label);
- null_value.Emit (ec);
-
- ig.MarkLabel (end_label);
- }
- }
-
- public class OperatorTrueOrFalse : Expression
- {
- public readonly bool IsTrue;
-
- Expression expr;
- Unwrap unwrap;
-
- public OperatorTrueOrFalse (Expression expr, bool is_true, Location loc)
- {
- this.IsTrue = is_true;
- this.expr = expr;
- this.loc = loc;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- unwrap = Unwrap.Create (expr, ec);
- if (unwrap == null)
- return null;
-
- if (unwrap.Type != TypeManager.bool_type)
- return null;
-
- type = TypeManager.bool_type;
- eclass = ExprClass.Value;
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- Label is_null_label = ig.DefineLabel ();
- Label end_label = ig.DefineLabel ();
-
- unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, is_null_label);
-
- unwrap.Emit (ec);
- if (!IsTrue) {
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Ceq);
- }
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (is_null_label);
- ig.Emit (OpCodes.Ldc_I4_0);
-
- ig.MarkLabel (end_label);
- }
- }
-
- public class NullCoalescingOperator : Expression
- {
- Expression left, right;
- Expression expr;
- Unwrap unwrap;
-
- public NullCoalescingOperator (Expression left, Expression right, Location loc)
- {
- this.left = left;
- this.right = right;
- this.loc = loc;
-
- eclass = ExprClass.Value;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- if (type != null)
- return this;
-
- left = left.Resolve (ec);
- if (left == null)
- return null;
-
- right = right.Resolve (ec);
- if (right == null)
- return null;
-
- Type ltype = left.Type, rtype = right.Type;
-
- if (TypeManager.IsNullableType (ltype)) {
- NullableInfo info = new NullableInfo (ltype);
-
- unwrap = Unwrap.Create (left, ec);
- if (unwrap == null)
- return null;
-
- expr = Convert.ImplicitConversion (ec, right, info.UnderlyingType, loc);
- if (expr != null) {
- left = unwrap;
- type = expr.Type;
- return this;
- }
- } else if (!TypeManager.IsReferenceType (ltype)) {
- Binary.Error_OperatorCannotBeApplied (loc, "??", ltype, rtype);
- return null;
- }
-
- expr = Convert.ImplicitConversion (ec, right, ltype, loc);
- if (expr != null) {
- type = expr.Type;
- return this;
- }
-
- Expression left_null = unwrap != null ? unwrap : left;
- expr = Convert.ImplicitConversion (ec, left_null, rtype, loc);
- if (expr != null) {
- left = expr;
- expr = right;
- type = rtype;
- return this;
- }
-
- Binary.Error_OperatorCannotBeApplied (loc, "??", ltype, rtype);
- return null;
- }
-
- public override void Emit (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- Label is_null_label = ig.DefineLabel ();
- Label end_label = ig.DefineLabel ();
-
- if (unwrap != null) {
- unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, is_null_label);
-
- left.Emit (ec);
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (is_null_label);
- expr.Emit (ec);
-
- ig.MarkLabel (end_label);
- } else {
- left.Emit (ec);
- ig.Emit (OpCodes.Dup);
- ig.Emit (OpCodes.Brtrue, end_label);
-
- ig.MarkLabel (is_null_label);
-
- ig.Emit (OpCodes.Pop);
- expr.Emit (ec);
-
- ig.MarkLabel (end_label);
- }
- }
-
- protected override void CloneTo (CloneContext clonectx, Expression t)
- {
- NullCoalescingOperator target = (NullCoalescingOperator) t;
-
- target.left = left.Clone (clonectx);
- target.right = right.Clone (clonectx);
- }
- }
-
- public class LiftedUnaryMutator : ExpressionStatement
- {
- public readonly UnaryMutator.Mode Mode;
- Expression expr, null_value;
- UnaryMutator underlying;
- Unwrap unwrap;
-
- public LiftedUnaryMutator (UnaryMutator.Mode mode, Expression expr, Location loc)
- {
- this.expr = expr;
- this.Mode = mode;
- this.loc = loc;
-
- eclass = ExprClass.Value;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- expr = expr.Resolve (ec);
- if (expr == null)
- return null;
-
- unwrap = Unwrap.Create (expr, ec);
- if (unwrap == null)
- return null;
-
- underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap, loc).Resolve (ec);
- if (underlying == null)
- return null;
-
- null_value = new NullableLiteral (expr.Type, loc).Resolve (ec);
- if (null_value == null)
- return null;
-
- type = expr.Type;
- return this;
- }
-
- void DoEmit (EmitContext ec, bool is_expr)
- {
- ILGenerator ig = ec.ig;
- Label is_null_label = ig.DefineLabel ();
- Label end_label = ig.DefineLabel ();
-
- unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, is_null_label);
-
- if (is_expr)
- underlying.Emit (ec);
- else
- underlying.EmitStatement (ec);
- ig.Emit (OpCodes.Br, end_label);
-
- ig.MarkLabel (is_null_label);
- if (is_expr)
- null_value.Emit (ec);
-
- ig.MarkLabel (end_label);
- }
-
- public override void Emit (EmitContext ec)
- {
- DoEmit (ec, true);
- }
-
- public override void EmitStatement (EmitContext ec)
- {
- DoEmit (ec, false);
- }
- }
- }
}