Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to specialize generic references to functions, types and more #4909

Merged
merged 29 commits into from
Aug 27, 2024

Conversation

saipraveenb25
Copy link
Collaborator

@saipraveenb25 saipraveenb25 commented Aug 23, 2024

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).

Fixes: #4787, #4800

saipraveenb25 and others added 14 commits July 24, 2024 22:47
+ 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)
…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).
include/slang.h Outdated
SlangReflectionGenericArg const* args,
ISlangBlob** outDiagnostics);

SLANG_API bool spReflection_IsSubType(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isSubType

include/slang.h Outdated
return (GenericReflection*)spReflectionGeneric_applySpecializations((SlangReflectionGeneric*)this, (SlangReflectionGeneric*)generic);
}

/*GenericReflection* specializeGenericTypeParameter(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete?

@@ -7119,6 +7119,99 @@ namespace Slang

return args;
}

SubstitutionSet makeSubstitutionFromIncompleteSet(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can call SemanticsVisitor::inferGenericArguments, which implement the same logic. Let's try not duplicate the logic here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this specific function is different from inferGenericArguments. We want to use it for specializeGeneric which operates on struct types as well as callables, where we are provided specific argument substitutions for the generic parameters directly (not the arg types of the callables).

I plan on providing a separate function FunctionReflection::specializeWithArgTypes(...) that will invoke inferGenericArguments directly.

Alternatively, I can change up inferGenericArguments to also support struct types. With generic interfaces, we probably need to enforce constraints across the arguments of the same generic.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inferGenericArguments is not only for function calls but for types as well.

Basically if you have S<T:IFoo, int N = 4> and you pass in S<FooImpl>, inferGenericArguments will give you S<FooImpl, 4, FooImpl : IFoo>.

Copy link
Collaborator

@csyonghe csyonghe Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess for here, you want to reuse or factor out checkGenericAppWithCheckedArgs, which eventually will call into inferGenericArguments.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rerote this method with checkGenericAppWithCheckedArgs + added support for bool type args.

I think this is a good suggestion, since the new version should work seamlessly with variadics.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can delete this now?

@saipraveenb25 saipraveenb25 added pr: new feature pr: non-breaking PRs without breaking changes labels Aug 26, 2024
Copy link
Collaborator

@csyonghe csyonghe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but we need to remove makeSubstitutionFromIncompleteSet.

return result;
}

bool ComponentType::isSubType(Type* subType, Type* superType)
{
SharedSemanticsContext sharedSemanticsContext(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At somepoint it may make sense to hold a semantic visitor on the linkage, because it will become extensive to rebuild the type inheritance list for all referenced types everytime isSubType is called. These are cached on the semantic visitor and we should probably reuse it to speed up these reflection queries.

@saipraveenb25 saipraveenb25 merged commit 4aac22d into shader-slang:master Aug 27, 2024
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr: new feature pr: non-breaking PRs without breaking changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reflection API extensions: Support Namespaces
2 participants