Example #1
0
// Start with the substitutions from the apply.
// Try to propagate them to find out the real substitutions required
// to invoke the method.
static ArrayRef<Substitution>
getSubstitutionsForCallee(SILModule &M, CanSILFunctionType GenCalleeType,
                          SILType ClassInstanceType, FullApplySite AI) {
  // *NOTE*:
  // Apply instruction substitutions are for the Member from a protocol or
  // class B, where this member was first defined, before it got overridden by
  // derived classes.
  //
  // The implementation F (the implementing method) which was found may have
  // a different set of generic parameters, e.g. because it is implemented by a
  // class D1 derived from B.
  //
  // ClassInstanceType may have a type different from both the type B
  // the Member belongs to and from the ClassInstanceType, e.g. if
  // ClassInstance is of a class D2, which is derived from D1, but does not
  // override the Member.
  //
  // As a result, substitutions provided by AI are for Member, whereas
  // substitutions in ClassInstanceType are for D2. And substitutions for D1
  // are not available directly in a general case. Therefore, they have to
  // be computed.
  //
  // What we know for sure:
  //   B is a superclass of D1
  //   D1 is a superclass of D2.
  // D1 can be the same as D2. D1 can be the same as B.
  //
  // So, substitutions from AI are for class B.
  // Substitutions for class D1 by means of bindSuperclass(), which starts
  // with a bound type ClassInstanceType and checks its superclasses until it
  // finds a bound superclass matching D1 and returns its substitutions.

  // Class F belongs to.
  CanType FSelfClass = GenCalleeType->getSelfParameter().getType();

  SILType FSelfSubstType;
  Module *Module = M.getSwiftModule();

  ArrayRef<Substitution> ClassSubs;

  if (GenCalleeType->isPolymorphic()) {
    // Declaration of the class F belongs to.
    if (auto *FSelfTypeDecl = FSelfClass.getNominalOrBoundGenericNominal()) {
      // Get the unbound generic type F belongs to.
      CanType FSelfGenericType =
        FSelfTypeDecl->getDeclaredType()->getCanonicalType();

      assert((isa<BoundGenericType>(ClassInstanceType.getSwiftRValueType()) ||
              isa<NominalType>(ClassInstanceType.getSwiftRValueType())) &&
             "Self type should be either a bound generic type"
             "or a non-generic type");

      assert((isa<UnboundGenericType>(FSelfGenericType) ||
              isa<NominalType>(FSelfGenericType)) &&
             "Method implementation self type should be generic");

      if (isa<BoundGenericType>(ClassInstanceType.getSwiftRValueType())) {
        auto BoundBaseType = bindSuperclass(FSelfGenericType,
                                            ClassInstanceType);
        if (auto BoundTy = BoundBaseType->getAs<BoundGenericType>()) {
          ClassSubs = BoundTy->getSubstitutions(Module, nullptr);
        }
      }
    }
  } else {
    // If the callee is not polymorphic, no substitutions are required.
    return {};
  }

  if (ClassSubs.empty())
    return AI.getSubstitutions();

  auto AISubs = AI.getSubstitutions();

  CanSILFunctionType AIGenCalleeType =
      AI.getCallee().getType().castTo<SILFunctionType>();

  CanType AISelfClass = AIGenCalleeType->getSelfParameter().getType();

  unsigned NextMethodParamIdx = 0;
  unsigned NumMethodParams = 0;
  if (AIGenCalleeType->isPolymorphic()) {
    NextMethodParamIdx = 0;
    // Generic parameters of the method start after generic parameters
    // of the instance class.
    if (auto AISelfClassSig =
            AISelfClass.getClassBound()->getGenericSignature()) {
      NextMethodParamIdx = AISelfClassSig->getGenericParams().size();
    }
    NumMethodParams = AISubs.size() - NextMethodParamIdx;
  }

  unsigned NumSubs = ClassSubs.size() + NumMethodParams;

  if (ClassSubs.size() == NumSubs)
    return ClassSubs;

  // Mix class subs with method specific subs from the AI substitutions.

  // Assumptions: AI substitutions contain first the substitutions for
  // a class of the method being invoked and then the substitutions
  // for a method being invoked.
  auto Subs = M.getASTContext().Allocate<Substitution>(NumSubs);

  unsigned i = 0;
  for (auto &S : ClassSubs) {
    Subs[i++] = S;
  }

  for (; i < NumSubs; ++i, ++NextMethodParamIdx) {
    Subs[i] = AISubs[NextMethodParamIdx];
  }

  return Subs;
}