private EXPR CreateArgumentEXPR(ArgumentObject argument, LocalVariableSymbol local)
{
EXPR arg;
if (argument.Info.LiteralConstant)
{
if (argument.Value == null)
{
if (argument.Info.UseCompileTimeType)
{
arg = _exprFactory.CreateConstant(_symbolTable.GetCTypeFromType(argument.Type), new CONSTVAL());
}
else
{
arg = _exprFactory.CreateNull();
}
}
else
{
arg = _exprFactory.CreateConstant(_symbolTable.GetCTypeFromType(argument.Type), new CONSTVAL(argument.Value));
}
}
else
{
// If we have a dynamic argument and it was null, the type is going to be Object.
// But we want it to be typed NullType so we can have null conversions.
if (!argument.Info.UseCompileTimeType && argument.Value == null)
{
arg = _exprFactory.CreateNull();
}
else
{
arg = CreateLocal(argument.Type, argument.Info.IsOut, local);
}
}
// Now check if we have a named thing. If so, wrap this thing in a named argument.
if (argument.Info.NamedArgument)
{
Debug.Assert(argument.Info.Name != null);
arg = _exprFactory.CreateNamedArgumentSpecification(SymbolTable.GetName(argument.Info.Name, _semanticChecker.GetNameManager()), arg);
}
// If we have an object that was "dynamic" at compile time, we need
// to be able to convert it to every interface that the actual value
// implements. This allows conversion binders and overload resolution
// to behave as though type information is available for these EXPRs,
// even though it may be the case that the actual runtime type is
// inaccessible and therefore unused.
// This comes in handy for, e.g., iterators (they are nested private
// classes), and COM RCWs without type information (they do not expose
// their interfaces in a usual way).
// It is critical that arg.RuntimeObject is non-null only when the
// compile time type of the argument is dynamic, otherwise normal C#
// semantics on typed arguments will be broken.
if (!argument.Info.UseCompileTimeType && argument.Value != null)
{
arg.RuntimeObject = argument.Value;
arg.RuntimeObjectActualType = _symbolTable.GetCTypeFromType(argument.Value.GetType());
}
return arg;
}