/// <summary> /// If there is an anonymous delegate within a postcondition, then there /// will be a call to a delegate constructor. /// That call looks like "d..ctor(o,m)" where d is the type of the delegate. /// There are two cases depending on whether the anonymous delegate captured /// anything. In both cases, m is the method implementing the anonymous delegate. /// (1) It does capture something. Then o is the instance of the closure class /// implementing the delegate, and m is an instance method in the closure /// class. /// (2) It does *not* capture anything. Then o is the literal for null and /// m is a static method that was added directly to the class. /// /// This method will cause the method (i.e., m) to be visited to collect any /// Result<T>() expressions that occur in it. /// </summary> /// <param name="cons">The AST representing the call to the constructor /// of the delegate type.</param> /// <returns>Whatever the base visitor returns</returns> public override Expression VisitConstruct(Construct cons) { if (cons.Type is DelegateNode) { UnaryExpression ue = cons.Operands[1] as UnaryExpression; if (ue == null) { goto JustVisit; } MemberBinding mb = ue.Operand as MemberBinding; if (mb == null) { goto JustVisit; } Method m = mb.BoundMember as Method; if (!HelperMethods.IsCompilerGenerated(m)) { goto JustVisit; } Contract.Assume(m != null); m = Definition(m); this.delegateNestingLevel++; TypeNode savedClosureClass = this.currentClosureClassInstance; Method savedClosureMethod = this.currentClosureMethod; Expression savedCurrentAccessToTopLevelClosure = this.currentAccessToTopLevelClosure; try { this.currentClosureMethod = m; if (m.IsStatic) { this.currentClosureClassInstance = null; // no closure object } else { this.currentClosureClassInstance = cons.Operands[0].Type; if (savedClosureClass == null) { // Then this is the top-level closure class. this.topLevelClosureClassInstance = this.currentClosureClassInstance; this.topLevelClosureClassDefinition = Definition(this.topLevelClosureClassInstance); this.currentAccessToTopLevelClosure = new This(this.topLevelClosureClassDefinition); this.properlyInstantiatedFieldType = this.originalLocalForResult.Type; if (this.topLevelMethodFormals != null) { Contract.Assume(this.topLevelClosureClassDefinition.IsGeneric); Contract.Assume(topLevelClosureClassDefinition.TemplateParameters.Count >= this.topLevelMethodFormals.Count); // replace method type parameters in result properly with last n corresponding type parameters of closure class TypeNodeList closureFormals = topLevelClosureClassDefinition.TemplateParameters; if (closureFormals.Count > this.topLevelMethodFormals.Count) { int offset = closureFormals.Count - this.topLevelMethodFormals.Count; closureFormals = new TypeNodeList(this.topLevelMethodFormals.Count); for (int i = 0; i < this.topLevelMethodFormals.Count; i++) { closureFormals.Add(topLevelClosureClassDefinition.TemplateParameters[i + offset]); } } Duplicator dup = new Duplicator(this.declaringType.DeclaringModule, this.declaringType); Specializer spec = new Specializer(this.declaringType.DeclaringModule, topLevelMethodFormals, closureFormals); var type = dup.VisitTypeReference(this.originalLocalForResult.Type); type = spec.VisitTypeReference(type); this.properlyInstantiatedFieldType = type; } } else { while (currentClosureClassInstance.Template != null) { currentClosureClassInstance = currentClosureClassInstance.Template; } // Find the field in this.closureClass that the C# compiler generated // to point to the top-level closure foreach (Member mem in this.currentClosureClassInstance.Members) { Field f = mem as Field; if (f == null) { continue; } if (f.Type == this.topLevelClosureClassDefinition) { var consolidatedTemplateParams = this.currentClosureClassInstance.ConsolidatedTemplateParameters; TypeNode thisType; if (consolidatedTemplateParams != null && consolidatedTemplateParams.Count > 0) { thisType = this.currentClosureClassInstance.GetGenericTemplateInstance( this.assemblyBeingRewritten, consolidatedTemplateParams); } else { thisType = this.currentClosureClassInstance; } this.currentAccessToTopLevelClosure = new MemberBinding(new This(thisType), f); break; } } } } this.VisitBlock(m.Body); } finally { this.delegateNestingLevel--; this.currentClosureMethod = savedClosureMethod; this.currentClosureClassInstance = savedClosureClass; this.currentAccessToTopLevelClosure = savedCurrentAccessToTopLevelClosure; } } JustVisit: return(base.VisitConstruct(cons)); }