X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fnullable.cs;h=3988b0c62a5a714d3ab4c693c860bb6ee16384da;hb=484d2078d49d97f61f675bc4e31c75f2bafea901;hp=73f711a7e50394d00734d8c98ec2cc806d6582ce;hpb=03f6e7fdd6ba00253b5e6b0f2ba0caf3f776a59b;p=mono.git diff --git a/mcs/mcs/nullable.cs b/mcs/mcs/nullable.cs index 73f711a7e50..3988b0c62a5 100644 --- a/mcs/mcs/nullable.cs +++ b/mcs/mcs/nullable.cs @@ -20,9 +20,9 @@ namespace Mono.CSharp.Nullable { public class NullableType : TypeExpr { - Expression underlying; + TypeExpr underlying; - public NullableType (Expression underlying, Location l) + public NullableType (TypeExpr underlying, Location l) { this.underlying = underlying; loc = l; @@ -36,41 +36,44 @@ namespace Mono.CSharp.Nullable protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec) { - TypeArguments args = new TypeArguments (loc); - args.Add (underlying); - if (TypeManager.generic_nullable_type == null) { TypeManager.generic_nullable_type = TypeManager.CoreLookupType ( "System", "Nullable`1", Kind.Struct, true); } - ConstructedType ctype = new ConstructedType (TypeManager.generic_nullable_type, args, loc); + TypeArguments args = new TypeArguments (underlying); + GenericTypeExpr ctype = new GenericTypeExpr (TypeManager.generic_nullable_type, args, loc); return ctype.ResolveAsTypeTerminal (ec, false); } + + public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent) + { + return ResolveAsBaseTerminal (ec, silent); + } } public sealed class NullableInfo { public readonly Type Type; public readonly Type UnderlyingType; - public readonly MethodInfo HasValue; - public readonly MethodInfo Value; - public readonly MethodInfo GetValueOrDefault; - public readonly ConstructorInfo Constructor; + public MethodInfo HasValue; + public MethodInfo Value; + public MethodInfo GetValueOrDefault; + public ConstructorInfo Constructor; public NullableInfo (Type type) { Type = type; UnderlyingType = TypeManager.GetTypeArguments (type) [0]; - PropertyInfo has_value_pi = TypeManager.GetPredefinedProperty (type, "HasValue", Location.Null); - PropertyInfo value_pi = TypeManager.GetPredefinedProperty (type, "Value", Location.Null); + PropertyInfo has_value_pi = TypeManager.GetPredefinedProperty (type, "HasValue", Location.Null, Type.EmptyTypes); + PropertyInfo value_pi = TypeManager.GetPredefinedProperty (type, "Value", Location.Null, Type.EmptyTypes); GetValueOrDefault = TypeManager.GetPredefinedMethod (type, "GetValueOrDefault", Location.Null, Type.EmptyTypes); HasValue = has_value_pi.GetGetMethod (false); Value = value_pi.GetGetMethod (false); #if MS_COMPATIBLE - if (UnderlyingType.Module == CodeGen.Module.Builder) { + if (UnderlyingType.Module == RootContext.ToplevelTypes.Builder) { Type o_type = TypeManager.DropGenericTypeArguments (type); Constructor = TypeBuilder.GetConstructor (type, TypeManager.GetPredefinedConstructor (o_type, Location.Null, o_type.GetGenericArguments ())); @@ -87,58 +90,64 @@ namespace Mono.CSharp.Nullable NullableInfo info; LocalTemporary temp; + readonly bool useDefaultValue; - protected Unwrap (Expression expr) + Unwrap (Expression expr, bool useDefaultValue) { this.expr = expr; this.loc = expr.Location; + this.useDefaultValue = useDefaultValue; + + info = new NullableInfo (expr.Type); + type = info.UnderlyingType; + eclass = expr.eclass; } - public static Unwrap Create (Expression expr, EmitContext ec) + public static Expression Create (Expression expr) { - return new Unwrap (expr).Resolve (ec) as Unwrap; + // + // Avoid unwraping and wraping of same type + // + Wrap wrap = expr as Wrap; + if (wrap != null) + return wrap.Child; + + return Create (expr, false); + } + + public static Unwrap Create (Expression expr, bool useDefaultValue) + { + return new Unwrap (expr, useDefaultValue); } public override Expression CreateExpressionTree (EmitContext ec) { return expr.CreateExpressionTree (ec); - } + } public override Expression DoResolve (EmitContext ec) { - if (expr == null) - return null; - - info = new NullableInfo (expr.Type); - type = info.UnderlyingType; - eclass = expr.eclass; return this; } - + public override Expression DoResolveLValue (EmitContext ec, Expression right_side) { return DoResolve (ec); - } + } public override void Emit (EmitContext ec) { Store (ec); - AddressOf (ec, AddressOp.LoadStore); - ec.ig.EmitCall (OpCodes.Call, info.Value, null); + if (useDefaultValue) + Invocation.EmitCall (ec, false, this, info.GetValueOrDefault, null, loc); + else + Invocation.EmitCall (ec, false, this, info.Value, null, loc); } public void EmitCheck (EmitContext ec) { Store (ec); - AddressOf (ec, AddressOp.LoadStore); - ec.ig.EmitCall (OpCodes.Call, info.HasValue, null); - } - - public void EmitGetValueOrDefault (EmitContext ec) - { - Store (ec); - AddressOf (ec, AddressOp.LoadStore); - ec.ig.EmitCall (OpCodes.Call, info.GetValueOrDefault, null); + Invocation.EmitCall (ec, false, this, info.HasValue, null, loc); } public override bool Equals (object obj) @@ -184,6 +193,15 @@ namespace Mono.CSharp.Nullable LocalVariable.Emit (ec); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + type = storey.MutateType (type); + info.Constructor = storey.MutateConstructor (info.Constructor); + info.HasValue = storey.MutateGenericMethod (info.HasValue); + info.GetValueOrDefault = storey.MutateGenericMethod (info.GetValueOrDefault); + info.Value = storey.MutateGenericMethod (info.Value); + } + public void AddressOf (EmitContext ec, AddressOp mode) { IMemoryLocation ml = expr as VariableReference; @@ -263,6 +281,21 @@ namespace Mono.CSharp.Nullable eclass = ExprClass.Value; } + public Expression Child { + get { return child; } + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + TypeCast child_cast = child as TypeCast; + if (child_cast != null) { + child.Type = type; + return child_cast.CreateExpressionTree (ec); + } + + return base.CreateExpressionTree (ec); + } + public static Expression Create (Expression expr, Type type) { // @@ -335,57 +368,47 @@ namespace Mono.CSharp.Nullable } } - public abstract class Lifted : Expression, IMemoryLocation + public class Lifted : Expression, IMemoryLocation { - Expression expr, underlying, wrap, null_value; + Expression expr, wrap, null_value; Unwrap unwrap; - protected Lifted (Expression expr, Location loc) + public Lifted (Expression expr, Unwrap unwrap, Type type) { this.expr = expr; - this.loc = loc; + this.unwrap = unwrap; + this.loc = expr.Location; + this.type = type; + } + + public Lifted (Expression expr, Expression unwrap, Type type) + : this (expr, unwrap as Unwrap, type) + { } public override Expression CreateExpressionTree (EmitContext ec) { - ArrayList args = new ArrayList (2); - args.Add (new Argument (expr.CreateExpressionTree (ec))); - args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc))); - return CreateExpressionFactoryCall ("Convert", args); + return wrap.CreateExpressionTree (ec); } public override Expression DoResolve (EmitContext ec) { - expr = expr.Resolve (ec); - if (expr == null) + wrap = Wrap.Create (expr, type); + if (wrap == null) return null; - unwrap = Unwrap.Create (expr, ec); + // + // It's null when lifted conversion is transparent + // if (unwrap == null) - return null; - - underlying = ResolveUnderlying (unwrap, ec); - if (underlying == null) - return null; - - TypeExpr target_type = new NullableType (underlying.Type, loc); - target_type = target_type.ResolveAsTypeTerminal (ec, false); - if (target_type == null) - return null; - - wrap = Wrap.Create (underlying, target_type.Type); - if (wrap == null) - return null; + return wrap; - null_value = LiftedNull.Create (wrap.Type, loc); + null_value = LiftedNull.Create (type, loc); - 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; @@ -410,46 +433,13 @@ namespace Mono.CSharp.Nullable } } - 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) { - if (IsExplicit) - return Convert.ExplicitUserConversion (ec, unwrap, type, loc); - else - return Convert.ImplicitUserConversion (ec, unwrap, type, loc); - } else { - if (IsExplicit) - return Convert.ExplicitConversion (ec, unwrap, type, loc); - else - return Convert.ImplicitConversion (ec, unwrap, type, loc); - } - } - } - public class LiftedUnaryOperator : Unary, IMemoryLocation { Unwrap unwrap; Expression user_operator; - public LiftedUnaryOperator (Unary.Operator op, Expression expr, Location loc) - : base (op, expr, loc) + public LiftedUnaryOperator (Unary.Operator op, Expression expr) + : base (op, expr) { } @@ -474,7 +464,7 @@ namespace Mono.CSharp.Nullable if (eclass != ExprClass.Invalid) return this; - unwrap = Unwrap.Create (Expr, ec); + unwrap = Unwrap.Create (Expr, false); if (unwrap == null) return null; @@ -593,11 +583,10 @@ namespace Mono.CSharp.Nullable Constant c = new BoolConstant (Oper == Operator.Inequality, loc); if ((Oper & Operator.EqualityMask) != 0) { - Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " + - "This operation is undocumented and it is temporary supported for compatibility reasons only", + Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is `{1}'", expr.GetSignatureForError (), c.AsString ()); } else { - Report.Warning (464, 2, loc, "The result of comparing type `{0}' against null is always `{1}'", + Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'", expr.GetSignatureForError (), c.AsString ()); } @@ -614,16 +603,17 @@ namespace Mono.CSharp.Nullable return null; } + bool use_default_call = (Oper & (Operator.BitwiseMask | Operator.EqualityMask)) != 0; left_orig = left; if (TypeManager.IsNullableType (left.Type)) { - left = left_unwrap = Unwrap.Create (left, ec); + left = left_unwrap = Unwrap.Create (left, use_default_call); if (left == null) return null; } right_orig = right; if (TypeManager.IsNullableType (right.Type)) { - right = right_unwrap = Unwrap.Create (right, ec); + right = right_unwrap = Unwrap.Create (right, use_default_call); if (right == null) return null; } @@ -633,13 +623,13 @@ namespace Mono.CSharp.Nullable // Arguments can be lifted for equal operators when the return type is bool and both // arguments are of same type // - if (left is NullLiteral) { + if (left_orig.IsNull) { left = right; left_null_lifted = true; type = TypeManager.bool_type; } - if (right is NullLiteral) { + if (right_orig.IsNull) { right = left; right_null_lifted = true; type = TypeManager.bool_type; @@ -657,10 +647,10 @@ namespace Mono.CSharp.Nullable Label load_right = ig.DefineLabel (); Label end_label = ig.DefineLabel (); - left_unwrap.EmitGetValueOrDefault (ec); + left_unwrap.Emit (ec); ig.Emit (OpCodes.Brtrue_S, load_right); - right_unwrap.EmitGetValueOrDefault (ec); + right_unwrap.Emit (ec); ig.Emit (OpCodes.Brtrue_S, load_left); left_unwrap.EmitCheck (ec); @@ -687,7 +677,7 @@ namespace Mono.CSharp.Nullable // // Emits optimized equality or inequality operator when possible // - bool EmitEquality (EmitContext ec) + void EmitEquality (EmitContext ec) { ILGenerator ig = ec.ig; @@ -700,7 +690,7 @@ namespace Mono.CSharp.Nullable ig.Emit (OpCodes.Ldc_I4_0); ig.Emit (OpCodes.Ceq); } - return true; + return; } if (right_unwrap != null && (left_null_lifted || left.IsNull)) { @@ -709,29 +699,25 @@ namespace Mono.CSharp.Nullable ig.Emit (OpCodes.Ldc_I4_0); ig.Emit (OpCodes.Ceq); } - return true; + return; } - if (user_operator != null) - return false; - Label dissimilar_label = ig.DefineLabel (); Label end_label = ig.DefineLabel (); - if (left_unwrap != null) - left_unwrap.EmitGetValueOrDefault (ec); - else + if (user_operator != null) { + user_operator.Emit (ec); + ig.Emit (Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label); + } else { left.Emit (ec); - - if (right_unwrap != null) - right_unwrap.EmitGetValueOrDefault (ec); - else right.Emit (ec); - ig.Emit (OpCodes.Bne_Un_S, dissimilar_label); + ig.Emit (OpCodes.Bne_Un_S, dissimilar_label); + } if (left_unwrap != null) left_unwrap.EmitCheck (ec); + if (right_unwrap != null) right_unwrap.EmitCheck (ec); @@ -756,7 +742,6 @@ namespace Mono.CSharp.Nullable ig.Emit (OpCodes.Ldc_I4_0); ig.MarkLabel (end_label); - return true; } public override void EmitBranchable (EmitContext ec, Label target, bool onTrue) @@ -779,8 +764,8 @@ namespace Mono.CSharp.Nullable } if ((Oper & Operator.EqualityMask) != 0) { - if (EmitEquality (ec)) - return; + EmitEquality (ec); + return; } ILGenerator ig = ec.ig; @@ -810,10 +795,7 @@ namespace Mono.CSharp.Nullable ig.MarkLabel (is_null_label); if ((Oper & Operator.ComparisonMask) != 0) { - if (Oper == Operator.Equality) - ig.Emit (OpCodes.Ldc_I4_1); - else - ig.Emit (OpCodes.Ldc_I4_0); + ig.Emit (OpCodes.Ldc_I4_0); } else { LiftedNull.Create (type, loc).Emit (ec); } @@ -848,7 +830,7 @@ namespace Mono.CSharp.Nullable // // Avoid double conversion // - if (left_unwrap == null || left_null_lifted || !TypeManager.IsEqual (left_unwrap.Type, left.Type)) { + if (left_unwrap == null || left_null_lifted || !TypeManager.IsEqual (left_unwrap.Type, left.Type) || (left_unwrap != null && right_null_lifted)) { lifted_type = new NullableType (left.Type, loc); lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false); if (lifted_type == null) @@ -860,7 +842,7 @@ namespace Mono.CSharp.Nullable left = EmptyCast.Create (left, lifted_type.Type); } - if (right_unwrap == null || right_null_lifted || !TypeManager.IsEqual (right_unwrap.Type, right.Type)) { + if (right_unwrap == null || right_null_lifted || !TypeManager.IsEqual (right_unwrap.Type, right.Type) || (right_unwrap != null && left_null_lifted)) { lifted_type = new NullableType (right.Type, loc); lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false); if (lifted_type == null) @@ -963,7 +945,7 @@ namespace Mono.CSharp.Nullable public override Expression CreateExpressionTree (EmitContext ec) { - if (left is NullLiteral) + if (left.Type == TypeManager.null_type) Report.Error (845, loc, "An expression tree cannot contain a coalescing operator with null left side"); UserCast uc = left as UserCast; @@ -984,28 +966,22 @@ namespace Mono.CSharp.Nullable args.Add (new Argument (conversion)); return CreateExpressionFactoryCall ("Coalesce", args); - } + } - public override Expression DoResolve (EmitContext ec) + Expression ConvertExpression (EmitContext ec) { - if (type != null) - return this; - - left = left.Resolve (ec); - right = right.Resolve (ec); - - if (left == null || right == null) + // TODO: ImplicitConversionExists should take care of this + if (left.eclass == ExprClass.MethodGroup) return null; - eclass = ExprClass.Value; - Type ltype = left.Type, rtype = right.Type; + Type ltype = left.Type; // // If left is a nullable type and an implicit conversion exists from right to underlying type of left, // the result is underlying type of left // - if (TypeManager.IsNullableType (ltype) && left.eclass != ExprClass.MethodGroup) { - unwrap = Unwrap.Create (left, ec); + if (TypeManager.IsNullableType (ltype)) { + unwrap = Unwrap.Create (left, false); if (unwrap == null) return null; @@ -1014,8 +990,8 @@ namespace Mono.CSharp.Nullable type = left.Type; right = Convert.ImplicitConversion (ec, right, type, loc); return this; - } - } else if (TypeManager.IsReferenceType (ltype) && right.eclass != ExprClass.MethodGroup) { + } + } else if (TypeManager.IsReferenceType (ltype)) { if (Convert.ImplicitConversionExists (ec, right, ltype)) { // // Reduce (constant ?? expr) to constant @@ -1035,14 +1011,12 @@ namespace Mono.CSharp.Nullable return this; } } else { - Binary.Error_OperatorCannotBeApplied (left, right, "??", loc); return null; } - if (!Convert.ImplicitConversionExists (ec, unwrap != null ? unwrap : left, rtype)) { - Binary.Error_OperatorCannotBeApplied (left, right, "??", loc); + Type rtype = right.Type; + if (!Convert.ImplicitConversionExists (ec, unwrap != null ? unwrap : left, rtype) || right.eclass == ExprClass.MethodGroup) return null; - } // // Reduce (null ?? right) to right @@ -1055,6 +1029,28 @@ namespace Mono.CSharp.Nullable return this; } + public override Expression DoResolve (EmitContext ec) + { + if (eclass != ExprClass.Invalid) + return this; + + left = left.Resolve (ec); + right = right.Resolve (ec); + + if (left == null || right == null) + return null; + + eclass = ExprClass.Value; + + Expression e = ConvertExpression (ec); + if (e == null) { + Binary.Error_OperatorCannotBeApplied (left, right, "??", loc); + return null; + } + + return e; + } + public override void Emit (EmitContext ec) { ILGenerator ig = ec.ig; @@ -1088,6 +1084,13 @@ namespace Mono.CSharp.Nullable ig.MarkLabel (end_label); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + left.MutateHoistedGenericType (storey); + right.MutateHoistedGenericType (storey); + type = storey.MutateType (type); + } + protected override void CloneTo (CloneContext clonectx, Expression t) { NullCoalescingOperator target = (NullCoalescingOperator) t; @@ -1124,11 +1127,11 @@ namespace Mono.CSharp.Nullable if (expr == null) return null; - unwrap = Unwrap.Create (expr, ec); + unwrap = Unwrap.Create (expr, false); if (unwrap == null) return null; - underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap, loc).Resolve (ec); + underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap).Resolve (ec); if (underlying == null) return null;