X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fgeneric.cs;h=ad69957df20d8196ec18c990fd533164084b325d;hb=b16cf37a8d93db28650210c829d53dc2b339e4e7;hp=7c8d03345cb8e8704c6008ad2f1888e4f6b4e27f;hpb=223695b452f40371741b60c7428975d277a1ebd8;p=mono.git diff --git a/mcs/gmcs/generic.cs b/mcs/gmcs/generic.cs index 7c8d03345cb..ad69957df20 100644 --- a/mcs/gmcs/generic.cs +++ b/mcs/gmcs/generic.cs @@ -156,6 +156,11 @@ namespace Mono.CSharp { } } + public Constraints Clone () + { + return new Constraints (name, constraints, loc); + } + GenericParameterAttributes attrs; TypeExpr class_constraint; ArrayList iface_constraints; @@ -171,7 +176,7 @@ namespace Mono.CSharp { /// Resolve the constraints - but only resolve things into Expression's, not /// into actual types. /// - public bool Resolve (EmitContext ec) + public bool Resolve (IResolveContext ec) { if (resolved) return true; @@ -182,7 +187,7 @@ namespace Mono.CSharp { foreach (object obj in constraints) { if (HasConstructorConstraint) { Report.Error (401, loc, - "The new() constraint must be last."); + "The new() constraint must be the last constraint specified"); return false; } @@ -195,17 +200,14 @@ namespace Mono.CSharp { continue; } - Report.Error ( - 451, loc, "The new () constraint " + - "cannot be used with the `struct' " + - "constraint."); + Report.Error (451, loc, "The `new()' constraint " + + "cannot be used with the `struct' constraint"); return false; } if ((num_constraints > 0) || HasReferenceTypeConstraint || HasValueTypeConstraint) { - Report.Error (449, loc, - "The `class' or `struct' " + - "constraint must be first"); + Report.Error (449, loc, "The `class' or `struct' " + + "constraint must be the first constraint specified"); return false; } @@ -217,13 +219,13 @@ namespace Mono.CSharp { } int errors = Report.Errors; - FullNamedExpression fn = ((Expression) obj).ResolveAsTypeStep (ec); + FullNamedExpression fn = ((Expression) obj).ResolveAsTypeStep (ec, false); if (fn == null) { if (errors != Report.Errors) return false; - Report.Error (246, loc, "Cannot find type '{0}'", ((Expression) obj).GetSignatureForError ()); + NamespaceEntry.Error_NamespaceNotFound (loc, ((Expression)obj).GetSignatureForError ()); return false; } @@ -235,11 +237,20 @@ namespace Mono.CSharp { expr = cexpr; } else - expr = fn.ResolveAsTypeTerminal (ec); + 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)) { + Report.SymbolRelatedToPreviousError (fn.Type); + Report.Error (703, loc, + "Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'", + fn.GetSignatureForError (), ec.GenericDeclContainer.GetSignatureForError ()); + return false; + } + TypeParameterExpr texpr = expr as TypeParameterExpr; if (texpr != null) type_param_constraints.Add (expr); @@ -254,7 +265,7 @@ namespace Mono.CSharp { } else if (HasReferenceTypeConstraint || HasValueTypeConstraint) { Report.Error (450, loc, "`{0}': cannot specify both " + "a constraint class and the `class' " + - "or `struct' constraint.", expr.Name); + "or `struct' constraint", expr.GetSignatureForError ()); return false; } else class_constraint = expr; @@ -301,10 +312,16 @@ namespace Mono.CSharp { return false; if (class_constraint_type.IsSealed) { - Report.Error (701, loc, - "`{0}' is not a valid bound. Bounds " + - "must be interfaces or non sealed " + - "classes", TypeManager.CSharpName (class_constraint_type)); + if (class_constraint_type.IsAbstract) + { + Report.Error (717, loc, "`{0}' is not a valid constraint. Static classes cannot be used as constraints", + TypeManager.CSharpName (class_constraint_type)); + } + else + { + Report.Error (701, loc, "`{0}' is not a valid constraint. A constraint must be an interface, " + + "a non-sealed class or a type parameter", TypeManager.CSharpName(class_constraint_type)); + } return false; } @@ -368,7 +385,7 @@ namespace Mono.CSharp { /// /// Resolve the constraints into actual types. /// - public bool ResolveTypes (EmitContext ec) + public bool ResolveTypes (IResolveContext ec) { if (resolved_types) return true; @@ -390,13 +407,17 @@ namespace Mono.CSharp { return false; } - foreach (TypeExpr iface_constraint in iface_constraints) { - if (iface_constraint.ResolveType (ec) == null) + for (int i = 0; i < iface_constraints.Count; ++i) { + TypeExpr iface_constraint = (TypeExpr) iface_constraints [i]; + iface_constraint = iface_constraint.ResolveAsTypeTerminal (ec, false); + if (iface_constraint == null) return false; + iface_constraints [i] = iface_constraint; } if (class_constraint != null) { - if (class_constraint.ResolveType (ec) == null) + class_constraint = class_constraint.ResolveAsTypeTerminal (ec, false); + if (class_constraint == null) return false; } @@ -412,17 +433,17 @@ namespace Mono.CSharp { /// where T : class /// where U : T, struct /// - public bool CheckDependencies (EmitContext ec) + public bool CheckDependencies () { foreach (TypeParameterExpr expr in type_param_constraints) { - if (!CheckDependencies (expr.TypeParameter, ec)) + if (!CheckDependencies (expr.TypeParameter)) return false; } return true; } - bool CheckDependencies (TypeParameter tparam, EmitContext ec) + bool CheckDependencies (TypeParameter tparam) { Constraints constraints = tparam.Constraints; if (constraints == null) @@ -442,8 +463,8 @@ namespace Mono.CSharp { Type t2 = constraints.ClassConstraint; TypeExpr e2 = constraints.class_constraint; - if (!Convert.ImplicitReferenceConversionExists (ec, e1, t2) && - !Convert.ImplicitReferenceConversionExists (ec, e2, t1)) { + if (!Convert.ImplicitReferenceConversionExists (e1, t2) && + !Convert.ImplicitReferenceConversionExists (e2, t1)) { Report.Error (455, loc, "Type parameter `{0}' inherits " + "conflicting constraints `{1}' and `{2}'", @@ -456,7 +477,7 @@ namespace Mono.CSharp { return true; foreach (TypeParameterExpr expr in constraints.type_param_constraints) { - if (!CheckDependencies (expr.TypeParameter, ec)) + if (!CheckDependencies (expr.TypeParameter)) return false; } @@ -500,6 +521,12 @@ namespace Mono.CSharp { return false; } + public Location Location { + get { + return loc; + } + } + /// /// This is used when we're implementing a generic interface method. /// Each method type parameter in implementing method must have the same @@ -507,7 +534,7 @@ namespace Mono.CSharp { /// method. To do that, we're called on each of the implementing method's /// type parameters. /// - public bool CheckInterfaceMethod (EmitContext ec, GenericConstraints gc) + public bool CheckInterfaceMethod (GenericConstraints gc) { if (gc.Attributes != attrs) return false; @@ -540,6 +567,27 @@ namespace Mono.CSharp { return true; } + + public void VerifyClsCompliance () + { + if (class_constraint_type != null && !AttributeTester.IsClsCompliant (class_constraint_type)) + Warning_ConstrainIsNotClsCompliant (class_constraint_type, class_constraint.Location); + + if (iface_constraint_types != null) { + for (int i = 0; i < iface_constraint_types.Length; ++i) { + if (!AttributeTester.IsClsCompliant (iface_constraint_types [i])) + Warning_ConstrainIsNotClsCompliant (iface_constraint_types [i], + ((TypeExpr)iface_constraints [i]).Location); + } + } + } + + void Warning_ConstrainIsNotClsCompliant (Type t, Location loc) + { + Report.SymbolRelatedToPreviousError (t); + Report.Warning (3024, 1, loc, "Constraint type `{0}' is not CLS-compliant", + TypeManager.CSharpName (t)); + } } /// @@ -564,36 +612,23 @@ namespace Mono.CSharp { } public GenericConstraints GenericConstraints { - get { - return gc != null ? gc : constraints; - } + get { return gc != null ? gc : constraints; } } public Constraints Constraints { - get { - return constraints; - } + get { return constraints; } } public bool HasConstructorConstraint { - get { - if (constraints != null) - return constraints.HasConstructorConstraint; - - return false; - } + get { return constraints != null && constraints.HasConstructorConstraint; } } public DeclSpace DeclSpace { - get { - return decl; - } + get { return decl; } } public Type Type { - get { - return type; - } + get { return type; } } /// @@ -630,7 +665,7 @@ namespace Mono.CSharp { public bool Resolve (DeclSpace ds) { if (constraints != null) { - if (!constraints.Resolve (ds.EmitContext)) { + if (!constraints.Resolve (ds)) { constraints = null; return false; } @@ -649,7 +684,7 @@ namespace Mono.CSharp { /// Note that we may have circular dependencies on type parameters - this /// is why Resolve() and ResolveType() are separate. /// - public bool ResolveType (EmitContext ec) + public bool ResolveType (IResolveContext ec) { if (constraints != null) { if (!constraints.ResolveTypes (ec)) { @@ -666,7 +701,7 @@ namespace Mono.CSharp { /// process. We're called after everything is fully resolved and actually /// register the constraints with SRE and the TypeManager. /// - public bool DefineType (EmitContext ec) + public bool DefineType (IResolveContext ec) { return DefineType (ec, null, null, false); } @@ -679,7 +714,7 @@ namespace Mono.CSharp { /// The `builder', `implementing' and `is_override' arguments are only /// applicable to method type parameters. /// - public bool DefineType (EmitContext ec, MethodBuilder builder, + public bool DefineType (IResolveContext ec, MethodBuilder builder, MethodInfo implementing, bool is_override) { if (!ResolveType (ec)) @@ -687,11 +722,9 @@ namespace Mono.CSharp { if (implementing != null) { if (is_override && (constraints != null)) { - Report.Error ( - 460, loc, "Constraints for override and " + - "explicit interface implementation methods " + - "are inherited from the base method so they " + - "cannot be specified directly"); + Report.Error (460, loc, + "`{0}': Cannot specify constraints for overrides or explicit interface implementation methods", + TypeManager.CSharpSignature (builder)); return false; } @@ -710,7 +743,7 @@ namespace Mono.CSharp { if (constraints != null) { if (temp_gc == null) ok = false; - else if (!constraints.CheckInterfaceMethod (ec, gc)) + else if (!constraints.CheckInterfaceMethod (gc)) ok = false; } else { if (!is_override && (temp_gc != null)) @@ -730,7 +763,7 @@ namespace Mono.CSharp { TypeManager.CSharpName (mparam), TypeManager.CSharpSignature (mb)); return false; } - } else if (DeclSpace is Iterator) { + } else if (DeclSpace is CompilerGeneratedClass) { TypeParameter[] tparams = DeclSpace.TypeParameters; Type[] types = new Type [tparams.Length]; for (int i = 0; i < tparams.Length; i++) @@ -764,10 +797,10 @@ namespace Mono.CSharp { /// where T : class /// where U : T, struct /// - public bool CheckDependencies (EmitContext ec) + public bool CheckDependencies () { if (constraints != null) - return constraints.CheckDependencies (ec); + return constraints.CheckDependencies (); return true; } @@ -780,15 +813,12 @@ namespace Mono.CSharp { /// check that they're the same. /// con /// - public bool UpdateConstraints (EmitContext ec, Constraints new_constraints) + public bool UpdateConstraints (IResolveContext ec, Constraints new_constraints) { if (type == null) throw new InvalidOperationException (); - if (constraints == null) { - new_constraints = constraints; - return true; - } else if (new_constraints == null) + if (new_constraints == null) return true; if (!new_constraints.Resolve (ec)) @@ -796,13 +826,17 @@ namespace Mono.CSharp { if (!new_constraints.ResolveTypes (ec)) return false; - return constraints.CheckInterfaceMethod (ec, new_constraints); + if (constraints != null) + return constraints.CheckInterfaceMethod (new_constraints); + + constraints = new_constraints; + return true; } - public void EmitAttributes (EmitContext ec) + public void EmitAttributes () { if (OptAttributes != null) - OptAttributes.Emit (ec, this); + OptAttributes.Emit (); } public override string DocCommentHeader { @@ -867,7 +901,7 @@ namespace Mono.CSharp { public MemberList FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria) { - if (constraints == null) + if (gc == null) return MemberList.Empty; ArrayList members = new ArrayList (); @@ -979,9 +1013,15 @@ namespace Mono.CSharp { return null; if (t.IsGenericParameter) return dargs [t.GenericParameterPosition]; - if (t.IsGenericInstance) { + if (t.IsGenericType) { + Type[] args = t.GetGenericArguments (); + Type[] inflated = new Type [args.Length]; + + for (int i = 0; i < args.Length; i++) + inflated [i] = inflate (args [i]); + t = t.GetGenericTypeDefinition (); - t = t.MakeGenericType (dargs); + t = t.MakeGenericType (inflated); } return t; @@ -1039,7 +1079,7 @@ namespace Mono.CSharp { this.loc = loc; } - protected override TypeExpr DoResolveAsTypeStep (EmitContext ec) + protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec) { type = type_parameter.Type; @@ -1057,7 +1097,7 @@ namespace Mono.CSharp { public void Error_CannotUseAsUnmanagedType (Location loc) { - Report.Error (-203, loc, "Can not use type parameter as unamanged type"); + Report.Error (-203, loc, "Can not use type parameter as unmanaged type"); } } @@ -1177,10 +1217,23 @@ namespace Mono.CSharp { return s.ToString (); } + public string GetSignatureForError() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < Count; ++i) + { + Expression expr = (Expression)args [i]; + sb.Append(expr.GetSignatureForError()); + if (i + 1 < Count) + sb.Append(','); + } + return sb.ToString(); + } + /// /// Resolve the type arguments. /// - public bool Resolve (EmitContext ec) + public bool Resolve (IResolveContext ec) { int count = args.Count; bool ok = true; @@ -1188,7 +1241,7 @@ namespace Mono.CSharp { atypes = new Type [count]; for (int i = 0; i < count; i++){ - TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec); + TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec, false); if (te == null) { ok = false; continue; @@ -1196,13 +1249,21 @@ namespace Mono.CSharp { if (te is TypeParameterExpr) has_type_args = true; +#if !MS_COMPATIBLE + if (te.Type.IsSealed && te.Type.IsAbstract) { + Report.Error (718, Location, "`{0}': static classes cannot be used as generic arguments", + te.GetSignatureForError ()); + return false; + } +#endif if (te.Type.IsPointer) { Report.Error (306, Location, "The type `{0}' may not be used " + - "as a type argument.", TypeManager.CSharpName (te.Type)); + "as a type argument", TypeManager.CSharpName (te.Type)); return false; - } else if (te.Type == TypeManager.void_type) { - Report.Error (1547, Location, - "Keyword `void' cannot be used in this context"); + } + + if (te.Type == TypeManager.void_type) { + Expression.Error_VoidInvalidInTheContext (Location); return false; } @@ -1303,10 +1364,10 @@ namespace Mono.CSharp { public override string GetSignatureForError () { - return TypeManager.CSharpName (gt); + return TypeManager.RemoveGenericArity (gt.FullName) + "<" + args.GetSignatureForError () + ">"; } - protected override TypeExpr DoResolveAsTypeStep (EmitContext ec) + protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec) { if (!ResolveConstructedType (ec)) return null; @@ -1318,7 +1379,7 @@ namespace Mono.CSharp { /// Check the constraints; we're called from ResolveAsTypeTerminal() /// after fully resolving the constructed type. /// - public bool CheckConstraints (EmitContext ec) + public bool CheckConstraints (IResolveContext ec) { return ConstraintChecker.CheckConstraints (ec, gt, gen_params, atypes, loc); } @@ -1326,7 +1387,7 @@ namespace Mono.CSharp { /// /// Resolve the constructed type, but don't check the constraints. /// - public bool ResolveConstructedType (EmitContext ec) + public bool ResolveConstructedType (IResolveContext ec) { if (type != null) return true; @@ -1355,7 +1416,7 @@ namespace Mono.CSharp { return DoResolveType (ec); } - bool DoResolveType (EmitContext ec) + bool DoResolveType (IResolveContext ec) { // // Resolve the arguments. @@ -1394,6 +1455,11 @@ namespace Mono.CSharp { public override bool AsAccessible (DeclSpace ds, int flags) { + foreach (Type t in atypes) { + if (!ds.AsAccessible (t, flags)) + return false; + } + return ds.AsAccessible (gt, flags); } @@ -1436,7 +1502,6 @@ namespace Mono.CSharp { } } - public override string FullName { get { return full_name; @@ -1461,7 +1526,7 @@ namespace Mono.CSharp { /// Check the constraints; we're called from ResolveAsTypeTerminal() /// after fully resolving the constructed type. /// - public bool CheckConstraints (EmitContext ec) + public bool CheckConstraints (IResolveContext ec) { for (int i = 0; i < gen_params.Length; i++) { if (!CheckConstraints (ec, i)) @@ -1471,7 +1536,7 @@ namespace Mono.CSharp { return true; } - protected bool CheckConstraints (EmitContext ec, int index) + protected bool CheckConstraints (IResolveContext ec, int index) { Type atype = atypes [index]; Type ptype = gen_params [index]; @@ -1489,12 +1554,18 @@ namespace Mono.CSharp { if (atype.IsGenericParameter) { GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype); if (agc != null) { - is_class = agc.HasReferenceTypeConstraint; - is_struct = agc.HasValueTypeConstraint; + if (agc is Constraints) + ((Constraints) agc).Resolve (ec); + is_class = agc.IsReferenceType; + is_struct = agc.IsValueType; } else { is_class = is_struct = false; } } else { +#if MS_COMPATIBLE + is_class = false; + if (!atype.IsGenericType) +#endif is_class = atype.IsClass || atype.IsInterface; is_struct = atype.IsValueType && !TypeManager.IsNullableType (atype); } @@ -1533,9 +1604,11 @@ namespace Mono.CSharp { // // Now, check the interface constraints. // - foreach (Type it in gc.InterfaceConstraints) { - if (!CheckConstraint (ec, ptype, aexpr, it)) - return false; + if (gc.InterfaceConstraints != null) { + foreach (Type it in gc.InterfaceConstraints) { + if (!CheckConstraint (ec, ptype, aexpr, it)) + return false; + } } // @@ -1548,7 +1621,7 @@ namespace Mono.CSharp { if (TypeManager.IsBuiltinType (atype) || atype.IsValueType) return true; - if (HasDefaultConstructor (ec, atype)) + if (HasDefaultConstructor (ec.DeclContainer.TypeBuilder, atype)) return true; Report_SymbolRelatedToPreviousError (); @@ -1563,7 +1636,7 @@ namespace Mono.CSharp { return false; } - protected bool CheckConstraint (EmitContext ec, Type ptype, Expression expr, + protected bool CheckConstraint (IResolveContext ec, Type ptype, Expression expr, Type ctype) { if (TypeManager.HasGenericArguments (ctype)) { @@ -1582,7 +1655,7 @@ namespace Mono.CSharp { } TypeExpr ct = new ConstructedType (ctype, new_args, loc); - if (ct.ResolveAsTypeStep (ec) == null) + if (ct.ResolveAsTypeStep (ec, false) == null) return false; ctype = ct.Type; } else if (ctype.IsGenericParameter) { @@ -1590,20 +1663,27 @@ namespace Mono.CSharp { ctype = atypes [pos]; } - if (Convert.ImplicitStandardConversionExists (ec, expr, ctype)) + if (Convert.ImplicitStandardConversionExists (expr, ctype)) return true; Error_TypeMustBeConvertible (expr.Type, ctype, ptype); return false; } - bool HasDefaultConstructor (EmitContext ec, Type atype) + bool HasDefaultConstructor (Type containerType, Type atype) { - if (atype is TypeBuilder) { - if (atype.IsAbstract) - return false; + if (atype.IsAbstract) + return false; + again: + atype = TypeManager.DropGenericTypeArguments (atype); + if (atype is TypeBuilder) { TypeContainer tc = TypeManager.LookupTypeContainer (atype); + if (tc.InstanceConstructors == null) { + atype = atype.BaseType; + goto again; + } + foreach (Constructor c in tc.InstanceConstructors) { if ((c.ModFlags & Modifiers.PUBLIC) == 0) continue; @@ -1617,18 +1697,22 @@ namespace Mono.CSharp { } } - MethodGroupExpr mg = Expression.MemberLookup ( - ec, atype, ".ctor", MemberTypes.Constructor, + TypeParameter tparam = TypeManager.LookupTypeParameter (atype); + if (tparam != null) + return tparam.HasConstructorConstraint; + + MemberList list = TypeManager.FindMembers ( + atype, MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance | - BindingFlags.DeclaredOnly, loc) - as MethodGroupExpr; + BindingFlags.DeclaredOnly, null, null); - if (!atype.IsAbstract && (mg != null) && mg.IsInstance) { - foreach (MethodBase mb in mg.Methods) { - ParameterData pd = TypeManager.GetParameterData (mb); - if (pd.Count == 0) - return true; - } + if (atype.IsAbstract || (list == null)) + return false; + + foreach (MethodBase mb in list) { + ParameterData pd = TypeManager.GetParameterData (mb); + if ((pd.Count == 0) && mb.IsPublic && !mb.IsStatic) + return true; } return false; @@ -1658,7 +1742,7 @@ namespace Mono.CSharp { return checker.CheckConstraints (ec); } - public static bool CheckConstraints (EmitContext ec, Type gt, Type[] gen_params, + public static bool CheckConstraints (IResolveContext ec, Type gt, Type[] gen_params, Type[] atypes, Location loc) { TypeConstraintChecker checker = new TypeConstraintChecker ( @@ -1720,7 +1804,7 @@ namespace Mono.CSharp { Expression return_type; Parameters parameters; - public GenericMethod (NamespaceEntry ns, TypeContainer parent, MemberName name, + public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name, Expression return_type, Parameters parameters) : base (ns, parent, name, null) { @@ -1735,8 +1819,6 @@ namespace Mono.CSharp { public override bool Define () { - ec = new EmitContext (this, this, Location, null, null, ModFlags, false); - for (int i = 0; i < TypeParameters.Length; i++) if (!TypeParameters [i].Resolve (this)) return false; @@ -1748,14 +1830,28 @@ namespace Mono.CSharp { /// Define and resolve the type parameters. /// We're called from Method.Define(). /// - public bool Define (MethodBuilder mb) + public bool Define (MethodBuilder mb, ToplevelBlock block) { - GenericTypeParameterBuilder[] gen_params; TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations (); string[] snames = new string [names.Length]; - for (int i = 0; i < names.Length; i++) - snames [i] = names [i].Name; - gen_params = mb.DefineGenericParameters (snames); + 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; + } + if (block != null) { + LocalInfo li = (LocalInfo)block.Variables[type_argument_name]; + if (li != null) { + Error_ParameterNameCollision (li.Location, type_argument_name, "local variable"); + return false; + } + } + snames[i] = type_argument_name; + } + + GenericTypeParameterBuilder[] gen_params = mb.DefineGenericParameters (snames); for (int i = 0; i < TypeParameters.Length; i++) TypeParameters [i].Define (gen_params [i]); @@ -1763,13 +1859,19 @@ namespace Mono.CSharp { return false; for (int i = 0; i < TypeParameters.Length; i++) { - if (!TypeParameters [i].ResolveType (ec)) + if (!TypeParameters [i].ResolveType (this)) return false; } return true; } + 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); + } + /// /// We're called from MethodData.Define() after creating the MethodBuilder. /// @@ -1786,19 +1888,19 @@ namespace Mono.CSharp { if (!p.Resolve (ec)) ok = false; } - if ((return_type != null) && (return_type.ResolveAsTypeTerminal (ec) == null)) + if ((return_type != null) && (return_type.ResolveAsTypeTerminal (ec, false) == null)) ok = false; return ok; } - public void EmitAttributes (EmitContext ec) + public void EmitAttributes () { for (int i = 0; i < TypeParameters.Length; i++) - TypeParameters [i].EmitAttributes (ec); + TypeParameters [i].EmitAttributes (); if (OptAttributes != null) - OptAttributes.Emit (ec, this); + OptAttributes.Emit (); } public override bool DefineMembers () @@ -1818,11 +1920,6 @@ namespace Mono.CSharp { } } - public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) - { - base.ApplyAttributeBuilder (a, cb); - } - public override AttributeTargets AttributeTargets { get { return AttributeTargets.Method | AttributeTargets.ReturnValue; @@ -1832,6 +1929,16 @@ namespace Mono.CSharp { public override string DocCommentHeader { get { return "M:"; } } + + public new void VerifyClsCompliance () + { + foreach (TypeParameter tp in TypeParameters) { + if (tp.Constraints == null) + continue; + + tp.Constraints.VerifyClsCompliance (); + } + } } public class DefaultValueExpression : Expression @@ -1846,26 +1953,43 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - TypeExpr texpr = expr.ResolveAsTypeTerminal (ec); + TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false); if (texpr == null) return null; type = texpr.Type; + if (type == TypeManager.void_type) { + Error_VoidInvalidInTheContext (loc); + return null; + } + + if (type.IsGenericParameter) + { + GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type); + if (constraints != null && constraints.IsReferenceType) + return new NullDefault (new NullLiteral (Location), type); + } + else + { + Constant c = New.Constantify(type); + if (c != null) + return new NullDefault (c, type); + + if (!TypeManager.IsValueType (type)) + return new NullDefault (new NullLiteral (Location), type); + } eclass = ExprClass.Variable; return this; } public override void Emit (EmitContext ec) { - if (type.IsGenericParameter || TypeManager.IsValueType (type)) { - LocalTemporary temp_storage = new LocalTemporary (ec, type); + LocalTemporary temp_storage = new LocalTemporary(type); - temp_storage.AddressOf (ec, AddressOp.LoadStore); - ec.ig.Emit (OpCodes.Initobj, type); - temp_storage.Emit (ec); - } else - ec.ig.Emit (OpCodes.Ldnull); + temp_storage.AddressOf(ec, AddressOp.LoadStore); + ec.ig.Emit(OpCodes.Initobj, type); + temp_storage.Emit(ec); } } @@ -1893,13 +2017,13 @@ namespace Mono.CSharp { get { return underlying.ToString () + "?"; } } - protected override TypeExpr DoResolveAsTypeStep (EmitContext ec) + 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); + return ctype.ResolveAsTypeTerminal (ec, false); } } @@ -1909,34 +2033,25 @@ namespace Mono.CSharp { // 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; - // - // Tracks the generic parameters. - // - static PtrHashtable builder_to_type_param; - // // These methods are called by code generated by the compiler // static public MethodInfo activator_create_instance; - static void InitGenerics () - { - builder_to_type_param = new PtrHashtable (); - } - - static void CleanUpGenerics () - { - builder_to_type_param = null; - } - 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 ( @@ -1958,23 +2073,12 @@ namespace Mono.CSharp { return CoreLookupType (ns, MemberName.MakeName (name, arity)); } - public static void AddTypeParameter (Type t, TypeParameter tparam) - { - if (!builder_to_type_param.Contains (t)) - builder_to_type_param.Add (t, tparam); - } - public static TypeContainer LookupGenericTypeContainer (Type t) { t = DropGenericTypeArguments (t); return LookupTypeContainer (t); } - public static TypeParameter LookupTypeParameter (Type t) - { - return (TypeParameter) builder_to_type_param [t]; - } - public static GenericConstraints GetTypeParameterConstraints (Type t) { if (!t.IsGenericParameter) @@ -1987,150 +2091,12 @@ namespace Mono.CSharp { return ReflectionConstraints.GetConstraints (t); } - public static bool HasGenericArguments (Type t) - { - return GetNumberOfTypeArguments (t) > 0; - } - - public static int GetNumberOfTypeArguments (Type t) - { - if (t.IsGenericParameter) - return 0; - DeclSpace tc = LookupDeclSpace (t); - if (tc != null) - return tc.IsGeneric ? tc.CountTypeParameters : 0; - else - return t.IsGenericType ? t.GetGenericArguments ().Length : 0; - } - - public static Type[] GetTypeArguments (Type t) - { - DeclSpace tc = LookupDeclSpace (t); - if (tc != null) { - if (!tc.IsGeneric) - return Type.EmptyTypes; - - TypeParameter[] tparam = tc.TypeParameters; - Type[] ret = new Type [tparam.Length]; - for (int i = 0; i < tparam.Length; i++) { - ret [i] = tparam [i].Type; - if (ret [i] == null) - throw new InternalErrorException (); - } - - return ret; - } else - return t.GetGenericArguments (); - } - - public static Type DropGenericTypeArguments (Type t) - { - if (!t.IsGenericType) - return t; - // Micro-optimization: a generic typebuilder is always a generic type definition - if (t is TypeBuilder) - return t; - return t.GetGenericTypeDefinition (); - } - - public static MethodBase DropGenericMethodArguments (MethodBase m) - { - if ((m is MethodBuilder) || (m is ConstructorInfo)) - return m; - if (m.IsGenericMethodDefinition) - return m; - if (m.IsGenericMethod || m.DeclaringType.IsGenericType) - return m.GetGenericMethodDefinition (); - return m; - } - - public static bool IsInstantiatedMethod (MethodBase m) - { - return m.IsGenericMethod || m.DeclaringType.IsGenericType; - } - - // - // Whether `array' is an array of T and `enumerator' is `IEnumerable'. - // For instance "string[]" -> "IEnumerable". - // - public static bool IsIEnumerable (Type array, Type enumerator) - { - if (!array.IsArray || !enumerator.IsGenericInstance) - return false; - - if (enumerator.GetGenericTypeDefinition () != generic_ienumerable_type) - return false; - - Type[] args = GetTypeArguments (enumerator); - return args [0] == GetElementType (array); - } - - public static bool IsEqual (Type a, Type b) - { - if (a.Equals (b)) - return true; - - if (a.IsGenericParameter && b.IsGenericParameter) { - if (a.DeclaringMethod != b.DeclaringMethod && - (a.DeclaringMethod == null || b.DeclaringMethod == null)) - return false; - return a.GenericParameterPosition == b.GenericParameterPosition; - } - - if (a.IsArray && b.IsArray) { - if (a.GetArrayRank () != b.GetArrayRank ()) - return false; - return IsEqual (a.GetElementType (), b.GetElementType ()); - } - - if (a.IsByRef && b.IsByRef) - return IsEqual (a.GetElementType (), b.GetElementType ()); - - if (a.IsGenericType && b.IsGenericType) { - if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ()) - return false; - - Type[] aargs = a.GetGenericArguments (); - Type[] bargs = b.GetGenericArguments (); - - if (aargs.Length != bargs.Length) - return false; - - for (int i = 0; i < aargs.Length; i++) { - if (!IsEqual (aargs [i], bargs [i])) - return false; - } - - return true; - } - - // - // This is to build with the broken circular dependencies between - // System and System.Configuration in the 2.x profile where we - // end up with a situation where: - // - // System on the second build is referencing the System.Configuration - // that has references to the first System build. - // - // Point in case: NameValueCollection built on the first pass, vs - // NameValueCollection build on the second one. The problem is that - // we need to override some methods sometimes, or we need to - // - if (RootContext.BrokenCircularDeps){ - if (a.Name == b.Name && a.Namespace == b.Namespace){ - Console.WriteLine ("GonziMatch: {0}.{1}", a.Namespace, a.Name); - return true; - } - } - return false; - } - /// /// Check whether `a' and `b' may become equal generic types. /// The algorithm to do that is a little bit complicated. /// - public static bool MayBecomeEqualGenericTypes (Type a, Type b, Type[] class_infered, - Type[] method_infered) + public static bool MayBecomeEqualGenericTypes (Type a, Type b, Type[] class_inferred, + Type[] method_inferred) { if (a.IsGenericParameter) { // @@ -2150,9 +2116,9 @@ namespace Mono.CSharp { // class X : I, I // class X : I, I // - if (b.IsGenericParameter || !b.IsGenericInstance) { + if (b.IsGenericParameter || !b.IsGenericType) { int pos = a.GenericParameterPosition; - Type[] args = a.DeclaringMethod != null ? method_infered : class_infered; + Type[] args = a.DeclaringMethod != null ? method_inferred : class_inferred; if (args [pos] == null) { args [pos] = b; return true; @@ -2184,7 +2150,7 @@ namespace Mono.CSharp { } if (b.IsGenericParameter) - return MayBecomeEqualGenericTypes (b, a, class_infered, method_infered); + return MayBecomeEqualGenericTypes (b, a, class_inferred, method_inferred); // // At this point, neither a nor b are a type parameter. @@ -2195,8 +2161,8 @@ namespace Mono.CSharp { // become equal). // - if (a.IsGenericInstance || b.IsGenericInstance) - return MayBecomeEqualGenericInstances (a, b, class_infered, method_infered); + if (a.IsGenericType || b.IsGenericType) + return MayBecomeEqualGenericInstances (a, b, class_inferred, method_inferred); // // If both of them are arrays. @@ -2209,7 +2175,7 @@ namespace Mono.CSharp { a = a.GetElementType (); b = b.GetElementType (); - return MayBecomeEqualGenericTypes (a, b, class_infered, method_infered); + return MayBecomeEqualGenericTypes (a, b, class_inferred, method_inferred); } // @@ -2224,123 +2190,72 @@ namespace Mono.CSharp { // particular instantiation (26.3.1). // public static bool MayBecomeEqualGenericInstances (Type a, Type b, - Type[] class_infered, - Type[] method_infered) + Type[] class_inferred, + Type[] method_inferred) { - if (!a.IsGenericInstance || !b.IsGenericInstance) + if (!a.IsGenericType || !b.IsGenericType) return false; if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ()) return false; return MayBecomeEqualGenericInstances ( - GetTypeArguments (a), GetTypeArguments (b), class_infered, method_infered); + GetTypeArguments (a), GetTypeArguments (b), class_inferred, method_inferred); } public static bool MayBecomeEqualGenericInstances (Type[] aargs, Type[] bargs, - Type[] class_infered, - Type[] method_infered) + Type[] class_inferred, + Type[] method_inferred) { if (aargs.Length != bargs.Length) return false; for (int i = 0; i < aargs.Length; i++) { - if (!MayBecomeEqualGenericTypes (aargs [i], bargs [i], class_infered, method_infered)) + if (!MayBecomeEqualGenericTypes (aargs [i], bargs [i], class_inferred, method_inferred)) return false; } return true; } - /// - /// Check whether `type' and `parent' are both instantiations of the same - /// generic type. Note that we do not check the type parameters here. - /// - public static bool IsInstantiationOfSameGenericType (Type type, Type parent) - { - int tcount = GetNumberOfTypeArguments (type); - int pcount = GetNumberOfTypeArguments (parent); - - if (tcount != pcount) - return false; - - type = DropGenericTypeArguments (type); - parent = DropGenericTypeArguments (parent); - - return type.Equals (parent); - } - - /// - /// Whether `mb' is a generic method definition. - /// - public static bool IsGenericMethodDefinition (MethodBase mb) + static bool UnifyType (Type pt, Type at, Type[] inferred) { - if (mb.DeclaringType is TypeBuilder) { - IMethodData method = (IMethodData) builder_to_method [mb]; - if (method == null) - return false; + if (pt.IsGenericParameter) { + if (pt.DeclaringMethod == null) + return pt == at; - return method.GenericMethod != null; - } - - return mb.IsGenericMethodDefinition; - } - - /// - /// Whether `mb' is a generic method definition. - /// - public static bool IsGenericMethod (MethodBase mb) - { - if (mb.DeclaringType is TypeBuilder) { - IMethodData method = (IMethodData) builder_to_method [mb]; - if (method == null) - return false; - - return method.GenericMethod != null; - } - - return mb.IsGenericMethod; - } - - // - // Type inference. - // - - static bool InferType (Type pt, Type at, Type[] infered) - { - if (pt.IsGenericParameter && (pt.DeclaringMethod != null)) { int pos = pt.GenericParameterPosition; - if (infered [pos] == null) { - Type check = at; - while (check.IsArray) - check = check.GetElementType (); - - if (pt == check) - return false; - - infered [pos] = at; - return true; - } - - if (infered [pos] != at) - return false; + if (inferred [pos] == null) + inferred [pos] = at; - return true; + return inferred [pos] == at; } if (!pt.ContainsGenericParameters) { if (at.ContainsGenericParameters) - return InferType (at, pt, infered); + return UnifyType (at, pt, inferred); else return true; } if (at.IsArray) { - if (!pt.IsArray || - (at.GetArrayRank () != pt.GetArrayRank ())) + if (pt.IsArray) { + if (at.GetArrayRank () != pt.GetArrayRank ()) + return false; + + return UnifyType (pt.GetElementType (), at.GetElementType (), inferred); + } + + if (!pt.IsGenericType) return false; - return InferType (pt.GetElementType (), at.GetElementType (), infered); + Type gt = pt.GetGenericTypeDefinition (); + if ((gt != generic_ilist_type) && (gt != generic_icollection_type) && + (gt != generic_ienumerable_type)) + return false; + + Type[] args = GetTypeArguments (pt); + return UnifyType (args [0], at.GetElementType (), inferred); } if (pt.IsArray) { @@ -2348,64 +2263,39 @@ namespace Mono.CSharp { (pt.GetArrayRank () != at.GetArrayRank ())) return false; - return InferType (pt.GetElementType (), at.GetElementType (), infered); + return UnifyType (pt.GetElementType (), at.GetElementType (), inferred); } if (pt.IsByRef && at.IsByRef) - return InferType (pt.GetElementType (), at.GetElementType (), infered); + return UnifyType (pt.GetElementType (), at.GetElementType (), inferred); ArrayList list = new ArrayList (); - if (at.IsGenericInstance) + if (at.IsGenericType) list.Add (at); for (Type bt = at.BaseType; bt != null; bt = bt.BaseType) list.Add (bt); list.AddRange (TypeManager.GetInterfaces (at)); - bool found_one = false; - foreach (Type type in list) { - if (!type.IsGenericInstance) + if (!type.IsGenericType) continue; - Type[] infered_types = new Type [infered.Length]; - - if (!InferGenericInstance (pt, type, infered_types)) + if (DropGenericTypeArguments (pt) != DropGenericTypeArguments (type)) continue; - for (int i = 0; i < infered_types.Length; i++) { - if (infered [i] == null) { - infered [i] = infered_types [i]; - continue; - } - - if (infered [i] != infered_types [i]) - return false; - } - - found_one = true; + if (!UnifyTypes (pt.GetGenericArguments (), type.GetGenericArguments (), inferred)) + return false; } - return found_one; + return true; } - static bool InferGenericInstance (Type pt, Type at, Type[] infered_types) + static bool UnifyTypes (Type[] pts, Type [] ats, Type [] inferred) { - Type[] at_args = at.GetGenericArguments (); - Type[] pt_args = pt.GetGenericArguments (); - - if (at_args.Length != pt_args.Length) - return false; - - for (int i = 0; i < at_args.Length; i++) { - if (!InferType (pt_args [i], at_args [i], infered_types)) - return false; - } - - for (int i = 0; i < infered_types.Length; i++) { - if (infered_types [i] == null) + for (int i = 0; i < ats.Length; i++) { + if (!UnifyType (pts [i], ats [i], inferred)) return false; } - return true; } @@ -2418,34 +2308,28 @@ namespace Mono.CSharp { public static bool InferParamsTypeArguments (EmitContext ec, ArrayList arguments, ref MethodBase method) { - if ((arguments == null) || !TypeManager.IsGenericMethod (method)) + if (!TypeManager.IsGenericMethod (method)) return true; - int arg_count; - - if (arguments == null) - arg_count = 0; - else - arg_count = arguments.Count; - - ParameterData pd = TypeManager.GetParameterData (method); + // if there are no arguments, there's no way to infer the type-arguments + if (arguments == null || arguments.Count == 0) + return false; + ParameterData pd = TypeManager.GetParameterData (method); int pd_count = pd.Count; + int arg_count = arguments.Count; if (pd_count == 0) return false; - + if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) return false; - + if (pd_count - 1 > arg_count) return false; - - if (pd_count == 1 && arg_count == 0) - return true; Type[] method_args = method.GetGenericArguments (); - Type[] infered_types = new Type [method_args.Length]; + Type[] inferred_types = new Type [method_args.Length]; // // If we have come this far, the case which @@ -2461,7 +2345,7 @@ namespace Mono.CSharp { Type pt = pd.ParameterType (i); Type at = a.Type; - if (!InferType (pt, at, infered_types)) + if (!UnifyType (pt, at, inferred_types)) return false; } @@ -2473,34 +2357,31 @@ namespace Mono.CSharp { if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr)) continue; - if (!InferType (element_type, a.Type, infered_types)) + if (!UnifyType (element_type, a.Type, inferred_types)) return false; } - for (int i = 0; i < infered_types.Length; i++) - if (infered_types [i] == null) + for (int i = 0; i < inferred_types.Length; i++) + if (inferred_types [i] == null) return false; - method = ((MethodInfo)method).MakeGenericMethod (infered_types); + method = ((MethodInfo)method).MakeGenericMethod (inferred_types); return true; } static bool InferTypeArguments (Type[] param_types, Type[] arg_types, - Type[] infered_types) + Type[] inferred_types) { - if (infered_types == null) - return false; - for (int i = 0; i < arg_types.Length; i++) { if (arg_types [i] == null) continue; - if (!InferType (param_types [i], arg_types [i], infered_types)) + if (!UnifyType (param_types [i], arg_types [i], inferred_types)) return false; } - for (int i = 0; i < infered_types.Length; i++) - if (infered_types [i] == null) + for (int i = 0; i < inferred_types.Length; i++) + if (inferred_types [i] == null) return false; return true; @@ -2512,7 +2393,7 @@ namespace Mono.CSharp { /// when resolving an Invocation or a DelegateInvocation and the user /// did not explicitly specify type arguments. /// - public static bool InferTypeArguments (EmitContext ec, ArrayList arguments, + public static bool InferTypeArguments (ArrayList arguments, ref MethodBase method) { if (!TypeManager.IsGenericMethod (method)) @@ -2537,10 +2418,12 @@ namespace Mono.CSharp { break; } } + + // If none of the method parameters mention a generic parameter, we can't infer the generic parameters if (!is_open) - return true; + return !TypeManager.IsGenericMethodDefinition (method); - Type[] infered_types = new Type [method_args.Length]; + Type[] inferred_types = new Type [method_args.Length]; Type[] param_types = new Type [pd.Count]; Type[] arg_types = new Type [pd.Count]; @@ -2550,23 +2433,23 @@ namespace Mono.CSharp { Argument a = (Argument) arguments [i]; if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr) || - (a.Expr is AnonymousMethod)) + (a.Expr is AnonymousMethodExpression)) continue; arg_types [i] = a.Type; } - if (!InferTypeArguments (param_types, arg_types, infered_types)) + if (!InferTypeArguments (param_types, arg_types, inferred_types)) return false; - method = ((MethodInfo)method).MakeGenericMethod (infered_types); + method = ((MethodInfo)method).MakeGenericMethod (inferred_types); return true; } /// /// Type inference. /// - public static bool InferTypeArguments (EmitContext ec, ParameterData apd, + public static bool InferTypeArguments (ParameterData apd, ref MethodBase method) { if (!TypeManager.IsGenericMethod (method)) @@ -2577,7 +2460,7 @@ namespace Mono.CSharp { return false; Type[] method_args = method.GetGenericArguments (); - Type[] infered_types = new Type [method_args.Length]; + Type[] inferred_types = new Type [method_args.Length]; Type[] param_types = new Type [pd.Count]; Type[] arg_types = new Type [pd.Count]; @@ -2587,22 +2470,17 @@ namespace Mono.CSharp { arg_types [i] = apd.ParameterType (i); } - if (!InferTypeArguments (param_types, arg_types, infered_types)) + if (!InferTypeArguments (param_types, arg_types, inferred_types)) return false; - method = ((MethodInfo)method).MakeGenericMethod (infered_types); + method = ((MethodInfo)method).MakeGenericMethod (inferred_types); return true; } - - public static bool IsNullableType (Type t) - { - return generic_nullable_type == DropGenericTypeArguments (t); - } } public abstract class Nullable { - protected sealed class NullableInfo + public sealed class NullableInfo { public readonly Type Type; public readonly Type UnderlyingType; @@ -2624,7 +2502,7 @@ namespace Mono.CSharp { } } - protected class Unwrap : Expression, IMemoryLocation, IAssignMethod + public class Unwrap : Expression, IMemoryLocation, IAssignMethod { Expression expr; NullableInfo info; @@ -2632,10 +2510,15 @@ namespace Mono.CSharp { LocalTemporary temp; bool has_temp; - public Unwrap (Expression expr, Location loc) + protected Unwrap (Expression expr) { this.expr = expr; - this.loc = loc; + 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) @@ -2644,8 +2527,7 @@ namespace Mono.CSharp { if (expr == null) return null; - if (!(expr is IMemoryLocation)) - temp = new LocalTemporary (ec, expr.Type); + temp = new LocalTemporary (expr.Type); info = new NullableInfo (expr.Type); type = info.UnderlyingType; @@ -2665,6 +2547,11 @@ namespace Mono.CSharp { 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) { @@ -2699,26 +2586,52 @@ namespace Mono.CSharp { public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { - source.Emit (ec); - ec.ig.Emit (OpCodes.Newobj, info.Constructor); + InternalWrap wrap = new InternalWrap (source, info, loc); + ((IAssignMethod) expr).EmitAssign (ec, wrap, leave_copy, false); + } - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); + 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; - Expression empty = new EmptyExpression (expr.Type); - ((IAssignMethod) expr).EmitAssign (ec, empty, false, prepare_for_load); + 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); + } } } - protected class Wrap : Expression + public class Wrap : Expression { Expression expr; NullableInfo info; - public Wrap (Expression expr, Location loc) + protected Wrap (Expression expr) { this.expr = expr; - this.loc = loc; + 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) @@ -2728,7 +2641,7 @@ namespace Mono.CSharp { return null; TypeExpr target_type = new NullableType (expr.Type, loc); - target_type = target_type.ResolveAsTypeTerminal (ec); + target_type = target_type.ResolveAsTypeTerminal (ec, false); if (target_type == null) return null; @@ -2745,11 +2658,11 @@ namespace Mono.CSharp { } } - public class NullableLiteral : Expression, IMemoryLocation { + public class NullableLiteral : NullLiteral, IMemoryLocation { public NullableLiteral (Type target_type, Location loc) + : base (loc) { this.type = target_type; - this.loc = loc; eclass = ExprClass.Value; } @@ -2761,7 +2674,7 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - LocalTemporary value_target = new LocalTemporary (ec, type); + LocalTemporary value_target = new LocalTemporary (type); value_target.AddressOf (ec, AddressOp.Store); ec.ig.Emit (OpCodes.Initobj, type); @@ -2770,7 +2683,7 @@ namespace Mono.CSharp { public void AddressOf (EmitContext ec, AddressOp Mode) { - LocalTemporary value_target = new LocalTemporary (ec, type); + LocalTemporary value_target = new LocalTemporary (type); value_target.AddressOf (ec, AddressOp.Store); ec.ig.Emit (OpCodes.Initobj, type); @@ -2795,7 +2708,7 @@ namespace Mono.CSharp { if (expr == null) return null; - unwrap = (Unwrap) new Unwrap (expr, loc).Resolve (ec); + unwrap = Unwrap.Create (expr, ec); if (unwrap == null) return null; @@ -2803,7 +2716,7 @@ namespace Mono.CSharp { if (underlying == null) return null; - wrap = new Wrap (underlying, loc).Resolve (ec); + wrap = Wrap.Create (underlying, ec); if (wrap == null) return null; @@ -2910,7 +2823,8 @@ namespace Mono.CSharp { { public readonly Binary.Operator Oper; - Expression left, right, underlying, null_value, bool_wrap; + Expression left, right, original_left, original_right; + Expression underlying, null_value, bool_wrap; Unwrap left_unwrap, right_unwrap; bool is_equality, is_comparision, is_boolean; @@ -2918,32 +2832,38 @@ namespace Mono.CSharp { Location loc) { this.Oper = op; - this.left = left; - this.right = right; + this.left = original_left = left; + this.right = original_right = right; this.loc = loc; } public override Expression DoResolve (EmitContext ec) { if (TypeManager.IsNullableType (left.Type)) { - left_unwrap = new Unwrap (left, loc); - left = left_unwrap.Resolve (ec); + left = left_unwrap = Unwrap.Create (left, ec); if (left == null) return null; } if (TypeManager.IsNullableType (right.Type)) { - right_unwrap = new Unwrap (right, loc); - right = right_unwrap.Resolve (ec); + right = right_unwrap = Unwrap.Create (right, ec); if (right == null) return null; } - if (((Oper == Binary.Operator.BitwiseAnd) || (Oper == Binary.Operator.BitwiseOr) || - (Oper == Binary.Operator.LogicalAnd) || (Oper == Binary.Operator.LogicalOr)) && + if ((Oper == Binary.Operator.LogicalAnd) || + (Oper == Binary.Operator.LogicalOr)) { + Binary.Error_OperatorCannotBeApplied ( + loc, Binary.OperName (Oper), + original_left.GetSignatureForError (), + original_right.GetSignatureForError ()); + 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 = new Wrap (empty, loc).Resolve (ec); + bool_wrap = Wrap.Create (empty, ec); null_value = new NullableLiteral (bool_wrap.Type, loc).Resolve (ec); type = bool_wrap.Type; @@ -2972,7 +2892,7 @@ namespace Mono.CSharp { if (underlying == null) return null; - underlying = new Wrap (underlying, loc).Resolve (ec); + underlying = Wrap.Create (underlying, ec); if (underlying == null) return null; @@ -3052,95 +2972,70 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - Label left_not_null_label = ig.DefineLabel (); - Label false_label = ig.DefineLabel (); - Label true_label = ig.DefineLabel (); - Label end_label = ig.DefineLabel (); - - bool false_label_used = false; - bool true_label_used = false; + // 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 (left_unwrap != null) { + if (right is NullLiteral) { + if (left_unwrap == null) + throw new InternalErrorException (); left_unwrap.EmitCheck (ec); - if (right is NullLiteral) { - if (Oper == Binary.Operator.Equality) { - true_label_used = true; - ig.Emit (OpCodes.Brfalse, true_label); - } else { - false_label_used = true; - ig.Emit (OpCodes.Brfalse, false_label); - } - } else if (right_unwrap != null) { - ig.Emit (OpCodes.Dup); - ig.Emit (OpCodes.Brtrue, left_not_null_label); - right_unwrap.EmitCheck (ec); + if (Oper == Binary.Operator.Equality) { + ig.Emit (OpCodes.Ldc_I4_0); ig.Emit (OpCodes.Ceq); - if (Oper == Binary.Operator.Inequality) { - ig.Emit (OpCodes.Ldc_I4_0); - ig.Emit (OpCodes.Ceq); - } - ig.Emit (OpCodes.Br, end_label); - - ig.MarkLabel (left_not_null_label); - ig.Emit (OpCodes.Pop); - } else { - if (Oper == Binary.Operator.Equality) { - false_label_used = true; - ig.Emit (OpCodes.Brfalse, false_label); - } else { - true_label_used = true; - ig.Emit (OpCodes.Brfalse, true_label); - } } + return; } - if (right_unwrap != null) { + 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); - if (left is NullLiteral) { - if (Oper == Binary.Operator.Equality) { - true_label_used = true; - ig.Emit (OpCodes.Brfalse, true_label); - } else { - false_label_used = true; - ig.Emit (OpCodes.Brfalse, false_label); - } - } else { - if (Oper == Binary.Operator.Equality) { - false_label_used = true; - ig.Emit (OpCodes.Brfalse, false_label); - } else { - true_label_used = true; - ig.Emit (OpCodes.Brfalse, true_label); - } - } - } + ig.Emit (OpCodes.Bne_Un, dissimilar_label); - bool left_is_null = left is NullLiteral; - bool right_is_null = right is NullLiteral; - if (left_is_null || right_is_null) { - if (((Oper == Binary.Operator.Equality) && (left_is_null == right_is_null)) || - ((Oper == Binary.Operator.Inequality) && (left_is_null != right_is_null))) { - true_label_used = true; - ig.Emit (OpCodes.Br, true_label); - } else { - false_label_used = true; - ig.Emit (OpCodes.Br, false_label); - } - } else { - underlying.Emit (ec); + 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 (false_label); - if (false_label_used) { - ig.Emit (OpCodes.Ldc_I4_0); - if (true_label_used) - 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"); } - ig.MarkLabel (true_label); - if (true_label_used) + // 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); } @@ -3173,6 +3068,11 @@ namespace Mono.CSharp { 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; @@ -3225,9 +3125,8 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - unwrap = new Unwrap (expr, loc); - expr = unwrap.Resolve (ec); - if (expr == null) + unwrap = Unwrap.Create (expr, ec); + if (unwrap == null) return null; if (unwrap.Type != TypeManager.bool_type) @@ -3300,7 +3199,7 @@ namespace Mono.CSharp { if (TypeManager.IsNullableType (ltype)) { NullableInfo info = new NullableInfo (ltype); - unwrap = (Unwrap) new Unwrap (left, loc).Resolve (ec); + unwrap = Unwrap.Create (left, ec); if (unwrap == null) return null; @@ -3318,14 +3217,13 @@ namespace Mono.CSharp { return this; } - if (unwrap != null) { - expr = Convert.ImplicitConversion (ec, unwrap, rtype, loc); - if (expr != null) { - left = expr; - expr = right; - 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); @@ -3387,7 +3285,7 @@ namespace Mono.CSharp { if (expr == null) return null; - unwrap = (Unwrap) new Unwrap (expr, loc).Resolve (ec); + unwrap = Unwrap.Create (expr, ec); if (unwrap == null) return null;