protected override Expression DoResolve (ResolveContext ec) { unwrap = Unwrap.Create (Expr, false); if (unwrap == null) return null; Expression res = base.ResolveOperator (ec, unwrap); if (res == null) { Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type); return null; } 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 LiftedConversion (Expression expr, Unwrap unwrap, TypeSpec type) { this.expr = expr; this.unwrap = unwrap; this.loc = expr.Location; this.type = type; }
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); 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.IsNull && 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 { 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); type = rtype; 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)); } 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.IsNull && 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 { 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); type = rtype; return(this); }