public void TestSpecialization()
    {
        var x = new Specializer();

        x.Save(new SpecificClass());
        Assert.IsTrue(x.SpecializedCalled);
        Assert.IsFalse(x.GenericCalled);
    }
        public EmitAsyncClosure(Method from, Rewriter rewriter)
        {
            Contract.Requires(from != null);
            Contract.Requires(from.DeclaringType != null);
            Contract.Requires(rewriter != null);

            if (TaskExtensionsTypeNode == null)
            {
                throw new InvalidOperationException(
                          "Can't generate async closure because System.Threading.Tasks.TaskExceptions class is unavailable.");
            }

            this.rewriter      = rewriter;
            this.declaringType = from.DeclaringType;

            var closureName = HelperMethods.NextUnusedMemberName(declaringType, "<" + from.Name.Name + ">AsyncContractClosure");

            this.closureClass = new Class(
                declaringModule: declaringType.DeclaringModule,
                declaringType: declaringType,
                attributes: null,
                flags: TypeFlags.NestedPrivate,
                Namespace: null,
                name: Identifier.For(closureName),
                baseClass: SystemTypes.Object,
                interfaces: null,
                members: null);

            declaringType.Members.Add(this.closureClass);
            RewriteHelper.TryAddCompilerGeneratedAttribute(this.closureClass);

            var taskType = from.ReturnType;

            this.aggregateExceptionType = new Cache <TypeNode>(() =>
                                                               HelperMethods.FindType(rewriter.AssemblyBeingRewritten, StandardIds.System,
                                                                                      Identifier.For("AggregateException")));

            this.func2Type = new Cache <TypeNode>(() =>
                                                  HelperMethods.FindType(SystemTypes.SystemAssembly, StandardIds.System, Identifier.For("Func`2")));

            if (from.IsGeneric)
            {
                this.closureClass.TemplateParameters = CreateTemplateParameters(closureClass, from, declaringType);

                this.closureClass.IsGeneric = true;
                this.closureClass.EnsureMangledName();

                this.forwarder = new Specializer(
                    targetModule: this.declaringType.DeclaringModule,
                    pars: from.TemplateParameters,
                    args: this.closureClass.TemplateParameters);

                this.forwarder.VisitTypeParameterList(this.closureClass.TemplateParameters);

                taskType = this.forwarder.VisitTypeReference(taskType);
            }
            else
            {
                this.closureClassInstance = this.closureClass;
            }

            this.checkMethodTaskType = taskType;

            // Emiting CheckPost method declaration
            EmitCheckPostMethodCore(checkMethodTaskType);

            // Generate closure constructor.
            // Constructor should be generated AFTER visiting type parameters in
            // the previous block of code. Otherwise current class would not have
            // appropriate number of generic arguments!
            var ctor = CreateConstructor(closureClass);

            closureClass.Members.Add(ctor);

            // Now that we added the ctor and the check method, let's instantiate the closure class if necessary
            if (this.closureClassInstance == null)
            {
                var consArgs = new TypeNodeList();
                var args     = new TypeNodeList();

                var parentCount = this.closureClass.DeclaringType.ConsolidatedTemplateParameters == null
                    ? 0
                    : this.closureClass.DeclaringType.ConsolidatedTemplateParameters.Count;

                for (int i = 0; i < parentCount; i++)
                {
                    consArgs.Add(this.closureClass.DeclaringType.ConsolidatedTemplateParameters[i]);
                }

                var methodCount = from.TemplateParameters == null ? 0 : from.TemplateParameters.Count;
                for (int i = 0; i < methodCount; i++)
                {
                    consArgs.Add(from.TemplateParameters[i]);
                    args.Add(from.TemplateParameters[i]);
                }

                this.closureClassInstance =
                    (Class)
                    this.closureClass.GetConsolidatedTemplateInstance(this.rewriter.AssemblyBeingRewritten,
                                                                      closureClass.DeclaringType, closureClass.DeclaringType, args, consArgs);
            }

            // create closure initializer for context method
            this.closureLocal       = new Local(this.ClosureClass);
            this.ClosureInitializer = new Block(new StatementList());

            // TODO: What is this?
            // Add ClosureLocal instantiation?
            this.ClosureInitializer.Statements.Add(
                new AssignmentStatement(
                    this.closureLocal,
                    new Construct(new MemberBinding(null, this.Ctor), new ExpressionList())));
        }
示例#3
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));
        }