this.loc = loc;
}
- public override TypeSpec ResolveAsType (IMemberContext ec)
+ public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments = false)
{
eclass = ExprClass.Type;
}
public static TypeSpec GetEnumUnderlyingType (ModuleContainer module, TypeSpec nullableEnum)
+ {
+ return MakeType (module, EnumSpec.GetUnderlyingType (GetUnderlyingType (nullableEnum)));
+ }
+
+ public static TypeSpec MakeType (ModuleContainer module, TypeSpec underlyingType)
{
return module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (module,
- new[] { EnumSpec.GetUnderlyingType (GetUnderlyingType (nullableEnum)) });
+ new[] { underlyingType });
+
}
}
call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
}
+ public override void EmitSideEffect (EmitContext ec)
+ {
+ expr.EmitSideEffect (ec);
+ }
+
public override Expression EmitToField (EmitContext ec)
{
if (temp_field == null)
{
}
+ public override bool IsNull {
+ get {
+ return expr.IsNull;
+ }
+ }
+
public override bool ContainsEmitWithAwait ()
{
return unwrap.ContainsEmitWithAwait ();
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;
}
if (!type.IsNullableType)
- type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { type });
+ type = NullableInfo.MakeType (rc.Module, type);
return Wrap.Create (expr, type);
}
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);
+ 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;
}
-
- right = Convert.ImplicitConversion (ec, right, ltype, loc);
- type = ltype;
- return this;
}
} else if (TypeSpec.IsReferenceType (ltype)) {
if (Convert.ImplicitConversionExists (ec, right, ltype)) {
//
Constant lc = left as Constant;
if (lc != null && !lc.IsDefaultValue)
- return ReducedExpression.Create (lc, this);
+ return ReducedExpression.Create (lc, this, false);
//
// Reduce (left ?? null) to left OR (null-constant ?? right) to right
//
- if (right.IsNull || lc != null)
- return ReducedExpression.Create (lc != null ? right : left, this);
+ 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;
}
-
- //
- // 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).Resolve (ec);
+ return ReducedExpression.Create (right, this, false).Resolve (ec);
left = Convert.ImplicitConversion (ec, unwrap ?? left, rtype, loc);
+
+ if (TypeSpec.IsValueType (left.Type) && !left.Type.IsNullableType) {
+ Warning_UnreachableExpression (ec, right.Location);
+ return ReducedExpression.Create (left, this, false).Resolve (ec);
+ }
+
type = rtype;
return this;
}
unwrap.EmitCheck (ec);
ec.Emit (OpCodes.Brfalse, is_null_label);
- left.Emit (ec);
+ //
+ // When both expressions are nullable the unwrap
+ // is needed only for null check not for value uwrap
+ //
+ if (type.IsNullableType && TypeSpecComparer.IsEqual (NullableInfo.GetUnderlyingType (type), unwrap.Type))
+ unwrap.Load (ec);
+ else
+ left.Emit (ec);
+
ec.Emit (OpCodes.Br, end_label);
ec.MarkLabel (is_null_label);