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()))); }
/// <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)); }