Ejemplo n.º 1
0
 public Lifted(Expression expr, Unwrap unwrap, TypeSpec type)
 {
     this.expr = expr;
     this.unwrap = unwrap;
     this.loc = expr.Location;
     this.type = type;
 }
Ejemplo n.º 2
0
		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;
		}
Ejemplo n.º 3
0
		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;
		}
Ejemplo n.º 4
0
		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;
		}
Ejemplo n.º 5
0
		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;
		}
Ejemplo n.º 6
0
		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;
		}
Ejemplo n.º 7
0
		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);
		}
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 9
0
		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);
		}
Ejemplo n.º 10
0
		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;
		}
Ejemplo n.º 11
0
		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;
		}
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 13
0
        public override bool Equals(object obj)
        {
            Unwrap uw = obj as Unwrap;

            return(uw != null && expr.Equals(uw.expr));
        }
Ejemplo n.º 14
0
        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);
        }
Ejemplo n.º 15
0
		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);
		}
Ejemplo n.º 16
0
		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);
		}
Ejemplo n.º 17
0
		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);
		}
Ejemplo n.º 18
0
        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);
        }