summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-11-07 08:31:06 -0800
committerTim Foley <tfoley@nvidia.com>2017-11-07 10:40:04 -0800
commit9640df03814593d2f4b34c36bbec6756b1ed7fba (patch)
tree3a155f58f7afe94d5b5fba3c9f6bfe6d0db32110 /source
parent19c7c371aaef9dc537f6a6ed8cbfd77355f219ff (diff)
Handle "ThisType" subsitutions when specialization generics in the IR
The original code is handling the issue where a call site might be specializing a generic function, so it has a `DeclRef` that represents what it wants to specialize, but the callee is actually a different overload of the same generic function (e.g., a target-specific overload) and so we need to construct a set of substitutions that are equivalent (same arguments), but point to different `GenericDecl`s. That code was making some bad assumptions, though: 1. It assumed that the substitutions list would always start with a generic substitution (no longer true with `ThisTypeSubstitution`. 2. It assumed that only the top-most substitution would need to be translated. This assumption is probably safe for now, but it could break down if we ever introduced an ability for a type to be re-opened to introduce new (target-specific) overloads of its members. The new approach goes ahead and does a deep copy of the substitition list (but a shallow copy of the arguments), and only copies the generic substititions for now.
Diffstat (limited to 'source')
-rw-r--r--source/slang/ir.cpp80
1 files changed, 76 insertions, 4 deletions
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index d6a01a484..439bc7797 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -3866,6 +3866,78 @@ namespace Slang
return originalType->Substitute(subst).As<Type>();
}
+ // Given a list of substitutions, return the inner-most
+ // generic substitution in the list, or NULL if there
+ // are no generic substitutions.
+ RefPtr<GenericSubstitution> getInnermostGenericSubst(
+ Substitutions* inSubst)
+ {
+ auto subst = inSubst;
+ while( subst )
+ {
+ GenericSubstitution* genericSubst = dynamic_cast<GenericSubstitution*>(subst);
+ if(genericSubst)
+ return genericSubst;
+
+ subst = subst->outer;
+ }
+ return nullptr;
+ }
+
+ RefPtr<GenericDecl> getInnermostGenericDecl(
+ Decl* inDecl)
+ {
+ auto decl = inDecl;
+ while( decl )
+ {
+ GenericDecl* genericDecl = dynamic_cast<GenericDecl*>(decl);
+ if(genericDecl)
+ return genericDecl;
+
+ decl = decl->ParentDecl;
+ }
+ return nullptr;
+ }
+
+ // This function takes a list of substitutions that we'd
+ // like to apply, but which (1) might apply to a different
+ // declaration in cases where we have got target-specific
+ // overloads in the mix, and (2) might include some `ThisType`
+ // substitutions, which we don't care about in this context,
+ // and produces a new set of substitutiosn without these
+ // two issues.
+ RefPtr<Substitutions> cloneSubstitutionsForSpecialization(
+ IRSharedGenericSpecContext* sharedContext,
+ Substitutions* oldSubst,
+ Decl* newDecl)
+ {
+ // We will "peel back" layers of substitutions until
+ // we find our first generic subsitution.
+ auto oldGenericSubst = getInnermostGenericSubst(oldSubst);
+ if(!oldGenericSubst)
+ return nullptr;
+
+ // We will also peel back layers of declarations until
+ // we find our first generic decl.
+ auto newGenericDecl = getInnermostGenericDecl(newDecl);
+ if( !newGenericDecl )
+ {
+// SLANG_UNEXPECTED("generic subst without generic decl");
+ return nullptr;
+ }
+
+ RefPtr<GenericSubstitution> newSubst = new GenericSubstitution();
+ newSubst->genericDecl = newGenericDecl;
+ newSubst->args = oldGenericSubst->args;
+
+ newSubst->outer = cloneSubstitutionsForSpecialization(
+ sharedContext,
+ oldGenericSubst->outer,
+ newGenericDecl->ParentDecl);
+
+ return newSubst;
+ }
+
IRFunc* getSpecializedFunc(
IRSharedGenericSpecContext* sharedContext,
@@ -3897,10 +3969,10 @@ namespace Slang
// using a different overload of a target-specific function,
// so we need to create a dummy substitution here, to make
// sure it used the correct generic.
- RefPtr<GenericSubstitution> newSubst = new GenericSubstitution();
- newSubst->genericDecl = genericFunc->genericDecl;
- auto specDeclRefSubst = specDeclRef.substitutions.As<GenericSubstitution>();
- newSubst->args = specDeclRefSubst->args;
+ RefPtr<Substitutions> newSubst = cloneSubstitutionsForSpecialization(
+ sharedContext,
+ specDeclRef.substitutions,
+ genericFunc->genericDecl);
IRGenericSpecContext context;
context.shared = sharedContext;