Esempio n. 1
0
        private static void DuplicateMember(DuplicatorForContractsAndClosures dup, FindClosurePartsToDuplicate fmd,
            int memindex, TypeNode targetType)
        {
            Member mem = fmd.MembersToDuplicate[memindex];
            
            TypeNode nestedType = mem as TypeNode;
            Method closureInstanceMethod = mem as Method;
            Method closureMethodTemplate = closureInstanceMethod;
            
            while (closureMethodTemplate != null && closureMethodTemplate.Template != null)
            {
                closureMethodTemplate = closureMethodTemplate.Template;
            }

            if (nestedType != null)
            {
                // if nested type is nested inside another type to be duplicated, skip it
                if (nestedType.DeclaringType != null && fmd.MembersToDuplicate.Contains(nestedType.DeclaringType))
                    return;
                
                // For call-site wrappers, we end up having multiple methods from the same original contract method
                // thus we have to avoid duplicating the same closure type multiple times.
                var duplicatedNestedType = FindExistingClosureType(targetType, nestedType);
                if (duplicatedNestedType == null)
                {
                    dup.FindTypesToBeDuplicated(new TypeNodeList(nestedType));

                    // if parent type is generic and different from the target type, then we may have to include all the
                    // consolidated type parameters excluding the ones from the target type.
                    TypeNodeList originalTemplateParameters = FindNonStandardTypeParametersToBeDuplicated(fmd,
                        nestedType, targetType);

                    duplicatedNestedType = dup.Visit(mem) as TypeNode;
                    if (originalTemplateParameters != null)
                    {
                        int parentParameters = (targetType.ConsolidatedTemplateParameters == null)
                            ? 0
                            : targetType.ConsolidatedTemplateParameters.Count;

                        if (parentParameters > 0 &&
                            (nestedType.DeclaringType.ConsolidatedTemplateParameters == null ||
                             nestedType.DeclaringType.ConsolidatedTemplateParameters.Count == 0))
                        {
                            // type is turning from non-generic to generic
                            Debug.Assert(false);
                        }

                        TypeNodeList dupTPs = DuplicateTypeParameterList(originalTemplateParameters, parentParameters, duplicatedNestedType);

                        duplicatedNestedType.TemplateParameters = dupTPs;
                        dup.SafeAddMember(targetType, duplicatedNestedType, mem);


                        // populate the self specialization forwarding
                        //  OriginalDecl<X,Y,Z>.NestedType<A,B,C> -> WrapperType<U,V,W>.NewNestedType<X,Y,Z,A,B,C>
                        //var oldSelfInstanceType = nestedType.GetGenericTemplateInstance(targetModule, nestedType.ConsolidatedTemplateParameters);
                        //var newSelfInstanceType = duplicatedNestedType.GetGenericTemplateInstance(targetModule, duplicatedNestedType.ConsolidatedTemplateParameters);
                        //dup.DuplicateFor[oldSelfInstanceType.UniqueKey] = newSelfInstanceType;
                        // specialize duplicated type
                        var specializer = new Specializer(targetType.DeclaringModule, originalTemplateParameters, dupTPs);
                        
                        specializer.VisitTypeParameterList(dupTPs); // for constraints etc.
                        specializer.VisitTypeNode(duplicatedNestedType);

                        var bodySpecializer = new MethodBodySpecializer(targetType.DeclaringModule,
                            originalTemplateParameters, dupTPs);

                        bodySpecializer.Visit(duplicatedNestedType);
                        
                        // after copying the closure class, clear the self specialization forwarding
                        //  OriginalDecl<X,Y,Z>.NestedType<A,B,C> -> WrapperType<U,V,W>.NewNestedType<X,Y,Z,A,B,C>
                        //dup.DuplicateFor[oldSelfInstanceType.UniqueKey] = null;
                    }
                    else
                    {
                        dup.SafeAddMember(targetType, duplicatedNestedType, mem);
                    }
                }
                else
                {
                    // already copied type previously
                    dup.DuplicateFor[nestedType.UniqueKey] = duplicatedNestedType;
#if false
        if (nestedType.ConsolidatedTemplateArguments != null)
        {
            // populate the self specialization forwarding
            //  NestedType<Self1,Self2> -> NewNestedType<NewSelf1,NewSelf2>
            var origSelfInstantiation = nestedType.DeclaringType.GetTemplateInstance(nestedType, nestedType.DeclaringType.TemplateParameters).GetNestedType(nestedType.Name);
            var newSelfInstantiation = duplicatedNestedType.GetGenericTemplateInstance(targetModule, duplicatedNestedType.ConsolidatedTemplateParameters);
            dup.DuplicateFor[origSelfInstantiation.UniqueKey] = newSelfInstantiation;
            // Also forward ContractType<A,B>.NestedType instantiated at target ContractType<X,Y>.NestedType to
            // TargetType<X,Y,Z>.NewNestedType<X,Y>, since this reference may appear in the contract itself.
            var consolidatedContractTemplateArguments = sourceMethod.DeclaringType.ConsolidatedTemplateArguments;
            var instantiatedNestedOriginal = nestedType.DeclaringType.GetGenericTemplateInstance(targetModule, consolidatedContractTemplateArguments).GetNestedType(nestedType.Name);
            dup.DuplicateFor[instantiatedNestedOriginal.UniqueKey] = duplicatedNestedType.GetTemplateInstance(targetType, consolidatedContractTemplateArguments);
        }
        else
        {
            Debugger.Break();
        }
#endif
                }
            }
            else if (closureInstanceMethod != null && closureMethodTemplate != null &&
                     !fmd.MembersToDuplicate.Contains(closureMethodTemplate.DeclaringType))
            {
                Method closureMethod = closureMethodTemplate;

                Debug.Assert(closureMethod.Template == null);
                
                //var m = FindExistingClosureMethod(targetType, closureMethod);
                Method m = null;
                
                // why did we ever try to find an existing one? This can capture a completely unrelated closure that happens to match by name.
                if (m == null)
                {
                    Method dupMethod = dup.Visit(closureMethod) as Method;
                    TypeNodeList actuals;

                    TransformOriginalConsolidatedTypeFormalsIntoMethodFormals(dupMethod, closureMethod,
                        closureInstanceMethod, out actuals);

                    // now setup a forwarding from the closureInstanceMethod to the new instance
                    Method newInstance = dupMethod.GetTemplateInstance(dupMethod.DeclaringType, actuals);
                    newInstance.Name = dupMethod.Name;

                    dup.DuplicateFor[closureInstanceMethod.UniqueKey] = newInstance;

                    dup.SafeAddMember(targetType, dupMethod, closureMethod);

                    // special case when resulting method is generic and instance, then we need to make "this" a parameter
                    // and the method static, otherwise, there's a type mismatch between the "this" and the explicitly generic parameter types used
                    // in arguments.
                    var originalParentTemplateParameters = closureMethod.DeclaringType.ConsolidatedTemplateParameters;
                    if (!dupMethod.IsStatic && originalParentTemplateParameters != null && originalParentTemplateParameters.Count > 0)
                    {
                        var oldThis = dupMethod.ThisParameter;
                        oldThis.Type = dup.PossiblyRemapContractClassToInterface(oldThis.Type);
                        
                        dupMethod.Flags |= MethodFlags.Static;
                        dupMethod.CallingConvention &= ~CallingConventionFlags.HasThis;
                        
                        var oldParameters = dupMethod.Parameters;
                        
                        dupMethod.Parameters = new ParameterList(oldParameters.Count + 1);
                        dupMethod.Parameters.Add(oldThis); // make explicit
                        
                        for (int i = 0; i < oldParameters.Count; i++)
                        {
                            dupMethod.Parameters.Add(oldParameters[i]);
                        }

                        // now need to specialize transforming original parameters into first n method template parameters
                        var targetTypeParameters = new TypeNodeList(originalParentTemplateParameters.Count);
                        for (int i = 0; i < originalParentTemplateParameters.Count; i++)
                        {
                            targetTypeParameters.Add(dupMethod.TemplateParameters[i]);
                        }

                        var specializer = new Specializer(targetType.DeclaringModule, originalParentTemplateParameters, targetTypeParameters);
                        specializer.VisitMethod(dupMethod);

                        var bodySpecializer = new MethodBodySpecializer(targetType.DeclaringModule,
                            originalParentTemplateParameters, targetTypeParameters);

                        bodySpecializer.VisitMethod(dupMethod);
                    }
                }
            }
            else if (closureInstanceMethod != null)
            {
                var m = FindExistingClosureMethod(targetType, closureInstanceMethod);
                if (m == null)
                {
                    Member duplicatedMember = dup.Visit(mem) as Member;
                    dup.SafeAddMember(targetType, duplicatedMember, mem);
                }
            }
            else
            {
                Member duplicatedMember = dup.Visit(mem) as Member;
                dup.SafeAddMember(targetType, duplicatedMember, mem);
            }
        }
Esempio n. 2
0
    internal static MethodContract DuplicateContractAndClosureParts(
      DuplicatorForContractsAndClosures dup,
      Method targetMethod,
      Method sourceMethod, 
      ContractNodes contractNodes,
      bool copyValidations
    )
    {

      //System.Console.WriteLine(">>>" + sourceMethod.FullName);

      // materialize source contract:
      var sourceContract = sourceMethod.Contract;
      ForceSideEffect(sourceContract.ContractInitializer);
      TypeNode targetType = targetMethod.DeclaringType;
      TypeNode sourceType = sourceMethod.DeclaringType;

      // need to null out ProvideNestedTypes so the NestedTypes property doesn't use
      // metadata to fill in the list of nested types. Because maybe sourceType has
      // had nested types added to it in memory and those nested types don't exist
      // in the assembly that sourceType is defined in.

      // The source type itself shouldn't be duplicated, because any references to its
      // members (e.g., method calls) in a contract should remain as references to that
      // member. I.e., a contract on virtual method B.M might contain a call to "this.P()". When copying
      // the contract from B.M to an override C.M, "this" of type B should become "this" of type C (which
      // is why the self parameter is mapped below), but the member B.P() should remain B.P().
      // However, any nested types within the source type, such as any closure classes, *should* be
      // duplicated.
      sourceType.ProvideNestedTypes = null;
      targetType.ProvideNestedTypes = null;

      #region HACK
      // For some reason, it is important to materialize the name of the targetType here!!!
      // Otherwise the duplicator will fail.
      ForceSideEffect(targetType.Name.Name);
      #endregion

      Local closureLocal;
      FindClosureInitialization(sourceMethod, sourceContract.ContractInitializer, out closureLocal);

      #region Duplicate anonymous delegates that turn into static methods (and their caching fields)
      FindClosurePartsToDuplicate fmd = new FindClosurePartsToDuplicate(sourceType, sourceMethod);
      fmd.VisitMethodContract(sourceContract);

      // special handling of closures that are not used.
      if (closureLocal != null)
      {
        var closureType = Unspecialize(closureLocal.Type);
        if (!fmd.MembersToDuplicate.Contains(closureType))
        {
          // contracts do not depend on closure and won't copy it, so remove the initialization, otherwise debugger gets confused
          DeleteClosureInitialization(sourceMethod, sourceContract, closureLocal);
        }
      }
      for (var memindex = fmd.MembersToDuplicate.Count - 1; memindex >= 0; memindex--) {
        Member mem = fmd.MembersToDuplicate[memindex];
        TypeNode nestedType = mem as TypeNode;
        Method closureInstanceMethod = mem as Method;
        Method closureMethodTemplate = closureInstanceMethod;
        while (closureMethodTemplate != null && closureMethodTemplate.Template != null)
        {
          closureMethodTemplate = closureMethodTemplate.Template;
        }
        if (nestedType != null)
        {
          // if nested type is nested inside another type to be duplicated, skip it
          if (nestedType.DeclaringType != null && fmd.MembersToDuplicate.Contains(nestedType.DeclaringType)) continue;
          // For call-site wrappers, we end up having multiple methods from the same original contract method
          // thus we have to avoid duplicating the same closure type multiple times.
          var duplicatedNestedType = FindExistingClosureType(targetType, nestedType);
          if (duplicatedNestedType == null) {
            dup.FindTypesToBeDuplicated(new TypeNodeList(nestedType));

            // if parent type is generic and different from the target type, then we may have to include all the
            // consolidated type parameters excluding the ones from the target type.
            TypeNodeList originalTemplateParameters = FindNonStandardTypeParametersToBeDuplicated(fmd, nestedType, targetType);
            duplicatedNestedType = dup.Visit(mem) as TypeNode;
            if (originalTemplateParameters != null) {
              int parentParameters = (targetType.ConsolidatedTemplateParameters == null) ? 0 : targetType.ConsolidatedTemplateParameters.Count;
              if (parentParameters > 0 && (nestedType.DeclaringType.ConsolidatedTemplateParameters == null || nestedType.DeclaringType.ConsolidatedTemplateParameters.Count == 0))
              {
                // type is turning from non-generic to generic
                Debug.Assert(false);
              }
              TypeNodeList dupTPs = DuplicateTypeParameterList(originalTemplateParameters, parentParameters, duplicatedNestedType);
              duplicatedNestedType.TemplateParameters = dupTPs;
              dup.SafeAddMember(targetType, duplicatedNestedType, mem);


              // populate the self specialization forwarding
              //  OriginalDecl<X,Y,Z>.NestedType<A,B,C> -> WrapperType<U,V,W>.NewNestedType<X,Y,Z,A,B,C>
              //var oldSelfInstanceType = nestedType.GetGenericTemplateInstance(targetModule, nestedType.ConsolidatedTemplateParameters);
              //var newSelfInstanceType = duplicatedNestedType.GetGenericTemplateInstance(targetModule, duplicatedNestedType.ConsolidatedTemplateParameters);
              //dup.DuplicateFor[oldSelfInstanceType.UniqueKey] = newSelfInstanceType;
              // specialize duplicated type
              var specializer = new Specializer(targetType.DeclaringModule, originalTemplateParameters, dupTPs);
              specializer.VisitTypeParameterList(dupTPs); // for constraints etc.
              specializer.VisitTypeNode(duplicatedNestedType);

              var bodySpecializer = new MethodBodySpecializer(targetType.DeclaringModule, originalTemplateParameters, dupTPs);
              bodySpecializer.Visit(duplicatedNestedType);
              // after copying the closure class, clear the self specialization forwarding
              //  OriginalDecl<X,Y,Z>.NestedType<A,B,C> -> WrapperType<U,V,W>.NewNestedType<X,Y,Z,A,B,C>
              //dup.DuplicateFor[oldSelfInstanceType.UniqueKey] = null;
            }
            else
            {
              dup.SafeAddMember(targetType, duplicatedNestedType, mem);
            }
          }
          else {
            // already copied type previously
            dup.DuplicateFor[nestedType.UniqueKey] = duplicatedNestedType;
#if false
            if (nestedType.ConsolidatedTemplateArguments != null)
            {
              // populate the self specialization forwarding
              //  NestedType<Self1,Self2> -> NewNestedType<NewSelf1,NewSelf2>
              var origSelfInstantiation = nestedType.DeclaringType.GetTemplateInstance(nestedType, nestedType.DeclaringType.TemplateParameters).GetNestedType(nestedType.Name);
              var newSelfInstantiation = duplicatedNestedType.GetGenericTemplateInstance(targetModule, duplicatedNestedType.ConsolidatedTemplateParameters);
              dup.DuplicateFor[origSelfInstantiation.UniqueKey] = newSelfInstantiation;
              // Also forward ContractType<A,B>.NestedType instantiated at target ContractType<X,Y>.NestedType to
              // TargetType<X,Y,Z>.NewNestedType<X,Y>, since this reference may appear in the contract itself.
              var consolidatedContractTemplateArguments = sourceMethod.DeclaringType.ConsolidatedTemplateArguments;
              var instantiatedNestedOriginal = nestedType.DeclaringType.GetGenericTemplateInstance(targetModule, consolidatedContractTemplateArguments).GetNestedType(nestedType.Name);
              dup.DuplicateFor[instantiatedNestedOriginal.UniqueKey] = duplicatedNestedType.GetTemplateInstance(targetType, consolidatedContractTemplateArguments);
            }
            else
            {
              Debugger.Break();
            }
#endif
          }
        }
        else if (closureInstanceMethod != null && closureMethodTemplate != null &&  !fmd.MembersToDuplicate.Contains(closureMethodTemplate.DeclaringType))
        {
          Method closureMethod = closureMethodTemplate;
          Debug.Assert(closureMethod.Template == null);
          //var m = FindExistingClosureMethod(targetType, closureMethod);
          Method m = null; // why did we ever try to find an existing one? This can capture a completely unrelated closure that happens to match by name.
          if (m == null)
          {
            Method dupMethod = dup.Visit(closureMethod) as Method;
            TypeNodeList actuals;
            TransformOriginalConsolidatedTypeFormalsIntoMethodFormals(dupMethod, closureMethod, closureInstanceMethod, out actuals);

            // now setup a forwarding from the closureInstanceMethod to the new instance
            Method newInstance = dupMethod.GetTemplateInstance(dupMethod.DeclaringType, actuals);
            newInstance.Name = dupMethod.Name;
            dup.DuplicateFor[closureInstanceMethod.UniqueKey] = newInstance;

            dup.SafeAddMember(targetType, dupMethod, closureMethod);

            // special case when resulting method is generic and instance, then we need to make "this" a parameter
            // and the method static, otherwise, there's a type mismatch between the "this" and the explicitly generic parameter types used
            // in arguments.
            var originalParentTemplateParameters = closureMethod.DeclaringType.ConsolidatedTemplateParameters;
            if (!dupMethod.IsStatic && originalParentTemplateParameters != null && originalParentTemplateParameters.Count > 0)
            {
              var oldThis = dupMethod.ThisParameter;
              oldThis.Type = dup.PossiblyRemapContractClassToInterface(oldThis.Type);
              dupMethod.Flags |= MethodFlags.Static;
              dupMethod.CallingConvention &= ~CallingConventionFlags.HasThis;
              var oldParameters = dupMethod.Parameters;
              dupMethod.Parameters = new ParameterList(oldParameters.Count + 1);
              dupMethod.Parameters.Add(oldThis); // make explicit
              for (int i = 0; i < oldParameters.Count; i++)
              {
                dupMethod.Parameters.Add(oldParameters[i]);
              }
              // now need to specialize transforming original parameters into first n method template parameters
              var targetTypeParameters = new TypeNodeList(originalParentTemplateParameters.Count);
              for (int i = 0; i < originalParentTemplateParameters.Count; i++)
              {
                targetTypeParameters.Add(dupMethod.TemplateParameters[i]);
              }
              var specializer = new Specializer(targetType.DeclaringModule, originalParentTemplateParameters, targetTypeParameters);
              specializer.VisitMethod(dupMethod);

              var bodySpecializer = new MethodBodySpecializer(targetType.DeclaringModule, originalParentTemplateParameters, targetTypeParameters);
              bodySpecializer.VisitMethod(dupMethod);
            }
          }
        }
        else if (closureInstanceMethod != null)
        {
          var m = FindExistingClosureMethod(targetType, closureInstanceMethod);
          if (m == null)
          {
            Member duplicatedMember = dup.Visit(mem) as Member;
            dup.SafeAddMember(targetType, duplicatedMember, mem);
          }
        }
        else
        {
          Member duplicatedMember = dup.Visit(mem) as Member;
          dup.SafeAddMember(targetType, duplicatedMember, mem);
        }
      }
      #endregion Duplicate anonymous delegates that turn into static methods (and their caching fields)


      var duplicateContract = dup.VisitMethodContract(sourceContract);
      if (copyValidations) { duplicateContract.Validations = dup.VisitRequiresList(sourceContract.Validations); }

      foreach (Member mem in sourceType.Members)
      {
        if (mem == null) continue;
        Member newMember = (Member)dup.DuplicateFor[mem.UniqueKey];
        if (newMember != null && mem != (Member)targetType && newMember.DeclaringType == targetType && !targetType.Members.Contains(newMember))
        {
          TypeNode nestedType = mem as TypeNode;
          if (nestedType != null && nestedType.Template != null)
          {
            // don't add instantiations
            continue;
          }
          Method nestedMethod = mem as Method;
          if (nestedMethod != null && nestedMethod.Template != null)
          {
            // don't add instantiations
            continue;
          }
          // second conjunct is to make sure we don't recursively add a nested type to itself
          // e.g., ArrayList+IListWrapper extends ArrayList and so inherits contracts from it
          // so this method could be called with sourceMethod "ArrayList.M" and targetMethod "ArrayList+IListWrapper.M"

          // But need to make sure that there isn't already a type with the same name!!!
          TypeNode possibleClash = targetType.GetNestedType(newMember.Name);
          if (possibleClash != null)
          {
            newMember.Name = Identifier.For(newMember.Name.Name + "_1");
          }
          // System.Console.WriteLine("found nested member that wasn't there before closure and contract duplication: {0}", newMember.FullName);
          dup.SafeAddMember(targetType, newMember, mem);
          //targetType.Members.Add(newMember);
        }
      }

      return duplicateContract;
    }