Skip to content

SIL: Tiny conformance substitution cleanups #80594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -153,7 +153,6 @@ func specializeWitnessTable(forConformance conformance: Conformance,
context, notifyNewWitnessTable)
}
return .associatedConformance(requirement: requirement,
substType: substType.subst(with: conformance.specializedSubstitutions),
witness: concreteAssociateConf)
}
}
Expand Down
6 changes: 2 additions & 4 deletions SwiftCompilerSources/Sources/SIL/WitnessTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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),
Expand All @@ -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):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eeckstein I was lazy but the substType tuple element can be removed from this enum case entirely now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove the enum case in this PR? Shouldn't be too much work.

Copy link
Contributor Author

@slavapestov slavapestov Apr 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. (it's a tuple field in an enum case, not the whole enum case that I removed.)

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)
Expand Down
2 changes: 0 additions & 2 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down
6 changes: 0 additions & 6 deletions include/swift/SIL/SILBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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};
}
Expand Down Expand Up @@ -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()}));
}

Expand Down
94 changes: 37 additions & 57 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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())));
}

Expand Down Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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(
Expand All @@ -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(
Expand Down
14 changes: 0 additions & 14 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
21 changes: 5 additions & 16 deletions include/swift/SIL/SILWitnessTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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.
Expand Down
7 changes: 3 additions & 4 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1522,8 +1522,7 @@ class AccessorConformanceInfo : public ConformanceInfo {
SpecializedBaseConformances;

ArrayRef<SILWitnessTable::Entry> SILEntries;
ArrayRef<SILWitnessTable::ConditionalConformance>
SILConditionalConformances;
ArrayRef<ProtocolConformanceRef> SILConditionalConformances;

const ProtocolInfo &PI;

Expand Down Expand Up @@ -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),
Expand Down
Loading