public override void Emit(EmitContext ec) { Label is_null_label = ec.DefineLabel(); Label end_label = ec.DefineLabel(); unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brfalse, is_null_label); if (user_operator != null) { user_operator.Emit(ec); } else { EmitOperator(ec, NullableInfo.GetUnderlyingType(type)); } ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); LiftedNull.Create(type, loc).Emit(ec); ec.MarkLabel(end_label); }
protected override Expression DoResolve(ResolveContext ec) { // // It's null when lifting non-nullable type // if (unwrap == null) { // S -> T? is wrap only if (type.IsNullableType) return Wrap.Create (expr, type); // S -> T can be simplified return expr; } // Wrap target for T? if (type.IsNullableType) { if (!expr.Type.IsNullableType) { expr = Wrap.Create (expr, type); if (expr == null) return null; } null_value = LiftedNull.Create (type, loc); } else if (TypeSpec.IsValueType (type)) { null_value = LiftedNull.Create (type, loc); } else { null_value = new NullConstant (type, loc); } eclass = ExprClass.Value; return this; }
protected override void EmitOperation(EmitContext ec) { Label is_null_label = ec.DefineLabel(); Label end_label = ec.DefineLabel(); 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); call = new CallEmitter(); call.InstanceExpression = lt; call.EmitPredefined(ec, NullableInfo.GetGetValueOrDefault(expr.Type), null); lt.Release(ec); base.EmitOperation(ec); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); LiftedNull.Create(type, loc).Emit(ec); ec.MarkLabel(end_label); }
void DoEmit(EmitContext ec, bool is_expr) { Label is_null_label = ec.DefineLabel(); Label end_label = ec.DefineLabel(); unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brfalse, is_null_label); if (is_expr) { underlying.Emit(ec); ec.Emit(OpCodes.Br_S, end_label); } else { underlying.EmitStatement(ec); } ec.MarkLabel(is_null_label); if (is_expr) { LiftedNull.Create(type, loc).Emit(ec); } ec.MarkLabel(end_label); }
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); NullableInfo ni = new NullableInfo(type); if (user_operator != null) { user_operator.Emit(ec); } else { EmitOperator(ec, ni.UnderlyingType); } ig.Emit(OpCodes.Newobj, ni.Constructor); ig.Emit(OpCodes.Br_S, end_label); ig.MarkLabel(is_null_label); LiftedNull.Create(type, loc).Emit(ec); ig.MarkLabel(end_label); }
public override Expression DoResolve(EmitContext ec) { wrap = Wrap.Create(expr, type); if (wrap == null) { return(null); } // // It's null when lifted conversion is transparent // if (unwrap == null) { return(wrap); } null_value = LiftedNull.Create(type, loc); eclass = ExprClass.Value; return(this); }
public override Expression DoResolve(ResolveContext ec) { // // It's null when lifting non-nullable type // if (unwrap == null) { // S -> T? is wrap only if (TypeManager.IsNullableType(type)) { return(Wrap.Create(expr, type)); } // S -> T can be simplified return(expr); } // Wrap target for T? if (TypeManager.IsNullableType(type)) { expr = Wrap.Create(expr, type); if (expr == null) { return(null); } null_value = LiftedNull.Create(type, loc); } else { null_value = new NullLiteral(type, loc); } eclass = ExprClass.Value; return(this); }
void EmitBitwiseBoolean(EmitContext ec) { Label load_left = ec.DefineLabel(); Label load_right = ec.DefineLabel(); Label end_label = ec.DefineLabel(); Label is_null_label = ec.DefineLabel(); bool or = Binary.Oper == Binary.Operator.BitwiseOr; // // Both operands are bool? types // if ((UnwrapLeft != null && !Left.IsNull) && (UnwrapRight != null && !Right.IsNull)) { if (ec.HasSet(BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait()) { Left = Left.EmitToField(ec); Right = Right.EmitToField(ec); } else { UnwrapLeft.Store(ec); UnwrapRight.Store(ec); } Left.Emit(ec); ec.Emit(OpCodes.Brtrue_S, load_right); Right.Emit(ec); ec.Emit(OpCodes.Brtrue_S, load_left); UnwrapLeft.EmitCheck(ec); ec.Emit(OpCodes.Brfalse_S, load_right); // load left ec.MarkLabel(load_left); if (or) { UnwrapRight.Load(ec); } else { UnwrapLeft.Load(ec); } ec.Emit(OpCodes.Br_S, end_label); // load right ec.MarkLabel(load_right); if (or) { UnwrapLeft.Load(ec); } else { UnwrapRight.Load(ec); } ec.MarkLabel(end_label); return; } // // Faster version when one operand is bool // if (UnwrapLeft == null) { // // (bool, bool?) // // Optimizes remaining (false & bool?), (true | bool?) which are not easy to handle // in binary expression reduction // var c = Left as BoolConstant; if (c != null) { // Keep evaluation order UnwrapRight.Store(ec); ec.EmitInt(or ? 1 : 0); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } else if (Left.IsNull) { UnwrapRight.Emit(ec); ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label); UnwrapRight.Load(ec); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); LiftedNull.Create(type, loc).Emit(ec); } else { Left.Emit(ec); UnwrapRight.Store(ec); ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_right); ec.EmitInt(or ? 1 : 0); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(load_right); UnwrapRight.Load(ec); } } else { // // (bool?, bool) // // Keep left-right evaluation order UnwrapLeft.Store(ec); // // Optimizes remaining (bool? & false), (bool? | true) which are not easy to handle // in binary expression reduction // var c = Right as BoolConstant; if (c != null) { ec.EmitInt(or ? 1 : 0); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } else if (Right.IsNull) { UnwrapLeft.Emit(ec); ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label); UnwrapLeft.Load(ec); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); LiftedNull.Create(type, loc).Emit(ec); } else { Right.Emit(ec); ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_left); ec.EmitInt(or ? 1 : 0); ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(load_left); UnwrapLeft.Load(ec); } } ec.MarkLabel(end_label); }
public override void Emit(EmitContext ec) { if (IsBitwiseBoolean && UserOperator == null) { EmitBitwiseBoolean(ec); return; } if ((Binary.Oper & Binary.Operator.EqualityMask) != 0) { EmitEquality(ec); return; } Label is_null_label = ec.DefineLabel(); Label end_label = ec.DefineLabel(); if (ec.HasSet(BuilderContext.Options.AsyncBody) && Right.ContainsEmitWithAwait()) { Left = Left.EmitToField(ec); Right = Right.EmitToField(ec); } if (UnwrapLeft != null) { UnwrapLeft.EmitCheck(ec); } // // Don't emit HasValue check when left and right expressions are same // if (UnwrapRight != null && !Binary.Left.Equals(Binary.Right)) { UnwrapRight.EmitCheck(ec); if (UnwrapLeft != null) { ec.Emit(OpCodes.And); } } ec.Emit(OpCodes.Brfalse, is_null_label); if (UserOperator != null) { var args = new Arguments(2); args.Add(new Argument(Left)); args.Add(new Argument(Right)); var call = new CallEmitter(); call.EmitPredefined(ec, UserOperator, args); } else { Binary.EmitOperator(ec, Left, Right); } // // Wrap the result when the operator return type is nullable type // if (type.IsNullableType) { ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); if ((Binary.Oper & Binary.Operator.ComparisonMask) != 0) { ec.EmitInt(0); } else { LiftedNull.Create(type, loc).Emit(ec); } ec.MarkLabel(end_label); }
public override void Emit(EmitContext ec) { // // Optimize same expression operation // if (right_unwrap != null && right.Equals(left)) { right_unwrap = left_unwrap; } if (user_operator == null && IsBitwiseBoolean) { EmitBitwiseBoolean(ec); return; } if ((Oper & Operator.EqualityMask) != 0) { EmitEquality(ec); return; } Label is_null_label = ec.DefineLabel(); Label end_label = ec.DefineLabel(); if (left_unwrap != null) { left_unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brfalse, is_null_label); } // // Don't emit HasValue check when left and right expressions are same // if (right_unwrap != null && !left.Equals(right)) { right_unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brfalse, is_null_label); } EmitOperator(ec, left.Type); if (wrap_ctor != null) { ec.Emit(OpCodes.Newobj, wrap_ctor); } ec.Emit(OpCodes.Br_S, end_label); ec.MarkLabel(is_null_label); if ((Oper & Operator.ComparisonMask) != 0) { ec.Emit(OpCodes.Ldc_I4_0); } else { LiftedNull.Create(type, loc).Emit(ec); } ec.MarkLabel(end_label); }
Expression LiftResult(ResolveContext ec, Expression res_expr) { TypeExpr 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); if (lifted_type == null) { return(null); } if (left is UserCast || left is TypeCast) { left.Type = lifted_type.Type; } else { left = EmptyCast.Create(left, lifted_type.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); if (lifted_type == null) { return(null); } var r = right; if (r is ReducedExpression) { r = ((ReducedExpression)r).OriginalExpression; } if (r is UserCast || r is TypeCast) { r.Type = lifted_type.Type; } else { right = EmptyCast.Create(right, lifted_type.Type); } } if ((Oper & Operator.ComparisonMask) == 0) { lifted_type = new NullableType(res_expr.Type, loc); lifted_type = lifted_type.ResolveAsTypeTerminal(ec, false); if (lifted_type == null) { return(null); } wrap_ctor = NullableInfo.GetConstructor(lifted_type.Type); type = res_expr.Type = lifted_type.Type; } if (IsLeftNullLifted) { left = LiftedNull.Create(right.Type, left.Location); // // 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).BuiltinType == BuiltinTypeSpec.Type.Bool) { return(res_expr); } if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) { return(LiftedNull.CreateFromExpression(ec, res_expr)); } // // Value types and null comparison // if (right_unwrap == null || (Oper & Operator.RelationalMask) != 0) { return(CreateNullConstant(ec, right_orig)); } } if (IsRightNullLifted) { right = LiftedNull.Create(left.Type, right.Location); // // 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).BuiltinType == BuiltinTypeSpec.Type.Bool) { return(res_expr); } if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) { return(LiftedNull.CreateFromExpression(ec, res_expr)); } // // Value types and null comparison // if (left_unwrap == null || (Oper & Operator.RelationalMask) != 0) { return(CreateNullConstant(ec, left_orig)); } } return(res_expr); }
Expression LiftResult(ResolveContext ec, Expression res_expr) { TypeExpr lifted_type; // // Avoid double conversion // 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) { return(null); } if (left is UserCast || left is TypeCast) { left.Type = lifted_type.Type; } else { left = EmptyCast.Create(left, lifted_type.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) { return(null); } if (right is UserCast || right is TypeCast) { right.Type = lifted_type.Type; } else { right = EmptyCast.Create(right, lifted_type.Type); } } if ((Oper & Operator.ComparisonMask) == 0) { lifted_type = new NullableType(res_expr.Type, loc); lifted_type = lifted_type.ResolveAsTypeTerminal(ec, false); if (lifted_type == null) { return(null); } wrap_ctor = new NullableInfo(lifted_type.Type).Constructor; type = res_expr.Type = lifted_type.Type; } if (left_null_lifted) { left = LiftedNull.Create(right.Type, left.Location); if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) { return(LiftedNull.CreateFromExpression(ec, res_expr)); } // // Value types and null comparison // if (right_unwrap == null || (Oper & Operator.RelationalMask) != 0) { return(CreateNullConstant(ec, right_orig).Resolve(ec)); } } if (right_null_lifted) { right = LiftedNull.Create(left.Type, right.Location); if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) { return(LiftedNull.CreateFromExpression(ec, res_expr)); } // // Value types and null comparison // if (left_unwrap == null || (Oper & Operator.RelationalMask) != 0) { return(CreateNullConstant(ec, left_orig).Resolve(ec)); } } return(res_expr); }