From 4aac22da6ae902eca1e7750f4e5b83ba238b5874 Mon Sep 17 00:00:00 2001 From: Sai Praveen Bangaru <31557731+saipraveenb25@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:47:05 -0400 Subject: Add ability to specialize generic references to functions, types and more (#4909) * More reflection API features. + Lookup methods and members (by string) on types + Fix issue with looking up non-static members through the scope operator '::' + `GenericReflection`: Cast a decl to generic to access unspecialized generic parameter names and constraints + `GenericReflection`: Use `getGenericContainer()` from function, variable or type to access the 'nearest' generic parent along with specialization info + `GenericReflection::getConcreteType` and `GenericReflection::getConcreteIntVal`: to get the concrete type of a param in the context of the reflection object + `GenericReflection::getOuterGenericContainer` to go up one level and get the outer generic declarations (if there are more than one enclosing generic scopes) + `DeclReflection::getParent`: go to parent declaration. + Change `VariableReflection` to be a `DeclRef` rather than a decl (allows us to return properly substituted types for methods, members, and more) * Fix Falcor issue * Initial namespace reflection support * FIx issue with specializing witness tables * Add API method for specializing parameters of a generic decl * Add ability to specialize generic references to functions, types and more This PR adds the following end-points: - `specializeGeneric()` method that can be called on a generic reflection to substitute arguments for generic type and value parameters. It returns another generic reflection, but this time with the appropriate substitution. - `applySpecializations()` method to then copy these specializations onto an existing type or function reflection. - `isSubType()` to check if a type is a subtype of another type (useful to check if a type is differentiable by checking `IDifferentiable`) This PR also: - Adds `DeclReflection::Kind::Namespace` so that namespace containers are correctly reflected when walking the decl-tree. the name can be obtained through `getName()` but there's no need to cast to a namespace (since there's nothing else we can do with a namespace decl) - Fixes an issue with name-based lookups that fail if a type or function is referenced without specializations. Its helpful to be able to form a reference to a function with default substitutions, so that we can we can specialize it later (either directly, or via argument types). * Update slang.h * Fix up naming * Update slang-compiler.h * Update slang-reflection-api.cpp * Update slang.cpp * Update slang.cpp * Update slang.cpp * Use `checkGenericAppWithCheckedArgs` to do specialization * Update slang-reflection-api.cpp * Update slang-check-decl.cpp --- source/slang/slang.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'source/slang/slang.cpp') diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 3072ef0a7..aa114e44d 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -1348,6 +1348,43 @@ SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL Linkage::specializeType( return asExternal(specializedType); } + +DeclRef Linkage::specializeGeneric( + DeclRef declRef, + List argExprs, + DiagnosticSink* sink) +{ + SLANG_AST_BUILDER_RAII(getASTBuilder()); + SLANG_ASSERT(declRef); + + SharedSemanticsContext sharedSemanticsContext(this, nullptr, sink); + SemanticsVisitor visitor(&sharedSemanticsContext); + + // Create substituted parent decl ref. + auto decl = declRef.getDecl(); + + while (!as(decl)) + { + decl = decl->parentDecl; + } + + auto genericDecl = as(decl); + auto genericDeclRef = createDefaultSubstitutionsIfNeeded(getASTBuilder(), &visitor, DeclRef(genericDecl)).as(); + genericDeclRef = substituteDeclRef(SubstitutionSet(declRef), getASTBuilder(), genericDeclRef).as(); + + + DeclRefExpr* declRefExpr = getASTBuilder()->create(); + declRefExpr->declRef = genericDeclRef; + + GenericAppExpr* genericAppExpr = getASTBuilder()->create(); + genericAppExpr->functionExpr = declRefExpr; + genericAppExpr->arguments = argExprs; + + auto specializedDeclRef = as(visitor.checkGenericAppWithCheckedArgs(genericAppExpr))->declRef; + + return specializedDeclRef; +} + SLANG_NO_THROW slang::TypeLayoutReflection* SLANG_MCALL Linkage::getTypeLayout( slang::TypeReflection* inType, SlangInt targetIndex, @@ -2373,9 +2410,28 @@ DeclRef ComponentType::findDeclFromStringInType( result = declRefExpr->declRef; } + if (auto genericDeclRef = result.as()) + { + result = createDefaultSubstitutionsIfNeeded( + astBuilder, &visitor, DeclRef(genericDeclRef.getDecl()->inner)); + result = substituteDeclRef(SubstitutionSet(genericDeclRef), astBuilder, result); + } + return result; } +bool ComponentType::isSubType(Type* subType, Type* superType) +{ + SharedSemanticsContext sharedSemanticsContext( + getLinkage(), + nullptr, + nullptr); + SemanticsContext context(&sharedSemanticsContext); + SemanticsVisitor visitor(context); + + return (visitor.isSubtype(subType, superType, IsSubTypeOptions::None) != nullptr); +} + static void collectExportedConstantInContainer( Dictionary& dict, ASTBuilder* builder, @@ -6805,4 +6861,4 @@ SlangResult EndToEndCompileRequest::isParameterLocationUsed(Int entryPointIndex, return SLANG_OK; } -} // namespace Slang +} // namespace Slang \ No newline at end of file -- cgit v1.2.3