summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/core/text-io.cpp30
-rw-r--r--source/slang/check.cpp281
-rw-r--r--source/slang/decl-defs.h4
-rw-r--r--source/slang/diagnostic-defs.h79
-rw-r--r--source/slang/emit.cpp12
-rw-r--r--source/slang/ir-insts.h3
-rw-r--r--source/slang/ir.cpp79
-rw-r--r--source/slang/lookup.cpp24
-rw-r--r--source/slang/lower-to-ir.cpp57
-rw-r--r--source/slang/lower.cpp37
-rw-r--r--source/slang/mangle.cpp2
-rw-r--r--source/slang/parser.cpp65
-rw-r--r--source/slang/slang.cpp1
-rw-r--r--source/slang/slang.natvis62
-rw-r--r--source/slang/syntax-base-defs.h54
-rw-r--r--source/slang/syntax.cpp312
-rw-r--r--source/slang/syntax.h6
-rw-r--r--source/slang/type-defs.h3
-rw-r--r--tests/compute/assoctype-complex.slang50
-rw-r--r--tests/compute/assoctype-complex.slang.expected.txt4
-rw-r--r--tests/compute/assoctype-simple.slang35
-rw-r--r--tests/compute/assoctype-simple.slang.expected.txt4
-rw-r--r--tests/compute/explicit-this-expr.slang2
-rw-r--r--tests/compute/generics-constructor.slang17
-rw-r--r--tests/compute/generics-constructor.slang.expected.txt4
-rw-r--r--tests/compute/implicit-this-expr.slang2
-rw-r--r--tools/render-test/render-d3d11.cpp3
-rw-r--r--tools/slang-test/main.cpp5
28 files changed, 942 insertions, 295 deletions
diff --git a/source/core/text-io.cpp b/source/core/text-io.cpp
index ec41b8d7d..d0d0a3cc6 100644
--- a/source/core/text-io.cpp
+++ b/source/core/text-io.cpp
@@ -194,6 +194,17 @@ namespace Slang
this->encoding = determinedEncoding;
}
+ bool HasNullBytes(char * str, int len)
+ {
+ bool hasSeenNull = false;
+ for (int i = 0; i < len - 1; i++)
+ if (str[i] == 0)
+ hasSeenNull = true;
+ else if (hasSeenNull)
+ return true;
+ return false;
+ }
+
Encoding * StreamReader::DetermineEncoding()
{
if (buffer.Count() >= 3 && (unsigned char)(buffer[0]) == 0xEF && (unsigned char)(buffer[1]) == 0xBB && (unsigned char)(buffer[2]) == 0xBF)
@@ -213,19 +224,11 @@ namespace Slang
}
else
{
-#ifdef _WIN32
- int flag = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_ASCII16;
- int rs = IsTextUnicode(buffer.Buffer(), (int) buffer.Count(), &flag);
- if (rs)
- {
- if (flag & (IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS))
- return Encoding::UTF16;
- else if (flag & (IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_STATISTICS))
- return Encoding::UTF16Reversed;
- else if (flag & IS_TEXT_UNICODE_ASCII16)
- return Encoding::UTF8;
- }
-#endif
+ // find null bytes
+ if (HasNullBytes(buffer.Buffer(), (int)buffer.Count()))
+ {
+ return Encoding::UTF16;
+ }
return Encoding::UTF8;
}
}
@@ -233,6 +236,7 @@ namespace Slang
void StreamReader::ReadBuffer()
{
buffer.SetSize(4096);
+ memset(buffer.Buffer(), 0, buffer.Count() * sizeof(buffer[0]));
auto len = stream->Read(buffer.Buffer(), buffer.Count());
buffer.SetSize((int)len);
ptr = 0;
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 65b2295cc..ed2ed4a1b 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -140,6 +140,15 @@ namespace Slang
return result;
}
+ RefPtr<DeclRefType> getExprDeclRefType(Expr * expr)
+ {
+ if (auto typetype = expr->type->As<TypeType>())
+ return typetype->type.As<DeclRefType>();
+ else
+ return expr->type->As<DeclRefType>();
+ }
+
+
RefPtr<Expr> ConstructDeclRefExpr(
DeclRef<Decl> declRef,
RefPtr<Expr> baseExpr,
@@ -147,26 +156,63 @@ namespace Slang
{
if (baseExpr)
{
+ RefPtr<Expr> expr;
+ DeclRef<Decl> *declRefOut;
if (baseExpr->type->As<TypeType>())
{
- auto expr = new StaticMemberExpr();
- expr->loc = loc;
- expr->BaseExpression = baseExpr;
- expr->name = declRef.GetName();
- expr->type = GetTypeForDeclRef(declRef);
- expr->declRef = declRef;
- return expr;
+ auto sexpr = new StaticMemberExpr();
+ sexpr->loc = loc;
+ sexpr->BaseExpression = baseExpr;
+ sexpr->name = declRef.GetName();
+ sexpr->declRef = declRef;
+ declRefOut = &sexpr->declRef;
+ expr = sexpr;
}
else
{
- auto expr = new MemberExpr();
- expr->loc = loc;
- expr->BaseExpression = baseExpr;
- expr->name = declRef.GetName();
- expr->type = GetTypeForDeclRef(declRef);
- expr->declRef = declRef;
+ auto sexpr = new MemberExpr();
+ sexpr->loc = loc;
+ sexpr->BaseExpression = baseExpr;
+ sexpr->name = declRef.GetName();
+ sexpr->declRef = declRef;
+ declRefOut = &sexpr->declRef;
+ expr = sexpr;
+ }
+
+ RefPtr<ThisTypeSubstitution> baseThisTypeSubst;
+ if (auto baseDeclRefExpr = baseExpr->As<DeclRefExpr>())
+ {
+ baseThisTypeSubst = getThisTypeSubst(baseDeclRefExpr->declRef, false);
+ if (auto baseAssocType = baseDeclRefExpr->declRef.As<AssocTypeDecl>())
+ {
+ baseThisTypeSubst = new ThisTypeSubstitution();
+ baseThisTypeSubst->sourceType = baseDeclRefExpr->type.type;
+ if (auto typetype = baseThisTypeSubst->sourceType.As<TypeType>())
+ baseThisTypeSubst->sourceType = typetype->type;
+ }
+ }
+ if (auto assocTypeDecl = declRef.As<AssocTypeDecl>())
+ {
+ auto newThisTypeSubst = new ThisTypeSubstitution();
+ if (baseThisTypeSubst)
+ newThisTypeSubst->sourceType = baseThisTypeSubst->sourceType;
+ expr->type = GetTypeForDeclRef(DeclRef<AssocTypeDecl>(assocTypeDecl.getDecl(), newThisTypeSubst));
+ auto declOutThisTypeSubst = getNewThisTypeSubst(*declRefOut);
+ if (baseThisTypeSubst)
+ declOutThisTypeSubst->sourceType = baseThisTypeSubst->sourceType;
return expr;
}
+
+ // propagate "this-type" substitutions
+ if (baseThisTypeSubst)
+ {
+ if (auto declRefExpr = expr.As<DeclRefExpr>())
+ {
+ getNewThisTypeSubst(declRefExpr->declRef)->sourceType = baseThisTypeSubst->sourceType;
+ }
+ }
+ expr->type = GetTypeForDeclRef(declRef);
+ return expr;
}
else
{
@@ -174,6 +220,21 @@ namespace Slang
expr->loc = loc;
expr->name = declRef.GetName();
expr->type = GetTypeForDeclRef(declRef);
+ if (auto exprDeclRefType = getExprDeclRefType(expr))
+ {
+ if (auto genParmDecl = exprDeclRefType->declRef.As<GenericTypeParamDecl>())
+ {
+ // if this is a reference to generic type param, insert a this-type substitution
+ auto exprType = GetTypeForDeclRef(declRef);
+ auto thisSubst = new ThisTypeSubstitution();
+ if (auto typetype = exprType.type.As<TypeType>())
+ thisSubst->sourceType = typetype->type;
+ else
+ thisSubst->sourceType = exprType.type;
+ thisSubst->outer = declRef.substitutions;
+ declRef.substitutions = thisSubst;
+ }
+ }
expr->declRef = declRef;
return expr;
}
@@ -401,7 +462,7 @@ namespace Slang
DeclRef<GenericDecl> genericDeclRef,
List<RefPtr<Expr>> const& args)
{
- RefPtr<Substitutions> subst = new Substitutions();
+ RefPtr<GenericSubstitution> subst = new GenericSubstitution();
subst->genericDecl = genericDeclRef.getDecl();
subst->outer = genericDeclRef.substitutions;
@@ -892,8 +953,6 @@ namespace Slang
}
//
-
-
if (auto toDeclRefType = toType->As<DeclRefType>())
{
auto toTypeDeclRef = toDeclRefType->declRef;
@@ -911,8 +970,42 @@ namespace Slang
return true;
}
}
- }
+ else if (auto genParamDeclRef = toTypeDeclRef.As<GenericTypeParamDecl>())
+ {
+ // We need to enumerate the constraints placed on this type by its outer
+ // generic declaration, and see if any of them guarantees that we
+ // satisfy the given interface..
+ auto genericDeclRef = genParamDeclRef.GetParent().As<GenericDecl>();
+ SLANG_ASSERT(genericDeclRef);
+
+ for (auto constraintDeclRef : getMembersOfType<GenericTypeConstraintDecl>(genericDeclRef))
+ {
+ auto sub = GetSub(constraintDeclRef);
+ auto sup = GetSup(constraintDeclRef);
+ auto subDeclRef = sub->As<DeclRefType>();
+ if (!subDeclRef)
+ continue;
+ if (subDeclRef->declRef != genParamDeclRef)
+ continue;
+ auto supDeclRefType = sup->As<DeclRefType>();
+ if (supDeclRefType)
+ {
+ auto toInterfaceDeclRef = supDeclRefType->declRef.As<InterfaceDecl>();
+ if (DoesTypeConformToInterface(fromType, toInterfaceDeclRef))
+ {
+ if (outToExpr)
+ *outToExpr = CreateImplicitCastExpr(toType, fromExpr);
+ if (outCost)
+ *outCost = kConversionCost_CastToInterface;
+ return true;
+ }
+ }
+ }
+
+ }
+
+ }
// Look for an initializer/constructor declaration in the target type,
// which is marked as usable for implicit conversion, and which takes
// the source type as an argument.
@@ -1224,6 +1317,14 @@ namespace Slang
checkDecl(genericDecl->inner);
}
+ void visitGenericTypeConstraintDecl(GenericTypeConstraintDecl * genericConstraintDecl)
+ {
+ // check the type being inherited from
+ auto base = genericConstraintDecl->sup;
+ base = TranslateTypeNode(base);
+ genericConstraintDecl->sup = base;
+ }
+
void visitInheritanceDecl(InheritanceDecl* inheritanceDecl)
{
// check the type being inherited from
@@ -1287,11 +1388,6 @@ namespace Slang
// These are only used in the stdlib, so no checking is needed for now
}
- void visitGenericTypeConstraintDecl(GenericTypeConstraintDecl*)
- {
- // These are only used in the stdlib, so no checking is needed for now
- }
-
void visitModifier(Modifier*)
{
// Do nothing with modifiers for now
@@ -1538,7 +1634,50 @@ namespace Slang
requiredInitDecl);
}
}
+ else if (auto subStructTypeDecl = dynamic_cast<AggTypeDecl*>(memberDecl))
+ {
+ // this is a sub type (e.g. nested struct declaration) in an aggregate type
+ // check if this sub type declaration satisfies the constraints defined by the associated type
+ if (auto requiredTypeDeclRef = requiredMemberDeclRef.As<AssocTypeDecl>())
+ {
+ bool conformance = true;
+ for (auto & inheritanceDecl : requiredTypeDeclRef.getDecl()->getMembersOfType<InheritanceDecl>())
+ {
+ conformance = conformance && checkConformance(subStructTypeDecl, inheritanceDecl.Ptr());
+ }
+ return conformance;
+ }
+ }
+ else if (auto typedefDecl = dynamic_cast<TypeDefDecl*>(memberDecl))
+ {
+ // this is a type-def decl in an aggregate type
+ // check if the specified type satisfies the constraints defined by the associated type
+ if (auto requiredTypeDecl = requiredMemberDeclRef.As<AssocTypeDecl>())
+ {
+ auto constraintList = requiredTypeDecl.getDecl()->getMembersOfType<InheritanceDecl>();
+ if (constraintList.Count())
+ {
+ auto declRefType = typedefDecl->type->AsDeclRefType();
+ if (!declRefType)
+ return false;
+ auto structTypeDecl = declRefType->declRef.getDecl()->As<AggTypeDecl>();
+ if (!structTypeDecl)
+ return false;
+ //TODO: What do we do if type is a generic specialization?
+ // i.e. if the struct defines typedef Generic<float> T;
+ // how to check if T satisfies the associatedtype constraints?
+ // the code below will only work when T is defined to be a simple aggregated type (no generics).
+ bool conformance = true;
+ for (auto & inheritanceDecl : constraintList)
+ {
+ conformance = conformance && checkConformance(structTypeDecl, inheritanceDecl.Ptr());
+ }
+ return conformance;
+ }
+ return true;
+ }
+ }
// Default: just assume that thing aren't being satisfied.
return false;
}
@@ -1623,11 +1762,13 @@ namespace Slang
// declares conformance to the interface `interfaceDeclRef`,
// (via the given `inheritanceDecl`) actually provides
// members to satisfy all the requirements in the interface.
- void checkInterfaceConformance(
+ bool checkInterfaceConformance(
AggTypeDecl* typeDecl,
InheritanceDecl* inheritanceDecl,
DeclRef<InterfaceDecl> interfaceDeclRef)
{
+ bool result = true;
+
// We need to check the declaration of the interface
// before we can check that we conform to it.
EnsureDecl(interfaceDeclRef.getDecl());
@@ -1654,7 +1795,7 @@ namespace Slang
// to the inherited interface.
//
// TODO: we *really* need a linearization step here!!!!
- checkConformanceToType(
+ result = result && checkConformanceToType(
typeDecl,
inheritanceDecl,
getBaseType(requiredInheritanceDeclRef));
@@ -1670,16 +1811,20 @@ namespace Slang
requiredMemberDeclRef);
if (!conformanceWitness)
+ {
+ result = false;
continue;
+ }
// Store that witness into a table stored on the `inheritnaceDecl`
// so that it can be used for downstream code generation.
inheritanceDecl->requirementWitnesses.Add(requiredMemberDeclRef, conformanceWitness);
}
+ return result;
}
- void checkConformanceToType(
+ bool checkConformanceToType(
AggTypeDecl* typeDecl,
InheritanceDecl* inheritanceDecl,
Type* baseType)
@@ -1692,29 +1837,29 @@ namespace Slang
// The type is stating that it conforms to an interface.
// We need to check that it provides all of the members
// required by that interface.
- checkInterfaceConformance(
+ return checkInterfaceConformance(
typeDecl,
inheritanceDecl,
baseInterfaceDeclRef);
- return;
}
}
getSink()->diagnose(inheritanceDecl, Diagnostics::unimplemented, "type not supported for inheritance");
+ return false;
}
// Check that the type declaration `typeDecl`, which
// declares that it inherits from another type via
// `inheritanceDecl` actually does what it needs to
// for that inheritance to be valid.
- void checkConformance(
+ bool checkConformance(
AggTypeDecl* typeDecl,
InheritanceDecl* inheritanceDecl)
{
// Look at the type being inherited from, and validate
// appropriately.
auto baseType = inheritanceDecl->base.type;
- checkConformanceToType(typeDecl, inheritanceDecl, baseType);
+ return checkConformanceToType(typeDecl, inheritanceDecl, baseType);
}
void visitAggTypeDecl(AggTypeDecl* decl)
@@ -1758,6 +1903,11 @@ namespace Slang
// Don't check that an interface conforms to the
// things it inherits from.
}
+ else if (auto assocTypeDecl = dynamic_cast<AssocTypeDecl*>(decl))
+ {
+ // Don't check that an associated type decl conforms to the
+ // things it inherits from.
+ }
else
{
// For non-interface types we need to check conformance.
@@ -1794,6 +1944,24 @@ namespace Slang
decl->SetCheckState(DeclCheckState::Checked);
}
+ void visitAssocTypeDecl(AssocTypeDecl* decl)
+ {
+ if (decl->IsChecked(DeclCheckState::Checked)) return;
+ decl->SetCheckState(DeclCheckState::CheckedHeader);
+
+ // assoctype only allowed in an interface
+ auto interfaceDecl = decl->ParentDecl->As<InterfaceDecl>();
+ if (!interfaceDecl)
+ getSink()->diagnose(decl, Slang::Diagnostics::assocTypeInInterfaceOnly);
+
+ // Now check all of the member declarations.
+ for (auto member : decl->Members)
+ {
+ checkDecl(member);
+ }
+ decl->SetCheckState(DeclCheckState::Checked);
+ }
+
void checkStmt(Stmt* stmt)
{
if (!stmt) return;
@@ -1806,7 +1974,7 @@ namespace Slang
return;
VisitFunctionDeclaration(functionNode);
- // TODO: This should really onlye set "checked header"
+ // TODO: This should really only set "checked header"
functionNode->SetCheckState(DeclCheckState::Checked);
// TODO: should put the checking of the body onto a "work list"
@@ -1977,10 +2145,10 @@ namespace Slang
return true;
}
- RefPtr<Substitutions> createDummySubstitutions(
+ RefPtr<GenericSubstitution> createDummySubstitutions(
GenericDecl* genericDecl)
{
- RefPtr<Substitutions> subst = new Substitutions();
+ RefPtr<GenericSubstitution> subst = new GenericSubstitution();
subst->genericDecl = genericDecl;
for (auto dd : genericDecl->Members)
{
@@ -2239,7 +2407,6 @@ namespace Slang
{
if (functionNode->IsChecked(DeclCheckState::CheckedHeader)) return;
functionNode->SetCheckState(DeclCheckState::CheckingHeader);
-
this->function = functionNode;
auto returnType = CheckProperType(functionNode->ReturnType);
functionNode->ReturnType = returnType;
@@ -2996,7 +3163,7 @@ namespace Slang
session, "Vector").As<GenericDecl>();
auto vectorTypeDecl = vectorGenericDecl->inner;
- auto substitutions = new Substitutions();
+ auto substitutions = new GenericSubstitution();
substitutions->genericDecl = vectorGenericDecl.Ptr();
substitutions->args.Add(elementType);
substitutions->args.Add(elementCount);
@@ -3742,7 +3909,7 @@ namespace Slang
// Consruct a reference to the extension with our constraint variables
// as the
- RefPtr<Substitutions> solvedSubst = new Substitutions();
+ RefPtr<GenericSubstitution> solvedSubst = new GenericSubstitution();
solvedSubst->genericDecl = genericDeclRef.getDecl();
solvedSubst->outer = genericDeclRef.substitutions;
solvedSubst->args = args;
@@ -4011,8 +4178,9 @@ namespace Slang
// We will go ahead and hang onto the arguments that we've
// already checked, since downstream validation might need
// them.
- candidate.subst = new Substitutions();
- auto& checkedArgs = candidate.subst->args;
+ auto genSubst = new GenericSubstitution();
+ candidate.subst = genSubst;
+ auto& checkedArgs = genSubst->args;
int aa = 0;
for (auto memberRef : getMembers(genericDeclRef))
@@ -4185,7 +4353,7 @@ namespace Slang
// We should have the existing arguments to the generic
// handy, so that we can construct a substitution list.
- RefPtr<Substitutions> subst = candidate.subst;
+ RefPtr<GenericSubstitution> subst = candidate.subst.As<GenericSubstitution>();
assert(subst);
subst->genericDecl = genericDeclRef.getDecl();
@@ -4252,7 +4420,7 @@ namespace Slang
RefPtr<Expr> createGenericDeclRef(
RefPtr<Expr> baseExpr,
RefPtr<Expr> originalExpr,
- RefPtr<Substitutions> subst)
+ RefPtr<GenericSubstitution> subst)
{
auto baseDeclRefExpr = baseExpr.As<DeclRefExpr>();
if (!baseDeclRefExpr)
@@ -4364,7 +4532,7 @@ namespace Slang
return createGenericDeclRef(
baseExpr,
context.originalExpr,
- candidate.subst);
+ candidate.subst.As<GenericSubstitution>());
break;
default:
@@ -4659,22 +4827,23 @@ namespace Slang
// They must both be NULL or non-NULL
if (!fst || !snd)
return fst == snd;
-
+ auto fstGen = fst.As<GenericSubstitution>();
+ auto sndGen = snd.As<GenericSubstitution>();
// They must be specializing the same generic
- if (fst->genericDecl != snd->genericDecl)
+ if (fstGen->genericDecl != sndGen->genericDecl)
return false;
// Their arguments must unify
- SLANG_RELEASE_ASSERT(fst->args.Count() == snd->args.Count());
- UInt argCount = fst->args.Count();
+ SLANG_RELEASE_ASSERT(fstGen->args.Count() == sndGen->args.Count());
+ UInt argCount = fstGen->args.Count();
for (UInt aa = 0; aa < argCount; ++aa)
{
- if (!TryUnifyVals(constraints, fst->args[aa], snd->args[aa]))
+ if (!TryUnifyVals(constraints, fstGen->args[aa], sndGen->args[aa]))
return false;
}
// Their "base" specializations must unify
- if (!TryUnifySubstitutions(constraints, fst->outer, snd->outer))
+ if (!TryUnifySubstitutions(constraints, fstGen->outer, sndGen->outer))
return false;
return true;
@@ -5229,11 +5398,12 @@ namespace Slang
if( parentGenericDeclRef )
{
SLANG_RELEASE_ASSERT(declRef.substitutions);
- SLANG_RELEASE_ASSERT(declRef.substitutions->genericDecl == parentGenericDeclRef.getDecl());
+ auto genSubst = declRef.substitutions.As<GenericSubstitution>();
+ SLANG_RELEASE_ASSERT(genSubst->genericDecl == parentGenericDeclRef.getDecl());
sb << "<";
bool first = true;
- for(auto arg : declRef.substitutions->args)
+ for(auto arg : genSubst->args)
{
if(!first) sb << ", ";
formatVal(sb, arg);
@@ -5660,7 +5830,6 @@ namespace Slang
RefPtr<Expr> CheckInvokeExprWithCheckedOperands(InvokeExpr *expr)
{
-
auto rs = ResolveInvoke(expr);
if (auto invoke = dynamic_cast<InvokeExpr*>(rs.Ptr()))
{
@@ -5695,6 +5864,7 @@ namespace Slang
{
// check the base expression first
expr->FunctionExpr = CheckExpr(expr->FunctionExpr);
+
// Next check the argument expressions
for (auto & arg : expr->Arguments)
@@ -6419,6 +6589,11 @@ namespace Slang
*outTypeResult = type;
return QualType(getTypeType(type));
}
+ else if (auto funcDeclRef = declRef.As<CallableDecl>())
+ {
+ auto type = getFuncType(session, funcDeclRef);
+ return QualType(type);
+ }
else if (auto constraintDeclRef = declRef.As<GenericTypeConstraintDecl>())
{
// When we access a constraint or an inheritance decl (as a member),
@@ -6427,12 +6602,6 @@ namespace Slang
auto type = GetSup(constraintDeclRef);
return QualType(type);
}
- else if (auto funcDeclRef = declRef.As<CallableDecl>())
- {
- auto type = getFuncType(session, funcDeclRef);
- return QualType(type);
- }
-
if( sink )
{
sink->diagnose(declRef, Diagnostics::unimplemented, "cannot form reference to this kind of declaration");
@@ -6476,7 +6645,7 @@ namespace Slang
if(decl != genericDecl->inner)
return parentSubst;
- RefPtr<Substitutions> subst = new Substitutions();
+ RefPtr<GenericSubstitution> subst = new GenericSubstitution();
subst->genericDecl = genericDecl;
subst->outer = parentSubst;
diff --git a/source/slang/decl-defs.h b/source/slang/decl-defs.h
index c96fe6d09..9c010d156 100644
--- a/source/slang/decl-defs.h
+++ b/source/slang/decl-defs.h
@@ -122,6 +122,10 @@ SYNTAX_CLASS(TypeDefDecl, SimpleTypeDecl)
SYNTAX_FIELD(TypeExp, type)
END_SYNTAX_CLASS()
+// An 'assoctype' declaration, it is a container of inheritance clauses
+SYNTAX_CLASS(AssocTypeDecl, AggTypeDecl)
+END_SYNTAX_CLASS()
+
// A scope for local declarations (e.g., as part of a statement)
SIMPLE_SYNTAX_CLASS(ScopeDecl, ContainerDecl)
diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h
index cc7db7eb4..52f5d48a0 100644
--- a/source/slang/diagnostic-defs.h
+++ b/source/slang/diagnostic-defs.h
@@ -191,83 +191,10 @@ DIAGNOSTIC(30035, Error, componentOverloadTypeMismatch, "'$0': type of overloade
DIAGNOSTIC(30041, Error, bitOperationNonIntegral, "bit operation: operand must be integral type.")
DIAGNOSTIC(30047, Error, argumentExpectedLValue, "argument passed to parameter '$0' must be l-value.")
DIAGNOSTIC(30051, Error, invalidValueForArgument, "invalid value for argument '$0'")
-DIAGNOSTIC(30052, Error, ordinaryFunctionAsModuleArgument, "ordinary functions not allowed as argument to function-typed module parameter.")
-DIAGNOSTIC(30079, Error, selectPrdicateTypeMismatch, "selector must evaluate to bool.");
-DIAGNOSTIC(30080, Error, selectValuesTypeMismatch, "the two value expressions in a select clause must have same type.");
-DIAGNOSTIC(31040, Error, undefinedTypeName, "undefined type name: '$0'.")
-DIAGNOSTIC(32013, Error, circularReferenceNotAllowed, "'$0': circular reference is not allowed.");
-DIAGNOSTIC(32014, Error, shaderDoesProvideRequirement, "shader '$0' does not provide '$1' as required by '$2'.")
-DIAGNOSTIC(32015, Error, argumentNotAvilableInWorld, "argument '$0' is not available in world '$1' as required by '$2'.")
-DIAGNOSTIC(32015, Error, componentNotAvilableInWorld, "component '$0' is not available in world '$1' as required by '$2'.")
-DIAGNOSTIC(32047, Error, firstArgumentToImportNotComponent, "first argument of an import operator call does not resolve to a component.");
-DIAGNOSTIC(32051, Error, componentTypeNotWhatPipelineRequires, "component '$0' has type '$1', but pipeline '$2' requires it to be '$3'.")
-DIAGNOSTIC(32052, Error, shaderDoesNotDefineComponentAsRequiredByPipeline, "shader '$0' does not define '$1' as required by pipeline '$2''.")
-DIAGNOSTIC(33001, Error, worldNameAlreadyDefined, "world '$0' is already defined.")
-DIAGNOSTIC(33002, Error, explicitPipelineSpecificationRequiredForShader, "explicit pipeline specification required for shader '$0' because multiple pipelines are defined in current context.")
-DIAGNOSTIC(33003, Error, cannotDefineComponentsInAPipeline, "cannot define components in a pipeline.")
-DIAGNOSTIC(33004, Error, undefinedWorldName, "undefined world name '$0'.")
-DIAGNOSTIC(33005, Error, abstractWorldAsTargetOfImport, "abstract world cannot appear as target as an import operator.")
-
-// Note(tfoley): This is a duplicate of 33004 above.
-DIAGNOSTIC(33006, Error, undefinedWorldName2, "undefined world name '$0'.")
-
-DIAGNOSTIC(33007, Error, importOperatorCircularity, "import operator '$0' creates a circular dependency between world '$1' and '$2'")
-DIAGNOSTIC(33009, Error, parametersOnlyAllowedInModules, "parameters can only be defined in modules.")
-DIAGNOSTIC(33010, Error, undefinedPipelineName, "pipeline '$0' is undefined.")
-DIAGNOSTIC(33011, Error, shaderCircularity, "shader '$0' involves circular reference.")
-DIAGNOSTIC(33012, Error, worldIsNotDefinedInPipeline, "'$0' is not a defined world in '$1'.")
-DIAGNOSTIC(33013, Error, abstractWorldCannotAppearWithOthers, "abstract world cannot appear with other worlds.")
-DIAGNOSTIC(33014, Error, nonAbstractComponentMustHaveImplementation, "non-abstract component must have an implementation.")
-DIAGNOSTIC(33016, Error, usingInComponentDefinition, "'using': importing not allowed in component definition.")
-DIAGNOSTIC(33018, Error, nameAlreadyDefined, "'$0' is already defined.")
-DIAGNOSTIC(33018, Error, shaderAlreadyDefined, "shader '$0' has already been defined.")
-DIAGNOSTIC(33019, Error, componentMarkedExportMustHaveWorld, "component '$0': definition marked as 'export' must have an explicitly specified world.")
-DIAGNOSTIC(33020, Error, componentIsAlreadyDefined, "'$0' is already defined.")
-DIAGNOSTIC(33020, Error, componentIsAlreadyDefinedInThatWorld, "'$0' is already defined at '$1'.")
-DIAGNOSTIC(33021, Error, inconsistentSignatureForComponent, "'$0': inconsistent signature.")
-DIAGNOSTIC(33022, Error, nameAlreadyDefinedInCurrentScope, "'$0' is already defined in current scope.")
-DIAGNOSTIC(33022, Error, parameterNameConflictsWithExistingDefinition, "'$0': parameter name conflicts with existing definition.")
-DIAGNOSTIC(33023, Error, parameterOfModuleIsUnassigned, "parameter '$0' of module '$1' is unassigned.")
-DIAGNOSTIC(33027, Error, argumentTypeDoesNotMatchParameterType, "argument type ($0) does not match parameter type ($1)")
-DIAGNOSTIC(33028, Error, nameIsNotAParameterOfCallee, "'$0' is not a parameter of '$1'.")
-DIAGNOSTIC(33029, Error, requirementsClashWithPreviousDef, "'$0': requirement clash with previous definition.")
-DIAGNOSTIC(33030, Error, positionArgumentAfterNamed, "positional argument cannot appear after a named argument.")
-DIAGNOSTIC(33032, Error, functionRedefinition, "'$0': function redefinition.")
-DIAGNOSTIC(33034, Error, recordTypeVariableInImportOperator, "cannot declare a record-typed variable in an import operator.")
-DIAGNOSTIC(33037, Error, componetMarkedExportCannotHaveParameters, "component '$0': definition marked as 'export' cannot have parameters.")
-DIAGNOSTIC(33039, Error, componentInInputWorldCantHaveCode, "'$0': no code allowed for component defined in input world.")
-DIAGNOSTIC(33040, Error, requireWithComputation, "'require': cannot define computation on component requirements.")
-DIAGNOSTIC(33042, Error, paramWithComputation, "'param': cannot define computation on parameters.")
-DIAGNOSTIC(33041, Error, pipelineOfModuleIncompatibleWithPipelineOfShader, "pipeline '$0' targeted by module '$1' is incompatible with pipeline '$2' targeted by shader '$3'.")
DIAGNOSTIC(33070, Error, expectedFunction, "expression preceding parenthesis of apparent call must have function type.")
-DIAGNOSTIC(33071, Error, importOperatorCalledFromAutoPlacedComponent, "cannot call an import operator from an auto-placed component '$0'. try qualify the component with explicit worlds.")
-DIAGNOSTIC(33072, Error, noApplicableImportOperator, "'$0' is an import operator defined in pipeline '$1', but none of the import operator overloads converting to world '$2' matches argument list ($3).")
-DIAGNOSTIC(33073, Error, importOperatorCalledFromMultiWorldComponent, "cannot call an import operator from a multi-world component definition. consider qualify the component with only one explicit world.")
-DIAGNOSTIC(33080, Error, componentTypeDoesNotMatchInterface, "'$0': component type does not match definition in interface '$1'.")
-DIAGNOSTIC(33081, Error, shaderDidNotDefineComponentFunction, "shader '$0' did not define component function $1 as required by interface '$2'.")
-DIAGNOSTIC(33082, Error, shaderDidNotDefineComponent, "shader '$0' did not define component '$1' as required by interface '$2'.")
-DIAGNOSTIC(33083, Error, interfaceImplMustBePublic, "'$0': component fulfilling interface '$1' must be declared as 'public'.")
-DIAGNOSTIC(33084, Error, defaultParamNotAllowedInInterface, "'$0': default parameter value not allowed in interface definition.")
-
-DIAGNOSTIC(33100, Error, componentCantBeComputedAtWorldBecauseDependentNotAvailable, "'$0' cannot be computed at '$1' because the dependent component '$2' is not accessible.")
-DIAGNOSTIC(33101, Warning, worldIsNotAValidChoiceForKey, "'$0' is not a valid choice for '$1'.")
-DIAGNOSTIC(33102, Error, componentDefinitionCircularity, "component definition '$0' involves circular reference.")
-DIAGNOSTIC(34024, Error, componentAlreadyDefinedWhenCompiling, "component named '$0' is already defined when compiling '$1'.")
-DIAGNOSTIC(34025, Error, globalComponentConflictWithPreviousDeclaration, "'$0': global component conflicts with previous declaration.")
-DIAGNOSTIC(34026, Warning, componentIsAlreadyDefinedUseRequire, "'$0': component is already defined when compiling shader '$1'. use 'require' to declare it as a parameter.")
-DIAGNOSTIC(34062, Error, cylicReference, "cyclic reference: $0");
-DIAGNOSTIC(34064, Error, noApplicableImplicitImportOperator, "cannot find import operator to import component '$0' to world '$1' when compiling '$2'.")
-DIAGNOSTIC(34065, Error, resourceTypeMustBeParamOrRequire, "'$0': resource typed component must be declared as 'param' or 'require'.");
-DIAGNOSTIC(34066, Error, cannotDefineComputationOnResourceType, "'$0': cannot define computation on resource typed component.");
-
-DIAGNOSTIC(35001, Error, fragDepthAttributeCanOnlyApplyToOutput, "FragDepth attribute can only apply to an output component.");
-DIAGNOSTIC(35002, Error, fragDepthAttributeCanOnlyApplyToFloatComponent, "FragDepth attribute can only apply to a float component.");
-
-
-DIAGNOSTIC(36001, Error, insufficientTemplateShaderArguments, "instantiating template shader '$0': insufficient arguments.");
-DIAGNOSTIC(36002, Error, tooManyTemplateShaderArguments, "instantiating template shader '$0': too many arguments.");
-DIAGNOSTIC(36003, Error, templateShaderArgumentIsNotDefined, "'$0' provided as template shader argument to '$1' is not a defined module.");
-DIAGNOSTIC(36004, Error, templateShaderArgumentDidNotImplementRequiredInterface, "module '$0' provided as template shader argument to '$1' did not implement required interface '$2'.");
+
+// 303xx: interfaces and associated types
+DIAGNOSTIC(30300, Error, assocTypeInInterfaceOnly, "'associatedtype' can only be defined in an 'interface'.")
// TODO: need to assign numbers to all these extra diagnostics...
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index 336d73abe..056454845 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -395,8 +395,7 @@ struct EmitVisitor
void emitRawTextSpan(char const* textBegin, char const* textEnd)
{
// TODO(tfoley): Need to make "corelib" not use `int` for pointer-sized things...
- auto len = int(textEnd - textBegin);
-
+ auto len = textEnd - textBegin;
context->shared->sb.Append(textBegin, len);
}
@@ -1039,7 +1038,6 @@ struct EmitVisitor
UNEXPECTED(PtrType);
#undef UNEXPECTED
-
void visitNamedExpressionType(NamedExpressionType* type, TypeEmitArg const& arg)
{
// Named types are valid for GLSL
@@ -2917,7 +2915,7 @@ struct EmitVisitor
return;
}
- Substitutions* subst = declRef.substitutions.Ptr();
+ GenericSubstitution* subst = declRef.substitutions.As<GenericSubstitution>().Ptr();
if (!subst)
return;
@@ -3009,6 +3007,12 @@ struct EmitVisitor
Emit(";\n");
}
+ void visitAssocTypeDecl(AssocTypeDecl * /*assocType*/, DeclEmitArg const&)
+ {
+ SLANG_UNREACHABLE("visitAssocTypeDecl in EmitVisitor");
+ }
+
+
void visitImportDecl(ImportDecl* decl, DeclEmitArg const&)
{
// When in "rewriter" mode, we need to emit the code of the imported
diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h
index 8127fb70f..f70ab46ff 100644
--- a/source/slang/ir-insts.h
+++ b/source/slang/ir-insts.h
@@ -346,10 +346,9 @@ struct IRBuilder
IRValue* getBoolValue(bool value);
IRValue* getIntValue(IRType* type, IRIntegerValue value);
IRValue* getFloatValue(IRType* type, IRFloatingPointValue value);
-
IRValue* getDeclRefVal(
DeclRefBase const& declRef);
-
+ IRValue* getTypeVal(IRType* type); // create an IR value that represents a type
IRValue* emitSpecializeInst(
IRType* type,
IRValue* genericVal,
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index ca82b21e7..ab961a159 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -178,27 +178,27 @@ namespace Slang
//
// Add an instruction to a specific parent
- void IRBuilder::addInst(IRBlock* block, IRInst* inst)
+ void IRBuilder::addInst(IRBlock* pblock, IRInst* inst)
{
- inst->parent = block;
+ inst->parent = pblock;
- if (!block->firstInst)
+ if (!pblock->firstInst)
{
inst->prev = nullptr;
inst->next = nullptr;
- block->firstInst = inst;
- block->lastInst = inst;
+ pblock->firstInst = inst;
+ pblock->lastInst = inst;
}
else
{
- auto prev = block->lastInst;
+ auto prev = pblock->lastInst;
inst->prev = prev;
inst->next = nullptr;
prev->next = inst;
- block->lastInst = inst;
+ pblock->lastInst = inst;
}
}
@@ -560,6 +560,18 @@ namespace Slang
return irValue;
}
+ IRValue * IRBuilder::getTypeVal(IRType * type)
+ {
+ auto irValue = createValue<IRValue>(
+ this,
+ kIROp_TypeType,
+ nullptr);
+ irValue->type = type;
+ if (auto typetype = dynamic_cast<TypeType*>(type))
+ irValue->type = typetype->type;
+ return irValue;
+ }
+
IRValue* IRBuilder::emitSpecializeInst(
Type* type,
IRValue* genericVal,
@@ -620,7 +632,7 @@ namespace Slang
IRInst* IRBuilder::emitCallInst(
IRType* type,
- IRValue* func,
+ IRValue* pFunc,
UInt argCount,
IRValue* const* args)
{
@@ -629,7 +641,7 @@ namespace Slang
kIROp_Call,
type,
1,
- &func,
+ &pFunc,
argCount,
args);
addInst(inst);
@@ -1531,7 +1543,7 @@ namespace Slang
if(genericParentDeclRef)
{
- auto subst = declRef.substitutions;
+ auto subst = declRef.substitutions.As<GenericSubstitution>();
if( !subst || subst->genericDecl != genericParentDeclRef.getDecl() )
{
// No actual substitutions in place here
@@ -3058,7 +3070,12 @@ namespace Slang
return builder->getDeclRefVal(declRef);
}
break;
-
+ case kIROp_TypeType:
+ {
+ IRValue* od = (IRValue*)originalValue;
+ return builder->getTypeVal(od->type);
+ }
+ break;
default:
SLANG_UNEXPECTED("no value registered for IR value");
UNREACHABLE_RETURN(nullptr);
@@ -3093,18 +3110,27 @@ namespace Slang
{
if (!subst)
return nullptr;
+ if (auto genSubst = dynamic_cast<GenericSubstitution*>(subst))
+ {
+ RefPtr<GenericSubstitution> newSubst = new GenericSubstitution();
+ newSubst->outer = cloneSubstitutions(context, subst->outer);
+ newSubst->genericDecl = genSubst->genericDecl;
- RefPtr<Substitutions> newSubst = new Substitutions();
- newSubst->outer = cloneSubstitutions(context, subst->outer);
- newSubst->genericDecl = subst->genericDecl;
-
- for (auto arg : subst->args)
+ for (auto arg : genSubst->args)
+ {
+ auto newArg = cloneSubstitutionArg(context, arg);
+ newSubst->args.Add(arg);
+ }
+ return newSubst;
+ }
+ else if (auto thisSubst = dynamic_cast<ThisTypeSubstitution*>(subst))
{
- auto newArg = cloneSubstitutionArg(context, arg);
- newSubst->args.Add(arg);
+ RefPtr<ThisTypeSubstitution> newSubst = new ThisTypeSubstitution();
+ newSubst->sourceType = thisSubst->sourceType;
+ newSubst->outer = cloneSubstitutions(context, subst->outer);
+ return newSubst;
}
-
- return newSubst;
+ return nullptr;
}
DeclRef<Decl> IRSpecContext::maybeCloneDeclRef(DeclRef<Decl> const& declRef)
@@ -3738,7 +3764,8 @@ namespace Slang
IRGenericSpecContext* context,
DeclRef<Decl> declRef)
{
- auto subst = context->subst;
+ auto subst = context->subst.As<GenericSubstitution>();
+ SLANG_ASSERT(subst);
auto genericDecl = subst->genericDecl;
UInt orinaryParamCount = 0;
@@ -3788,12 +3815,13 @@ namespace Slang
{
auto declRefVal = (IRDeclRef*) originalVal;
auto declRef = declRefVal->declRef;
-
+ auto genSubst = subst.As<GenericSubstitution>();
+ SLANG_ASSERT(genSubst);
// We may have a direct reference to one of the parameters
// of the generic we are specializing, and in that case
// we nee to translate it over to the equiavalent of
// the `Val` we have been given.
- if(declRef.getDecl()->ParentDecl == subst->genericDecl)
+ if(declRef.getDecl()->ParentDecl == genSubst->genericDecl)
{
return getSubstValue(this, declRef);
}
@@ -3848,9 +3876,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<Substitutions> newSubst = new Substitutions();
+ RefPtr<GenericSubstitution> newSubst = new GenericSubstitution();
newSubst->genericDecl = genericFunc->genericDecl;
- newSubst->args = specDeclRef.substitutions->args;
+ auto specDeclRefSubst = specDeclRef.substitutions.As<GenericSubstitution>();
+ newSubst->args = specDeclRefSubst->args;
IRGenericSpecContext context;
context.shared = sharedContext;
diff --git a/source/slang/lookup.cpp b/source/slang/lookup.cpp
index c0cb657c4..b01732362 100644
--- a/source/slang/lookup.cpp
+++ b/source/slang/lookup.cpp
@@ -410,7 +410,27 @@ void lookUpMemberImpl(
if (auto declRefType = type->As<DeclRefType>())
{
auto declRef = declRefType->declRef;
- if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>())
+ if (auto assocTypeDeclRef = declRef.As<AssocTypeDecl>())
+ {
+ for (auto constraintDeclRef : getMembersOfType<GenericTypeConstraintDecl>(assocTypeDeclRef))
+ {
+ // The super-type in the constraint (e.g., `Foo` in `T : Foo`)
+ // will tell us a type we should use for lookup.
+ auto bound = GetSup(constraintDeclRef);
+
+ // Go ahead and use the target type, with an appropriate breadcrumb
+ // to indicate that we indirected through a type constraint.
+
+ BreadcrumbInfo breadcrumb;
+ breadcrumb.prev = inBreadcrumbs;
+ breadcrumb.kind = LookupResultItem::Breadcrumb::Kind::Constraint;
+ breadcrumb.declRef = constraintDeclRef;
+
+ // TODO: Need to consider case where this might recurse infinitely.
+ lookUpMemberImpl(session, semantics, name, bound, ioResult, &breadcrumb);
+ }
+ }
+ else if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>())
{
LookupRequest request;
request.semantics = semantics;
@@ -452,7 +472,9 @@ void lookUpMemberImpl(
lookUpMemberImpl(session, semantics, name, bound, ioResult, &breadcrumb);
}
}
+
}
+
}
LookupResult lookUpMember(
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index a659326e4..2672c5698 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -871,9 +871,12 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
auto subs = declRef.substitutions;
while(subs)
{
- for(auto aa : subs->args)
+ if (auto genSubst = subs.As<GenericSubstitution>())
{
- (*ioArgs).Add(getSimpleVal(context, lowerVal(context, aa)));
+ for (auto aa : genSubst->args)
+ {
+ (*ioArgs).Add(getSimpleVal(context, lowerVal(context, aa)));
+ }
}
subs = subs->outer;
}
@@ -2060,6 +2063,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
SLANG_UNIMPLEMENTED_X("decl catch-all");
}
+ LoweredValInfo visitTypeDefDecl(TypeDefDecl * decl)
+ {
+ return LoweredValInfo::simple(context->irBuilder->getTypeVal(decl->type.type));
+ }
+
LoweredValInfo visitGenericTypeParamDecl(GenericTypeParamDecl* /*decl*/)
{
return LoweredValInfo();
@@ -2303,9 +2311,13 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
ensureDecl(context, inheritanceDecl);
}
- // For now, we don't have an IR-level representation
- // for the type itself.
- return LoweredValInfo();
+ // TODO: we currently store a Decl* in the witness table, which causes this function
+ // being invoked to translate the witness table entry into an IRValue.
+ // We should really allow a witness table entry to represent a type and not having to
+ // construct the type here. The current implementation will not work when the struct type
+ // is defined in a generic parent (we lose the environmental substitutions).
+ return LoweredValInfo::simple(context->irBuilder->getTypeVal(DeclRefType::Create(context->getSession(),
+ DeclRef<Decl>(decl, nullptr))));
}
@@ -3029,24 +3041,33 @@ RefPtr<Substitutions> lowerSubstitutions(
{
if(!subst)
return nullptr;
+ RefPtr<Substitutions> result;
+ if (auto genSubst = dynamic_cast<GenericSubstitution*>(subst))
+ {
+ RefPtr<GenericSubstitution> newSubst = new GenericSubstitution();
+ newSubst->genericDecl = genSubst->genericDecl;
+
+ for (auto arg : genSubst->args)
+ {
+ auto newArg = lowerSubstitutionArg(context, arg);
+ newSubst->args.Add(newArg);
+ }
- RefPtr<Substitutions> newSubst = new Substitutions();
+ result = newSubst;
+ }
+ else if (auto thisSubst = dynamic_cast<ThisTypeSubstitution*>(subst))
+ {
+ RefPtr<ThisTypeSubstitution> newSubst = new ThisTypeSubstitution();
+ newSubst->sourceType = lowerSubstitutionArg(context, thisSubst->sourceType);
+ result = newSubst;
+ }
if (subst->outer)
{
- newSubst->outer = lowerSubstitutions(
+ result->outer = lowerSubstitutions(
context,
subst->outer);
}
-
- newSubst->genericDecl = subst->genericDecl;
-
- for (auto arg : subst->args)
- {
- auto newArg = lowerSubstitutionArg(context, arg);
- newSubst->args.Add(newArg);
- }
-
- return newSubst;
+ return result;
}
LoweredValInfo emitDeclRef(
@@ -3059,7 +3080,7 @@ LoweredValInfo emitDeclRef(
// If this declaration reference doesn't involve any specializations,
// then we are done at this point.
- if(!declRef.substitutions)
+ if(!hasGenericSubstitutions(declRef.substitutions))
return loweredDecl;
auto val = getSimpleVal(context, loweredDecl);
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp
index 73854a5c7..44ad5c272 100644
--- a/source/slang/lower.cpp
+++ b/source/slang/lower.cpp
@@ -2554,14 +2554,24 @@ struct LoweringVisitor
Substitutions* inSubstitutions)
{
if (!inSubstitutions) return nullptr;
-
- RefPtr<Substitutions> result = new Substitutions();
- result->genericDecl = translateDeclRef(inSubstitutions->genericDecl).As<GenericDecl>();
- for (auto arg : inSubstitutions->args)
+ if (auto genSubst = dynamic_cast<GenericSubstitution*>(inSubstitutions))
+ {
+ RefPtr<GenericSubstitution> result = new GenericSubstitution();
+ result->genericDecl = translateDeclRef(genSubst->genericDecl).As<GenericDecl>();
+ for (auto arg : genSubst->args)
+ {
+ result->args.Add(translateVal(arg));
+ }
+ return result;
+ }
+ else if (auto thisSubst = dynamic_cast<ThisTypeSubstitution*>(inSubstitutions))
{
- result->args.Add(translateVal(arg));
+ RefPtr<ThisTypeSubstitution> result = new ThisTypeSubstitution();
+ if (result->sourceType)
+ result->sourceType = translateVal(result->sourceType);
+ return result;
}
- return result;
+ return nullptr;
}
static Decl* getModifiedDecl(Decl* decl)
@@ -2718,7 +2728,11 @@ struct LoweringVisitor
RefPtr<VarLayout> tryToFindLayout(
Decl* decl)
{
- auto loweredParent = translateDeclRef(decl->ParentDecl);
+ RefPtr<Decl> loweredParent;
+ if (auto genericParentDecl = decl->ParentDecl->As<GenericDecl>())
+ loweredParent = translateDeclRef(genericParentDecl->ParentDecl);
+ else
+ loweredParent = translateDeclRef(decl->ParentDecl);
if (loweredParent)
{
auto layoutMod = loweredParent->FindModifier<ComputedLayoutModifier>();
@@ -2820,6 +2834,13 @@ struct LoweringVisitor
return LoweredDecl();
}
+ LoweredDecl visitAssocTypeDecl(AssocTypeDecl * /*assocType*/)
+ {
+ // not supported
+ SLANG_UNREACHABLE("visitAssocTypeDecl in LowerVisitor");
+ UNREACHABLE_RETURN(LoweredDecl());
+ }
+
LoweredDecl visitTypeDefDecl(TypeDefDecl* decl)
{
if (shared->target == CodeGenTarget::GLSL)
@@ -3809,7 +3830,7 @@ struct LoweringVisitor
"Vector").As<GenericDecl>();
auto vectorTypeDecl = vectorGenericDecl->inner;
- auto substs = new Substitutions();
+ auto substs = new GenericSubstitution();
substs->genericDecl = vectorGenericDecl.Ptr();
substs->args.Add(elementType);
substs->args.Add(elementCount);
diff --git a/source/slang/mangle.cpp b/source/slang/mangle.cpp
index a690e5b74..b9fba6380 100644
--- a/source/slang/mangle.cpp
+++ b/source/slang/mangle.cpp
@@ -195,7 +195,7 @@ namespace Slang
// There are two cases here: either we have specializations
// in place for the parent generic declaration, or we don't.
- auto subst = declRef.substitutions;
+ auto subst = declRef.substitutions.As<GenericSubstitution>();
if( subst && subst->genericDecl == parentGenericDeclRef.getDecl() )
{
// This is the case where we *do* have substitutions.
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index 8ec6f70ca..57956485a 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -1396,6 +1396,16 @@ namespace Slang
return genericApp;
}
+ static RefPtr<Expr> parseMemberType(Parser * parser, RefPtr<Expr> base)
+ {
+ RefPtr<MemberExpr> memberExpr = new MemberExpr();
+ parser->ReadToken(TokenType::Dot);
+ parser->FillPosition(memberExpr.Ptr());
+ memberExpr->BaseExpression = base;
+ memberExpr->name = expectIdentifier(parser).name;
+ return memberExpr;
+ }
+
// Parse option `[]` braces after a type expression, that indicate an array type
static RefPtr<Expr> parsePostfixTypeSuffix(
Parser* parser,
@@ -1418,8 +1428,7 @@ namespace Slang
return typeExpr;
}
- static TypeSpec
- parseTypeSpec(Parser* parser)
+ static TypeSpec parseTypeSpec(Parser* parser)
{
TypeSpec typeSpec;
@@ -1452,9 +1461,20 @@ namespace Slang
RefPtr<Expr> typeExpr = basicType;
- if (parser->LookAheadToken(TokenType::OpLess))
+ bool shouldLoop = true;
+ while (shouldLoop)
{
- typeExpr = parseGenericApp(parser, typeExpr);
+ switch (peekTokenType(parser))
+ {
+ case TokenType::OpLess:
+ typeExpr = parseGenericApp(parser, typeExpr);
+ break;
+ case TokenType::Dot:
+ typeExpr = parseMemberType(parser, typeExpr);
+ break;
+ default:
+ shouldLoop = false;
+ }
}
// GLSL allows `[]` directly in a type specifier
@@ -2089,6 +2109,41 @@ namespace Slang
}
}
+ RefPtr<RefObject> ParseAssocType(Parser * parser, void *)
+ {
+ RefPtr<AssocTypeDecl> assocTypeDecl = new AssocTypeDecl();
+
+ auto nameToken = parser->ReadToken(TokenType::Identifier);
+ assocTypeDecl->nameAndLoc = NameLoc(nameToken);
+ assocTypeDecl->loc = nameToken.loc;
+ if (AdvanceIf(parser, TokenType::Colon))
+ {
+ while (!parser->tokenReader.IsAtEnd())
+ {
+ auto paramConstraint = new GenericTypeConstraintDecl();
+ parser->FillPosition(paramConstraint);
+
+ auto paramType = DeclRefType::Create(
+ parser->getSession(),
+ DeclRef<Decl>(assocTypeDecl, nullptr));
+
+ auto paramTypeExpr = new SharedTypeExpr();
+ paramTypeExpr->loc = assocTypeDecl->loc;
+ paramTypeExpr->base.type = paramType;
+ paramTypeExpr->type = QualType(getTypeType(paramType));
+
+ paramConstraint->sub = TypeExp(paramTypeExpr);
+ paramConstraint->sup = parser->ParseTypeExp();
+
+ AddMember(assocTypeDecl, paramConstraint);
+ if (!AdvanceIf(parser, TokenType::Comma))
+ break;
+ }
+ }
+ parser->ReadToken(TokenType::Semicolon);
+ return assocTypeDecl;
+ }
+
static RefPtr<RefObject> parseInterfaceDecl(Parser* parser, void* /*userData*/)
{
RefPtr<InterfaceDecl> decl = new InterfaceDecl();
@@ -4029,8 +4084,8 @@ namespace Slang
// Add syntax for declaration keywords
#define DECL(KEYWORD, CALLBACK) \
addBuiltinSyntax<Decl>(session, scope, #KEYWORD, &CALLBACK)
-
DECL(typedef, ParseTypeDef);
+ DECL(associatedtype,ParseAssocType);
DECL(cbuffer, parseHLSLCBufferDecl);
DECL(tbuffer, parseHLSLTBufferDecl);
DECL(__generic, ParseGenericDecl);
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index ecee38777..1cda8e7d0 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -300,6 +300,7 @@ int CompileRequest::executeActionsInner()
// Generate initial IR for all the translation
// units, if we are in a mode where IR is called for.
generateIR();
+
if (mSink.GetErrorCount() != 0)
return 1;
diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis
index 7e6fd3753..5bf8a1b09 100644
--- a/source/slang/slang.natvis
+++ b/source/slang/slang.natvis
@@ -35,4 +35,66 @@
<Type Name="Slang::NameLoc">
<DisplayString>{{name={(char*)((*name).text.buffer.pointer+1), s} loc={loc.raw}}}</DisplayString>
</Type>
+ <Type Name="Slang::IRValue">
+ <DisplayString>{{{op}}}</DisplayString>
+ <Expand>
+ <Item Name="[OpCode]">op</Item>
+ <Item Name="[Type]">type</Item>
+ <Item Name="[IRInst]">(Slang::IRInst*)this</Item>
+ <ExpandedItem Condition="op==kIROp_decl_ref">(Slang::IRDeclRef*)this</ExpandedItem>
+ <ExpandedItem Condition="op==kIROp_Func">(Slang::IRFunc*)this</ExpandedItem>
+ <ExpandedItem Condition="op==kIROp_Block">(Slang::IRBlock*)this</ExpandedItem>
+ <Item Name="====Uses====">"-------"</Item>
+ <LinkedListItems>
+ <HeadPointer>firstUse</HeadPointer>
+ <NextPointer>nextUse</NextPointer>
+ <ValueNode>usedValue</ValueNode>
+ </LinkedListItems>
+
+ </Expand>
+ </Type>
+ <Type Name="Slang::IRUser">
+ <DisplayString>{{{op}}}</DisplayString>
+ <Expand>
+ <Item Name="[OpCode]">op</Item>
+ <Item Name="[ArgCount]">argCount</Item>
+ <ArrayItems>
+ <Size>argCount</Size>
+ <ValuePointer>(IRUse*)(this + 1)</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+ <Type Name="Slang::IRBlock">
+ <Expand>
+ <LinkedListItems>
+ <HeadPointer>firstInst</HeadPointer>
+ <NextPointer>(Slang::IRInst*)next</NextPointer>
+ <ValueNode>this</ValueNode>
+ </LinkedListItems>
+ </Expand>
+ </Type>
+ <Type Name="Slang::IRFunc">
+ <DisplayString>{{{mangledName}}}</DisplayString>
+ <Expand>
+ <Item Name="[Name]">mangledName</Item>
+ <Item Name="[ResultType]">(*(IRFuncType*)(type.pointer)).resultType</Item>
+ <Item Name="[ParameterTypes]">(*(IRFuncType*)(type.pointer)).paramTypes</Item>
+ <Item Name="[FirstBlock]">firstBlock</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Slang::IRDeclRef">
+ <DisplayString>{{IRDeclRef {declRef}}}</DisplayString>
+ <Expand>
+ <Item Name="[OpCode]">op</Item>
+ <ExpandedItem>declRef</ExpandedItem>
+ </Expand>
+ </Type>
+ <Type Name="Slang::IRUse">
+ <DisplayString>{{IRUse {usedValue}}}</DisplayString>
+ <Expand>
+ <Item Name="[NextUse]">nextUse</Item>
+ <ExpandedItem>usedValue</ExpandedItem>
+ </Expand>
+ </Type>
</AutoVisualizer> \ No newline at end of file
diff --git a/source/slang/syntax-base-defs.h b/source/slang/syntax-base-defs.h
index 8a22a61d2..3c7e8c5ae 100644
--- a/source/slang/syntax-base-defs.h
+++ b/source/slang/syntax-base-defs.h
@@ -126,31 +126,44 @@ protected:
)
END_SYNTAX_CLASS()
+
// A substitution represents a binding of certain
// type-level variables to concrete argument values
-SYNTAX_CLASS(Substitutions, RefObject)
+ABSTRACT_SYNTAX_CLASS(Substitutions, RefObject)
+
+ // Any further substitutions, relating to outer generic declarations
+ SYNTAX_FIELD(RefPtr<Substitutions>, outer)
+
+ RAW(
+ // Apply a set of substitutions to the bindings in this substitution
+ virtual RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff) = 0;
+ // Check if these are equivalent substitutiosn to another set
+ virtual bool Equals(Substitutions* subst) = 0;
+ virtual bool operator == (const Substitutions & subst) = 0;
+ virtual int GetHashCode() const = 0;
+ )
+END_SYNTAX_CLASS()
+
+SYNTAX_CLASS(GenericSubstitution, Substitutions)
// The generic declaration that defines the
// parametesr we are binding to arguments
- DECL_FIELD(GenericDecl*, genericDecl)
+ DECL_FIELD(GenericDecl*, genericDecl)
// The actual values of the arguments
SYNTAX_FIELD(List<RefPtr<Val>>, args)
-
- // Any further substitutions, relating to outer generic declarations
- SYNTAX_FIELD(RefPtr<Substitutions>, outer)
-
+
RAW(
// Apply a set of substitutions to the bindings in this substitution
- RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff);
+ virtual RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff) override;
// Check if these are equivalent substitutiosn to another set
- bool Equals(Substitutions* subst);
- bool operator == (const Substitutions & subst)
+ virtual bool Equals(Substitutions* subst) override;
+ virtual bool operator == (const Substitutions & subst) override
{
return Equals(const_cast<Substitutions*>(&subst));
}
- int GetHashCode() const
+ virtual int GetHashCode() const override
{
int rs = 0;
for (auto && v : args)
@@ -163,6 +176,27 @@ SYNTAX_CLASS(Substitutions, RefObject)
)
END_SYNTAX_CLASS()
+SYNTAX_CLASS(ThisTypeSubstitution, Substitutions)
+ // The actual type that provides the lookup scope for an associated type
+ SYNTAX_FIELD(RefPtr<Val>, sourceType)
+
+ RAW(
+ // Apply a set of substitutions to the bindings in this substitution
+ virtual RefPtr<Substitutions> SubstituteImpl(Substitutions* subst, int* ioDiff) override;
+
+ // Check if these are equivalent substitutiosn to another set
+ virtual bool Equals(Substitutions* subst) override;
+ virtual bool operator == (const Substitutions & subst) override
+ {
+ return Equals(const_cast<Substitutions*>(&subst));
+ }
+ virtual int GetHashCode() const override
+ {
+ return sourceType->GetHashCode();
+ }
+ )
+END_SYNTAX_CLASS()
+
ABSTRACT_SYNTAX_CLASS(SyntaxNode, SyntaxNodeBase)
END_SYNTAX_CLASS()
diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp
index 149e0b811..9acdadad6 100644
--- a/source/slang/syntax.cpp
+++ b/source/slang/syntax.cpp
@@ -91,6 +91,8 @@ ABSTRACT_SYNTAX_CLASS(Modifier, SyntaxNodeBase);
ABSTRACT_SYNTAX_CLASS(Expr, SyntaxNode);
ABSTRACT_SYNTAX_CLASS(Substitutions, SyntaxNode);
+ABSTRACT_SYNTAX_CLASS(GenericSubstitution, Substitutions);
+ABSTRACT_SYNTAX_CLASS(ThisTypeSubstitution, Substitutions);
#include "expr-defs.h"
#include "decl-defs.h"
@@ -98,8 +100,6 @@ ABSTRACT_SYNTAX_CLASS(Substitutions, SyntaxNode);
#include "stmt-defs.h"
#include "type-defs.h"
#include "val-defs.h"
-
-
#include "object-meta-end.h"
bool SyntaxClassBase::isSubClassOfImpl(SyntaxClassBase const& super) const
@@ -283,7 +283,7 @@ void Type::accept(IValVisitor* visitor, void* extra)
this, "PtrType").As<GenericDecl>();
auto typeDecl = genericDecl->inner;
- auto substitutions = new Substitutions();
+ auto substitutions = new GenericSubstitution();
substitutions->genericDecl = genericDecl.Ptr();
substitutions->args.Add(valueType);
@@ -414,38 +414,69 @@ void Type::accept(IValVisitor* visitor, void* extra)
// search for a substitution that might apply to us
for (auto s = subst; s; s = s->outer.Ptr())
{
- // the generic decl associated with the substitution list must be
- // the generic decl that declared this parameter
- auto genericDecl = s->genericDecl;
- if (genericDecl != genericTypeParamDecl->ParentDecl)
- continue;
-
- int index = 0;
- for (auto m : genericDecl->Members)
+ if (auto genericSubst = dynamic_cast<GenericSubstitution*>(s))
{
- if (m.Ptr() == genericTypeParamDecl)
- {
- // We've found it, so return the corresponding specialization argument
- (*ioDiff)++;
- return s->args[index];
- }
- else if(auto typeParam = m.As<GenericTypeParamDecl>())
- {
- index++;
- }
- else if(auto valParam = m.As<GenericValueParamDecl>())
+ // the generic decl associated with the substitution list must be
+ // the generic decl that declared this parameter
+ auto genericDecl = genericSubst->genericDecl;
+ if (genericDecl != genericTypeParamDecl->ParentDecl)
+ continue;
+
+ int index = 0;
+ for (auto m : genericDecl->Members)
{
- index++;
+ if (m.Ptr() == genericTypeParamDecl)
+ {
+ // We've found it, so return the corresponding specialization argument
+ (*ioDiff)++;
+ return genericSubst->args[index];
+ }
+ else if (auto typeParam = m.As<GenericTypeParamDecl>())
+ {
+ index++;
+ }
+ else if (auto valParam = m.As<GenericValueParamDecl>())
+ {
+ index++;
+ }
+ else
+ {
+ }
}
- else
+ }
+
+ }
+ }
+ // the second case we care about is when this decl type refers to an associatedtype decl
+ // we want to replace it with the actual associated type
+ else if (auto assocTypeDecl = dynamic_cast<AssocTypeDecl*>(declRef.getDecl()))
+ {
+ auto thisSubst = getThisTypeSubst(declRef, false);
+ auto oldSubstSrc = thisSubst ? thisSubst->sourceType : nullptr;
+ bool restore = false;
+ if (thisSubst && thisSubst->sourceType.Ptr() == dynamic_cast<Val*>(this))
+ thisSubst->sourceType = nullptr;
+ auto newSubst = declRef.substitutions->SubstituteImpl(subst, ioDiff);
+ if (restore)
+ thisSubst->sourceType = oldSubstSrc;
+ if (auto thisTypeSubst = newSubst.As<ThisTypeSubstitution>())
+ {
+ if (thisTypeSubst->sourceType)
+ {
+ if (auto aggTypeDeclRef = thisTypeSubst->sourceType.As<DeclRefType>()->declRef.As<AggTypeDecl>())
{
+ Decl * targetType = nullptr;
+ if (aggTypeDeclRef.getDecl()->memberDictionary.TryGetValue(assocTypeDecl->getName(), targetType))
+ {
+ if (auto typeDefDecl = dynamic_cast<TypeDefDecl*>(targetType))
+ return typeDefDecl->type.type;
+ else
+ return DeclRefType::Create(getSession(), DeclRef<Decl>(targetType, aggTypeDeclRef.substitutions));
+ }
}
}
-
}
}
-
-
int diff = 0;
DeclRef<Decl> substDeclRef = declRef.SubstituteImpl(subst, &diff);
@@ -486,10 +517,25 @@ void Type::accept(IValVisitor* visitor, void* extra)
// we will construct a default specialization at the use
// site if needed.
- if( auto genericParent = declRef.GetParent().As<GenericDecl>() )
+ if (auto genericParent = declRef.GetParent().As<GenericDecl>())
{
auto subst = declRef.substitutions;
- if( !subst || subst->genericDecl != genericParent.decl )
+ // try find a substitution targeting this generic decl
+ bool substFound = false;
+ while (subst)
+ {
+ if (auto genSubst = dynamic_cast<GenericSubstitution*>(subst.Ptr()))
+ {
+ if (genSubst->genericDecl == genericParent.decl)
+ {
+ substFound = true;
+ break;
+ }
+ }
+ subst = subst->outer;
+ }
+ // we did not find an existing substituion, create a default one
+ if (!substFound)
{
declRef.substitutions = createDefaultSubstitutions(
session,
@@ -507,7 +553,7 @@ void Type::accept(IValVisitor* visitor, void* extra)
}
else if (auto magicMod = declRef.getDecl()->FindModifier<MagicTypeModifier>())
{
- Substitutions* subst = declRef.substitutions.Ptr();
+ GenericSubstitution* subst = declRef.substitutions.As<GenericSubstitution>().Ptr();
if (magicMod->name == "SamplerState")
{
@@ -972,24 +1018,24 @@ void Type::accept(IValVisitor* visitor, void* extra)
Type* MatrixExpressionType::getElementType()
{
- return this->declRef.substitutions->args[0].As<Type>().Ptr();
+ return this->declRef.substitutions.As<GenericSubstitution>()->args[0].As<Type>().Ptr();
}
IntVal* MatrixExpressionType::getRowCount()
{
- return this->declRef.substitutions->args[1].As<IntVal>().Ptr();
+ return this->declRef.substitutions.As<GenericSubstitution>()->args[1].As<IntVal>().Ptr();
}
IntVal* MatrixExpressionType::getColumnCount()
{
- return this->declRef.substitutions->args[2].As<IntVal>().Ptr();
+ return this->declRef.substitutions.As<GenericSubstitution>()->args[2].As<IntVal>().Ptr();
}
// PtrTypeBase
Type* PtrTypeBase::getValueType()
{
- return this->declRef.substitutions->args[0].As<Type>().Ptr();
+ return this->declRef.substitutions.As<GenericSubstitution>()->args[0].As<Type>().Ptr();
}
// GenericParamIntVal
@@ -1018,31 +1064,34 @@ void Type::accept(IValVisitor* visitor, void* extra)
// search for a substitution that might apply to us
for (auto s = subst; s; s = s->outer.Ptr())
{
- // the generic decl associated with the substitution list must be
- // the generic decl that declared this parameter
- auto genericDecl = s->genericDecl;
- if (genericDecl != declRef.getDecl()->ParentDecl)
- continue;
-
- int index = 0;
- for (auto m : genericDecl->Members)
+ if (auto genSubst = dynamic_cast<GenericSubstitution*>(s))
{
- if (m.Ptr() == declRef.getDecl())
- {
- // We've found it, so return the corresponding specialization argument
- (*ioDiff)++;
- return s->args[index];
- }
- else if(auto typeParam = m.As<GenericTypeParamDecl>())
- {
- index++;
- }
- else if(auto valParam = m.As<GenericValueParamDecl>())
- {
- index++;
- }
- else
+ // the generic decl associated with the substitution list must be
+ // the generic decl that declared this parameter
+ auto genericDecl = genSubst->genericDecl;
+ if (genericDecl != declRef.getDecl()->ParentDecl)
+ continue;
+
+ int index = 0;
+ for (auto m : genericDecl->Members)
{
+ if (m.Ptr() == declRef.getDecl())
+ {
+ // We've found it, so return the corresponding specialization argument
+ (*ioDiff)++;
+ return genSubst->args[index];
+ }
+ else if (auto typeParam = m.As<GenericTypeParamDecl>())
+ {
+ index++;
+ }
+ else if (auto valParam = m.As<GenericValueParamDecl>())
+ {
+ index++;
+ }
+ else
+ {
+ }
}
}
}
@@ -1053,12 +1102,12 @@ void Type::accept(IValVisitor* visitor, void* extra)
// Substitutions
- RefPtr<Substitutions> Substitutions::SubstituteImpl(Substitutions* subst, int* ioDiff)
+ RefPtr<Substitutions> GenericSubstitution::SubstituteImpl(Substitutions* subst, int* ioDiff)
{
if (!this) return nullptr;
int diff = 0;
- auto outerSubst = outer->SubstituteImpl(subst, &diff);
+ auto outerSubst = outer ? outer->SubstituteImpl(subst, &diff) : nullptr;
List<RefPtr<Val>> substArgs;
for (auto a : args)
@@ -1069,35 +1118,85 @@ void Type::accept(IValVisitor* visitor, void* extra)
if (!diff) return this;
(*ioDiff)++;
- auto substSubst = new Substitutions();
+ auto substSubst = new GenericSubstitution();
substSubst->genericDecl = genericDecl;
substSubst->args = substArgs;
return substSubst;
}
- bool Substitutions::Equals(Substitutions* subst)
+ bool GenericSubstitution::Equals(Substitutions* subst)
{
// both must be NULL, or non-NULL
if (!this || !subst)
return !this && !subst;
-
- if (genericDecl != subst->genericDecl)
+ auto genericSubst = dynamic_cast<GenericSubstitution*>(subst);
+ if (!genericSubst)
+ return false;
+ if (genericDecl != genericSubst->genericDecl)
return false;
UInt argCount = args.Count();
- SLANG_RELEASE_ASSERT(args.Count() == subst->args.Count());
+ SLANG_RELEASE_ASSERT(args.Count() == genericSubst->args.Count());
for (UInt aa = 0; aa < argCount; ++aa)
{
- if (!args[aa]->EqualsVal(subst->args[aa].Ptr()))
+ if (!args[aa]->EqualsVal(genericSubst->args[aa].Ptr()))
return false;
}
+ if (!outer)
+ return !subst->outer || subst->outer.As<ThisTypeSubstitution>();
+
if (!outer->Equals(subst->outer.Ptr()))
return false;
return true;
}
+ RefPtr<Substitutions> ThisTypeSubstitution::SubstituteImpl(Substitutions* subst, int* ioDiff)
+ {
+ if (!this) return nullptr;
+
+ int diff = 0;
+ RefPtr<Substitutions> outerSubst;
+ if (outer)
+ outerSubst = outer->SubstituteImpl(subst, &diff);
+ RefPtr<Val> newSourceType;
+ if (sourceType)
+ newSourceType = sourceType->SubstituteImpl(subst, &diff);
+ else
+ {
+ // this_type is a free variable, use this_type from subst
+ auto psubst = subst;
+ while (psubst)
+ {
+ if (auto pthisSubst = dynamic_cast<ThisTypeSubstitution*>(subst))
+ {
+ diff++;
+ newSourceType = pthisSubst->sourceType;
+ break;
+ }
+ psubst = psubst->outer;
+ }
+ }
+ if (!diff) return this;
+
+ (*ioDiff)++;
+ auto substSubst = new ThisTypeSubstitution();
+ substSubst->sourceType = newSourceType;
+ substSubst->outer = outerSubst;
+ return substSubst;
+ }
+
+ bool ThisTypeSubstitution::Equals(Substitutions* subst)
+ {
+ if (!subst)
+ return true;
+ if (subst && dynamic_cast<ThisTypeSubstitution*>(subst))
+ return true;
+ return false;
+ }
+
+
// DeclRefBase
@@ -1158,7 +1257,8 @@ void Type::accept(IValVisitor* visitor, void* extra)
{
if (decl != declRef.decl)
return false;
-
+ if (!substitutions)
+ return !declRef.substitutions || declRef.substitutions.As<ThisTypeSubstitution>();
if (!substitutions->Equals(declRef.substitutions.Ptr()))
return false;
@@ -1179,7 +1279,8 @@ void Type::accept(IValVisitor* visitor, void* extra)
if (auto parentGeneric = dynamic_cast<GenericDecl*>(parentDecl))
{
- if (substitutions && substitutions->genericDecl == parentDecl)
+ auto genSubst = substitutions.As<GenericSubstitution>();
+ if (genSubst && genSubst->genericDecl == parentDecl)
{
// We strip away the specializations that were applied to
// the parent, since we were asked for a reference *to* the parent.
@@ -1318,12 +1419,12 @@ void Type::accept(IValVisitor* visitor, void* extra)
Type* HLSLPatchType::getElementType()
{
- return this->declRef.substitutions->args[0].As<Type>().Ptr();
+ return this->declRef.substitutions.As<GenericSubstitution>()->args[0].As<Type>().Ptr();
}
IntVal* HLSLPatchType::getElementCount()
{
- return this->declRef.substitutions->args[1].As<IntVal>().Ptr();
+ return this->declRef.substitutions.As<GenericSubstitution>()->args[1].As<IntVal>().Ptr();
}
// Constructors for types
@@ -1469,4 +1570,77 @@ void Type::accept(IValVisitor* visitor, void* extra)
+ void insertSubstAtTop(DeclRefBase & declRef, RefPtr<Substitutions> substToInsert)
+ {
+ substToInsert->outer = declRef.substitutions;
+ declRef.substitutions = substToInsert;
+ }
+
+ RefPtr<ThisTypeSubstitution> getThisTypeSubst(DeclRefBase & declRef, bool insertSubstEntry)
+ {
+ RefPtr<ThisTypeSubstitution> thisSubst;
+ auto subst = declRef.substitutions;
+ while (subst)
+ {
+ if (auto s = subst.As<ThisTypeSubstitution>())
+ {
+ thisSubst = s;
+ break;
+ }
+ subst = subst->outer;
+ }
+ if (!thisSubst)
+ {
+ thisSubst = new ThisTypeSubstitution();
+ if (insertSubstEntry)
+ {
+ insertSubstAtTop(declRef, thisSubst);
+ }
+ }
+ return thisSubst;
+ }
+
+ RefPtr<ThisTypeSubstitution> getNewThisTypeSubst(DeclRefBase & declRef)
+ {
+ auto oldSubst = getThisTypeSubst(declRef, false);
+ if (oldSubst)
+ removeSubstitution(declRef, oldSubst);
+ return getThisTypeSubst(declRef, true);
+ }
+
+ void removeSubstitution(DeclRefBase & declRef, RefPtr<Substitutions> toRemove)
+ {
+ if (!declRef.substitutions)
+ return;
+ if (toRemove == declRef.substitutions)
+ {
+ declRef.substitutions = declRef.substitutions->outer;
+ return;
+ }
+ auto prev = declRef.substitutions;
+ auto subst = prev->outer;
+ while (subst)
+ {
+ if (subst == toRemove)
+ {
+ prev->outer = subst->outer;
+ break;
+ }
+ prev = subst;
+ subst = subst->outer;
+ }
+ }
+
+ bool hasGenericSubstitutions(RefPtr<Substitutions> subst)
+ {
+ auto p = subst.Ptr();
+ while (p)
+ {
+ if (dynamic_cast<GenericSubstitution*>(p))
+ return true;
+ p = p->outer.Ptr();
+ }
+ return false;
+ }
+
}
diff --git a/source/slang/syntax.h b/source/slang/syntax.h
index 0b5a38631..bda43b336 100644
--- a/source/slang/syntax.h
+++ b/source/slang/syntax.h
@@ -439,6 +439,7 @@ namespace Slang
// Apply substitutions to this declaration reference
DeclRefBase SubstituteImpl(Substitutions* subst, int* ioDiff);
+
// Check if this is an equivalent declaration reference to another
bool Equals(DeclRefBase const& declRef) const;
bool operator == (const DeclRefBase& other) const
@@ -1155,6 +1156,11 @@ namespace Slang
Session* session,
Decl* decl);
+ RefPtr<ThisTypeSubstitution> getNewThisTypeSubst(DeclRefBase & declRef);
+ RefPtr<ThisTypeSubstitution> getThisTypeSubst(DeclRefBase & declRef, bool insertSubstEntry);
+ void removeSubstitution(DeclRefBase & declRef, RefPtr<Substitutions> subst);
+ bool hasGenericSubstitutions(RefPtr<Substitutions> subst);
+
} // namespace Slang
#endif \ No newline at end of file
diff --git a/source/slang/type-defs.h b/source/slang/type-defs.h
index 2010d07b4..60f519c82 100644
--- a/source/slang/type-defs.h
+++ b/source/slang/type-defs.h
@@ -449,7 +449,6 @@ SYNTAX_CLASS(FuncType, Type)
FIELD(List<RefPtr<Type>>, paramTypes)
FIELD(RefPtr<Type>, resultType)
-
RAW(
FuncType()
{}
@@ -490,4 +489,4 @@ protected:
virtual int GetHashCode() override;
virtual Type* CreateCanonicalType() override;
)
-END_SYNTAX_CLASS()
+END_SYNTAX_CLASS() \ No newline at end of file
diff --git a/tests/compute/assoctype-complex.slang b/tests/compute/assoctype-complex.slang
new file mode 100644
index 000000000..fa7fc3b0f
--- /dev/null
+++ b/tests/compute/assoctype-complex.slang
@@ -0,0 +1,50 @@
+//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
+
+RWStructuredBuffer<int> outputBuffer;
+interface IBase
+{
+ associatedtype V;
+ V sub(V a0, V a1);
+}
+interface ISimple
+{
+ associatedtype U : IBase;
+ U.V add(U v0, U v1);
+}
+
+struct Val : IBase
+{
+ typedef int V;
+ int base;
+ V sub(V a0, V a1)
+ {
+ return a0 - a1 + base;
+ }
+};
+
+struct Simple : ISimple
+{
+ typedef Val U;
+ Val.V add(U v0, U v1)
+ {
+ return v0.sub(4, v1.sub(1,2));
+ }
+};
+
+__generic<T:ISimple>
+T.U.V test(T simple, T.U v0, T.U v1)
+{
+ return simple.add(v0, v1);
+}
+
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ Simple s;
+ Val v0, v1;
+ v0.base = 1;
+ v1.base = 2;
+ int outVal = test<Simple>(s, v0, v1); // == 4.0
+ outputBuffer[dispatchThreadID.x] = outVal;
+} \ No newline at end of file
diff --git a/tests/compute/assoctype-complex.slang.expected.txt b/tests/compute/assoctype-complex.slang.expected.txt
new file mode 100644
index 000000000..e43ad329a
--- /dev/null
+++ b/tests/compute/assoctype-complex.slang.expected.txt
@@ -0,0 +1,4 @@
+4
+4
+4
+4 \ No newline at end of file
diff --git a/tests/compute/assoctype-simple.slang b/tests/compute/assoctype-simple.slang
new file mode 100644
index 000000000..0f160c9c0
--- /dev/null
+++ b/tests/compute/assoctype-simple.slang
@@ -0,0 +1,35 @@
+//TEST(smoke,compute):COMPARE_COMPUTE:-xslang -use-ir
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
+// Confirm that generics syntax can be used in user
+// code and generates valid output.
+
+RWStructuredBuffer<float> outputBuffer;
+
+interface ISimple
+{
+ associatedtype U;
+ U add(U v0, U v1);
+}
+
+struct Simple : ISimple
+{
+ typedef float U;
+ U add(U v0, float v1)
+ {
+ return v0 + v1;
+ }
+};
+
+__generic<T:ISimple>
+T.U test(T simple, T.U v0, T.U v1)
+{
+ return simple.add(v0, v1);
+}
+
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ Simple s;
+ float outVal = test<Simple>(s, 2.0, 1.0); // == 3.0
+ outputBuffer[dispatchThreadID.x] = outVal;
+} \ No newline at end of file
diff --git a/tests/compute/assoctype-simple.slang.expected.txt b/tests/compute/assoctype-simple.slang.expected.txt
new file mode 100644
index 000000000..e54af3bc8
--- /dev/null
+++ b/tests/compute/assoctype-simple.slang.expected.txt
@@ -0,0 +1,4 @@
+40400000
+40400000
+40400000
+40400000
diff --git a/tests/compute/explicit-this-expr.slang b/tests/compute/explicit-this-expr.slang
index 7bd8dff99..59ce64ed5 100644
--- a/tests/compute/explicit-this-expr.slang
+++ b/tests/compute/explicit-this-expr.slang
@@ -1,4 +1,4 @@
-//TEST(smoke,compute):COMPARE_COMPUTE:-xslang -use-ir
+//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
// Access fields of a `struct` type from within a "method" by
diff --git a/tests/compute/generics-constructor.slang b/tests/compute/generics-constructor.slang
new file mode 100644
index 000000000..47dc0272a
--- /dev/null
+++ b/tests/compute/generics-constructor.slang
@@ -0,0 +1,17 @@
+//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
+
+RWStructuredBuffer<float> outputBuffer;
+
+__generic<T:__BuiltinFloatingPointType>
+T test(T v0, T v1)
+{
+ return T(3.0);
+}
+
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ float outVal = test<float>(1.0, 2.0);
+ outputBuffer[dispatchThreadID.x] = outVal;
+} \ No newline at end of file
diff --git a/tests/compute/generics-constructor.slang.expected.txt b/tests/compute/generics-constructor.slang.expected.txt
new file mode 100644
index 000000000..e54af3bc8
--- /dev/null
+++ b/tests/compute/generics-constructor.slang.expected.txt
@@ -0,0 +1,4 @@
+40400000
+40400000
+40400000
+40400000
diff --git a/tests/compute/implicit-this-expr.slang b/tests/compute/implicit-this-expr.slang
index 339c5fb6a..32cbd88fc 100644
--- a/tests/compute/implicit-this-expr.slang
+++ b/tests/compute/implicit-this-expr.slang
@@ -1,4 +1,4 @@
-//TEST(smoke,compute):COMPARE_COMPUTE:-xslang -use-ir
+//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
// Access fields of a `struct` type from within a "method" by
diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp
index 65d66f812..c5c3f68b8 100644
--- a/tools/render-test/render-d3d11.cpp
+++ b/tools/render-test/render-d3d11.cpp
@@ -714,7 +714,8 @@ public:
if (request.computeShader.name)
{
auto dxComputeShaderBlob = compileHLSLShader(request.computeShader.source.path, request.computeShader.source.text, request.computeShader.name, request.computeShader.profile);
- if (!dxComputeShaderBlob) return nullptr;
+ if (!dxComputeShaderBlob)
+ return nullptr;
ID3D11ComputeShader* dxComputeShader;
diff --git a/tools/slang-test/main.cpp b/tools/slang-test/main.cpp
index 7cfa981ae..cb1730c6e 100644
--- a/tools/slang-test/main.cpp
+++ b/tools/slang-test/main.cpp
@@ -1137,6 +1137,7 @@ TestResult runComputeComparisonImpl(TestInput& input, const char * langOption, S
spawner.pushArgument("-o");
auto actualOutputFile = outputStem + ".actual.txt";
spawner.pushArgument(actualOutputFile);
+ spawner.pushArgument("-xslang -use-ir");
// clear the stale actual output file first. This will allow us to detect error if render-test fails and outputs nothing.
File::WriteAllText(actualOutputFile, "");
@@ -1183,8 +1184,8 @@ TestResult runComputeComparisonImpl(TestInput& input, const char * langOption, S
}
for (int i = 0; i < (int)referenceProgramOutput.Count(); i++)
{
- auto reference = referenceProgramOutput[i];
- auto actual = actualProgramOutput[i];
+ auto reference = String(referenceProgramOutput[i].Trim());
+ auto actual = String(actualProgramOutput[i].Trim());
if (actual != reference)
{
// try to parse reference as float, and compare again