diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index e5cfcf9d58c..428d08071fb 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -537,6 +537,10 @@ public: SILType MethodTy, bool Volatile = false) { + assert((!Conformance || + F.getModule().lookUpWitnessTable(Conformance).first) && + "Can not create a witness method inst for a conformance that does " + "not have a witness table mapped to it."); return insert(new (F.getModule()) WitnessMethodInst(Loc, LookupTy, Conformance, Member, MethodTy, diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index 015b6a3acf9..b17f06d59ce 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -308,6 +308,11 @@ public: std::pair> lookUpWitnessTable(const ProtocolConformance *C); + // Given a protocol conformance, attempt to create a witness table declaration + // for it. + SILWitnessTable * + createWitnessTableDeclaration(ProtocolConformance *C); + /// \brief Return the stage of processing this module is at. SILStage getStage() const { return Stage; } diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 9ff5010bba0..8cd74dba159 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -2694,6 +2694,10 @@ ProtocolInfo::getConformance(IRGenModule &IGM, CanType concreteType, } void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) { + // Don't emit a witness table if it is a declaration. + if (wt->isDeclaration()) + return; + // Build the witnesses. SmallVector witnesses; WitnessTableBuilder(*this, witnesses, wt) diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp index 80ea3b8c099..8078b30bf66 100644 --- a/lib/SIL/SILModule.cpp +++ b/lib/SIL/SILModule.cpp @@ -93,6 +93,38 @@ SILModule::~SILModule() { delete (SILTypeListUniquingType*)TypeListUniquing; } +SILWitnessTable * +SILModule::createWitnessTableDeclaration(ProtocolConformance *C) { + // Walk down to the base NormalProtocolConformance. + ProtocolConformance *ParentC = C; + ArrayRef Subs; + while (!isa(ParentC)) { + switch (ParentC->getKind()) { + case ProtocolConformanceKind::Normal: + llvm_unreachable("should have exited the loop?!"); + case ProtocolConformanceKind::Inherited: + ParentC = cast(ParentC) + ->getInheritedConformance(); + break; + case ProtocolConformanceKind::Specialized: { + auto SC = cast(ParentC); + ParentC = SC->getGenericConformance(); + assert(Subs.empty() && "multiple conformance specializations?!"); + Subs = SC->getGenericSubstitutions(); + break; + } + } + } + NormalProtocolConformance *NormalC + = cast(ParentC); + + SILWitnessTable *WT = SILWitnessTable::create(*this, + SILLinkage::PublicExternal, + NormalC); + WitnessTableLookupCache[NormalC] = WT; + return WT; +} + std::pair> SILModule::lookUpWitnessTable(const ProtocolConformance *C) { // Walk down to the base NormalProtocolConformance. @@ -143,6 +175,7 @@ SILModule::lookUpWitnessTable(const ProtocolConformance *C) { return {nullptr, Subs}; } + SILFunction *SILModule::getOrCreateSharedFunction(SILLocation loc, StringRef name, CanSILFunctionType type, diff --git a/lib/SILPasses/GenericSpecializer.cpp b/lib/SILPasses/GenericSpecializer.cpp index e4c40311e76..fb0e393e269 100644 --- a/lib/SILPasses/GenericSpecializer.cpp +++ b/lib/SILPasses/GenericSpecializer.cpp @@ -124,6 +124,12 @@ private: assert(sub.Conformance.size() == 1 && "didn't get conformance from substitution?!"); + // If we don't have a witness table for this conformance, create a witness + // table declaration for it. + SILModule &OtherMod = getCloned()->getModule(); + if (!OtherMod.lookUpWitnessTable(sub.Conformance[0]).first) + OtherMod.createWitnessTableDeclaration(sub.Conformance[0]); + doPostProcess(Inst,Builder. createWitnessMethod(getOpLocation(Inst->getLoc()), getOpType(Inst->getLookupType()), diff --git a/test/IRGen/Inputs/sil_witness_tables_external_input.swift b/test/IRGen/Inputs/sil_witness_tables_external_input.swift new file mode 100644 index 00000000000..1f0866dc705 --- /dev/null +++ b/test/IRGen/Inputs/sil_witness_tables_external_input.swift @@ -0,0 +1,12 @@ + +struct Y {} + +protocol P { + func doSomething() -> Y +} + +struct X : P { + func doSomething() -> Y { + return Y() + } +} diff --git a/test/IRGen/sil_witness_tables_external_witnesstable.swift b/test/IRGen/sil_witness_tables_external_witnesstable.swift new file mode 100644 index 00000000000..4d53af89360 --- /dev/null +++ b/test/IRGen/sil_witness_tables_external_witnesstable.swift @@ -0,0 +1,18 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: %swift -emit-module %S/Inputs/sil_witness_tables_external_input.swift -o %t/Swift.swiftmodule -parse-stdlib -parse-as-library -module-name Swift -sil-serialize-all -module-link-name swift_stdlib_core +// RUN: %swift -O3 -sil-inline-threshold 0 -I=%t %s -emit-ir | FileCheck %s + +import Swift + +// CHECK: @_TWPVSs1XSs1PSs = external global i8* +// CHECK: @_TMdVSs1X = external global %swift.full_type + +func doSomething(t : T) -> Y { + return t.doSomething() +} + +func done() -> Y { + var x = X() + return doSomething(x) +} diff --git a/test/SILPasses/Inputs/sil_witness_tables_external_input.swift b/test/SILPasses/Inputs/sil_witness_tables_external_input.swift new file mode 100644 index 00000000000..1f0866dc705 --- /dev/null +++ b/test/SILPasses/Inputs/sil_witness_tables_external_input.swift @@ -0,0 +1,12 @@ + +struct Y {} + +protocol P { + func doSomething() -> Y +} + +struct X : P { + func doSomething() -> Y { + return Y() + } +} diff --git a/test/SILPasses/sil_witness_tables_external_witnesstable.swift b/test/SILPasses/sil_witness_tables_external_witnesstable.swift new file mode 100644 index 00000000000..fd9c418429c --- /dev/null +++ b/test/SILPasses/sil_witness_tables_external_witnesstable.swift @@ -0,0 +1,21 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: %swift -emit-module %S/Inputs/sil_witness_tables_external_input.swift -o %t/Swift.swiftmodule -parse-stdlib -parse-as-library -module-name Swift -sil-serialize-all -module-link-name swift_stdlib_core +// RUN: %swift -O3 -sil-inline-threshold 0 -I=%t %s -emit-sil | FileCheck %s + +import Swift + +// Make sure the specializer produces an external witness table. +// +// CHECK-NOT: sil_witness_table X: P module Swift { +// CHECK: sil_witness_table X: P module Swift +// CHECK-NOT: sil_witness_table X: P module Swift { + +func doSomething(t : T) -> Y { + return t.doSomething() +} + +func done() -> Y { + var x = X() + return doSomething(x) +}