//
// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
// Copyright 2004-2008 Novell, Inc
+// Copyright 2011 Xamarin Inc
//
using System;
+
+#if STATIC
+using IKVM.Reflection.Emit;
+#else
using System.Reflection.Emit;
+#endif
namespace Mono.CSharp.Nullable
{
public class NullableType : TypeExpr
{
- TypeExpr underlying;
+ readonly TypeSpec underlying;
- public NullableType (TypeExpr underlying, Location l)
+ public NullableType (TypeSpec type, Location loc)
{
- this.underlying = underlying;
- loc = l;
-
- eclass = ExprClass.Type;
+ this.underlying = type;
+ this.loc = loc;
}
- public NullableType (TypeSpec type, Location loc)
- : this (new TypeExpression (type, loc), loc)
- { }
-
- protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
+ public override TypeSpec ResolveAsType (IMemberContext ec)
{
- if (TypeManager.generic_nullable_type == null) {
- TypeManager.generic_nullable_type = TypeManager.CoreLookupType (ec.Compiler,
- "System", "Nullable", 1, MemberKind.Struct, true);
- }
+ eclass = ExprClass.Type;
+
+ var otype = ec.Module.PredefinedTypes.Nullable.Resolve ();
+ if (otype == null)
+ return null;
- TypeArguments args = new TypeArguments (underlying);
- GenericTypeExpr ctype = new GenericTypeExpr (TypeManager.generic_nullable_type, args, loc);
- return ctype.ResolveAsTypeTerminal (ec, false);
+ TypeArguments args = new TypeArguments (new TypeExpression (underlying, loc));
+ GenericTypeExpr ctype = new GenericTypeExpr (otype, args, loc);
+
+ type = ctype.ResolveAsType (ec);
+ return type;
}
}
{
public static MethodSpec GetConstructor (TypeSpec nullableType)
{
- return TypeManager.GetPredefinedConstructor (nullableType, Location.Null, GetUnderlyingType (nullableType));
+ return (MethodSpec) MemberCache.FindMember (nullableType,
+ MemberFilter.Constructor (ParametersCompiled.CreateFullyResolved (GetUnderlyingType (nullableType))), BindingRestriction.DeclaredOnly);
}
public static MethodSpec GetHasValue (TypeSpec nullableType)
{
return ((InflatedTypeSpec) nullableType).TypeArguments[0];
}
-
- public static bool IsNullableType (TypeSpec type)
- {
- throw new NotImplementedException ("net");
- }
}
- public class Unwrap : Expression, IMemoryLocation, IAssignMethod
+ public class Unwrap : Expression, IMemoryLocation
{
Expression expr;
eclass = expr.eclass;
}
+ public override bool ContainsEmitWithAwait ()
+ {
+ return expr.ContainsEmitWithAwait ();
+ }
+
public static Expression Create (Expression expr)
{
//
public override void Emit (EmitContext ec)
{
Store (ec);
+
+ var call = new CallEmitter ();
+ call.InstanceExpression = this;
+
if (useDefaultValue)
- Invocation.EmitCall (ec, this, NullableInfo.GetGetValueOrDefault (expr.Type), null, loc);
+ call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null);
else
- Invocation.EmitCall (ec, this, NullableInfo.GetValue (expr.Type), null, loc);
+ call.EmitPredefined (ec, NullableInfo.GetValue (expr.Type), null);
}
public void EmitCheck (EmitContext ec)
{
Store (ec);
- Invocation.EmitCall (ec, this, NullableInfo.GetHasValue (expr.Type), null, loc);
+
+ var call = new CallEmitter ();
+ call.InstanceExpression = this;
+
+ call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
}
public override bool Equals (object obj)
void Store (EmitContext ec)
{
- if (expr is VariableReference)
+ if (temp != null)
return;
- if (temp != null)
+ if (expr is VariableReference)
return;
expr.Emit (ec);
return temp;
}
}
-
- public void Emit (EmitContext ec, bool leave_copy)
- {
- if (leave_copy)
- Load (ec);
-
- Emit (ec);
- }
-
- public void EmitAssign (EmitContext ec, Expression source,
- bool leave_copy, bool prepare_for_load)
- {
- InternalWrap wrap = new InternalWrap (source, expr.Type, loc);
- ((IAssignMethod) expr).EmitAssign (ec, wrap, leave_copy, false);
- }
-
- class InternalWrap : Expression
- {
- public Expression expr;
-
- public InternalWrap (Expression expr, TypeSpec type, Location loc)
- {
- this.expr = expr;
- this.loc = loc;
- this.type = type;
-
- eclass = ExprClass.Value;
- }
-
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- throw new NotSupportedException ("ET");
- }
-
- protected override Expression DoResolve (ResolveContext ec)
- {
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- expr.Emit (ec);
- ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
- }
- }
}
//
public override void Emit (EmitContext ec)
{
- Invocation.EmitCall (ec, Child, NullableInfo.GetValue (Child.Type), null, loc);
+ var call = new CallEmitter ();
+ call.InstanceExpression = Child;
+ call.EmitPredefined (ec, NullableInfo.GetValue (Child.Type), null);
}
}
value_target.AddressOf (ec, AddressOp.Store);
ec.Emit (OpCodes.Initobj, type);
value_target.Emit (ec);
+ value_target.Release (ec);
}
public void AddressOf (EmitContext ec, AddressOp Mode)
: this (expr, unwrap as Unwrap, type)
{
}
+
+ public override bool ContainsEmitWithAwait ()
+ {
+ return unwrap.ContainsEmitWithAwait ();
+ }
public override Expression CreateExpressionTree (ResolveContext ec)
{
//
if (unwrap == null) {
// S -> T? is wrap only
- if (TypeManager.IsNullableType (type))
+ if (type.IsNullableType)
return Wrap.Create (expr, type);
// S -> T can be simplified
}
// Wrap target for T?
- if (TypeManager.IsNullableType (type)) {
+ if (type.IsNullableType) {
expr = Wrap.Create (expr, type);
if (expr == null)
return null;
null_value = LiftedNull.Create (type, loc);
- } else if (TypeManager.IsValueType (type)) {
+ } else if (TypeSpec.IsValueType (type)) {
null_value = LiftedNull.Create (type, loc);
} else {
null_value = new NullConstant (type, loc);
Expression LiftExpression (ResolveContext ec, Expression expr)
{
- TypeExpr lifted_type = new NullableType (expr.Type, expr.Location);
- lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
- if (lifted_type == null)
+ var lifted_type = new NullableType (expr.Type, expr.Location);
+ if (lifted_type.ResolveAsType (ec) == null)
return null;
expr.Type = lifted_type.Type;
return expr;
}
- protected override Expression ResolveEnumOperator (ResolveContext ec, Expression expr)
+ protected override Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
{
- expr = base.ResolveEnumOperator (ec, expr);
+ expr = base.ResolveEnumOperator (ec, expr, predefined);
if (expr == null)
return null;
bool IsBitwiseBoolean {
get {
return (Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) &&
- ((left_unwrap != null && left_unwrap.Type == TypeManager.bool_type) ||
- (right_unwrap != null && right_unwrap.Type == TypeManager.bool_type));
+ ((left_unwrap != null && left_unwrap.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) ||
+ (right_unwrap != null && right_unwrap.Type.BuiltinType == BuiltinTypeSpec.Type.Bool));
}
}
Constant CreateNullConstant (ResolveContext ec, Expression expr)
{
// FIXME: Handle side effect constants
- Constant c = new BoolConstant (Oper == Operator.Inequality, loc).Resolve (ec);
+ Constant c = new BoolConstant (ec.BuiltinTypes, Oper == Operator.Inequality, loc);
if ((Oper & Operator.EqualityMask) != 0) {
ec.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is `{1}'",
- TypeManager.CSharpName (expr.Type), c.AsString ());
+ TypeManager.CSharpName (expr.Type), c.GetValueAsLiteral ());
} else {
ec.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
- TypeManager.CSharpName (expr.Type), c.AsString ());
+ TypeManager.CSharpName (expr.Type), c.GetValueAsLiteral ());
}
return ReducedExpression.Create (c, this);
bool use_default_call = (Oper & (Operator.BitwiseMask | Operator.EqualityMask)) != 0;
left_orig = left;
- if (TypeManager.IsNullableType (left.Type)) {
+ if (left.Type.IsNullableType) {
left = left_unwrap = Unwrap.Create (left, use_default_call);
if (left == null)
return null;
}
right_orig = right;
- if (TypeManager.IsNullableType (right.Type)) {
+ if (right.Type.IsNullableType) {
right = right_unwrap = Unwrap.Create (right, use_default_call);
if (right == null)
return null;
if (left_orig is NullLiteral) {
left = right;
state |= State.LeftNullLifted;
- type = TypeManager.bool_type;
+ type = ec.BuiltinTypes.Bool;
}
if (right_orig.IsNull) {
if ((Oper & Operator.ShiftMask) != 0)
- right = new EmptyExpression (TypeManager.int32_type);
+ right = new EmptyExpression (ec.BuiltinTypes.Int);
else
right = left;
state |= State.RightNullLifted;
- type = TypeManager.bool_type;
+ type = ec.BuiltinTypes.Bool;
}
eclass = ExprClass.Value;
}
left_unwrap.Emit (ec);
- ec.Emit (OpCodes.Brtrue_S, load_right);
+ ec.Emit (OpCodes.Brtrue, load_right);
// value & null, value | null
if (right_unwrap != null) {
if (left_unwrap != null && (IsRightNullLifted || right.IsNull)) {
left_unwrap.EmitCheck (ec);
if (Oper == Binary.Operator.Equality) {
- ec.Emit (OpCodes.Ldc_I4_0);
+ ec.EmitInt (0);
ec.Emit (OpCodes.Ceq);
}
return;
if (right_unwrap != null && (IsLeftNullLifted || left.IsNull)) {
right_unwrap.EmitCheck (ec);
if (Oper == Binary.Operator.Equality) {
- ec.Emit (OpCodes.Ldc_I4_0);
+ ec.EmitInt (0);
ec.Emit (OpCodes.Ceq);
}
return;
user_operator.Emit (ec);
ec.Emit (Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label);
} else {
+ if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
+ left = left.EmitToField (ec);
+ right = right.EmitToField (ec);
+ }
+
left.Emit (ec);
right.Emit (ec);
ec.Emit (OpCodes.Ceq);
} else {
if (Oper == Operator.Inequality) {
- ec.Emit (OpCodes.Ldc_I4_0);
+ ec.EmitInt (0);
ec.Emit (OpCodes.Ceq);
}
}
ec.MarkLabel (dissimilar_label);
if (Oper == Operator.Inequality)
- ec.Emit (OpCodes.Ldc_I4_1);
+ ec.EmitInt (1);
else
- ec.Emit (OpCodes.Ldc_I4_0);
+ ec.EmitInt (0);
ec.MarkLabel (end_label);
}
ec.MarkLabel (is_null_label);
if ((Oper & Operator.ComparisonMask) != 0) {
- ec.Emit (OpCodes.Ldc_I4_0);
+ ec.EmitInt (0);
} else {
LiftedNull.Create (type, loc).Emit (ec);
}
return;
}
- if (TypeManager.IsNullableType (l))
- l = TypeManager.GetTypeArguments (l) [0];
+ if (left.Type.IsNullableType) {
+ l = NullableInfo.GetUnderlyingType (left.Type);
+ left = EmptyCast.Create (left, l);
+ }
+
+ if (right.Type.IsNullableType) {
+ right = EmptyCast.Create (right, NullableInfo.GetUnderlyingType (right.Type));
+ }
base.EmitOperator (ec, l);
}
Expression LiftResult (ResolveContext ec, Expression res_expr)
{
- TypeExpr lifted_type;
+ TypeSpec lifted_type;
//
// Avoid double conversion
//
if (left_unwrap == null || IsLeftNullLifted || left_unwrap.Type != left.Type || (left_unwrap != null && IsRightNullLifted)) {
- lifted_type = new NullableType (left.Type, loc);
- lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
+ lifted_type = new NullableType (left.Type, loc).ResolveAsType (ec);
if (lifted_type == null)
return null;
if (left is UserCast || left is TypeCast)
- left.Type = lifted_type.Type;
+ left.Type = lifted_type;
else
- left = EmptyCast.Create (left, lifted_type.Type);
+ left = EmptyCast.Create (left, lifted_type);
}
if (left != right && (right_unwrap == null || IsRightNullLifted || right_unwrap.Type != right.Type || (right_unwrap != null && IsLeftNullLifted))) {
- lifted_type = new NullableType (right.Type, loc);
- lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
+ lifted_type = new NullableType (right.Type, loc).ResolveAsType (ec);
if (lifted_type == null)
return null;
r = ((ReducedExpression) r).OriginalExpression;
if (r is UserCast || r is TypeCast)
- r.Type = lifted_type.Type;
+ r.Type = lifted_type;
else
- right = EmptyCast.Create (right, lifted_type.Type);
+ right = EmptyCast.Create (right, lifted_type);
}
if ((Oper & Operator.ComparisonMask) == 0) {
- lifted_type = new NullableType (res_expr.Type, loc);
- lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
+ lifted_type = new NullableType (res_expr.Type, loc).ResolveAsType (ec);
if (lifted_type == null)
return null;
- wrap_ctor = NullableInfo.GetConstructor (lifted_type.Type);
- type = res_expr.Type = lifted_type.Type;
+ wrap_ctor = NullableInfo.GetConstructor (lifted_type);
+ type = res_expr.Type = lifted_type;
}
if (IsLeftNullLifted) {
//
// Special case for bool?, the result depends on both null right side and left side value
//
- if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType (type) == TypeManager.bool_type) {
+ if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType (type).BuiltinType == BuiltinTypeSpec.Type.Bool) {
return res_expr;
}
// Value types and null comparison
//
if (right_unwrap == null || (Oper & Operator.RelationalMask) != 0)
- return CreateNullConstant (ec, right_orig).Resolve (ec);
+ return CreateNullConstant (ec, right_orig);
}
if (IsRightNullLifted) {
//
// Special case for bool?, the result depends on both null right side and left side value
//
- if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType (type) == TypeManager.bool_type) {
+ if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType (type).BuiltinType == BuiltinTypeSpec.Type.Bool) {
return res_expr;
}
// Lift the result in the case it can be null and predefined or user operator
// result type is of a value type
//
- if (!TypeManager.IsValueType (expr.Type))
+ if (!TypeSpec.IsValueType (expr.Type))
return null;
if (state != orig_state)
this.right = right;
this.loc = loc;
}
+
+ public Expression LeftExpression {
+ get {
+ return left;
+ }
+ }
+
+ public Expression RightExpression {
+ get {
+ return right;
+ }
+ }
public override Expression CreateExpressionTree (ResolveContext ec)
{
// 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)) {
+ if (ltype.IsNullableType) {
unwrap = Unwrap.Create (left, false);
if (unwrap == null)
return null;
//
// If right is a dynamic expression, the result type is dynamic
//
- if (right.Type == InternalType.Dynamic) {
+ if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
type = right.Type;
// Need to box underlying value type
type = ltype;
return this;
}
- } else if (TypeManager.IsReferenceType (ltype)) {
+ } else if (TypeSpec.IsReferenceType (ltype)) {
if (Convert.ImplicitConversionExists (ec, right, ltype)) {
//
// If right is a dynamic expression, the result type is dynamic
//
- if (right.Type == InternalType.Dynamic) {
+ if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
type = right.Type;
return this;
}
//
Constant lc = left as Constant;
if (lc != null && !lc.IsDefaultValue)
- return ReducedExpression.Create (lc, this).Resolve (ec);
+ return ReducedExpression.Create (lc, this);
//
// Reduce (left ?? null) to left OR (null-constant ?? right) to right
type = ltype;
return this;
}
+
+ //
+ // Special case null ?? null
+ //
+ if (ltype == right.Type) {
+ type = ltype;
+ return this;
+ }
} else {
return null;
}
// Reduce (null ?? right) to right
//
if (left.IsNull)
- return ReducedExpression.Create (right, this);
+ return ReducedExpression.Create (right, this).Resolve (ec);
left = Convert.ImplicitConversion (ec, unwrap != null ? unwrap : left, rtype, loc);
type = rtype;
return this;
}
+ public override bool ContainsEmitWithAwait ()
+ {
+ if (unwrap != null)
+ return unwrap.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
+
+ return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
+ }
+
protected override Expression DoResolve (ResolveContext ec)
{
left = left.Resolve (ec);
target.left = left.Clone (clonectx);
target.right = right.Clone (clonectx);
}
- }
-
- public class LiftedUnaryMutator : ExpressionStatement
- {
- public readonly UnaryMutator.Mode Mode;
- Expression expr;
- UnaryMutator underlying;
- Unwrap unwrap;
-
- public LiftedUnaryMutator (UnaryMutator.Mode mode, Expression expr, Location loc)
+
+ public override object Accept (StructuralVisitor visitor)
{
- this.expr = expr;
- this.Mode = mode;
- this.loc = loc;
+ return visitor.Visit (this);
}
+ }
- public override Expression CreateExpressionTree (ResolveContext ec)
+ class LiftedUnaryMutator : UnaryMutator
+ {
+ public LiftedUnaryMutator (Mode mode, Expression expr, Location loc)
+ : base (mode, expr, loc)
{
- return new SimpleAssign (this, this).CreateExpressionTree (ec);
}
protected override Expression DoResolve (ResolveContext ec)
{
- expr = expr.Resolve (ec);
- if (expr == null)
- return null;
+ var orig_expr = expr;
- unwrap = Unwrap.Create (expr, false);
- if (unwrap == null)
- return null;
+ expr = Unwrap.Create (expr);
- underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap, loc).Resolve (ec);
- if (underlying == null)
- return null;
+ var res = base.DoResolveOperation (ec);
-
- eclass = ExprClass.Value;
+ expr = orig_expr;
type = expr.Type;
- return this;
+
+ return res;
}
- void DoEmit (EmitContext ec, bool is_expr)
+ protected override void EmitOperation (EmitContext ec)
{
Label is_null_label = ec.DefineLabel ();
Label end_label = ec.DefineLabel ();
- unwrap.EmitCheck (ec);
+ LocalTemporary lt = new LocalTemporary (type);
+
+ // Value is on the stack
+ lt.Store (ec);
+
+ var call = new CallEmitter ();
+ call.InstanceExpression = lt;
+ call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
+
ec.Emit (OpCodes.Brfalse, is_null_label);
- if (is_expr) {
- underlying.Emit (ec);
- ec.Emit (OpCodes.Br_S, end_label);
- } else {
- underlying.EmitStatement (ec);
- }
+ call = new CallEmitter ();
+ call.InstanceExpression = lt;
+ call.EmitPredefined (ec, NullableInfo.GetValue (expr.Type), null);
- ec.MarkLabel (is_null_label);
- if (is_expr)
- LiftedNull.Create (type, loc).Emit (ec);
+ lt.Release (ec);
- ec.MarkLabel (end_label);
- }
+ base.EmitOperation (ec);
- public override void Emit (EmitContext ec)
- {
- DoEmit (ec, true);
- }
+ ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
+ ec.Emit (OpCodes.Br_S, end_label);
- public override void EmitStatement (EmitContext ec)
- {
- DoEmit (ec, false);
+ ec.MarkLabel (is_null_label);
+ LiftedNull.Create (type, loc).Emit (ec);
+
+ ec.MarkLabel (end_label);
}
}
}