+ //
+ // Null constant can have its own type, think of `default (Foo)'
+ //
+ public class NullConstant : Constant
+ {
+ public NullConstant (TypeSpec type, Location loc)
+ : base (loc)
+ {
+ eclass = ExprClass.Value;
+ this.type = type;
+ }
+
+ public override Expression CreateExpressionTree (ResolveContext ec)
+ {
+ if (type == InternalType.NullLiteral || type.BuiltinType == BuiltinTypeSpec.Type.Object) {
+ // Optimized version, also avoids referencing literal internal type
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (this));
+ return CreateExpressionFactoryCall (ec, "Constant", args);
+ }
+
+ return base.CreateExpressionTree (ec);
+ }
+
+ public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
+ {
+ switch (targetType.BuiltinType) {
+ case BuiltinTypeSpec.Type.Object:
+ // Type it as string cast
+ enc.Encode (rc.Module.Compiler.BuiltinTypes.String);
+ goto case BuiltinTypeSpec.Type.String;
+ case BuiltinTypeSpec.Type.String:
+ case BuiltinTypeSpec.Type.Type:
+ enc.Encode (byte.MaxValue);
+ return;
+ default:
+ var ac = targetType as ArrayContainer;
+ if (ac != null && ac.Rank == 1 && !ac.Element.IsArray) {
+ enc.Encode (uint.MaxValue);
+ return;
+ }
+
+ break;
+ }
+
+ base.EncodeAttributeValue (rc, enc, targetType);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.EmitNull ();
+
+ // Only to make verifier happy
+ if (type.IsGenericParameter)
+ ec.Emit (OpCodes.Unbox_Any, type);
+ }
+
+ public override string ExprClassName {
+ get {
+ return GetSignatureForError ();
+ }
+ }
+
+ public override Constant ConvertExplicitly (bool inCheckedContext, TypeSpec targetType)
+ {
+ if (targetType.IsPointer) {
+ if (IsLiteral || this is NullPointer)
+ return new NullPointer (targetType, loc);
+
+ return null;
+ }
+
+ // Exlude internal compiler types
+ if (targetType.Kind == MemberKind.InternalCompilerType && targetType.BuiltinType != BuiltinTypeSpec.Type.Dynamic)
+ return null;
+
+ if (!IsLiteral && !Convert.ImplicitStandardConversionExists (this, targetType))
+ return null;
+
+ if (TypeSpec.IsReferenceType (targetType))
+ return new NullConstant (targetType, loc);
+
+ if (targetType.IsNullableType)
+ return Nullable.LiftedNull.Create (targetType, loc);
+
+ return null;
+ }
+
+ public override Constant ConvertImplicitly (TypeSpec targetType)
+ {
+ return ConvertExplicitly (false, targetType);
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return "null";
+ }
+
+ public override object GetValue ()
+ {
+ return null;
+ }
+
+ public override string GetValueAsLiteral ()
+ {
+ return GetSignatureForError ();
+ }
+
+ public override long GetValueAsLong ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override bool IsDefaultValue {
+ get { return true; }
+ }
+
+ public override bool IsNegative {
+ get { return false; }
+ }
+
+ public override bool IsNull {
+ get { return true; }
+ }
+
+ public override bool IsZeroInteger {
+ get { return true; }
+ }
+ }
+
+
+ //
+ // A null constant in a pointer context
+ //
+ class NullPointer : NullConstant
+ {
+ public NullPointer (TypeSpec type, Location loc)
+ : base (type, loc)
+ {
+ }
+
+ public override Expression CreateExpressionTree (ResolveContext ec)
+ {
+ Error_PointerInsideExpressionTree (ec);
+ return base.CreateExpressionTree (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ //
+ // Emits null pointer
+ //
+ ec.EmitInt (0);
+ ec.Emit (OpCodes.Conv_U);
+ }
+ }
+