summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-specialize.cpp
diff options
context:
space:
mode:
authorkaizhangNV <149626564+kaizhangNV@users.noreply.github.com>2025-09-23 11:06:44 -0500
committerGitHub <noreply@github.com>2025-09-23 11:06:44 -0500
commit21c663605330d629e9022314a4720b86b017f295 (patch)
treefcbfadeddd8f1d68f1034f89288c960b6ba7294a /source/slang/slang-ir-specialize.cpp
parent7740f7905fdebebdbe22011787d432b385f4cd9d (diff)
Lookup refactor (#8467)
Close #8201. This PR unify the lowering logic for LookupDeclRef of an interface requirement. We will always lower this AST node to a LookupWitness IR. The key of this IR is the special witnessTableType `ThisTypeWitness`, this witness Table is simply a wrapper for an interface type. Our current specialization pass doesn't handle this kind of LookupWitness IR at all, so we will also add the specialization of this_type IR as well.
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)
{