예제 #1
0
        /// <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&lt;T&gt;() 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));
        }