/////////////////////////////////////////////////////////////////////////////////
private static EXPR GenerateOptionalArgument(
SymbolLoader symbolLoader,
ExprFactory exprFactory,
MethodOrPropertySymbol methprop,
CType type,
int index)
{
CType pParamType = type;
CType pRawParamType = type.IsNullableType() ? type.AsNullableType().GetUnderlyingType() : type;
EXPR optionalArgument = null;
if (methprop.HasDefaultParameterValue(index))
{
CType pConstValType = methprop.GetDefaultParameterValueConstValType(index);
CONSTVAL cv = methprop.GetDefaultParameterValue(index);
if (pConstValType.isPredefType(PredefinedType.PT_DATETIME) &&
(pRawParamType.isPredefType(PredefinedType.PT_DATETIME) || pRawParamType.isPredefType(PredefinedType.PT_OBJECT) || pRawParamType.isPredefType(PredefinedType.PT_VALUE)))
{
// This is the specific case where we want to create a DateTime
// but the constval that stores it is a long.
AggregateType dateTimeType = symbolLoader.GetReqPredefType(PredefinedType.PT_DATETIME);
optionalArgument = exprFactory.CreateConstant(dateTimeType, new CONSTVAL(DateTime.FromBinary(cv.longVal)));
}
else if (pConstValType.isSimpleOrEnumOrString())
{
// In this case, the constval is a simple type (all the numerics, including
// decimal), or an enum or a string. This covers all the substantial values,
// and everything else that can be encoded is just null or default(something).
// For enum parameters, we create a constant of the enum type. For everything
// else, we create the appropriate constant.
if (pRawParamType.isEnumType() && pConstValType == pRawParamType.underlyingType())
{
optionalArgument = exprFactory.CreateConstant(pRawParamType, cv);
}
else
{
optionalArgument = exprFactory.CreateConstant(pConstValType, cv);
}
}
else if ((pParamType.IsRefType() || pParamType.IsNullableType()) && cv.IsNullRef())
{
// We have an "= null" default value with a reference type or a nullable type.
optionalArgument = exprFactory.CreateNull();
}
else
{
// We have a default value that is encoded as a nullref, and that nullref is
// interpreted as default(something). For instance, the pParamType could be
// a type parameter type or a non-simple value type.
optionalArgument = exprFactory.CreateZeroInit(pParamType);
}
}
else
{
// There was no default parameter specified, so generally use default(T),
// except for some cases when the parameter type in metatdata is object.
if (pParamType.isPredefType(PredefinedType.PT_OBJECT))
{
if (methprop.MarshalAsObject(index))
{
// For [opt] parameters of type object, if we have marshal(iunknown),
// marshal(idispatch), or marshal(interface), then we emit a null.
optionalArgument = exprFactory.CreateNull();
}
else
{
// Otherwise, we generate Type.Missing
AggregateSymbol agg = symbolLoader.GetOptPredefAgg(PredefinedType.PT_MISSING);
Name name = symbolLoader.GetNameManager().GetPredefinedName(PredefinedName.PN_CAP_VALUE);
FieldSymbol field = symbolLoader.LookupAggMember(name, agg, symbmask_t.MASK_FieldSymbol).AsFieldSymbol();
FieldWithType fwt = new FieldWithType(field, agg.getThisType());
EXPRFIELD exprField = exprFactory.CreateField(0, agg.getThisType(), null, 0, fwt, null);
if (agg.getThisType() != type)
{
optionalArgument = exprFactory.CreateCast(0, type, exprField);
}
else
{
optionalArgument = exprField;
}
}
}
else
{
// Every type aside from object that doesn't have a default value gets
// its default value.
optionalArgument = exprFactory.CreateZeroInit(pParamType);
}
}
Debug.Assert(optionalArgument != null);
optionalArgument.IsOptionalArgument = true;
return optionalArgument;
}