summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-specialize.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-ir-specialize.cpp')
-rw-r--r--source/slang/slang-ir-specialize.cpp45
1 files changed, 43 insertions, 2 deletions
diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp
index ed96b23c1..bc7bcab12 100644
--- a/source/slang/slang-ir-specialize.cpp
+++ b/source/slang/slang-ir-specialize.cpp
@@ -845,10 +845,31 @@ struct SpecializationContext
// the result of a `specialize` instruction or other
// operation that will yield such a table.
//
+ // Since we unify the frontend such that all LookupDeclRef node
+ // on a interface requirement will always be lowered to lookup
+ // witness, it creats an exception that IRThisTypeWitness, a non-concrete
+ // witness table, also need to be specialized. Otherwise, there is
+ // no logic in the later passes can handle it. However, we know for
+ // sure that the IRThisTypeWitness is only used to wrap an interface
+ // type, therefore, it must be only used to exact the interface requirement.
auto witnessTable = as<IRWitnessTable>(lookupInst->getWitnessTable());
+ IRInterfaceType* interfaceType = nullptr;
if (!witnessTable)
{
- return false;
+ if (auto thisTypeWitness = as<IRThisTypeWitness>(lookupInst->getWitnessTable()))
+ {
+ if (auto witnessTableType =
+ as<IRWitnessTableTypeBase>(thisTypeWitness->getDataType()))
+ {
+ if (!areAllOperandsFullySpecialized(witnessTableType))
+ return false;
+
+ interfaceType = as<IRInterfaceType>(witnessTableType->getConformanceType());
+ }
+ }
+
+ if (!interfaceType)
+ return false;
}
// Because we have a concrete witness table, we can
@@ -856,7 +877,26 @@ struct SpecializationContext
// the given interface requirement.
//
auto requirementKey = lookupInst->getRequirementKey();
- auto satisfyingVal = findWitnessVal(witnessTable, requirementKey);
+ IRInst* satisfyingVal = nullptr;
+
+ if (witnessTable)
+ satisfyingVal = findWitnessVal(witnessTable, requirementKey);
+ else
+ {
+ // If we are specializing ThisTypeWitness, the result of the specialization
+ // could be a WitnessTabelType, in such case, in order to not break the generality
+ // the specialziation (we don't specialize WitnessTableType here), we will wrap it
+ // into another ThisTypeWitnes and handle it later.
+ satisfyingVal = findInterfaceRequirement(interfaceType, requirementKey);
+ if (auto witnessTableType = as<IRWitnessTableType>(satisfyingVal))
+ {
+ auto newInterfaceType = as<IRInterfaceType>(witnessTableType->getConformanceType());
+ IRBuilder builderStorage(module);
+ IRBuilder* builder = &builderStorage;
+ builder->setInsertBefore(lookupInst);
+ satisfyingVal = builder->createThisTypeWitness(newInterfaceType);
+ }
+ }
// We expect to always find a satisfying value, but
// we will go ahead and code defensively so that
@@ -915,6 +955,7 @@ struct SpecializationContext
}
return nullptr;
}
+
template<typename TDict>
void _readSpecializationDictionaryImpl(TDict& dict, IRInst* dictInst)
{