Exemple #1
0
    private Method CreateWrapperMethod(bool virtcall, TypeNode virtcallConstraint, Method templateMethod, TypeNode templateType, TypeNode wrapperType, Method methodWithContract, Method instanceMethod, SourceContext callingContext)
    {
      bool isProtected = IsProtected(templateMethod);
      Identifier name = templateMethod.Name;
      if (virtcall) {
        if (virtcallConstraint != null) {
          name = Identifier.For("CV$" + name.Name);
        }
        else {
          name = Identifier.For("V$" + name.Name);
        }
      }
      else {
        name = Identifier.For("NV$" + name.Name);
      }
      Duplicator dup = new Duplicator(this.assemblyBeingRewritten, wrapperType);
      TypeNodeList typeParameters = null;
      TypeNodeList typeParameterFormals = new TypeNodeList();
      TypeNodeList typeParameterActuals = new TypeNodeList();

      if (templateMethod.TemplateParameters != null) {
        dup.FindTypesToBeDuplicated(templateMethod.TemplateParameters);
        typeParameters = dup.VisitTypeParameterList(templateMethod.TemplateParameters);
        for (int i = 0; i < typeParameters.Count; i++) {
          typeParameterFormals.Add(typeParameters[i]);
          typeParameterActuals.Add(templateMethod.TemplateParameters[i]);
        }
      }
      ITypeParameter constraintTypeParam = null;
      if (virtcallConstraint != null) {
        if (typeParameters == null) { typeParameters = new TypeNodeList(); }
        var constraint = templateMethod.DeclaringType;
        var classConstraint = constraint as Class;
        if (classConstraint != null) {
          var classParam = new MethodClassParameter();
          classParam.BaseClass = classConstraint;
          classParam.Name = Identifier.For("TC");
          classParam.DeclaringType = wrapperType;
          typeParameters.Add(classParam);
          constraintTypeParam = classParam;
        }
        else {
          var mtp = new MethodTypeParameter();
          Interface intf = constraint as Interface;
          if (intf != null) {
            mtp.Interfaces.Add(intf);
          }
          mtp.Name = Identifier.For("TC");
          mtp.DeclaringType = wrapperType;
          typeParameters.Add(mtp);
          constraintTypeParam = mtp;
        }
      }
      var consolidatedTemplateTypeParameters = templateType.ConsolidatedTemplateParameters;
      if (consolidatedTemplateTypeParameters != null && consolidatedTemplateTypeParameters.Count > 0) {
        var consolidatedWrapperTypeParameters = wrapperType.ConsolidatedTemplateParameters;
        for (int i = 0; i < consolidatedTemplateTypeParameters.Count; i++) {
          typeParameterFormals.Add(consolidatedWrapperTypeParameters[i]);
          typeParameterActuals.Add(consolidatedTemplateTypeParameters[i]);
        }
      }
      Specializer spec = null;
      if (typeParameterActuals.Count > 0) {
        spec = new Specializer(this.assemblyBeingRewritten, typeParameterActuals, typeParameterFormals);
      }
      var parameters = new ParameterList();
      var asTypeConstraintTypeParam = constraintTypeParam as TypeNode;

      if (!isProtected && !templateMethod.IsStatic) {
        TypeNode thisType = GetThisTypeInstance(templateType, wrapperType, asTypeConstraintTypeParam);
        parameters.Add(new Parameter(Identifier.For("@this"), thisType));
      }
      for (int i = 0; i < templateMethod.Parameters.Count; i++) {
        parameters.Add((Parameter)dup.VisitParameter(templateMethod.Parameters[i]));
      }
      var retType = dup.VisitTypeReference(templateMethod.ReturnType);
      if (spec != null) {
        parameters = spec.VisitParameterList(parameters);
        retType = spec.VisitTypeReference(retType);
      }

      var wrapperMethod = new Method(wrapperType, null, name, parameters, retType, null);
      RewriteHelper.TryAddCompilerGeneratedAttribute(wrapperMethod);

      if (isProtected) {
        wrapperMethod.Flags = templateMethod.Flags & ~MethodFlags.Abstract;
        wrapperMethod.CallingConvention = templateMethod.CallingConvention;
      }
      else {
        wrapperMethod.Flags |= MethodFlags.Static | MethodFlags.Assembly;
      }
      if (constraintTypeParam != null) {
        constraintTypeParam.DeclaringMember = wrapperMethod;
      }
      if (typeParameters != null) {
        if (spec != null) {
          typeParameters = spec.VisitTypeParameterList(typeParameters);
        }
        wrapperMethod.IsGeneric = true;
        wrapperMethod.TemplateParameters = typeParameters;
      }

      // create body
      var sl = new StatementList();
      Block b = new Block(sl);

      // insert requires
      AddRequiresToWrapperMethod(wrapperMethod, b, methodWithContract);

      // create original call
      var targetType = templateType;
      if (isProtected)
      {
        // need to use base chain instantiation of target type.
        targetType = instanceMethod.DeclaringType;
      }
      else
      {
        if (targetType.ConsolidatedTemplateParameters != null && targetType.ConsolidatedTemplateParameters.Count > 0)
        {
          // need selfinstantiation
          targetType = targetType.GetGenericTemplateInstance(this.assemblyBeingRewritten, wrapperType.ConsolidatedTemplateParameters);
        }
      }
      Method targetMethod = GetMatchingMethod(targetType, templateMethod, wrapperMethod);
      if (targetMethod.IsGeneric) {
        if (typeParameters.Count > targetMethod.TemplateParameters.Count) {
          // omit the extra constrained type arg.
          TypeNodeList origArgs = new TypeNodeList();
          for (int i = 0; i < targetMethod.TemplateParameters.Count; i++) {
            origArgs.Add(typeParameters[i]);
          }
          targetMethod = targetMethod.GetTemplateInstance(wrapperType, origArgs);
        }
        else {
          targetMethod = targetMethod.GetTemplateInstance(wrapperType, typeParameters);
        }
      }
      MethodCall call;
      NodeType callType = virtcall ? NodeType.Callvirt : NodeType.Call;
      if (isProtected) {
        var mb = new MemberBinding(wrapperMethod.ThisParameter, targetMethod);
        var elist = new ExpressionList(wrapperMethod.Parameters.Count);
        for (int i = 0; i < wrapperMethod.Parameters.Count; i++) {
          elist.Add(wrapperMethod.Parameters[i]);
        }
        call = new MethodCall(mb, elist, callType);
      }
      else if (templateMethod.IsStatic) {
        var elist = new ExpressionList(wrapperMethod.Parameters.Count);
        for (int i = 0; i < wrapperMethod.Parameters.Count; i++) {
          elist.Add(wrapperMethod.Parameters[i]);
        }
        call = new MethodCall(new MemberBinding(null, targetMethod), elist, callType);
      }
      else {
        var mb = new MemberBinding(wrapperMethod.Parameters[0], targetMethod);
        var elist = new ExpressionList(wrapperMethod.Parameters.Count - 1);
        for (int i = 1; i < wrapperMethod.Parameters.Count; i++) {
          elist.Add(wrapperMethod.Parameters[i]);
        }
        call = new MethodCall(mb, elist, callType);
      }
      if (constraintTypeParam != null) {
        call.Constraint = asTypeConstraintTypeParam;
      }
      if (HelperMethods.IsVoidType(templateMethod.ReturnType)) {
        sl.Add(new ExpressionStatement(call,callingContext));
        sl.Add(new Return(callingContext));
      }
      else {
        sl.Add(new Return(call,callingContext));
      }
      wrapperMethod.Body = b;

      wrapperType.Members.Add(wrapperMethod);
      return wrapperMethod;
    }
Exemple #2
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);
    }