From 7f7864e80e8b5631ba5ec1aa9657fdaf1b4adb06 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Wed, 21 Jun 2017 10:43:25 -0700 Subject: Support texture `Gather*()` operations The catch with these operations is that they return a vector based on the scalar of the element type of the texture. That is, given `Texture2D t` the operation `t.GatherRed(...)` should return a `float4`. The ideal way to solve this would use associated types, but we aren't there yet, so I am using extension declarations. An extension can "capture" the identity of the element type, like so: __generic __extension Texture2D > { ... } That extension will match `Texture2D` and correctly capture `T == float`, so that we can use it in other operations. Getting this working required a bunch of changes: - Actually emit the relevant extension declarations in the stdlib - Fix the parser to be able to parse `Texture2D >` (that is, a nested generic app). - I actually went ahead and significantly overhauled the expression parser while I was there, because I just couldn't deal with the existing code any longer. - Added support for general-case lookup to look through `__extension` declarations. I had logic in place to special-case this for looking up "constructors" but hadn't done anything for general member lookup yet. - This required some annoying holes to be punched through the layers, because lookup might need to invoke semantic analysis to ensure that an extension has been checked. - There is some first-pass code trying to support looking up a `typedef` nested inside the `vector` type. This is a nice idea in principle, but the problem is that the `Texture2D` definition would be looking up `T.Element` and not `float4.Element`, and that means we'd need machinery for doing lookup *through* interface conformances for a type parameter like `T` The big gotcha here is that none of this logic applies to `Texture2D` (the original case I mentioned) because I am matching vector types and not scalars. Matching scalars *should* be as easy as: __generic __extension Texture2D { ... } But I'd need to confirm that interface constraints like that actually work, or else that extension would *also* apply to `Texture2D` and break everything. --- source/slang/lookup.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 6 deletions(-) (limited to 'source/slang/lookup.cpp') diff --git a/source/slang/lookup.cpp b/source/slang/lookup.cpp index e9c2177de..f5e472ec5 100644 --- a/source/slang/lookup.cpp +++ b/source/slang/lookup.cpp @@ -5,6 +5,14 @@ namespace Slang { // +DeclRef ApplyExtensionToType( + SemanticsVisitor* semantics, + ExtensionDecl* extDecl, + RefPtr type); + +// + + // Helper for constructing breadcrumb trails during lookup, without unnecessary heap allocaiton struct BreadcrumbInfo { @@ -190,7 +198,7 @@ void DoMemberLookupImpl( // Look for members of the given name in the given container for declarations void DoLocalLookupImpl( String const& name, - DeclRef containerDeclRef, + DeclRef containerDeclRef, LookupRequest const& request, LookupResult& result, BreadcrumbInfo* inBreadcrumbs) @@ -241,7 +249,24 @@ void DoLocalLookupImpl( DoMemberLookupImpl(name, transparentMemberDeclRef, request, result, &memberRefBreadcrumb); } - // TODO(tfoley): need to consider lookup via extension here? + // Consider lookup via extension + if( auto aggTypeDeclRef = containerDeclRef.As() ) + { + RefPtr type = DeclRefType::Create(aggTypeDeclRef); + + for (auto ext = GetCandidateExtensions(aggTypeDeclRef); ext; ext = ext->nextCandidateExtension) + { + auto extDeclRef = ApplyExtensionToType(request.semantics, ext, type); + if (!extDeclRef) + continue; + + // TODO: eventually we need to insert a breadcrumb here so that + // the constructed result can somehow indicate that a member + // was found through an extension. + + DoLocalLookupImpl(name, extDeclRef, request, result, inBreadcrumbs); + } + } } void DoLookupImpl( @@ -258,10 +283,34 @@ void DoLookupImpl( // also finding a hit in another for(auto link = scope; link; link = link->nextSibling) { - if(!link->containerDecl) + auto containerDecl = link->containerDecl; + + if(!containerDecl) continue; - DeclRef containerRef = DeclRef(link->containerDecl, nullptr).As(); + // If the container is a generic, then we need to instantiate it + // at the parameters themselves, so provide a fully-resolved + // declaration reference for lookup. + RefPtr subst = nullptr; + if(auto parentGenericDecl = dynamic_cast(containerDecl->ParentDecl)) + { + subst = new Substitutions(); + subst->genericDecl = parentGenericDecl; + + for( auto pp : parentGenericDecl->Members ) + { + if( auto genericTypeParam = pp.As() ) + { + subst->args.Add(DeclRefType::Create(DeclRef(genericTypeParam.Ptr(), nullptr))); + } + else if( auto genericValParam = pp.As() ) + { + subst->args.Add(new GenericParamIntVal(DeclRef(genericValParam.Ptr(), nullptr))); + } + } + } + + DeclRef containerRef = DeclRef(containerDecl, subst).As(); DoLocalLookupImpl(name, containerRef, request, result, nullptr); } @@ -283,18 +332,27 @@ LookupResult DoLookup(String const& name, LookupRequest const& request) return result; } -LookupResult LookUp(String const& name, RefPtr scope) +LookupResult LookUp( + SemanticsVisitor* semantics, + String const& name, + RefPtr scope) { LookupRequest request; + request.semantics = semantics; request.scope = scope; return DoLookup(name, request); } // perform lookup within the context of a particular container declaration, // and do *not* look further up the chain -LookupResult LookUpLocal(String const& name, DeclRef containerDeclRef) +LookupResult LookUpLocal( + SemanticsVisitor* semantics, + String const& name, + DeclRef containerDeclRef) { LookupRequest request; + request.semantics = semantics; + LookupResult result; DoLocalLookupImpl(name, containerDeclRef, request, result, nullptr); return result; -- cgit v1.2.3