From 109ee8aae399042fba6ea71e43e5ee2d441288dd Mon Sep 17 00:00:00 2001 From: Yong He Date: Fri, 24 Nov 2017 11:55:54 -0500 Subject: Fix substitution mechanism to remove special cases for global params (#297) Add a new function: `substituteSubstitutions(Substitutions * substHead, Substitutions subst, int * ioDiff)` This function substitutes the type arguments referenced in a linked list of substitutions headed at `substHead` using the substitutions specified by `subst`. If the linked list `substHead` does not contain `GlobalGenericParamSubstitution` entries, they will be added to the bottom (outter most) of the linked list. Note that this function should be called when `substHead` is known to be the head of substitution linked list because the existance of `GlobalGenericPaaramSubstitution` is detected assuming the linked lists starts at `substHead`. If a substitution that is not the head of a substitution linked list is passed in, duplicate `GlobalGenericParamSubstitution`s could be appended to the linked list. This means that this function should *not* be called in places like `GenericSubstitution::SubstitutionImpl()` for its outer substitutions, because `outer` is obviously not the head of the linked list. Instead, use this function to substitution the substitution lists of `DeclRef` etc. instead of calling `declRef.substitutions->SubstituteImpl()` where the head to the linked list is known as a member of that class. With this function, IRSpecContext::maybeCloneType() is simplified down to `originalType->Substitute(subst)` Updates `DeclRefBase::SubstituteImpl` and `DeclRefType::SubstituteImpl` to call `substituteSubstitutions` instead of making direct `substitutions->SubstituteImpl` call. Providing actual implementation of `GlobalGenericParamSubstitution::SubstituteImpl` instead of just returning `this` to deal with potential situations where a true substitution is needed. --- source/slang/ir.cpp | 19 +---------------- source/slang/syntax.cpp | 57 +++++++++++++++++++++++++++++++++++++++---------- source/slang/syntax.h | 17 +++++++++++++++ 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index 598445fcd..eb78d144e 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -3109,24 +3109,7 @@ namespace Slang RefPtr IRSpecContext::maybeCloneType(Type* originalType) { - auto rsType = originalType->GetCanonicalType()->Substitute(subst).As(); - if (auto declRefType = rsType.As()) - { - if (subst) - { - auto newSubst = cloneSubstitutions(this, subst); - insertSubstAtBottom(declRefType->declRef.substitutions, newSubst); - } - } - else if (auto funcType = rsType.As()) - { - RefPtr newFuncType = new FuncType(); - newFuncType->setSession(funcType->getSession()); - newFuncType->resultType = maybeCloneType(funcType->resultType); - for (auto paramType : funcType->paramTypes) - newFuncType->paramTypes.Add(maybeCloneType(paramType)); - } - return rsType; + return originalType->Substitute(subst).As(); } IRValue* IRSpecContext::maybeCloneValue(IRValue* originalValue) diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index 2c214a332..f8237359d 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -489,7 +489,7 @@ void Type::accept(IValVisitor* visitor, void* extra) bool restore = false; if (thisSubst && thisSubst->sourceType.Ptr() == dynamic_cast(this)) thisSubst->sourceType = nullptr; - auto newSubst = declRef.substitutions->SubstituteImpl(subst, ioDiff); + auto newSubst = substituteSubstitutions(declRef.substitutions, subst, ioDiff); if (restore) thisSubst->sourceType = oldSubstSrc; if (auto thisTypeSubst = newSubst.As()) @@ -1205,9 +1205,7 @@ void Type::accept(IValVisitor* visitor, void* extra) if (!this) return nullptr; int diff = 0; - RefPtr outerSubst; - if (outer) - outerSubst = outer->SubstituteImpl(subst, &diff); + RefPtr outerSubst = outer ? outer->SubstituteImpl(subst, &diff) : nullptr; RefPtr newSourceType; if (sourceType) newSourceType = sourceType->SubstituteImpl(subst, &diff); @@ -1244,9 +1242,36 @@ void Type::accept(IValVisitor* visitor, void* extra) return false; } - RefPtr GlobalGenericParamSubstitution::SubstituteImpl(Substitutions* /*subst*/, int* /*ioDiff*/) + RefPtr GlobalGenericParamSubstitution::SubstituteImpl(Substitutions* subst, int* ioDiff) { - // we will never replace values for this type of substitution + // if we find a GlobalGenericParamSubstitution in subst that references the same __generic_param decl + // return a copy of that GlobalGenericParamSubstitution + int diff = 0; + RefPtr outerSubst = outer ? outer->SubstituteImpl(subst, &diff) : nullptr; + while (subst) + { + if (auto gSubst = dynamic_cast(subst)) + { + if (gSubst->paramDecl == paramDecl) + { + // substitute only if we are really different + if (!gSubst->actualType->EqualsVal(actualType)) + { + RefPtr rs = new GlobalGenericParamSubstitution(*gSubst); + rs->outer = outerSubst; + return rs; + } + } + } + subst = subst->outer; + } + if (diff) + { + *ioDiff++; + RefPtr rs = new GlobalGenericParamSubstitution(*this); + rs->outer = outerSubst; + return rs; + } return this; } @@ -1322,8 +1347,9 @@ void Type::accept(IValVisitor* visitor, void* extra) } return false; } - void insertGlobalGenericSubstitutions(RefPtr & destSubst, Substitutions * srcSubst) + void insertGlobalGenericSubstitutions(RefPtr & destSubst, Substitutions * srcSubst, int * ioDiff) { + int diff = 0; while (srcSubst) { if (auto globalGenSubst = dynamic_cast(srcSubst)) @@ -1333,19 +1359,18 @@ void Type::accept(IValVisitor* visitor, void* extra) RefPtr cpyGlobalGenSubst = new GlobalGenericParamSubstitution(*globalGenSubst); cpyGlobalGenSubst->outer = nullptr; insertSubstAtBottom(destSubst, cpyGlobalGenSubst); + diff = 1; } } srcSubst = srcSubst->outer; } + *ioDiff += diff; } DeclRefBase DeclRefBase::SubstituteImpl(Substitutions* subst, int* ioDiff) { - insertGlobalGenericSubstitutions(substitutions, subst); - if (!substitutions) return *this; - int diff = 0; - RefPtr substSubst = substitutions->SubstituteImpl(subst, &diff); + RefPtr substSubst = substituteSubstitutions(substitutions, subst, &diff); if (!diff) return *this; @@ -1841,6 +1866,16 @@ void Type::accept(IValVisitor* visitor, void* extra) return nullptr; } + RefPtr substituteSubstitutions(RefPtr oldSubst, Substitutions * subst, int * ioDiff) + { + if (oldSubst) + oldSubst = oldSubst->SubstituteImpl(subst, ioDiff); + + RefPtr newSubst = oldSubst; + insertGlobalGenericSubstitutions(newSubst, subst, ioDiff); + return newSubst; + } + // FilteredTupleType String FilteredTupleType::ToString() diff --git a/source/slang/syntax.h b/source/slang/syntax.h index f3690d9ae..e6a010a4a 100644 --- a/source/slang/syntax.h +++ b/source/slang/syntax.h @@ -1162,6 +1162,23 @@ namespace Slang void removeSubstitution(DeclRefBase & declRef, RefPtr subst); bool hasGenericSubstitutions(RefPtr subst); RefPtr getGenericSubstitution(RefPtr subst); + + // This function substitutes the type arguments referenced in a linked list of substitutions + // which head is at `substHead` using the substitutions specified by `subst`. If the linked + // list `substHead` does not contain `GlobalGenericParamSubstitution` entries, they will be + // added to the bottom(outter most) of the linked list. + // Note that this function should be called when `substHead` is known to be the head of + // substitution linked list because the existance of `GlobalGenericPaaramSubstitution` is + // detected assuming the linked lists starts at `substHead`. If a substitution that is not + // the head of a substitution linked list is passed in, duplicate + // `GlobalGenericParamSubstitution`s could be appended to the linked list. + // This means that this function should * not* be called in places like + // `GenericSubstitution::SubstitutionImpl()` for its outer substitutions, because `outer` is + // obviously not the head of the linked list. Instead, use this function to substitution the + // substitution lists of `DeclRef` etc. to replace the call of + // `declRef.substitutions->SubstituteImpl()`, because the head to the linked list is known as a + // member of that class there. + RefPtr substituteSubstitutions(RefPtr oldSubst, Substitutions * subst, int * ioDiff); } // namespace Slang #endif \ No newline at end of file -- cgit v1.2.3