From 21c663605330d629e9022314a4720b86b017f295 Mon Sep 17 00:00:00 2001 From: kaizhangNV <149626564+kaizhangNV@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:06:44 -0500 Subject: 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. --- source/slang/slang-ir-specialize.cpp | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) (limited to 'source/slang/slang-ir-specialize.cpp') 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(lookupInst->getWitnessTable()); + IRInterfaceType* interfaceType = nullptr; if (!witnessTable) { - return false; + if (auto thisTypeWitness = as(lookupInst->getWitnessTable())) + { + if (auto witnessTableType = + as(thisTypeWitness->getDataType())) + { + if (!areAllOperandsFullySpecialized(witnessTableType)) + return false; + + interfaceType = as(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(satisfyingVal)) + { + auto newInterfaceType = as(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 void _readSpecializationDictionaryImpl(TDict& dict, IRInst* dictInst) { -- cgit v1.2.3