summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-type-layout.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-10-06 17:21:37 -0700
committerGitHub <noreply@github.com>2025-10-07 00:21:37 +0000
commit6af3381f47e3c22e1657c0e0064fa466e8bde0f6 (patch)
treebe187939b58bd6196fb0b2e5824d5d60f312b6b3 /source/slang/slang-type-layout.cpp
parentf4449d9376f0a5c32274fd812d135f3595159bae (diff)
Use symbol alias instead of wrapper synthesis to implement link-time types. (#8603)
This change achieves link-time type resolution with a different mechanism. For `extern struct Foo : IFoo = FooImpl;`, instead of synthesizing a wrapper type `Foo` that has a `FooImpl inner` field and dispatches all interface method calls to `inner.method()`, this PR completely removes this synthesis step, and instead just lower such `extern`/`export` types as `IRSymbolAlias` instructions that is just a reference to the type being wrapped. Then we extend the linker logic to clone the referenced symbol instead of the SymbolAlias insts itself during linking. By doing so, we greatly simply the logic need to support link-time types, and achieves higher robustness by not having to deal with many AST synthesis scenarios. Closes #8554. --------- Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'source/slang/slang-type-layout.cpp')
-rw-r--r--source/slang/slang-type-layout.cpp65
1 files changed, 57 insertions, 8 deletions
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index 0de6348bf..5bbcd2eb1 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -5191,9 +5191,11 @@ static TypeLayoutResult _createTypeLayout(TypeLayoutContext& context, Type* type
// If we are trying to get the layout of some extern type, do our best
// to look it up in other loaded modules and generate the type layout
// based on that.
- declRefType = context.lookupExternDeclRefType(declRefType);
- auto declRef = declRefType->getDeclRef();
+ auto resolvedType = context.lookupExternDeclRefType(declRefType);
+ if (resolvedType != type)
+ return _createTypeLayout(context, resolvedType);
+ auto declRef = declRefType->getDeclRef();
if (auto structDeclRef = declRef.as<StructDecl>())
{
@@ -5888,26 +5890,71 @@ GlobalGenericParamDecl* GenericParamTypeLayout::getGlobalGenericParamDecl()
return rsDeclRef.getDecl();
}
-DeclRefType* TypeLayoutContext::lookupExternDeclRefType(DeclRefType* declRefType)
+// Get the decl ref to the outer generic if the decl referenced by `declRef` is generic.
+DeclRef<GenericDecl> getOuterGeneric(DeclRef<Decl> declRef)
+{
+ if (auto directDeclRef = as<DirectDeclRef>(declRef.declRefBase))
+ {
+ if (as<GenericDecl>(directDeclRef->getDecl()))
+ return DeclRef<GenericDecl>(directDeclRef);
+ if (as<GenericDecl>(directDeclRef->getParent()->getDecl()))
+ return DeclRef<GenericDecl>(directDeclRef->getParent());
+ }
+ else if (auto genAppDeclRef = as<GenericAppDeclRef>(declRef.declRefBase))
+ {
+ return DeclRef<GenericDecl>(genAppDeclRef->getBase());
+ }
+ return DeclRef<GenericDecl>();
+}
+
+Type* TypeLayoutContext::lookupExternDeclRefType(DeclRefType* declRefType)
{
const auto declRef = declRefType->getDeclRef();
const auto decl = declRef.getDecl();
const auto isExtern =
decl->hasModifier<ExternAttribute>() || decl->hasModifier<ExternModifier>();
+ Type* resultType = declRefType;
if (isExtern)
{
if (!externTypeMap)
buildExternTypeMap();
const auto mangledName = getMangledName(targetReq->getLinkage()->getASTBuilder(), decl);
- externTypeMap->tryGetValue(mangledName, declRefType);
+ externTypeMap->tryGetValue(mangledName, resultType);
+ if (auto resolvedDeclRef = isDeclRefTypeOf<Decl>(resultType))
+ {
+ if (resolvedDeclRef != declRef)
+ {
+ // If declRef is a GenericApp, we should replace the generic base to
+ // resolveDeclRef's base.
+ if (auto originalGenericApp = as<GenericAppDeclRef>(declRef.declRefBase))
+ {
+ if (auto resolvedOuterGeneric = getOuterGeneric(resolvedDeclRef.getDecl()))
+ {
+ auto substGenericApp = astBuilder->getGenericAppDeclRef(
+ resolvedOuterGeneric,
+ originalGenericApp->getArgs());
+ resultType = DeclRefType::create(astBuilder, substGenericApp);
+ }
+ }
+ }
+ }
+ }
+
+ // If the type is an alias of another type, then we should create the type layout
+ // from the aliased type instead.
+ if (auto aggTypeDeclRef = isDeclRefTypeOf<AggTypeDecl>(resultType))
+ {
+ if (auto aliasedType = as<Type>(getAliasedType(astBuilder, aggTypeDeclRef)))
+ {
+ return aliasedType;
+ }
}
- return declRefType;
+ return resultType;
}
void TypeLayoutContext::buildExternTypeMap()
{
externTypeMap.emplace();
- const auto linkage = targetReq->getLinkage();
HashSet<String> externNames;
Dictionary<String, DeclRefType*> allTypes;
@@ -5916,6 +5963,8 @@ void TypeLayoutContext::buildExternTypeMap()
// We'll match them up later
auto processDecl = [&](auto&& go, Decl* decl) -> void
{
+ if (auto genericDecl = as<GenericDecl>(decl))
+ decl = genericDecl->inner;
const auto isExtern =
decl->hasModifier<ExternAttribute>() || decl->hasModifier<ExternModifier>();
@@ -5933,7 +5982,7 @@ void TypeLayoutContext::buildExternTypeMap()
}
}
- if (auto scopeDecl = as<ScopeDecl>(decl))
+ if (auto scopeDecl = isStaticScopeDecl(decl))
{
for (auto member : scopeDecl->getDirectMemberDecls())
{
@@ -5942,7 +5991,7 @@ void TypeLayoutContext::buildExternTypeMap()
}
};
- for (const auto& m : linkage->loadedModulesList)
+ for (const auto& m : programLayout->getProgram()->getModuleDependencies())
{
const auto& ast = m->getModuleDecl();
for (auto member : ast->getDirectMemberDecls())