diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-11-07 08:31:06 -0800 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-11-07 10:40:04 -0800 |
| commit | 9640df03814593d2f4b34c36bbec6756b1ed7fba (patch) | |
| tree | 3a155f58f7afe94d5b5fba3c9f6bfe6d0db32110 /source/slang/ir.cpp | |
| parent | 19c7c371aaef9dc537f6a6ed8cbfd77355f219ff (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/slang/ir.cpp')
| -rw-r--r-- | source/slang/ir.cpp | 80 |
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; |
