Repository: swiftlang/swift
Pull request #80594: SIL: Tiny conformance substitution cleanups
Author: login: slavapestov
Created: 2025-04-07T15:56:35Z | Merged: 2025-04-08T13:09:53Z

Follow-up to https://github.com/swiftlang/swift/pull/80482 that removes origType plumbing from a few more places in SIL.


Diff:
diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift
index e5f8dae6214a8..351a8373b5fa2 100644
--- a/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift
+++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift
@@ -144,7 +144,7 @@ func specializeWitnessTable(forConformance conformance: Conformance,
     case .associatedType(let requirement, let witness):
       let substType = witness.subst(with: conformance.specializedSubstitutions)
       return .associatedType(requirement: requirement, witness: substType)
-    case .associatedConformance(let requirement, let substType, let assocConf):
+    case .associatedConformance(let requirement, let assocConf):
       // FIXME: let concreteAssociateConf = assocConf.subst(with: conformance.specializedSubstitutions)
       let concreteAssociateConf = conformance.getAssociatedConformance(ofAssociatedType: requirement.rawType, to: assocConf.proto)
       if concreteAssociateConf.isSpecialized {
@@ -153,7 +153,6 @@ func specializeWitnessTable(forConformance conformance: Conformance,
                                context, notifyNewWitnessTable)
       }
       return .associatedConformance(requirement: requirement,
-                                    substType: substType.subst(with: conformance.specializedSubstitutions),
                                     witness: concreteAssociateConf)
     }
   }
diff --git a/SwiftCompilerSources/Sources/SIL/WitnessTable.swift b/SwiftCompilerSources/Sources/SIL/WitnessTable.swift
index 88df8fc194ab8..831ae2916267a 100644
--- a/SwiftCompilerSources/Sources/SIL/WitnessTable.swift
+++ b/SwiftCompilerSources/Sources/SIL/WitnessTable.swift
@@ -31,7 +31,7 @@ public struct WitnessTable : CustomStringConvertible, NoReflectionChildren {
     case associatedType(requirement: AssociatedTypeDecl, witness: CanonicalType)
 
     /// A witness table entry describing the witness for an associated type's protocol requirement.
-    case associatedConformance(requirement: CanonicalType, substType: CanonicalType, witness: Conformance)
+    case associatedConformance(requirement: CanonicalType, witness: Conformance)
 
     /// A witness table entry referencing the protocol conformance for a refined base protocol.
     case baseProtocol(requirement: ProtocolDecl, witness: Conformance)
@@ -48,7 +48,6 @@ public struct WitnessTable : CustomStringConvertible, NoReflectionChildren {
                                witness: CanonicalType(bridged: bridged.getAssociatedTypeWitness()))
       case .associatedConformance:
         self = .associatedConformance(requirement: CanonicalType(bridged: bridged.getAssociatedConformanceRequirement()),
-                                      substType: CanonicalType(bridged: bridged.getAssociatedConformanceSubstType()),
                                       witness: Conformance(bridged: bridged.getAssociatedConformanceWitness()))
       case .baseProtocol:
         self = .baseProtocol(requirement: bridged.getBaseProtocolRequirement().getAs(ProtocolDecl.self),
@@ -71,9 +70,8 @@ public struct WitnessTable : CustomStringConvertible, NoReflectionChildren {
                                                      OptionalBridgedFunction(obj: witness?.bridged.obj))
       case .associatedType(let requirement, let witness):
         return BridgedWitnessTableEntry.createAssociatedType(requirement.bridged, witness.bridged)
-      case .associatedConformance(let requirement, let substType, let witness):
+      case .associatedConformance(let requirement, let witness):
         return BridgedWitnessTableEntry.createAssociatedConformance(requirement.bridged,
-                                                                    substType.bridged,
                                                                     witness.bridged)
       case .baseProtocol(let requirement, let witness):
         return BridgedWitnessTableEntry.createBaseProtocol(requirement.bridged, witness.bridged)
diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h
index 5c1a2f218b0d4..0f6537a7c9ad3 100644
--- a/include/swift/SIL/SILBridging.h
+++ b/include/swift/SIL/SILBridging.h
@@ -1062,7 +1062,6 @@ struct BridgedWitnessTableEntry {
   SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj getAssociatedTypeRequirement() const;
   SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType getAssociatedTypeWitness() const;
   SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType getAssociatedConformanceRequirement() const;
-  SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType getAssociatedConformanceSubstType() const;
   SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformance getAssociatedConformanceWitness() const;
   SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj getBaseProtocolRequirement() const;
   SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformance getBaseProtocolWitness() const;
@@ -1077,7 +1076,6 @@ struct BridgedWitnessTableEntry {
                                                        BridgedCanType witness);
   SWIFT_IMPORT_UNSAFE BRIDGED_INLINE
   static BridgedWitnessTableEntry createAssociatedConformance(BridgedCanType requirement,
-                                                              BridgedCanType substType,
                                                               BridgedConformance witness);
   SWIFT_IMPORT_UNSAFE BRIDGED_INLINE
   static BridgedWitnessTableEntry createBaseProtocol(BridgedDeclObj requirement,
diff --git a/include/swift/SIL/SILBridgingImpl.h b/include/swift/SIL/SILBridgingImpl.h
index d750dbfc149c9..343cc82b84b54 100644
--- a/include/swift/SIL/SILBridgingImpl.h
+++ b/include/swift/SIL/SILBridgingImpl.h
@@ -1922,10 +1922,6 @@ BridgedCanType BridgedWitnessTableEntry::getAssociatedConformanceRequirement() c
   return unbridged().getAssociatedConformanceWitness().Requirement;
 }
 
-BridgedCanType BridgedWitnessTableEntry::getAssociatedConformanceSubstType() const {
-  return {unbridged().getAssociatedConformanceWitness().SubstType};
-}
-
 BridgedConformance BridgedWitnessTableEntry::getAssociatedConformanceWitness() const {
   return {unbridged().getAssociatedConformanceWitness().Witness};
 }
@@ -1957,11 +1953,9 @@ BridgedWitnessTableEntry BridgedWitnessTableEntry::createAssociatedType(BridgedD
 }
 
 BridgedWitnessTableEntry BridgedWitnessTableEntry::createAssociatedConformance(BridgedCanType requirement,
-                                                                               BridgedCanType substType,
                                                                                BridgedConformance witness) {
   return bridge(swift::SILWitnessTable::Entry(
     swift::SILWitnessTable::AssociatedConformanceWitness{requirement.unbridged(),
-                                                         substType.unbridged(),
                                                          witness.unbridged()}));
 }
 
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index d6827b2e94fed..d4003606ebc38 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -409,32 +409,16 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
       VarInfo->Scope = getOpScope(VarInfo->Scope);
   }
 
-  ProtocolConformanceRef getOpConformance(Type ty,
-                                          ProtocolConformanceRef conformance) {
-    auto substConf = asImpl().remapConformance(ty, conformance);
-
-#ifndef NDEBUG
-    if (substConf.isInvalid()) {
-      llvm::errs() << "Invalid conformance in SIL cloner:\n";
-      Functor.dump(llvm::errs());
-      llvm::errs() << "\nconformance:\n";
-      conformance.dump(llvm::errs());
-      llvm::errs() << "\noriginal type:\n";
-      ty.dump(llvm::errs());
-      abort();
-    }
-#endif
-
-    return substConf;
+  ProtocolConformanceRef getOpConformance(ProtocolConformanceRef conformance) {
+    return asImpl().remapConformance(conformance);
   }
 
   ArrayRef<ProtocolConformanceRef>
-  getOpConformances(Type ty,
-                    ArrayRef<ProtocolConformanceRef> conformances) {
+  getOpConformances(ArrayRef<ProtocolConformanceRef> conformances) {
     SmallVector<ProtocolConformanceRef, 4> newConformances;
     for (auto conformance : conformances)
-      newConformances.push_back(getOpConformance(ty, conformance));
-    return ty->getASTContext().AllocateCopy(newConformances);
+      newConformances.push_back(getOpConformance(conformance));
+    return getBuilder().getASTContext().AllocateCopy(newConformances);
   }
 
   bool isValueCloned(SILValue OrigValue) const {
@@ -558,28 +542,35 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
     return ty;
   }
 
-  ProtocolConformanceRef remapConformance(Type Ty, ProtocolConformanceRef C) {
-    if (Functor.SubsMap || Ty->hasLocalArchetype()) {
+  ProtocolConformanceRef remapConformance(ProtocolConformanceRef conformance) {
+    auto substConf = conformance;
+
+    if (Functor.SubsMap || substConf.getType()->hasLocalArchetype()) {
       SubstOptions options = SubstFlags::SubstitutePrimaryArchetypes;
       if (Functor.hasLocalArchetypes())
         options |= SubstFlags::SubstituteLocalArchetypes;
 
-      C = C.subst(Functor, Functor, options);
-      if (asImpl().shouldSubstOpaqueArchetypes())
-        Ty = Ty.subst(Functor, Functor, options);
+      substConf = substConf.subst(Functor, Functor, options);
+    }
+
+    if (substConf.isInvalid()) {
+      llvm::errs() << "Invalid substituted conformance in SIL cloner:\n";
+      Functor.dump(llvm::errs());
+      llvm::errs() << "\noriginal conformance:\n";
+      conformance.dump(llvm::errs());
+      abort();
     }
 
     if (asImpl().shouldSubstOpaqueArchetypes()) {
       auto context = getBuilder().getTypeExpansionContext();
 
-      if (!Ty->hasOpaqueArchetype() ||
-          !context.shouldLookThroughOpaqueTypeArchetypes())
-        return C;
-
-      return substOpaqueTypesWithUnderlyingTypes(C, context);
+      if (substConf.getType()->hasOpaqueArchetype() &&
+          context.shouldLookThroughOpaqueTypeArchetypes()) {
+        return substOpaqueTypesWithUnderlyingTypes(substConf, context);
+      }
     }
 
-    return C;
+    return substConf;
   }
 
   SubstitutionMap remapSubstitutionMap(SubstitutionMap Subs) {
@@ -599,11 +590,7 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
           !context.shouldLookThroughOpaqueTypeArchetypes())
         return Subs;
 
-      ReplaceOpaqueTypesWithUnderlyingTypes replacer(
-        context.getContext(), context.getResilienceExpansion(),
-        context.isWholeModuleContext());
-      return Subs.subst(replacer, replacer,
-                        SubstFlags::SubstituteOpaqueArchetypes);
+      return Subs.mapIntoTypeExpansionContext(context);
     }
 
     return Subs;
@@ -1135,8 +1122,7 @@ SILCloner<ImplClass>::visitAllocExistentialBoxInst(
   auto origExistentialType = Inst->getExistentialType();
   auto origFormalType = Inst->getFormalConcreteType();
 
-  auto conformances = getOpConformances(origFormalType,
-                                        Inst->getConformances());
+  auto conformances = getOpConformances(Inst->getConformances());
 
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   recordClonedInstruction(
@@ -2659,29 +2645,28 @@ SILCloner<ImplClass>::visitObjCSuperMethodInst(ObjCSuperMethodInst *Inst) {
 template<typename ImplClass>
 void
 SILCloner<ImplClass>::visitWitnessMethodInst(WitnessMethodInst *Inst) {
-  auto lookupType = Inst->getLookupType();
-  auto conformance = getOpConformance(lookupType, Inst->getConformance());
-  auto newLookupType = getOpASTType(lookupType);
+  auto conformance = getOpConformance(Inst->getConformance());
+  auto lookupType = getOpASTType(Inst->getLookupType());
 
   if (conformance.isConcrete()) {
-    CanType Ty = conformance.getConcrete()->getType()->getCanonicalType();
+    auto conformingType = conformance.getConcrete()->getType()->getCanonicalType();
 
-    if (Ty != newLookupType) {
+    if (conformingType != lookupType) {
       assert(
-          (Ty->isExactSuperclassOf(newLookupType) ||
+          (conformingType->isExactSuperclassOf(lookupType) ||
            getBuilder().getModule().Types.getLoweredRValueType(
-               getBuilder().getTypeExpansionContext(), Ty) == newLookupType) &&
+               getBuilder().getTypeExpansionContext(), conformingType) == lookupType) &&
           "Should only create upcasts for sub class.");
 
       // We use the super class as the new look up type.
-      newLookupType = Ty;
+      lookupType = conformingType;
     }
   }
 
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   recordClonedInstruction(Inst,
                           getBuilder().createWitnessMethod(
-                              getOpLocation(Inst->getLoc()), newLookupType,
+                              getOpLocation(Inst->getLoc()), lookupType,
                               conformance, Inst->getMember(), getOpType(Inst->getType())));
 }
 
@@ -2790,8 +2775,7 @@ void
 SILCloner<ImplClass>::visitInitExistentialAddrInst(InitExistentialAddrInst *Inst) {
   CanType origFormalType = Inst->getFormalConcreteType();
 
-  auto conformances = getOpConformances(origFormalType,
-                                        Inst->getConformances());
+  auto conformances = getOpConformances(Inst->getConformances());
 
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   recordClonedInstruction(
@@ -2806,8 +2790,7 @@ void SILCloner<ImplClass>::visitInitExistentialValueInst(
     InitExistentialValueInst *Inst) {
   CanType origFormalType = Inst->getFormalConcreteType();
 
-  auto conformances = getOpConformances(origFormalType,
-                                        Inst->getConformances());
+  auto conformances = getOpConformances(Inst->getConformances());
 
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   recordClonedInstruction(
@@ -2821,9 +2804,7 @@ template<typename ImplClass>
 void
 SILCloner<ImplClass>::
 visitInitExistentialMetatypeInst(InitExistentialMetatypeInst *Inst) {
-  auto origFormalType = Inst->getFormalErasedObjectType();
-  auto conformances = getOpConformances(origFormalType,
-                                        Inst->getConformances());
+  auto conformances = getOpConformances(Inst->getConformances());
 
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   recordClonedInstruction(Inst, getBuilder().createInitExistentialMetatype(
@@ -2837,8 +2818,7 @@ void
 SILCloner<ImplClass>::
 visitInitExistentialRefInst(InitExistentialRefInst *Inst) {
   CanType origFormalType = Inst->getFormalConcreteType();
-  auto conformances = getOpConformances(origFormalType,
-                                        Inst->getConformances());
+  auto conformances = getOpConformances(Inst->getConformances());
 
   getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
   recordClonedInstruction(
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index 25a811cde9280..fc482f81b828b 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -8077,20 +8077,6 @@ class InitExistentialMetatypeInst final
          SILFunction *parent);
 
 public:
-  /// Return the object type which was erased.  That is, if this
-  /// instruction erases Decoder<T>.Type.Type to Printable.Type.Type,
-  /// this method returns Decoder<T>.
-  CanType getFormalErasedObjectType() const {
-    auto exType = getType().getASTType();
-    auto concreteType = getOperand()->getType().getASTType();
-    while (auto exMetatype = dyn_cast<ExistentialMetatypeType>(exType)) {
-      exType = exMetatype->getExistentialInstanceType()->getCanonicalType();
-      concreteType = cast<MetatypeType>(concreteType).getInstanceType();
-    }
-    assert(exType.isExistentialType());
-    return concreteType;
-  }
-
   ArrayRef<ProtocolConformanceRef> getConformances() const;
 };
 
diff --git a/include/swift/SIL/SILWitnessTable.h b/include/swift/SIL/SILWitnessTable.h
index 39bc3c05110f1..57c663f083256 100644
--- a/include/swift/SIL/SILWitnessTable.h
+++ b/include/swift/SIL/SILWitnessTable.h
@@ -66,8 +66,6 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
   struct AssociatedConformanceWitness {
     /// The subject type of the associated requirement.
     CanType Requirement;
-    /// FIXME: Temporary.
-    CanType SubstType;
     /// The ProtocolConformanceRef satisfying the requirement.
     ProtocolConformanceRef Witness;
   };
@@ -154,15 +152,6 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
                const PrintOptions &options) const;
   };
 
-  /// An entry for a conformance requirement that makes the requirement
-  /// conditional. These aren't public, but any witness thunks need to feed them
-  /// into the true witness functions.
-  struct ConditionalConformance {
-    /// FIXME: Temporary.
-    CanType Requirement;
-    ProtocolConformanceRef Conformance;
-  };
-
 private:
   /// The module which contains the SILWitnessTable.
   SILModule &Mod;
@@ -186,7 +175,7 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
   ///
   /// (If other private entities are introduced this could/should be switched
   /// into a private version of Entries.)
-  MutableArrayRef<ConditionalConformance> ConditionalConformances;
+  MutableArrayRef<ProtocolConformanceRef> ConditionalConformances;
 
   /// Whether or not this witness table is a declaration. This is separate from
   /// whether or not entries is empty since you can have an empty witness table
@@ -201,7 +190,7 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
   SILWitnessTable(SILModule &M, SILLinkage Linkage, SerializedKind_t Serialized,
                   StringRef name, ProtocolConformance *conformance,
                   ArrayRef<Entry> entries,
-                  ArrayRef<ConditionalConformance> conditionalConformances);
+                  ArrayRef<ProtocolConformanceRef> conditionalConformances);
 
   /// Private constructor for making SILWitnessTable declarations.
   SILWitnessTable(SILModule &M, SILLinkage Linkage, StringRef Name,
@@ -214,7 +203,7 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
   static SILWitnessTable *
   create(SILModule &M, SILLinkage Linkage, SerializedKind_t SerializedKind,
          ProtocolConformance *conformance, ArrayRef<Entry> entries,
-         ArrayRef<ConditionalConformance> conditionalConformances);
+         ArrayRef<ProtocolConformanceRef> conditionalConformances);
 
   /// Create a new SILWitnessTable declaration.
   static SILWitnessTable *create(SILModule &M, SILLinkage Linkage,
@@ -271,7 +260,7 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
   ArrayRef<Entry> getEntries() const { return Entries; }
 
   /// Return all of the conditional conformances.
-  ArrayRef<ConditionalConformance> getConditionalConformances() const {
+  ArrayRef<ProtocolConformanceRef> getConditionalConformances() const {
     return ConditionalConformances;
   }
 
@@ -300,7 +289,7 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
   /// Change a SILWitnessTable declaration into a SILWitnessTable definition.
   void
   convertToDefinition(ArrayRef<Entry> newEntries,
-                      ArrayRef<ConditionalConformance> conditionalConformances,
+                      ArrayRef<ProtocolConformanceRef> conditionalConformances,
                       SerializedKind_t serializedKind);
 
   // Gets conformance serialized kind.
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index 8cd1e0d48f30d..2247e96de461c 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -1522,8 +1522,7 @@ class AccessorConformanceInfo : public ConformanceInfo {
       SpecializedBaseConformances;
 
     ArrayRef<SILWitnessTable::Entry> SILEntries;
-    ArrayRef<SILWitnessTable::ConditionalConformance>
-        SILConditionalConformances;
+    ArrayRef<ProtocolConformanceRef> SILConditionalConformances;
 
     const ProtocolInfo &PI;
 
@@ -2107,10 +2106,10 @@ llvm::Function *FragileWitnessTableBuilder::buildInstantiationFunction() {
     const auto &condConformance = SILConditionalConformances[idx];
     CanType reqTypeInContext =
       Conformance.getDeclContext()
-        ->mapTypeIntoContext(condConformance.Requirement)
+        ->mapTypeIntoContext(condConformance.getType())
         ->getCanonicalType();
     if (auto archetype = dyn_cast<ArchetypeType>(reqTypeInContext)) {
-      auto condProto = condConformance.Conformance.getProtocol();
+      auto condProto = condConformance.getProtocol();
       IGF.setUnscopedLocalTypeData(
              archetype,
              LocalTypeDataKind::forAbstractProtocolWitnessTable(condProto),
diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp
index 9e2337336ac65..359d02b29a8d3 100644
--- a/lib/SIL/IR/SILPrinter.cpp
+++ b/lib/SIL/IR/SILPrinter.cpp
@@ -4350,7 +4350,7 @@ void SILWitnessTable::Entry::print(llvm::raw_ostream &out, bool verbose,
       conformance.getConcrete()->printName(out, options);
     else {
       out << "dependent ";
-      assocProtoWitness.SubstType->print(out, options);
+      assocProtoWitness.Witness.getType()->print(out, options);
     }
     break;
   }
@@ -4392,18 +4392,21 @@ void SILWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const {
   for (auto conditionalConformance : getConditionalConformances()) {
     // conditional_conformance (TypeName: Protocol):
     // <conformance>
-    if (conditionalConformance.Conformance.isInvalid())
+    if (conditionalConformance.isInvalid()) {
+      OS << "  conditional_conformance invalid";
       continue;
+    }
 
     OS << "  conditional_conformance (";
-    conditionalConformance.Requirement.print(OS, Options);
-    OS << ": " << conditionalConformance.Conformance.getProtocol()->getName()
+    conditionalConformance.getType().print(OS, Options);
+    OS << ": " << conditionalConformance.getProtocol()->getName()
        << "): ";
-    if (conditionalConformance.Conformance.isConcrete())
-      conditionalConformance.Conformance.getConcrete()->printName(OS, Options);
+    if (conditionalConformance.isConcrete())
+      conditionalConformance.getConcrete()->printName(OS, Options);
     else {
+      ASSERT(conditionalConformance.isAbstract() && "Handle pack conformance here");
       OS << "dependent ";
-      conditionalConformance.Requirement->print(OS, Options);
+      conditionalConformance.getType()->print(OS, Options);
     }
 
     OS << '\n';
diff --git a/lib/SIL/IR/SILWitnessTable.cpp b/lib/SIL/IR/SILWitnessTable.cpp
index d301f37b9fdb4..18f820064b6f7 100644
--- a/lib/SIL/IR/SILWitnessTable.cpp
+++ b/lib/SIL/IR/SILWitnessTable.cpp
@@ -61,7 +61,7 @@ SILWitnessTable *SILWitnessTable::create(
     SILModule &M, SILLinkage Linkage, SerializedKind_t SerializedKind,
     ProtocolConformance *Conformance,
     ArrayRef<SILWitnessTable::Entry> entries,
-    ArrayRef<ConditionalConformance> conditionalConformances) {
+    ArrayRef<ProtocolConformanceRef> conditionalConformances) {
   assert(Conformance && "Cannot create a witness table for a null "
          "conformance.");
 
@@ -106,7 +106,7 @@ SILWitnessTable::create(SILModule &M, SILLinkage Linkage,
 SILWitnessTable::SILWitnessTable(
     SILModule &M, SILLinkage Linkage, SerializedKind_t SerializedKind, StringRef N,
     ProtocolConformance *Conformance, ArrayRef<Entry> entries,
-    ArrayRef<ConditionalConformance> conditionalConformances)
+    ArrayRef<ProtocolConformanceRef> conditionalConformances)
     : Mod(M), Name(N), Linkage(Linkage), Conformance(Conformance), Entries(),
       ConditionalConformances(), IsDeclaration(true),
       SerializedKind(SerializedKind) {
@@ -142,7 +142,7 @@ SILWitnessTable::~SILWitnessTable() {
 
 void SILWitnessTable::convertToDefinition(
     ArrayRef<Entry> entries,
-    ArrayRef<ConditionalConformance> conditionalConformances,
+    ArrayRef<ProtocolConformanceRef> conditionalConformances,
     SerializedKind_t serializedKind) {
   assert(isDeclaration() && "Definitions should never call this method.");
   IsDeclaration = false;
diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp
index 33d4d00580add..b95a4f9dbfca2 100644
--- a/lib/SIL/Parser/ParseSIL.cpp
+++ b/lib/SIL/Parser/ParseSIL.cpp
@@ -8157,8 +8157,7 @@ static bool parseSILWitnessTableEntry(
          GenericParamList *witnessParams,
          SILParser &witnessState,
          std::vector<SILWitnessTable::Entry> &witnessEntries,
-         std::vector<SILWitnessTable::ConditionalConformance>
-           &conditionalConformances) {
+         std::vector<ProtocolConformanceRef> &conditionalConformances) {
   Identifier EntryKeyword;
   SourceLoc KeywordLoc;
   if (P.parseIdentifier(EntryKeyword, KeywordLoc,
@@ -8230,7 +8229,6 @@ static bool parseSILWitnessTableEntry(
         P.parseToken(tok::colon, diag::expected_sil_witness_colon))
       return true;
 
-    CanType substType;
     ProtocolConformanceRef conformance;
     if (P.Tok.getText() != "dependent") {
       auto concrete =
@@ -8238,7 +8236,6 @@ static bool parseSILWitnessTableEntry(
       // Ignore invalid and abstract witness entries.
       if (concrete.isInvalid() || !concrete.isConcrete())
         return false;
-      substType = concrete.getConcrete()->getType()->getCanonicalType();
       conformance = concrete;
     } else {
       P.consumeToken();
@@ -8262,7 +8259,6 @@ static bool parseSILWitnessTableEntry(
       if (Ty->hasError())
         return true;
 
-      substType = Ty->getCanonicalType();
       conformance = ProtocolConformanceRef::forAbstract(
           Ty->getCanonicalType(), proto);
     }
@@ -8270,12 +8266,9 @@ static bool parseSILWitnessTableEntry(
     if (EntryKeyword.str() == "associated_conformance")
       witnessEntries.push_back(
           SILWitnessTable::AssociatedConformanceWitness{assocOrSubject,
-                                                        substType,
                                                         conformance});
     else
-      conditionalConformances.push_back(
-          SILWitnessTable::ConditionalConformance{assocOrSubject,
-                                                  conformance});
+      conditionalConformances.push_back(conformance);
 
     return false;
   }
@@ -8420,7 +8413,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) {
   Lexer::SILBodyRAII Tmp(*P.L);
   // Parse the entry list.
   std::vector<SILWitnessTable::Entry> witnessEntries;
-  std::vector<SILWitnessTable::ConditionalConformance> conditionalConformances;
+  std::vector<ProtocolConformanceRef> conditionalConformances;
 
   if (P.Tok.isNot(tok::r_brace)) {
     do {
@@ -8481,7 +8474,7 @@ bool SILParserState::parseSILDefaultWitnessTable(Parser &P) {
 
   // Parse the entry list.
   std::vector<SILWitnessTable::Entry> witnessEntries;
-  std::vector<SILWitnessTable::ConditionalConformance> conditionalConformances;
+  std::vector<ProtocolConformanceRef> conditionalConformances;
 
   if (P.Tok.isNot(tok::r_brace)) {
     do {
diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp
index 291661e488cae..d3380ad824f1a 100644
--- a/lib/SILGen/SILGenType.cpp
+++ b/lib/SILGen/SILGenType.cpp
@@ -540,7 +540,7 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
   SILGenModule &SGM;
   NormalProtocolConformance *Conformance;
   std::vector<SILWitnessTable::Entry> Entries;
-  std::vector<SILWitnessTable::ConditionalConformance> ConditionalConformances;
+  std::vector<ProtocolConformanceRef> ConditionalConformances;
   SILLinkage Linkage;
   SerializedKind_t SerializedKind;
 
@@ -692,12 +692,8 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
       Conformance->getAssociatedConformance(req.getAssociation(),
                                             req.getAssociatedRequirement());
     SGM.useConformance(assocConformance);
-
-    auto substType = (assocConformance
-                      ? assocConformance.getType()
-                      : ErrorType::get(SGM.getASTContext()))->getCanonicalType();
     Entries.push_back(SILWitnessTable::AssociatedConformanceWitness{
-        req.getAssociation(), substType, assocConformance});
+        req.getAssociation(), assocConformance});
   }
 
   void addConditionalRequirements() {
@@ -708,8 +704,7 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
           assert(conformance &&
                  "unable to find conformance that should be known");
 
-          ConditionalConformances.push_back(
-              SILWitnessTable::ConditionalConformance{type, conformance});
+          ConditionalConformances.push_back(conformance);
 
           return /*finished?*/ false;
         });
@@ -1126,7 +1121,7 @@ class SILGenDefaultWitnessTable
       return addMissingDefault();
 
     auto entry = SILWitnessTable::AssociatedConformanceWitness{
-        req.getAssociation(), req.getAssociation(), witness};
+        req.getAssociation(), witness};
     DefaultWitnesses.push_back(entry);
   }
 };
diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
index cfa93bde2983c..9bf28e7f8b837 100644
--- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
+++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
@@ -201,27 +201,13 @@ class DeadFunctionAndGlobalElimination {
           }
         } break;
 
-        case SILWitnessTable::AssociatedConformance: {
-          ProtocolConformanceRef CRef =
-             entry.getAssociatedConformanceWitness().Witness;
-          if (CRef.isConcrete())
-            ensureAliveConformance(CRef.getConcrete());
-          break;
-        }
+        case SILWitnessTable::AssociatedConformance:
         case SILWitnessTable::BaseProtocol:
-          ensureAliveConformance(entry.getBaseProtocolWitness().Witness);
-          break;
-
         case SILWitnessTable::Invalid:
         case SILWitnessTable::AssociatedType:
           break;
       }
     }
-
-    for (const auto &conf : WT->getConditionalConformances()) {
-      if (conf.Conformance.isConcrete())
-        ensureAliveConformance(conf.Conformance.getConcrete());
-    }
   }
 
   /// Marks the \p global and all functions, which are referenced from its
@@ -279,14 +265,6 @@ class DeadFunctionAndGlobalElimination {
       makeAlive(global);
   }
 
-  /// Marks a witness table as alive if it is not alive yet.
-  void ensureAliveConformance(const ProtocolConformance *C) {
-    SILWitnessTable *WT = Module->lookUpWitnessTable(C);
-    if (!WT || isAlive(WT))
-      return;
-    makeAlive(WT);
-  }
-
   /// Returns true if the implementation of method \p FD in class \p ImplCl
   /// may be called when the type of the class_method's operand is \p MethodCl.
   /// Both, \p MethodCl and \p ImplCl, may by null if not known or if it's a
@@ -322,7 +300,7 @@ class DeadFunctionAndGlobalElimination {
       if (!isAlive(FImpl.F) &&
           canHaveSameImplementation(FD, MethodCl,
                                     FImpl.Impl.get<ClassDecl *>())) {
-        makeAlive(FImpl.F);
+        ensureAlive(FImpl.F);
       } else {
         allImplsAreCalled = false;
       }
@@ -341,9 +319,9 @@ class DeadFunctionAndGlobalElimination {
       if (auto Conf = FImpl.Impl.dyn_cast<ProtocolConformance *>()) {
         SILWitnessTable *WT = Module->lookUpWitnessTable(Conf);
         if (!WT || isAlive(WT))
-          makeAlive(FImpl.F);
+          ensureAlive(FImpl.F);
       } else {
-        makeAlive(FImpl.F);
+        ensureAlive(FImpl.F);
       }
     }
   }
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index 9b96b3d54814f..2edfc7ef010ec 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -4464,8 +4464,7 @@ void SILDeserializer::getAllProperties() {
 void SILDeserializer::readWitnessTableEntries(
     llvm::BitstreamEntry &entry,
     std::vector<SILWitnessTable::Entry> &witnessEntries,
-    std::vector<SILWitnessTable::ConditionalConformance>
-      &conditionalConformances) {
+    std::vector<ProtocolConformanceRef> &conditionalConformances) {
   SmallVector<uint64_t, 64> scratch;
   llvm::Expected<unsigned> maybeKind = SILCursor.readRecord(entry.ID, scratch);
   if (!maybeKind)
@@ -4489,15 +4488,12 @@ void SILDeserializer::readWitnessTableEntries(
       });
     } else if (kind == SIL_WITNESS_ASSOC_PROTOCOL) {
       TypeID origTypeId;
-      DeclID substTypeId;
       ProtocolConformanceID conformanceId;
-      WitnessAssocProtocolLayout::readRecord(scratch, origTypeId, substTypeId,
-                                             conformanceId);
+      WitnessAssocProtocolLayout::readRecord(scratch, origTypeId, conformanceId);
       CanType origType = MF->getType(origTypeId)->getCanonicalType();
-      CanType substType = MF->getType(substTypeId)->getCanonicalType();
       auto conformance = MF->getConformance(conformanceId);
       witnessEntries.push_back(SILWitnessTable::AssociatedConformanceWitness{
-        origType, substType, conformance
+        origType, conformance
       });
     } else if (kind == SIL_WITNESS_ASSOC_ENTRY) {
       DeclID assocId;
@@ -4525,14 +4521,11 @@ void SILDeserializer::readWitnessTableEntries(
       assert(kind == SIL_WITNESS_CONDITIONAL_CONFORMANCE &&
              "Content of WitnessTable should be in "
              "SIL_WITNESS_CONDITIONAL_CONFORMANCE.");
-      TypeID assocId;
       ProtocolConformanceID conformanceId;
-      WitnessConditionalConformanceLayout::readRecord(scratch, assocId,
+      WitnessConditionalConformanceLayout::readRecord(scratch,
                                                       conformanceId);
-      CanType type = MF->getType(assocId)->getCanonicalType();
       auto conformance = MF->getConformance(conformanceId);
-      conditionalConformances.push_back(
-          SILWitnessTable::ConditionalConformance{type, conformance});
+      conditionalConformances.push_back(conformance);
     }
 
     // Fetch the next record.
@@ -4676,7 +4669,7 @@ llvm::Expected<SILWitnessTable *>
     return nullptr;
 
   std::vector<SILWitnessTable::Entry> witnessEntries;
-  std::vector<SILWitnessTable::ConditionalConformance> conditionalConformances;
+  std::vector<ProtocolConformanceRef> conditionalConformances;
   readWitnessTableEntries(entry, witnessEntries, conditionalConformances);
 
   // If we've already serialized the module, don't mark the witness table
@@ -4821,7 +4814,7 @@ readDefaultWitnessTable(DeclID WId, SILDefaultWitnessTable *existingWt) {
     return nullptr;
 
   std::vector<SILWitnessTable::Entry> witnessEntries;
-  std::vector<SILWitnessTable::ConditionalConformance> conditionalConformances;
+  std::vector<ProtocolConformanceRef> conditionalConformances;
   readWitnessTableEntries(entry, witnessEntries, conditionalConformances);
 
   wT->convertToDefinition(witnessEntries);
diff --git a/lib/Serialization/DeserializeSIL.h b/lib/Serialization/DeserializeSIL.h
index 8fa5d79b92ab5..21edb3f60b548 100644
--- a/lib/Serialization/DeserializeSIL.h
+++ b/lib/Serialization/DeserializeSIL.h
@@ -179,8 +179,7 @@ namespace swift {
     void readWitnessTableEntries(
            llvm::BitstreamEntry &entry,
            std::vector<SILWitnessTable::Entry> &witnessEntries,
-           std::vector<SILWitnessTable::ConditionalConformance>
-             &conditionalConformances);
+           std::vector<ProtocolConformanceRef> &conditionalConformances);
     SILProperty *readProperty(serialization::DeclID);
     SILDefaultWitnessTable *
     readDefaultWitnessTable(serialization::DeclID,
diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h
index fa5c9a4f2adfc..d54bf6aeb1f2c 100644
--- a/lib/Serialization/ModuleFormat.h
+++ b/lib/Serialization/ModuleFormat.h
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
 /// describe what change you made. The content of this comment isn't important;
 /// it just ensures a conflict if two people change the module format.
 /// Don't worry about adhering to the 80-column limit for this line.
-const uint16_t SWIFTMODULE_VERSION_MINOR = 935; // remove ExtensibleEnums feature
+const uint16_t SWIFTMODULE_VERSION_MINOR = 937; // Simplify SILWitnessTable
 
 /// A standard hash seed used for all string hashes in a serialized module.
 ///
diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h
index 5eeefeb60d517..959fab3a724fc 100644
--- a/lib/Serialization/SILFormat.h
+++ b/lib/Serialization/SILFormat.h
@@ -249,7 +249,6 @@ namespace sil_block {
   using WitnessAssocProtocolLayout = BCRecordLayout<
     SIL_WITNESS_ASSOC_PROTOCOL,
     TypeIDField, // ID of requirement subject type
-    TypeIDField, // ID of substituted subject type
     ProtocolConformanceIDField
   >;
 
@@ -261,7 +260,6 @@ namespace sil_block {
 
   using WitnessConditionalConformanceLayout = BCRecordLayout<
     SIL_WITNESS_CONDITIONAL_CONFORMANCE,
-    TypeIDField, // ID of associated type
     ProtocolConformanceIDField // ID of conformance
   >;
 
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index 5bb428b7063ff..b9029505b1a3e 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -3374,12 +3374,11 @@ void SILSerializer::writeSILWitnessTable(const SILWitnessTable &wt) {
   }
 
   for (auto conditional : wt.getConditionalConformances()) {
-    auto requirementID = S.addTypeRef(conditional.Requirement);
-    auto conformanceID = S.addConformanceRef(conditional.Conformance);
+    auto conformanceID = S.addConformanceRef(conditional);
     WitnessConditionalConformanceLayout::emitRecord(
         Out, ScratchRecord,
         SILAbbrCodes[WitnessConditionalConformanceLayout::Code],
-        requirementID, conformanceID);
+        conformanceID);
   }
 }
 
@@ -3402,13 +3401,12 @@ void SILSerializer::writeSILWitnessTableEntry(
     auto &assoc = entry.getAssociatedConformanceWitness();
 
     auto requirementID = S.addTypeRef(assoc.Requirement);
-    auto substTypeID = S.addTypeRef(assoc.SubstType);
     auto conformanceID = S.addConformanceRef(assoc.Witness);
 
     WitnessAssocProtocolLayout::emitRecord(
       Out, ScratchRecord,
       SILAbbrCodes[WitnessAssocProtocolLayout::Code],
-      requirementID, substTypeID, conformanceID);
+      requirementID, conformanceID);
     return;
   }
 


Reviews:
user: login: slavapestov
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:57:14Z
user: login: slavapestov
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:05:52Z
user: login: eeckstein
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T18:29:39Z
user: login: slavapestov
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T19:15:09Z
user: login: slavapestov
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T19:15:53Z
user: login: eeckstein
body: lgtm, thanks!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:38:41Z

Review comments:
diff_hunk: @@ -71,9 +71,8 @@ public struct WitnessTable : CustomStringConvertible, NoReflectionChildren {
                                                      OptionalBridgedFunction(obj: witness?.bridged.obj))
       case .associatedType(let requirement, let witness):
         return BridgedWitnessTableEntry.createAssociatedType(requirement.bridged, witness.bridged)
-      case .associatedConformance(let requirement, let substType, let witness):
path: SwiftCompilerSources/Sources/SIL/WitnessTable.swift
user: login: slavapestov
body: @eeckstein I was lazy but the `substType` tuple element can be removed from this enum case entirely now.
created_at: 2025-04-07T15:57:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -280,11 +279,22 @@ class DeadFunctionAndGlobalElimination {
   }
 
   /// Marks a witness table as alive if it is not alive yet.
-  void ensureAliveConformance(const ProtocolConformance *C) {
-    SILWitnessTable *WT = Module->lookUpWitnessTable(C);
-    if (!WT || isAlive(WT))
-      return;
-    makeAlive(WT);
+  void ensureAliveConformance(ProtocolConformanceRef conformance) {
+    if (conformance.isConcrete()) {
+      auto *concrete = conformance.getConcrete();
+      SILWitnessTable *WT = Module->lookUpWitnessTable(concrete);
+      if (!WT || isAlive(WT))
+        return;
+      makeAlive(WT);
+
+      // FIXME: If 'concrete' is a SpecializedProtocolConformance,
path: lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
user: login: slavapestov
body: @eeckstein Thoughts?
created_at: 2025-04-07T16:05:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -71,9 +71,8 @@ public struct WitnessTable : CustomStringConvertible, NoReflectionChildren {
                                                      OptionalBridgedFunction(obj: witness?.bridged.obj))
       case .associatedType(let requirement, let witness):
         return BridgedWitnessTableEntry.createAssociatedType(requirement.bridged, witness.bridged)
-      case .associatedConformance(let requirement, let substType, let witness):
path: SwiftCompilerSources/Sources/SIL/WitnessTable.swift
user: login: eeckstein
body: Can you remove the enum case in this PR? Shouldn't be too much work.
created_at: 2025-04-07T17:31:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -280,11 +279,22 @@ class DeadFunctionAndGlobalElimination {
   }
 
   /// Marks a witness table as alive if it is not alive yet.
-  void ensureAliveConformance(const ProtocolConformance *C) {
-    SILWitnessTable *WT = Module->lookUpWitnessTable(C);
-    if (!WT || isAlive(WT))
-      return;
-    makeAlive(WT);
+  void ensureAliveConformance(ProtocolConformanceRef conformance) {
+    if (conformance.isConcrete()) {
+      auto *concrete = conformance.getConcrete();
+      SILWitnessTable *WT = Module->lookUpWitnessTable(concrete);
+      if (!WT || isAlive(WT))
+        return;
+      makeAlive(WT);
+
+      // FIXME: If 'concrete' is a SpecializedProtocolConformance,
path: lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
user: login: eeckstein
body: It actually doesn't matter because we don't do dead witnesstable elimination. In `findAnchorsInTables` we set all witness tables alive. We had to do this because it's almost impossible to find all references to witness tables in SIL. Only IRGen knows that - and we emit witness tables lazily there.
created_at: 2025-04-07T18:28:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -71,9 +71,8 @@ public struct WitnessTable : CustomStringConvertible, NoReflectionChildren {
                                                      OptionalBridgedFunction(obj: witness?.bridged.obj))
       case .associatedType(let requirement, let witness):
         return BridgedWitnessTableEntry.createAssociatedType(requirement.bridged, witness.bridged)
-      case .associatedConformance(let requirement, let substType, let witness):
path: SwiftCompilerSources/Sources/SIL/WitnessTable.swift
user: login: slavapestov
body: Done. (it's a tuple field in an enum case, not the whole enum case that I removed.)
created_at: 2025-04-07T19:15:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -280,11 +279,22 @@ class DeadFunctionAndGlobalElimination {
   }
 
   /// Marks a witness table as alive if it is not alive yet.
-  void ensureAliveConformance(const ProtocolConformance *C) {
-    SILWitnessTable *WT = Module->lookUpWitnessTable(C);
-    if (!WT || isAlive(WT))
-      return;
-    makeAlive(WT);
+  void ensureAliveConformance(ProtocolConformanceRef conformance) {
+    if (conformance.isConcrete()) {
+      auto *concrete = conformance.getConcrete();
+      SILWitnessTable *WT = Module->lookUpWitnessTable(concrete);
+      if (!WT || isAlive(WT))
+        return;
+      makeAlive(WT);
+
+      // FIXME: If 'concrete' is a SpecializedProtocolConformance,
path: lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
user: login: slavapestov
body: Ah. I'll just delete the logic then since it's pointless to keep around code that is unused and incorrect.
created_at: 2025-04-07T19:15:53Z
author_association: CONTRIBUTOR

PR comments:
user: login: slavapestov
created_at: 2025-04-08T02:15:34Z
body: @swift-ci Please smoke test
author_association: CONTRIBUTOR
user: login: slavapestov
created_at: 2025-04-08T02:15:39Z
body: @swift-ci Please test source compatibility
author_association: CONTRIBUTOR
user: login: eeckstein
created_at: 2025-04-08T05:14:11Z
body: @swift-ci benchmark
author_association: CONTRIBUTOR