public Lifted(Expression expr, Unwrap unwrap, TypeSpec type) { this.expr = expr; this.unwrap = unwrap; this.loc = expr.Location; this.type = type; }
protected override Expression DoResolve (ResolveContext ec) { unwrap = Unwrap.Create (Expr, false); if (unwrap == null) return null; Expression res = base.ResolveOperator (ec, unwrap); if (res != this) { if (user_operator == null) return res; } else { res = Expr = LiftExpression (ec, Expr); } if (res == null) return null; eclass = ExprClass.Value; type = res.Type; return this; }
protected override Expression DoResolve (ResolveContext ec) { expr = expr.Resolve (ec); if (expr == null) return null; unwrap = Unwrap.Create (expr, false); if (unwrap == null) return null; underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap, loc).Resolve (ec); if (underlying == null) return null; eclass = ExprClass.Value; type = expr.Type; return this; }
Expression ConvertExpression (ResolveContext ec) { // TODO: ImplicitConversionExists should take care of this if (left.eclass == ExprClass.MethodGroup) return null; TypeSpec 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 (ltype.IsNullableType) { unwrap = Unwrap.Create (left, false); if (unwrap == null) return null; // // Reduce (left ?? null) to left // if (right.IsNull) return ReducedExpression.Create (left, this); if (Convert.ImplicitConversionExists (ec, right, unwrap.Type)) { left = unwrap; ltype = left.Type; // // If right is a dynamic expression, the result type is dynamic // if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { type = right.Type; // Need to box underlying value type left = Convert.ImplicitBoxingConversion (left, ltype, type); return this; } right = Convert.ImplicitConversion (ec, right, ltype, loc); type = ltype; return this; } } else if (TypeManager.IsReferenceType (ltype)) { if (Convert.ImplicitConversionExists (ec, right, ltype)) { // // If right is a dynamic expression, the result type is dynamic // if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { type = right.Type; return this; } // // Reduce ("foo" ?? expr) to expression // Constant lc = left as Constant; if (lc != null && !lc.IsDefaultValue) return ReducedExpression.Create (lc, this); // // Reduce (left ?? null) to left OR (null-constant ?? right) to right // if (right.IsNull || lc != null) return ReducedExpression.Create (lc != null ? right : left, this); right = Convert.ImplicitConversion (ec, right, ltype, loc); type = ltype; return this; } // // Special case null ?? null // if (ltype == right.Type) { type = ltype; return this; } } else { return null; } TypeSpec rtype = right.Type; if (!Convert.ImplicitConversionExists (ec, unwrap != null ? unwrap : left, rtype) || right.eclass == ExprClass.MethodGroup) return null; // // Reduce (null ?? right) to right // if (left.IsNull) return ReducedExpression.Create (right, this).Resolve (ec); left = Convert.ImplicitConversion (ec, unwrap != null ? unwrap : left, rtype, loc); type = rtype; return this; }
public override bool Resolve (BlockContext ec) { Expr = Expr.Resolve (ec); if (Expr == null) return false; new_expr = SwitchGoverningType (ec, Expr); if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) { unwrap = Nullable.Unwrap.Create (Expr, false); if (unwrap == null) return false; new_expr = SwitchGoverningType (ec, unwrap); } if (new_expr == null){ ec.Report.Error (151, loc, "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type", TypeManager.CSharpName (Expr.Type)); return false; } // Validate switch. SwitchType = new_expr.Type; if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) { ec.Report.FeatureIsNotAvailable (loc, "switch expression of boolean type"); return false; } if (!CheckSwitch (ec)) return false; if (HaveUnwrap) Elements.Remove (SwitchLabel.NullStringCase); Switch old_switch = ec.Switch; ec.Switch = this; ec.Switch.SwitchType = SwitchType; Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching); ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc); var constant = new_expr as Constant; if (constant != null) { is_constant = true; object key = constant.GetValue (); SwitchLabel label; if (Elements.TryGetValue (key, out label)) constant_section = FindSection (label); if (constant_section == null) constant_section = default_section; } bool first = true; bool ok = true; foreach (SwitchSection ss in Sections){ if (!first) ec.CurrentBranching.CreateSibling ( null, FlowBranching.SiblingType.SwitchSection); else first = false; if (is_constant && (ss != constant_section)) { // If we're a constant switch, we're only emitting // one single section - mark all the others as // unreachable. ec.CurrentBranching.CurrentUsageVector.Goto (); if (!ss.Block.ResolveUnreachable (ec, true)) { ok = false; } } else { if (!ss.Block.Resolve (ec)) ok = false; } } if (default_section == null) ec.CurrentBranching.CreateSibling ( null, FlowBranching.SiblingType.SwitchSection); ec.EndFlowBranching (); ec.Switch = old_switch; Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching); if (!ok) return false; if (SwitchType == TypeManager.string_type && !is_constant) { // TODO: Optimize single case, and single+default case ResolveStringSwitchMap (ec); } return true; }
Expression ConvertExpression (ResolveContext ec) { // TODO: ImplicitConversionExists should take care of this if (left.eclass == ExprClass.MethodGroup) return null; TypeSpec 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)) { unwrap = Unwrap.Create (left, false); if (unwrap == null) return null; if (Convert.ImplicitConversionExists (ec, right, unwrap.Type)) { left = unwrap; type = left.Type; right = Convert.ImplicitConversion (ec, right, type, loc); return this; } } else if (TypeManager.IsReferenceType (ltype)) { if (Convert.ImplicitConversionExists (ec, right, ltype)) { // // Reduce (constant ?? expr) to constant // Constant lc = left as Constant; if (lc != null && !lc.IsDefaultValue) return new SideEffectConstant (lc, right, loc).Resolve (ec); // // Reduce (left ?? null) to left OR (null-constant ?? right) to right // if (right.IsNull || lc != null) return ReducedExpression.Create (lc != null ? right : left, this); right = Convert.ImplicitConversion (ec, right, ltype, loc); type = left.Type; return this; } } else { return null; } TypeSpec rtype = right.Type; if (!Convert.ImplicitConversionExists (ec, unwrap != null ? unwrap : left, rtype) || right.eclass == ExprClass.MethodGroup) return null; // // Reduce (null ?? right) to right // if (left.IsNull) return ReducedExpression.Create (right, this); left = Convert.ImplicitConversion (ec, unwrap != null ? unwrap : left, rtype, loc); type = rtype; return this; }
protected override Expression DoResolve (ResolveContext ec) { if ((Oper & Operator.LogicalMask) != 0) { Error_OperatorCannotBeApplied (ec, left, right); 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, use_default_call); if (left == null) return null; } right_orig = right; if (TypeManager.IsNullableType (right.Type)) { right = right_unwrap = Unwrap.Create (right, use_default_call); if (right == null) return null; } // // Some details are in 6.4.2, 7.2.7 // Arguments can be lifted for equal operators when the return type is bool and both // arguments are of same type // if (left_orig.IsNull) { left = right; left_null_lifted = true; type = TypeManager.bool_type; } if (right_orig.IsNull) { right = left; right_null_lifted = true; type = TypeManager.bool_type; } eclass = ExprClass.Value; return DoResolveCore (ec, left_orig, right_orig); }
Expression ConvertExpression(ResolveContext ec) { // TODO: ImplicitConversionExists should take care of this if (left.eclass == ExprClass.MethodGroup) { return(null); } 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)) { unwrap = Unwrap.Create(left, false); if (unwrap == null) { return(null); } if (Convert.ImplicitConversionExists(ec, right, unwrap.Type)) { left = unwrap; type = left.Type; right = Convert.ImplicitConversion(ec, right, type, loc); return(this); } } else if (TypeManager.IsReferenceType(ltype)) { if (Convert.ImplicitConversionExists(ec, right, ltype)) { // // Reduce (constant ?? expr) to constant // Constant lc = left as Constant; if (lc != null && !lc.IsDefaultValue) { return(new SideEffectConstant(lc, right, loc).Resolve(ec)); } // // Reduce (left ?? null) to left OR (null-constant ?? right) to right // if (right.IsNull || lc != null) { return(ReducedExpression.Create(lc != null ? right : left, this).Resolve(ec)); } right = Convert.ImplicitConversion(ec, right, ltype, loc); type = left.Type; return(this); } } else { return(null); } Type rtype = right.Type; if (!Convert.ImplicitConversionExists(ec, unwrap != null ? unwrap : left, rtype) || right.eclass == ExprClass.MethodGroup) { return(null); } // // Reduce (null ?? right) to right // if (left.IsNull) { return(ReducedExpression.Create(right, this).Resolve(ec)); } left = Convert.ImplicitConversion(ec, unwrap != null ? unwrap : left, rtype, loc); type = rtype; return(this); }
public override Expression DoResolve (EmitContext ec) { if (eclass != ExprClass.Invalid) return this; if ((Oper & Operator.LogicalMask) != 0) { Error_OperatorCannotBeApplied (left, right); return null; } left_orig = left; if (TypeManager.IsNullableType (left.Type)) { left = left_unwrap = Unwrap.Create (left, ec); if (left == null) return null; } right_orig = right; if (TypeManager.IsNullableType (right.Type)) { right = right_unwrap = Unwrap.Create (right, ec); if (right == null) return null; } // // Some details are in 6.4.2, 7.2.7 // Arguments can be lifted for equal operators when the return type is bool and both // arguments are of same type // if (left is NullLiteral) { left = right; left_null_lifted = true; type = TypeManager.bool_type; } if (right is NullLiteral) { right = left; right_null_lifted = true; type = TypeManager.bool_type; } eclass = ExprClass.Value; return DoResolveCore (ec, left_orig, right_orig); }
public override Expression DoResolve (EmitContext ec) { if (eclass != ExprClass.Invalid) return this; unwrap = Unwrap.Create (Expr, ec); if (unwrap == null) return null; Expression res = base.ResolveOperator (ec, unwrap); if (res != this) { if (user_operator == null) return res; } else { res = Expr = LiftExpression (ec, Expr); } if (res == null) return null; eclass = ExprClass.Value; type = res.Type; return this; }
public override Expression DoResolve (EmitContext ec) { expr = expr.Resolve (ec); if (expr == null) return null; unwrap = Unwrap.Create (expr, ec); if (unwrap == null) return null; underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap).Resolve (ec); if (underlying == null) return null; type = expr.Type; return this; }
void EmitBitwiseBoolean(EmitContext ec) { Label load_left = ec.DefineLabel(); Label load_right = ec.DefineLabel(); Label end_label = ec.DefineLabel(); // null & value, null | value if (left_unwrap == null) { left_unwrap = right_unwrap; right_unwrap = null; right = left; } left_unwrap.Emit(ec); ec.Emit(OpCodes.Brtrue, load_right); // value & null, value | null if (right_unwrap != null) { right_unwrap.Emit(ec); ec.Emit(OpCodes.Brtrue_S, load_left); } left_unwrap.EmitCheck(ec); ec.Emit(OpCodes.Brfalse_S, load_right); // load left ec.MarkLabel(load_left); if (Oper == Operator.BitwiseAnd) { left_unwrap.Load(ec); } else { if (right_unwrap == null) { right.Emit(ec); if (right is EmptyConstantCast || right is EmptyCast) { ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } } else { right_unwrap.Load(ec); right_unwrap = left_unwrap; } } ec.Emit(OpCodes.Br_S, end_label); // load right ec.MarkLabel(load_right); if (right_unwrap == null) { if (Oper == Operator.BitwiseAnd) { right.Emit(ec); if (right is EmptyConstantCast || right is EmptyCast) { ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type)); } } else { left_unwrap.Load(ec); } } else { right_unwrap.Load(ec); } ec.MarkLabel(end_label); }
public override bool Equals(object obj) { Unwrap uw = obj as Unwrap; return(uw != null && expr.Equals(uw.expr)); }
Expression ConvertExpression(ResolveContext ec) { // TODO: ImplicitConversionExists should take care of this if (left.eclass == ExprClass.MethodGroup) { return(null); } TypeSpec 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 (ltype.IsNullableType) { unwrap = Unwrap.Create(left, false); if (unwrap == null) { return(null); } // // Reduce (left ?? null) to left // if (right.IsNull) { return(ReducedExpression.Create(left, this)); } if (Convert.ImplicitConversionExists(ec, right, unwrap.Type)) { left = unwrap; ltype = left.Type; // // If right is a dynamic expression, the result type is dynamic // if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { type = right.Type; // Need to box underlying value type left = Convert.ImplicitBoxingConversion(left, ltype, type); return(this); } right = Convert.ImplicitConversion(ec, right, ltype, loc); type = ltype; return(this); } } 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.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { type = right.Type; return(this); } // // Reduce ("foo" ?? expr) to expression // Constant lc = left as Constant; if (lc != null && !lc.IsDefaultValue) { return(ReducedExpression.Create(lc, this)); } // // Reduce (left ?? null) to left OR (null-constant ?? right) to right // if (right.IsNull || lc != null) { return(ReducedExpression.Create(lc != null ? right : left, this)); } right = Convert.ImplicitConversion(ec, right, ltype, loc); type = ltype; return(this); } // // Special case null ?? null // if (ltype == right.Type) { type = ltype; return(this); } } else { return(null); } TypeSpec rtype = right.Type; if (!Convert.ImplicitConversionExists(ec, unwrap != null ? unwrap : left, rtype) || right.eclass == ExprClass.MethodGroup) { return(null); } // // Reduce (null ?? right) to right // if (left.IsNull) { return(ReducedExpression.Create(right, this).Resolve(ec)); } left = Convert.ImplicitConversion(ec, unwrap != null ? unwrap : left, rtype, loc); type = rtype; return(this); }
public override Expression DoResolve (ResolveContext ec) { if (base.DoResolve (ec) == null) return null; Type d = expr.Type; bool d_is_nullable = false; // // If E is a method group or the null literal, or if the type of E is a reference // type or a nullable type and the value of E is null, the result is false // if (expr.IsNull || expr.eclass == ExprClass.MethodGroup) return CreateConstantResult (ec, false); if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) { d = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (d) [0]); d_is_nullable = true; } type = TypeManager.bool_type; eclass = ExprClass.Value; Type t = probe_type_expr.Type; bool t_is_nullable = false; if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) { t = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (t) [0]); t_is_nullable = true; } if (TypeManager.IsStruct (t)) { if (d == t) { // // D and T are the same value types but D can be null // if (d_is_nullable && !t_is_nullable) { expr_unwrap = Nullable.Unwrap.Create (expr, false); return this; } // // The result is true if D and T are the same value types // return CreateConstantResult (ec, true); } if (TypeManager.IsGenericParameter (d)) return ResolveGenericParameter (ec, t, d); // // An unboxing conversion exists // if (Convert.ExplicitReferenceConversionExists (d, t)) return this; } else { if (TypeManager.IsGenericParameter (t)) return ResolveGenericParameter (ec, d, t); if (TypeManager.IsStruct (d)) { bool temp; if (Convert.ImplicitBoxingConversionExists (expr, t, out temp)) return CreateConstantResult (ec, true); } else { if (TypeManager.IsGenericParameter (d)) return ResolveGenericParameter (ec, t, d); if (TypeManager.ContainsGenericParameters (d)) return this; if (Convert.ImplicitReferenceConversionExists (expr, t) || Convert.ExplicitReferenceConversionExists (d, t)) { return this; } } } return CreateConstantResult (ec, false); }
protected override Expression DoResolve (ResolveContext ec) { if ((Oper & Operator.LogicalMask) != 0) { Error_OperatorCannotBeApplied (ec, left, right); return null; } bool use_default_call = (Oper & (Operator.BitwiseMask | Operator.EqualityMask)) != 0; left_orig = left; if (left.Type.IsNullableType) { left = left_unwrap = Unwrap.Create (left, use_default_call); if (left == null) return null; } right_orig = right; if (right.Type.IsNullableType) { right = right_unwrap = Unwrap.Create (right, use_default_call); if (right == null) return null; } // // Some details are in 6.4.2, 7.2.7 // Arguments can be lifted for equal operators when the return type is bool and both // arguments are of same type // if (left_orig is NullLiteral) { left = right; state |= State.LeftNullLifted; type = ec.BuiltinTypes.Bool; } if (right_orig.IsNull) { if ((Oper & Operator.ShiftMask) != 0) right = new EmptyExpression (ec.BuiltinTypes.Int); else right = left; state |= State.RightNullLifted; type = ec.BuiltinTypes.Bool; } eclass = ExprClass.Value; return DoResolveCore (ec, left_orig, right_orig); }
void EmitBitwiseBoolean (EmitContext ec) { Label load_left = ec.DefineLabel (); Label load_right = ec.DefineLabel (); Label end_label = ec.DefineLabel (); // null & value, null | value if (left_unwrap == null) { left_unwrap = right_unwrap; right_unwrap = null; right = left; } left_unwrap.Emit (ec); ec.Emit (OpCodes.Brtrue_S, load_right); // value & null, value | null if (right_unwrap != null) { right_unwrap.Emit (ec); ec.Emit (OpCodes.Brtrue_S, load_left); } left_unwrap.EmitCheck (ec); ec.Emit (OpCodes.Brfalse_S, load_right); // load left ec.MarkLabel (load_left); if (Oper == Operator.BitwiseAnd) { left_unwrap.Load (ec); } else { if (right_unwrap == null) { right.Emit (ec); if (right is EmptyConstantCast || right is EmptyCast) ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); } else { right_unwrap.Load (ec); right_unwrap = left_unwrap; } } ec.Emit (OpCodes.Br_S, end_label); // load right ec.MarkLabel (load_right); if (right_unwrap == null) { if (Oper == Operator.BitwiseAnd) { right.Emit (ec); if (right is EmptyConstantCast || right is EmptyCast) ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); } else { left_unwrap.Load (ec); } } else { right_unwrap.Load (ec); } ec.MarkLabel (end_label); }
Expression ConvertExpression(ResolveContext ec) { // TODO: ImplicitConversionExists should take care of this if (left.eclass == ExprClass.MethodGroup) { return(null); } TypeSpec 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 (ltype.IsNullableType) { unwrap = Unwrap.Create(left, false); if (unwrap == null) { return(null); } // // Reduce (left ?? null) to left // if (right.IsNull) { return(ReducedExpression.Create(left, this)); } Expression conv; if (right.Type.IsNullableType) { conv = right.Type == ltype ? right : Convert.ImplicitNulableConversion(ec, right, ltype); if (conv != null) { right = conv; type = ltype; return(this); } } else { conv = Convert.ImplicitConversion(ec, right, unwrap.Type, loc); if (conv != null) { left = unwrap; ltype = left.Type; // // If right is a dynamic expression, the result type is dynamic // if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { type = right.Type; // Need to box underlying value type left = Convert.ImplicitBoxingConversion(left, ltype, type); return(this); } right = conv; type = ltype; return(this); } } } 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.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { type = right.Type; return(this); } // // Reduce ("foo" ?? expr) to expression // Constant lc = left as Constant; if (lc != null && !lc.IsDefaultValue) { return(ReducedExpression.Create(lc, this, false)); } // // Reduce (left ?? null) to left OR (null-constant ?? right) to right // if (right.IsNull || lc != null) { // // Special case null ?? null // if (right is NullLiteral && ltype == right.Type) { return(null); } return(ReducedExpression.Create(lc != null ? right : left, this, false)); } right = Convert.ImplicitConversion(ec, right, ltype, loc); type = ltype; return(this); } } else if (ltype == InternalType.ThrowExpr) { // // LAMESPEC: I am not really sure what's point of allowing throw on left side // return(ReducedExpression.Create(right, this, false).Resolve(ec)); } else { return(null); } TypeSpec rtype = right.Type; if (!Convert.ImplicitConversionExists(ec, unwrap ?? left, rtype) || right.eclass == ExprClass.MethodGroup) { return(null); } // // Reduce (null ?? right) to right // if (left.IsNull) { return(ReducedExpression.Create(right, this, false).Resolve(ec)); } left = Convert.ImplicitConversion(ec, unwrap ?? left, rtype, loc); user_conversion_left = left is UserCast; type = rtype; return(this); }