summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-08-20 20:51:57 -0700
committerGitHub <noreply@github.com>2024-08-20 20:51:57 -0700
commitf9f6a28df40f418ddd0c8ff3b9cacccdb085e202 (patch)
treea6bafa63cee4f9bbcfe496de54af6e5727bb021e /source
parent03e1e17745920c8e3a7b6f4e3b1e64062589604a (diff)
Support dependent generic constraints. (#4870)
* Support dependent generic constraints. * Fix warning. * Update comment. * Fix. * Add a test case to verify fix of #3804. * Address review.
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-ast-decl.h6
-rw-r--r--source/slang/slang-check-constraint.cpp294
-rw-r--r--source/slang/slang-check-decl.cpp6
-rw-r--r--source/slang/slang-check-impl.h3
-rw-r--r--source/slang/slang-check-overload.cpp3
-rw-r--r--source/slang/slang-ir-clone.cpp31
-rw-r--r--source/slang/slang-lower-to-ir.cpp35
7 files changed, 260 insertions, 118 deletions
diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h
index 4df5d7b39..4ed38ef69 100644
--- a/source/slang/slang-ast-decl.h
+++ b/source/slang/slang-ast-decl.h
@@ -550,6 +550,9 @@ class GenericDecl : public ContainerDecl
class GenericTypeParamDeclBase : public SimpleTypeDecl
{
SLANG_AST_CLASS(GenericTypeParamDeclBase)
+
+ // The index of the generic parameter.
+ Index parameterIndex = -1;
};
class GenericTypeParamDecl : public GenericTypeParamDeclBase
@@ -587,6 +590,9 @@ class GenericTypeConstraintDecl : public TypeConstraintDecl
class GenericValueParamDecl : public VarDeclBase
{
SLANG_AST_CLASS(GenericValueParamDecl)
+
+ // The index of the generic parameter.
+ Index parameterIndex = 0;
};
// An empty declaration (which might still have modifiers attached).
diff --git a/source/slang/slang-check-constraint.cpp b/source/slang/slang-check-constraint.cpp
index 0f6da156d..afcde8a5b 100644
--- a/source/slang/slang-check-constraint.cpp
+++ b/source/slang/slang-check-constraint.cpp
@@ -57,6 +57,7 @@
namespace Slang
{
Type* SemanticsVisitor::TryJoinVectorAndScalarType(
+ ConstraintSystem* constraints,
VectorExpressionType* vectorType,
BasicExpressionType* scalarType)
{
@@ -65,6 +66,7 @@ namespace Slang
// That is, the join of a vector and a scalar type is
// a vector type with a joined element type.
auto joinElementType = TryJoinTypes(
+ constraints,
vectorType->getElementType(),
scalarType);
if(!joinElementType)
@@ -76,6 +78,7 @@ namespace Slang
}
Type* SemanticsVisitor::_tryJoinTypeWithInterface(
+ ConstraintSystem* constraints,
Type* type,
Type* interfaceType)
{
@@ -158,6 +161,31 @@ namespace Slang
return bestType;
}
+ // If `interfaceType` represents some generic interface type, such as `IFoo<T>`, and `type` conforms to
+ // some `IFoo<X>`, then we should attempt to unify the them to discover constraints for
+ // `T`.
+ if (auto interfaceDeclRef = isDeclRefTypeOf<InterfaceDecl>(interfaceType))
+ {
+ if (as<GenericAppDeclRef>(interfaceDeclRef.declRefBase))
+ {
+ auto inheritanceInfo = getShared()->getInheritanceInfo(type);
+ for (auto facet : inheritanceInfo.facets)
+ {
+ if (facet->origin.declRef.getDecl() == interfaceDeclRef.getDecl())
+ {
+ auto unificationResult = TryUnifyTypes(
+ *constraints,
+ ValUnificationContext(),
+ QualType(facet->getType()),
+ interfaceType);
+
+ if (unificationResult)
+ return type;
+ }
+ }
+ }
+ }
+
// For all other cases, we will just bail out for now.
//
// TODO: In the future we should build some kind of side data structure
@@ -174,6 +202,7 @@ namespace Slang
}
Type* SemanticsVisitor::TryJoinTypes(
+ ConstraintSystem* constraints,
QualType left,
QualType right)
{
@@ -201,7 +230,7 @@ namespace Slang
// We can also join a vector and a scalar
if(auto rightVector = as<VectorExpressionType>(right))
{
- return TryJoinVectorAndScalarType(rightVector, leftBasic);
+ return TryJoinVectorAndScalarType(constraints, rightVector, leftBasic);
}
}
@@ -217,6 +246,7 @@ namespace Slang
// Try to join the element types
auto joinElementType = TryJoinTypes(
+ constraints,
QualType(leftVector->getElementType(), left.isLeftValue),
QualType(rightVector->getElementType(), right.isLeftValue));
if(!joinElementType)
@@ -230,7 +260,7 @@ namespace Slang
// We can also join a vector and a scalar
if(auto rightBasic = as<BasicExpressionType>(right))
{
- return TryJoinVectorAndScalarType(leftVector, rightBasic);
+ return TryJoinVectorAndScalarType(constraints, leftVector, rightBasic);
}
}
@@ -240,7 +270,7 @@ namespace Slang
if( auto leftInterfaceRef = leftDeclRefType->getDeclRef().as<InterfaceDecl>() )
{
//
- return _tryJoinTypeWithInterface(right, left);
+ return _tryJoinTypeWithInterface(constraints, right, left);
}
}
if(auto rightDeclRefType = as<DeclRefType>(right))
@@ -248,7 +278,7 @@ namespace Slang
if( auto rightInterfaceRef = rightDeclRefType->getDeclRef().as<InterfaceDecl>() )
{
//
- return _tryJoinTypeWithInterface(left, right);
+ return _tryJoinTypeWithInterface(constraints, left, right);
}
}
@@ -263,6 +293,7 @@ namespace Slang
for (Index i = 0; i < leftTypePack->getTypeCount(); ++i)
{
auto joinedType = TryJoinTypes(
+ constraints,
QualType(leftTypePack->getElementType(i), left.isLeftValue),
QualType(rightTypePack->getElementType(i), right.isLeftValue));
if(!joinedType)
@@ -285,6 +316,8 @@ namespace Slang
ArrayView<Val*> knownGenericArgs,
ConversionCost& outBaseCost)
{
+ ensureDecl(genericDeclRef.getDecl(), DeclCheckState::ReadyForLookup);
+
outBaseCost = kConversionCost_None;
// For now the "solver" is going to be ridiculously simplistic.
@@ -310,7 +343,7 @@ namespace Slang
return DeclRef<Decl>();
}
- // Once have built up the full list of constraints we are trying to satisfy,
+ // Once have built up the initial list of constraints we are trying to satisfy,
// we will attempt to solve for each parameter in a way that satisfies all
// the constraints that apply to that parameter.
//
@@ -321,7 +354,7 @@ namespace Slang
// solution for how to assign the parameters in a way that satisfies all
// the constraints.
//
- List<Val*> args;
+ ShortList<Val*> args;
// If the context is such that some of the arguments are already specified
// or known, we need to go ahead and use those arguments direclty (whether
@@ -337,38 +370,44 @@ namespace Slang
}
}
- // We will then iterate over the explicit parameters of the generic
- // and try to solve for each.
- //
- Count paramCounter = 0;
- for (auto m : getMembers(m_astBuilder, genericDeclRef))
+ // The state of currently solved arguments.
+ struct SolvedArg
+ {
+ IntVal* val = nullptr;
+ bool isOptional = true;
+ ShortList<QualType, 8> types;
+ };
+ ShortList<SolvedArg> solvedArgs;
+
+ // We will then iterate over the constraints trying to solve all generic parameters.
+ // Note that we do not use ranged for here, because processing one constraint may lead to
+ // new constraints being discovered.
+ for (Index constraintIndex = 0; constraintIndex < system->constraints.getCount(); constraintIndex++)
{
- if (auto typeParam = m.as<GenericTypeParamDeclBase>())
+ // Note: it is important to keep a copy of the constraint here instead of
+ // using a reference, because the constraint list may be modified during the
+ // loop as we discover new constraints.
+ //
+ auto c = system->constraints[constraintIndex];
+ if (auto typeParam = as<GenericTypeParamDeclBase>(c.decl))
{
- // If the parameter is a type pack, then we may have
- // constraints that apply to invidual elements of the pack.
- // We will need to handle the type pack case slightly differently.
- //
- bool isPack = as<GenericTypePackParamDecl>(typeParam) != nullptr;
-
+ SLANG_ASSERT(typeParam->parameterIndex != -1);
// If the parameter is one where we already know
// the argument value to use, we don't bother with
// trying to solve for it, and treat any constraints
// on such a parameter as implicitly solved-for.
//
- Index paramIndex = paramCounter++;
- if (paramIndex < knownGenericArgCount)
+ if (typeParam->parameterIndex < knownGenericArgCount)
{
- for (auto& c : system->constraints)
- {
- if (c.decl != typeParam.getDecl())
- continue;
-
- c.satisfied = true;
- }
+ system->constraints[constraintIndex].satisfied = true;
continue;
}
+ // If the parameter is a type pack, then we may have
+ // constraints that apply to invidual elements of the pack.
+ // We will need to handle the type pack case slightly differently.
+ //
+ bool isPack = as<GenericTypePackParamDecl>(typeParam) != nullptr;
// We will use a temporary list to hold the resolved types
// for this generic parameter.
@@ -376,50 +415,128 @@ namespace Slang
// in the list. For type pack parameters, there can be one type
// for each element in the pack.
//
- ShortList<QualType> types;
+ if (solvedArgs.getCount() <= typeParam->parameterIndex)
+ {
+ solvedArgs.setCount(typeParam->parameterIndex + 1);
+ }
+ auto& types = solvedArgs[typeParam->parameterIndex].types;
if (!isPack)
types.setCount(1);
- bool typeConstraintOptional = true;
+ bool& typeConstraintOptional = solvedArgs[typeParam->parameterIndex].isOptional;
- for (auto& c : system->constraints)
+ QualType* ptype = nullptr;
+ if (isPack)
{
- if (c.decl != typeParam.getDecl())
- continue;
- QualType* ptype = nullptr;
- if (isPack)
- {
- types.setCount(Math::Max(types.getCount(), c.indexInPack + 1));
- ptype = &types[c.indexInPack];
- }
- else
- ptype = &types[0];
- QualType& type = *ptype;
+ types.setCount(Math::Max(types.getCount(), c.indexInPack + 1));
+ ptype = &types[c.indexInPack];
+ }
+ else
+ ptype = &types[0];
+ QualType& type = *ptype;
- auto cType = QualType(as<Type>(c.val), c.isUsedAsLValue);
- SLANG_RELEASE_ASSERT(cType);
+ auto cType = QualType(as<Type>(c.val), c.isUsedAsLValue);
+ SLANG_RELEASE_ASSERT(cType);
- if (!type || (typeConstraintOptional && !c.isOptional))
+ if (!type || (typeConstraintOptional && !c.isOptional))
+ {
+ type = cType;
+ typeConstraintOptional = c.isOptional;
+ }
+ else if (!typeConstraintOptional)
+ {
+ // If the type parameter is already constrained to a known type,
+ // we need to make sure our resolved type can satisfy both constraints.
+ // We do so by updating the resolved type to be the "join" of the current
+ // solution and the type in the new constraint. If such join cannot be found,
+ // it means it is not possible to have a compatible solution that meets all
+ // constraints and we should fail.
+ //
+ // Another detail here is that during type joining, we may discover
+ // new constraints from the base types of the types being joined.
+ // We will pass the constraint system to `TryJoinTypes` which can
+ // add new constraints to the system, and we will process the new constraints
+ // in the next iteration.
+ //
+ auto joinType = TryJoinTypes(system, type, cType);
+ if (!joinType)
{
- type = cType;
- typeConstraintOptional = c.isOptional;
+ // failure!
+ return DeclRef<Decl>();
}
- else if (!typeConstraintOptional)
+ type = QualType(joinType, type.isLeftValue || cType.isLeftValue);
+ }
+
+ c.satisfied = true;
+ }
+ else if (auto valParam = as<GenericValueParamDecl>(c.decl))
+ {
+ SLANG_ASSERT(valParam->parameterIndex != -1);
+
+ // If the parameter is one where we already know
+ // the argument value to use, we don't bother with
+ // trying to solve for it, and treat any constraints
+ // on such a parameter as implicitly solved-for.
+ //
+ if (valParam->parameterIndex < knownGenericArgCount)
+ {
+ system->constraints[constraintIndex].satisfied = true;
+ continue;
+ }
+
+ if (solvedArgs.getCount() <= valParam->parameterIndex)
+ solvedArgs.setCount(valParam->parameterIndex + 1);
+ IntVal*& val = solvedArgs[valParam->parameterIndex].val;
+ bool& valOptional = solvedArgs[valParam->parameterIndex].isOptional;
+
+ auto cVal = as<IntVal>(c.val);
+ SLANG_RELEASE_ASSERT(cVal);
+
+ if (!val || (valOptional && !c.isOptional))
+ {
+ val = cVal;
+ valOptional = c.isOptional;
+ }
+ else
+ {
+ if(!valOptional && !val->equals(cVal))
{
- auto joinType = TryJoinTypes(type, cType);
- if (!joinType)
- {
- // failure!
- return DeclRef<Decl>();
- }
- type = QualType(joinType, type.isLeftValue || cType.isLeftValue);
+ // failure!
+ return DeclRef<Decl>();
}
-
- c.satisfied = true;
}
+ c.satisfied = true;
+ }
+ system->constraints[constraintIndex].satisfied = c.satisfied;
+ }
+
+ // After we processed all constraints, `solvedTypes` and `solvedVals`
+ // should have been filled with the resolved types and values for the
+ // generic parameters. We can now verify if they are complete and consolidate
+ // them into final argument list.
+ for (auto member : genericDeclRef.getDecl()->members)
+ {
+ if (auto typeParam = as<GenericTypeParamDeclBase>(member))
+ {
+ SLANG_ASSERT(typeParam->parameterIndex != -1);
+
+ if (typeParam->parameterIndex < knownGenericArgCount)
+ continue;
+ bool isPack = as<GenericTypePackParamDecl>(typeParam) != nullptr;
+ if (typeParam->parameterIndex >= solvedArgs.getCount())
+ {
+ // If the parameter is not a type pack and we don't have a
+ // resolved type for it, we should fail.
+ if (!isPack)
+ return DeclRef<Decl>();
+ // If the parameter is a type pack, we should add an empty
+ // type list to solvedTypes.
+ solvedArgs.setCount(typeParam->parameterIndex + 1);
+ }
+ auto& types = solvedArgs[typeParam->parameterIndex].types;
// Fail if any of the resolved type element is empty.
- for (auto t: types)
+ for (auto t : types)
{
if (!t)
return DeclRef<Decl>();
@@ -427,7 +544,9 @@ namespace Slang
if (!isPack)
{
// If the generic parameter is not a pack, we can simply add the first type.
- SLANG_ASSERT(types.getCount() == 1);
+ if (types.getCount() != 1)
+ return DeclRef<Decl>();
+
args.add(types[0]);
}
else
@@ -453,56 +572,17 @@ namespace Slang
}
}
}
- else if (auto valParam = m.as<GenericValueParamDecl>())
+ else if (auto valParam = as<GenericValueParamDecl>(member))
{
- // If the parameter is one where we already know
- // the argument value to use, we don't bother with
- // trying to solve for it, and treat any constraints
- // on such a parameter as implicitly solved-for.
- //
- Index paramIndex = paramCounter++;
- if (paramIndex < knownGenericArgCount)
- {
- for (auto& c : system->constraints)
- {
- if (c.decl != typeParam.getDecl())
- continue;
+ SLANG_ASSERT(valParam->parameterIndex != -1);
- c.satisfied = true;
- }
+ if (valParam->parameterIndex < knownGenericArgCount)
continue;
- }
-
- // TODO(tfoley): maybe support more than integers some day?
- // TODO(tfoley): figure out how this needs to interact with
- // compile-time integers that aren't just constants...
- IntVal* val = nullptr;
- bool valOptional = true;
- for (auto& c : system->constraints)
- {
- if (c.decl != valParam.getDecl())
- continue;
-
- auto cVal = as<IntVal>(c.val);
- SLANG_RELEASE_ASSERT(cVal);
- if (!val || (valOptional && !c.isOptional))
- {
- val = cVal;
- valOptional = c.isOptional;
- }
- else
- {
- if(!valOptional && !val->equals(cVal))
- {
- // failure!
- return DeclRef<Decl>();
- }
- }
-
- c.satisfied = true;
- }
+ if (valParam->parameterIndex >= solvedArgs.getCount())
+ return DeclRef<Decl>();
+ auto val = solvedArgs[valParam->parameterIndex].val;
if (!val)
{
// failure!
@@ -510,10 +590,6 @@ namespace Slang
}
args.add(val);
}
- else
- {
- // ignore anything that isn't a generic parameter
- }
}
// After we've solved for the explicit arguments, we need to
@@ -537,7 +613,7 @@ namespace Slang
for( auto constraintDecl : genericDeclRef.getDecl()->getMembersOfType<GenericTypeConstraintDecl>() )
{
DeclRef<GenericTypeConstraintDecl> constraintDeclRef = m_astBuilder->getGenericAppDeclRef(
- genericDeclRef, args.getArrayView(), constraintDecl).as<GenericTypeConstraintDecl>();
+ genericDeclRef, args.getArrayView().arrayView, constraintDecl).as<GenericTypeConstraintDecl>();
// Extract the (substituted) sub- and super-type from the constraint.
auto sub = getSub(m_astBuilder, constraintDeclRef);
@@ -597,7 +673,7 @@ namespace Slang
}
}
- return m_astBuilder->getGenericAppDeclRef(genericDeclRef, args.getArrayView());
+ return m_astBuilder->getGenericAppDeclRef(genericDeclRef, args.getArrayView().arrayView);
}
bool SemanticsVisitor::TryUnifyVals(
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 58fbb4689..c27e0c6f0 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -2520,18 +2520,22 @@ namespace Slang
// and likely a crash.
//
// Accessing the members via index side steps the issue.
+
+ Index parameterIndex = 0;
const auto& members = genericDecl->members;
for (Index i = 0; i < members.getCount(); ++i)
{
Decl* m = members[i];
- if (auto typeParam = as<GenericTypeParamDecl>(m))
+ if (auto typeParam = as<GenericTypeParamDeclBase>(m))
{
ensureDecl(typeParam, DeclCheckState::ReadyForReference);
+ typeParam->parameterIndex = parameterIndex++;
}
else if (auto valParam = as<GenericValueParamDecl>(m))
{
ensureDecl(valParam, DeclCheckState::ReadyForReference);
+ valParam->parameterIndex = parameterIndex++;
}
else if (auto constraint = as<GenericTypeConstraintDecl>(m))
{
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index fea81f68c..82ac8de59 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -2102,6 +2102,7 @@ namespace Slang
};
Type* TryJoinVectorAndScalarType(
+ ConstraintSystem* constraints,
VectorExpressionType* vectorType,
BasicExpressionType* scalarType);
@@ -2196,11 +2197,13 @@ namespace Slang
ConversionCost getConversionCost(Type* toType, QualType fromType);
Type* _tryJoinTypeWithInterface(
+ ConstraintSystem* constraints,
Type* type,
Type* interfaceType);
// Try to compute the "join" between two types
Type* TryJoinTypes(
+ ConstraintSystem* constraints,
QualType left,
QualType right);
diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp
index 29cb74c23..743d518af 100644
--- a/source/slang/slang-check-overload.cpp
+++ b/source/slang/slang-check-overload.cpp
@@ -883,7 +883,8 @@ namespace Slang
for( auto constraintDecl : genericDeclRef.getDecl()->getMembersOfType<GenericTypeConstraintDecl>() )
{
- DeclRef<GenericTypeConstraintDecl> constraintDeclRef = m_astBuilder->getGenericAppDeclRef(genericDeclRef, substArgs, constraintDecl).as<GenericTypeConstraintDecl>();
+ DeclRef<GenericTypeConstraintDecl> constraintDeclRef = m_astBuilder->getGenericAppDeclRef(
+ genericDeclRef, newArgs.getArrayView(), constraintDecl).as<GenericTypeConstraintDecl>();
auto sub = getSub(m_astBuilder, constraintDeclRef);
auto sup = getSup(m_astBuilder, constraintDeclRef);
diff --git a/source/slang/slang-ir-clone.cpp b/source/slang/slang-ir-clone.cpp
index 43b60d6ed..e2297bcb2 100644
--- a/source/slang/slang-ir-clone.cpp
+++ b/source/slang/slang-ir-clone.cpp
@@ -152,6 +152,7 @@ static void _cloneInstDecorationsAndChildren(
// require the second phase.
//
List<IRCloningOldNewPair> pairs;
+ ShortList<IRCloningOldNewPair> paramPairs;
for( auto oldChild : oldInst->getDecorationsAndChildren() )
{
@@ -172,7 +173,19 @@ static void _cloneInstDecorationsAndChildren(
// on the child, and register it in our map from
// old to new values.
//
- auto newChild = cloneInstAndOperands(env, builder, oldChild);
+ IRInst* newChild = nullptr;
+ if (oldChild->getOp() == kIROp_Param)
+ {
+ // For parameters, don't clone its type just yet, since
+ // the type might be a forward reference to things defined
+ // later in the block that we haven't cloned and registered yet.
+ newChild = builder->emitParam(nullptr);
+ paramPairs.add({ oldChild, newChild });
+ }
+ else
+ {
+ newChild = cloneInstAndOperands(env, builder, oldChild);
+ }
env->mapOldValToNew.add(oldChild, newChild);
// If and only if the old child had decorations
@@ -181,10 +194,7 @@ static void _cloneInstDecorationsAndChildren(
//
if( oldChild->getFirstDecorationOrChild() )
{
- IRCloningOldNewPair pair;
- pair.oldInst = oldChild;
- pair.newInst = newChild;
- pairs.add(pair);
+ pairs.add({ oldChild, newChild });
}
}
@@ -200,6 +210,17 @@ static void _cloneInstDecorationsAndChildren(
_cloneInstDecorationsAndChildren(env, module, oldChild, newChild);
}
+
+ // For params, we can now clone their types since we have done cloning the entire block.
+ for (auto pair : paramPairs)
+ {
+ auto oldParam = pair.oldInst;
+ auto newParam = pair.newInst;
+
+ auto oldType = oldParam->getFullType();
+ auto newType = (IRType*)findCloneForOperand(env, oldType);
+ newParam->setFullType(newType);
+ }
}
// The public version of `cloneInstDecorationsAndChildren` is then
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 44c62e858..2828752a0 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -9304,15 +9304,46 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
auto typeGeneric = typeBuilder.emitGeneric();
typeGeneric->setFullType(typeBuilder.getGenericKind());
typeBuilder.setInsertInto(typeGeneric);
- typeBuilder.emitBlock();
+ auto block = typeBuilder.emitBlock();
+ struct ParamCloneInfo
+ {
+ IRParam* originalParam;
+ IRParam* clonedParam;
+ };
+ ShortList<ParamCloneInfo> paramCloneInfos;
+
for (auto child : parentGeneric->getFirstBlock()->getChildren())
{
if (valuesToClone.contains(child))
{
- cloneInst(&cloneEnv, &typeBuilder, child);
+ if (child->getOp() == kIROp_Param)
+ {
+ // Params may have forward references in its type and
+ // decorations, so we just create a placeholder for it
+ // in this first pass.
+ IRParam* clonedParam = typeBuilder.emitParam(nullptr);
+ cloneEnv.mapOldValToNew[child] = clonedParam;
+ paramCloneInfos.add({ (IRParam*)child, clonedParam });
+ }
+ else
+ {
+ cloneInst(&cloneEnv, &typeBuilder, child);
+ }
}
}
+
+ // In a second pass, clone the types and decorations on params which may
+ // contain forward references.
+ for (auto param : paramCloneInfos)
+ {
+ typeBuilder.setInsertInto(param.clonedParam);
+ param.clonedParam->setFullType((IRType*)cloneInst(&cloneEnv, &typeBuilder, param.originalParam->getFullType()));
+ cloneInstDecorationsAndChildren(&cloneEnv, typeBuilder.getModule(), param.originalParam, param.clonedParam);
+ }
+
+ typeBuilder.setInsertInto(block);
+
IRInst* clonedReturnType = nullptr;
cloneEnv.mapOldValToNew.tryGetValue(returnType, clonedReturnType);
if (clonedReturnType)