TypeExpr CreateSiteType (EmitContext ec, Arguments arguments, int dyn_args_count, bool is_statement)
{
int default_args = is_statement ? 1 : 2;
var module = ec.MemberContext.Module;
bool has_ref_out_argument = false;
var targs = new TypeExpression[dyn_args_count + default_args];
targs [0] = new TypeExpression (module.PredefinedTypes.CallSite.TypeSpec, loc);
for (int i = 0; i < dyn_args_count; ++i) {
Argument a = arguments [i];
if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref)
has_ref_out_argument = true;
var t = a.Type;
// Convert any internal type like dynamic or null to object
if (t.Kind == MemberKind.InternalCompilerType)
t = TypeManager.object_type;
targs [i + 1] = new TypeExpression (t, loc);
}
TypeExpr del_type = null;
if (!has_ref_out_argument) {
string d_name = is_statement ? "Action" : "Func";
TypeExpr te = null;
Namespace type_ns = module.GlobalRootNamespace.GetNamespace ("System", true);
if (type_ns != null) {
te = type_ns.LookupType (module.Compiler, d_name, dyn_args_count + default_args, true, Location.Null);
}
if (te != null) {
if (!is_statement)
targs [targs.Length - 1] = new TypeExpression (type, loc);
del_type = new GenericTypeExpr (te.Type, new TypeArguments (targs), loc);
}
}
//
// Create custom delegate when no appropriate predefined one is found
//
if (del_type == null) {
TypeSpec rt = is_statement ? TypeManager.void_type : type;
Parameter[] p = new Parameter [dyn_args_count + 1];
p[0] = new Parameter (targs [0], "p0", Parameter.Modifier.NONE, null, loc);
var site = ec.CreateDynamicSite ();
int index = site.Types == null ? 0 : site.Types.Count;
if (site.Mutator != null)
rt = site.Mutator.Mutate (rt);
for (int i = 1; i < dyn_args_count + 1; ++i) {
var t = targs[i];
if (site.Mutator != null)
t.Type = site.Mutator.Mutate (t.Type);
p[i] = new Parameter (t, "p" + i.ToString ("X"), arguments[i - 1].Modifier, null, loc);
}
Delegate d = new Delegate (site.NamespaceEntry, site, new TypeExpression (rt, loc),
Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED,
new MemberName ("Container" + index.ToString ("X")),
new ParametersCompiled (p), null);
d.CreateType ();
d.DefineType ();
d.Define ();
d.Emit ();
var inflated = site.AddDelegate (d);
del_type = new TypeExpression (inflated, loc);
}
TypeExpr site_type = new GenericTypeExpr (module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments (del_type), loc);
return site_type;
}
}