X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fgeneric.cs;h=5406444662418957cd26daa44c1cf61fbe3ca863;hb=1733851d28faad34184ad6cbf25992e33f483e44;hp=512975246e8944751b251015350e1b6da9ce4326;hpb=077f5fdac02a90694b8924630fa21926225e8044;p=mono.git diff --git a/mcs/gmcs/generic.cs b/mcs/gmcs/generic.cs index 512975246e8..54064446624 100644 --- a/mcs/gmcs/generic.cs +++ b/mcs/gmcs/generic.cs @@ -152,7 +152,7 @@ namespace Mono.CSharp { TypeExpr class_constraint; ArrayList iface_constraints; ArrayList type_param_constraints; - int num_constraints, first_constraint; + int num_constraints; Type class_constraint_type; Type[] iface_constraint_types; Type effective_base_type; @@ -199,14 +199,26 @@ namespace Mono.CSharp { continue; } + int errors = Report.Errors; + FullNamedExpression fn = ((Expression) obj).ResolveAsTypeStep (ec); + + if (fn == null) { + if (errors != Report.Errors) + return false; + + Report.Error (246, loc, "Cannot find type '{0}'", obj); + return false; + } + TypeExpr expr; - if (obj is ConstructedType) { - ConstructedType cexpr = (ConstructedType) obj; + ConstructedType cexpr = fn as ConstructedType; + if (cexpr != null) { if (!cexpr.ResolveConstructedType (ec)) return false; + expr = cexpr; } else - expr = ((Expression) obj).ResolveAsTypeTerminal (ec); + expr = fn.ResolveAsTypeTerminal (ec); if (expr == null) return false; @@ -304,7 +316,11 @@ namespace Mono.CSharp { return false; } - list.Add (iface_constraint.Type); + TypeExpr te = iface_constraint.ResolveAsTypeTerminal (ec); + if (te == null) + return false; + + list.Add (te.Type); } foreach (TypeParameterExpr expr in type_param_constraints) { @@ -321,11 +337,30 @@ namespace Mono.CSharp { list.Add (expr.Type); } - iface_constraint_types = new Type [list.Count]; - list.CopyTo (iface_constraint_types, 0); + ArrayList new_list = new ArrayList (); + foreach (Type iface in list) { + if (new_list.Contains (iface)) + continue; + + new_list.Add (iface); + + Type [] implementing = TypeManager.GetInterfaces (iface); + + foreach (Type imp in implementing) { + if (!new_list.Contains (imp)) + new_list.Add (imp); + } + } + + iface_constraint_types = new Type [new_list.Count]; + new_list.CopyTo (iface_constraint_types, 0); if (class_constraint != null) { - class_constraint_type = class_constraint.Type; + TypeExpr te = class_constraint.ResolveAsTypeTerminal (ec); + if (te == null) + return false; + + class_constraint_type = te.Type; if (class_constraint_type == null) return false; @@ -598,7 +633,7 @@ namespace Mono.CSharp { mb = mb.GetGenericMethodDefinition (); int pos = type.GenericParameterPosition; - ParameterData pd = Invocation.GetParameterData (mb); + ParameterData pd = TypeManager.GetParameterData (mb); GenericConstraints temp_gc = pd.GenericConstraints (pos); Type mparam = mb.GetGenericArguments () [pos]; @@ -655,6 +690,32 @@ namespace Mono.CSharp { return true; } + public bool UpdateConstraints (EmitContext ec, Constraints new_constraints) + { + // + // We're used in partial generic type definitions. + // If `check' is false, we just encountered the first ClassPart which has + // constraints - they become our "real" constraints. + // Otherwise we're called after the type parameters have already been defined + // and check whether the constraints are the same in all parts. + // + if (type == null) + throw new InvalidOperationException (); + + if (constraints == null) { + new_constraints = constraints; + return true; + } else if (new_constraints == null) + return true; + + if (!new_constraints.Resolve (ec)) + return false; + if (!new_constraints.ResolveTypes (ec)) + return false; + + return constraints.CheckInterfaceMethod (ec, new_constraints); + } + public override string DocCommentHeader { get { throw new InvalidOperationException ( @@ -765,12 +826,10 @@ namespace Mono.CSharp { Type class_constraint; Type[] iface_constraints; Type[] dargs; - Type declaring; public InflatedConstraints (GenericConstraints gc, Type declaring) { this.gc = gc; - this.declaring = declaring; dargs = TypeManager.GetTypeArguments (declaring); @@ -1015,34 +1074,16 @@ namespace Mono.CSharp { } public class ConstructedType : TypeExpr { - string name, full_name; + string full_name; + FullNamedExpression name; TypeArguments args; Type[] gen_params, atypes; Type gt; - public ConstructedType (string name, TypeArguments args, Location l) - { - loc = l; - this.name = MemberName.MakeName (name, args.Count); - this.args = args; - - eclass = ExprClass.Type; - full_name = name + "<" + args.ToString () + ">"; - } - - public ConstructedType (string name, TypeParameter[] type_params, Location l) - : this (type_params, l) - { - loc = l; - - this.name = name; - full_name = name + "<" + args.ToString () + ">"; - } - public ConstructedType (FullNamedExpression fname, TypeArguments args, Location l) { loc = l; - this.name = fname.FullName; + this.name = fname; this.args = args; eclass = ExprClass.Type; @@ -1073,7 +1114,7 @@ namespace Mono.CSharp { { gt = t.GetGenericTypeDefinition (); - this.name = gt.FullName; + this.name = new TypeExpression (gt, l); full_name = gt.FullName + "<" + args.ToString () + ">"; } @@ -1082,7 +1123,7 @@ namespace Mono.CSharp { { gt = t.GetGenericTypeDefinition (); - this.name = gt.FullName; + this.name = new TypeExpression (gt, l); full_name = gt.FullName + "<" + args.ToString () + ">"; } @@ -1124,7 +1165,7 @@ namespace Mono.CSharp { } TypeExpr ct = new ConstructedType (ctype, new_args, loc); - if (ct.ResolveAsTypeTerminal (ec) == null) + if (ct.ResolveAsTypeStep (ec) == null) return false; ctype = ct.Type; } @@ -1258,17 +1299,6 @@ namespace Mono.CSharp { return true; } - public override TypeExpr ResolveAsTypeTerminal (EmitContext ec) - { - if (base.ResolveAsTypeTerminal (ec) == null) - return null; - - if (!CheckConstraints (ec)) - return null; - - return this; - } - public bool ResolveConstructedType (EmitContext ec) { if (type != null) @@ -1276,37 +1306,11 @@ namespace Mono.CSharp { if (gt != null) return DoResolveType (ec); - // - // First, resolve the generic type. - // - DeclSpace ds; - Type nested = ec.DeclSpace.FindNestedType (loc, name, out ds); - if (nested != null) { - gt = nested.GetGenericTypeDefinition (); - - TypeArguments new_args = new TypeArguments (loc); - if (ds.IsGeneric) { - foreach (TypeParameter param in ds.TypeParameters) - new_args.Add (new TypeParameterExpr (param, loc)); - } - new_args.Add (args); - - args = new_args; - return DoResolveType (ec); - } - - Type t; int num_args; + Type t = name.Type; - SimpleName sn = new SimpleName (name, loc); - TypeExpr resolved = sn.ResolveAsTypeTerminal (ec); - if (resolved == null) - return false; - - t = resolved.Type; if (t == null) { - Report.Error (246, loc, "Cannot find type `{0}'<...>", - Basename); + Report.Error (246, loc, "Cannot find type `{0}'<...>", Name); return false; } @@ -1352,7 +1356,7 @@ namespace Mono.CSharp { public Expression GetSimpleName (EmitContext ec) { - return new SimpleName (Basename, args, loc); + return this; } public override bool CheckAccessLevel (DeclSpace ds) @@ -1381,10 +1385,6 @@ namespace Mono.CSharp { get { return gt.IsSealed; } } - public override bool IsAttribute { - get { return false; } - } - public override bool Equals (object obj) { ConstructedType cobj = obj as ConstructedType; @@ -1402,16 +1402,6 @@ namespace Mono.CSharp { return base.GetHashCode (); } - public string Basename { - get { - int pos = name.LastIndexOf ('`'); - if (pos >= 0) - return name.Substring (0, pos); - else - return name; - } - } - public override string Name { get { return full_name; @@ -1440,26 +1430,25 @@ 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 (Parent)) + if (!TypeParameters [i].Resolve (this)) return false; return true; } - public bool Define (MethodBuilder mb, Type return_type) + public bool Define (MethodBuilder mb) { - if (!Define ()) - return false; - GenericTypeParameterBuilder[] gen_params; string[] names = MemberName.TypeArguments.GetDeclarations (); gen_params = mb.DefineGenericParameters (names); for (int i = 0; i < TypeParameters.Length; i++) TypeParameters [i].Define (gen_params [i]); - ec = new EmitContext ( - this, this, Location, null, return_type, ModFlags, false); + if (!Define ()) + return false; for (int i = 0; i < TypeParameters.Length; i++) { if (!TypeParameters [i].ResolveType (ec)) @@ -1521,7 +1510,6 @@ namespace Mono.CSharp { public class DefaultValueExpression : Expression { Expression expr; - LocalTemporary temp_storage; public DefaultValueExpression (Expression expr, Location loc) { @@ -1536,8 +1524,6 @@ namespace Mono.CSharp { return null; type = texpr.Type; - if (type.IsGenericParameter || TypeManager.IsValueType (type)) - temp_storage = new LocalTemporary (ec, type); eclass = ExprClass.Variable; return this; @@ -1545,7 +1531,9 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - if (temp_storage != null) { + if (type.IsGenericParameter || TypeManager.IsValueType (type)) { + LocalTemporary temp_storage = new LocalTemporary (ec, type); + temp_storage.AddressOf (ec, AddressOp.LoadStore); ec.ig.Emit (OpCodes.Initobj, type); temp_storage.Emit (ec); @@ -1566,6 +1554,10 @@ namespace Mono.CSharp { eclass = ExprClass.Type; } + public NullableType (Type type, Location loc) + : this (new TypeExpression (type, loc), loc) + { } + public override string Name { get { return underlying.ToString () + "?"; } } @@ -1658,15 +1650,6 @@ namespace Mono.CSharp { return (TypeParameter) builder_to_type_param [t]; } - public static bool HasConstructorConstraint (Type t) - { - GenericConstraints gc = GetTypeParameterConstraints (t); - if (gc == null) - return false; - - return (gc.Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; - } - public static GenericConstraints GetTypeParameterConstraints (Type t) { if (!t.IsGenericParameter) @@ -1720,6 +1703,22 @@ namespace Mono.CSharp { return t.GetGenericArguments (); } + // + // 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)) @@ -1998,12 +1997,10 @@ namespace Mono.CSharp { ArrayList list = new ArrayList (); if (at.IsGenericInstance) list.Add (at); - else { - for (Type bt = at.BaseType; bt != null; bt = bt.BaseType) - list.Add (bt); + for (Type bt = at.BaseType; bt != null; bt = bt.BaseType) + list.Add (bt); - list.AddRange (TypeManager.GetInterfaces (at)); - } + list.AddRange (TypeManager.GetInterfaces (at)); bool found_one = false; @@ -2066,7 +2063,7 @@ namespace Mono.CSharp { else arg_count = arguments.Count; - ParameterData pd = Invocation.GetParameterData (method); + ParameterData pd = TypeManager.GetParameterData (method); int pd_count = pd.Count; @@ -2155,7 +2152,7 @@ namespace Mono.CSharp { else arg_count = 0; - ParameterData pd = Invocation.GetParameterData (method); + ParameterData pd = TypeManager.GetParameterData (method); if (arg_count != pd.Count) return false; @@ -2180,7 +2177,8 @@ namespace Mono.CSharp { param_types [i] = pd.ParameterType (i); Argument a = (Argument) arguments [i]; - if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr)) + if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr) || + (a.Expr is AnonymousMethod)) continue; arg_types [i] = a.Type; @@ -2199,7 +2197,7 @@ namespace Mono.CSharp { if (!TypeManager.IsGenericMethod (method)) return true; - ParameterData pd = Invocation.GetParameterData (method); + ParameterData pd = TypeManager.GetParameterData (method); if (apd.Count != pd.Count) return false; @@ -2231,29 +2229,6 @@ namespace Mono.CSharp { } } - public class NullCoalescingOperator : Expression - { - Expression left; - Expression right; - - public NullCoalescingOperator (Expression left, Expression right, Location loc) - { - this.left = left; - this.right = right; - this.loc = loc; - } - - public override Expression DoResolve (EmitContext ec) - { - Error (-1, "The ?? operator is not yet implemented."); - return null; - } - - public override void Emit (EmitContext ec) - { - } - } - public abstract class Nullable { protected sealed class NullableInfo @@ -2278,8 +2253,129 @@ namespace Mono.CSharp { } } - public class NullLiteral : Expression, IMemoryLocation { - public NullLiteral (Type target_type, Location loc) + protected class Unwrap : Expression, IMemoryLocation, IAssignMethod + { + Expression expr; + NullableInfo info; + + LocalTemporary temp; + bool has_temp; + + public Unwrap (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; + + if (!(expr is IMemoryLocation)) + temp = new LocalTemporary (ec, 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); + } + + 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) + { + source.Emit (ec); + ec.ig.Emit (OpCodes.Newobj, info.Constructor); + + if (leave_copy) + ec.ig.Emit (OpCodes.Dup); + + Expression empty = new EmptyExpression (expr.Type); + ((IAssignMethod) expr).EmitAssign (ec, empty, false, prepare_for_load); + } + } + + protected class Wrap : Expression + { + Expression expr; + NullableInfo info; + + public Wrap (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; + + TypeExpr target_type = new NullableType (expr.Type, loc); + target_type = target_type.ResolveAsTypeTerminal (ec); + 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 : Expression, IMemoryLocation { + public NullableLiteral (Type target_type, Location loc) { this.type = target_type; this.loc = loc; @@ -2311,90 +2407,640 @@ namespace Mono.CSharp { } } - public class LiftedConversion : Expression + public abstract class Lifted : Expression, IMemoryLocation { - Expression source; - NullableInfo source_info, target_info; - Expression conversion; + Expression expr, underlying, wrap, null_value; + Unwrap unwrap; - protected LiftedConversion (Expression source, Type target_type, - NullableInfo source_info, NullableInfo target_info, - Expression conversion, Location loc) + protected Lifted (Expression expr, Location loc) { - this.source = source; - this.type = target_type; - this.source_info = source_info; - this.target_info = target_info; - this.conversion = conversion; + this.expr = expr; this.loc = loc; - - eclass = source.eclass; } - public static Expression Create (EmitContext ec, Expression source, Type target_type, - bool is_user, bool is_explicit, Location loc) + public override Expression DoResolve (EmitContext ec) { - NullableInfo source_info = new NullableInfo (source.Type); - NullableInfo target_info = new NullableInfo (target_type); + expr = expr.Resolve (ec); + if (expr == null) + return null; + + unwrap = (Unwrap) new Unwrap (expr, loc).Resolve (ec); + if (unwrap == null) + return null; + + underlying = ResolveUnderlying (unwrap, ec); + if (underlying == null) + return null; - source = source.Resolve (ec); - if (source == null) + wrap = new Wrap (underlying, loc).Resolve (ec); + if (wrap == null) return null; - Expression conversion; - if (is_user) { - conversion = Convert.UserDefinedConversion ( - ec, new EmptyExpression (source_info.UnderlyingType), - target_info.UnderlyingType, loc, is_explicit); + 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 (is_explicit) - conversion = Convert.ExplicitConversion ( - ec, new EmptyExpression (source_info.UnderlyingType), - target_info.UnderlyingType, loc); + if (IsExplicit) + return Convert.ExplicitConversion (ec, unwrap, type, loc); else - conversion = Convert.ImplicitConversion ( - ec, new EmptyExpression (source_info.UnderlyingType), - target_info.UnderlyingType, loc); + return Convert.ImplicitConversion (ec, unwrap, type, loc); } + } + } - if (conversion == null) - return null; + public class LiftedUnaryOperator : Lifted + { + public readonly Unary.Operator Oper; - return new LiftedConversion ( - source, target_type, source_info, target_info, conversion, loc); + 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, loc); + } + } + + public class LiftedBinaryOperator : Expression + { + public readonly Binary.Operator Oper; + + Expression left, right, 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) + { + this.Oper = op; + this.left = left; + this.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); + if (left == null) + return null; + } + + if (TypeManager.IsNullableType (right.Type)) { + right_unwrap = new Unwrap (right, loc); + right = right_unwrap.Resolve (ec); + if (right == null) + return null; + } + + if (((Oper == Binary.Operator.BitwiseAnd) || (Oper == Binary.Operator.BitwiseOr) || + (Oper == Binary.Operator.LogicalAnd) || (Oper == Binary.Operator.LogicalOr)) && + ((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); + 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, loc).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, loc).Resolve (ec); + if (underlying == null) + return null; + + type = TypeManager.bool_type; + is_comparision = true; + } else { + underlying = new Binary (Oper, left, right, loc).Resolve (ec); + if (underlying == null) + return null; + + underlying = new Wrap (underlying, loc).Resolve (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; + + Label left_not_null_label = ig.DefineLabel (); + Label false_label = ig.DefineLabel (); + Label true_label = ig.DefineLabel (); + Label end_label = ig.DefineLabel (); + + if (left_unwrap != null) { + left_unwrap.EmitCheck (ec); + if (right is NullLiteral) { + if (Oper == Binary.Operator.Equality) + ig.Emit (OpCodes.Brfalse, true_label); + else + 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); + 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) + ig.Emit (OpCodes.Brfalse, false_label); + else + ig.Emit (OpCodes.Brfalse, true_label); + } + } + + if (right_unwrap != null) { + right_unwrap.EmitCheck (ec); + if (left is NullLiteral) { + if (Oper == Binary.Operator.Equality) + ig.Emit (OpCodes.Brfalse, true_label); + else + ig.Emit (OpCodes.Brfalse, false_label); + } else { + if (Oper == Binary.Operator.Equality) + ig.Emit (OpCodes.Brfalse, false_label); + else + ig.Emit (OpCodes.Brfalse, true_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))) + ig.Emit (OpCodes.Br, true_label); + else + ig.Emit (OpCodes.Br, false_label); + } else { + underlying.Emit (ec); + ig.Emit (OpCodes.Br, end_label); + } + + ig.MarkLabel (false_label); + ig.Emit (OpCodes.Ldc_I4_0); + ig.Emit (OpCodes.Br, end_label); + + ig.MarkLabel (true_label); + ig.Emit (OpCodes.Ldc_I4_1); + + 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 Emit (EmitContext 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 has_value_label = ig.DefineLabel (); + + Label is_null_label = ig.DefineLabel (); Label end_label = ig.DefineLabel (); - ((IMemoryLocation) source).AddressOf (ec, AddressOp.LoadStore); - ig.EmitCall (OpCodes.Call, source_info.HasValue, null); - ig.Emit (OpCodes.Brtrue, has_value_label); + if (left_unwrap != null) { + left_unwrap.EmitCheck (ec); + ig.Emit (OpCodes.Brfalse, is_null_label); + } - LocalTemporary value_target = new LocalTemporary (ec, type); - value_target.AddressOf (ec, AddressOp.Store); - ig.Emit (OpCodes.Initobj, type); - value_target.Emit (ec); - value_target.Release (ec); + 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 = new Unwrap (expr, loc); + expr = unwrap.Resolve (ec); + if (expr == 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 (has_value_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) && ltype.IsValueType) { + Binary.Error_OperatorCannotBeApplied (loc, "??", ltype, rtype); + return null; + } + + if (TypeManager.IsNullableType (ltype)) { + NullableInfo info = new NullableInfo (ltype); + + unwrap = (Unwrap) new Unwrap (left, loc).Resolve (ec); + if (unwrap == null) + return null; + + expr = Convert.ImplicitConversion (ec, right, info.UnderlyingType, loc); + if (expr != null) { + left = unwrap; + type = expr.Type; + return this; + } + } + + expr = Convert.ImplicitConversion (ec, right, ltype, loc); + if (expr != null) { + type = expr.Type; + return this; + } + + if (unwrap != null) { + expr = Convert.ImplicitConversion (ec, unwrap, rtype, loc); + if (expr != null) { + left = expr; + expr = right; + type = expr.Type; + 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); + } + } + } + + 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) new Unwrap (expr, loc).Resolve (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); - ((IMemoryLocation) source).AddressOf (ec, AddressOp.LoadStore); - ig.EmitCall (OpCodes.Call, source_info.Value, null); - conversion.Emit (ec); - ig.Emit (OpCodes.Newobj, target_info.Constructor); + 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); + } } } }