protected override Expression VisitDynamic(DynamicExpression node) { DynamicMetaObjectBinder metaBinder = node.Binder as DynamicMetaObjectBinder; if (metaBinder == null) { // don't rewrite non meta-binder nodes, we can't compose them return(node); } // gather the real arguments for the new dynamic site node var args = node.Arguments; bool foundSideEffectingArgs = false; List <Expression> inputs = new List <Expression>(); // parameter mapping is 1 List<ComboParameterMappingInfo> for each meta binder, the inner list // contains the mapping info for each particular binder List <BinderMappingInfo> binders = new List <BinderMappingInfo>(); List <ParameterMappingInfo> myInfo = new List <ParameterMappingInfo>(); int actionCount = 0; for (int i = 0; i < args.Count; i++) { Expression e = args[i]; if (!foundSideEffectingArgs) { // attempt to combine the arguments... Expression rewritten = Visit(e); ComboDynamicSiteExpression combo = rewritten as ComboDynamicSiteExpression; ConstantExpression ce; if (combo != null) { // an action expression we can combine with our own expression // remember how many actions we have so far - if any of our children consume // actions their offset is bumped up int baseActionCount = actionCount; foreach (BinderMappingInfo comboInfo in combo.Binders) { List <ParameterMappingInfo> newInfo = new List <ParameterMappingInfo>(); foreach (ParameterMappingInfo info in comboInfo.MappingInfo) { if (info.IsParameter) { // all of the inputs from the child now become ours newInfo.Add(ParameterMappingInfo.Parameter(inputs.Count)); inputs.Add(combo.Inputs[info.ParameterIndex]); } else if (info.IsAction) { newInfo.Add(ParameterMappingInfo.Action(info.ActionIndex + baseActionCount)); actionCount++; } else { Debug.Assert(info.Constant != null); // constants can just flow through newInfo.Add(info); } } binders.Add(new BinderMappingInfo(comboInfo.Binder, newInfo)); } myInfo.Add(ParameterMappingInfo.Action(actionCount++)); } else if ((ce = rewritten as ConstantExpression) != null) { // we can hoist the constant into the combo myInfo.Add(ParameterMappingInfo.Fixed(ce)); } else if (IsSideEffectFree(rewritten)) { // we can treat this as an input parameter myInfo.Add(ParameterMappingInfo.Parameter(inputs.Count)); inputs.Add(rewritten); } else { // this argument is doing something we don't understand - we have to leave // it as is (an input we consume) and all the remaining arguments need to be // evaluated normally as this could have side effects on them. foundSideEffectingArgs = true; myInfo.Add(ParameterMappingInfo.Parameter(inputs.Count)); inputs.Add(e); } } else { // we've already seen an argument which may have side effects, don't do // any more combinations. myInfo.Add(ParameterMappingInfo.Parameter(inputs.Count)); inputs.Add(e); } } binders.Add(new BinderMappingInfo(metaBinder, myInfo)); // TODO: Remove any duplicate inputs (e.g. locals being fed in multiple times) return(new ComboDynamicSiteExpression(node.Type, binders, inputs.ToArray())); }