diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-06-21 10:43:25 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-06-21 11:59:51 -0700 |
| commit | 7f7864e80e8b5631ba5ec1aa9657fdaf1b4adb06 (patch) | |
| tree | a9d0bc921e9ead73e5ec9491c4f3925c041cdbf5 /source/slang/check.cpp | |
| parent | 5148c594c19da9466b151ab3b6b11441f265823e (diff) | |
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<float> 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<T, let N : int> __extension Texture2D<vector<T,N> > { ... }
That extension will match `Texture2D<float3>` 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<vector<T,N> >` (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<T>` 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<float>` (the original case I mentioned) because I am matching vector types and not scalars.
Matching scalars *should* be as easy as:
__generic<T : __BuitlinScalarType> __extension Texture2D<T> { ... }
But I'd need to confirm that interface constraints like that actually work, or else that extension would *also* apply to `Texture2D<float4>` and break everything.
Diffstat (limited to 'source/slang/check.cpp')
| -rw-r--r-- | source/slang/check.cpp | 132 |
1 files changed, 46 insertions, 86 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 5a82380d3..463052bc8 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -2269,7 +2269,7 @@ namespace Slang // Note(tfoley): The name used for lookup here is a bit magical, since // it must match what the parser installed in subscript declarations. - LookupResult lookupResult = LookUpLocal("operator[]", aggTypeDeclRef); + LookupResult lookupResult = LookUpLocal(this, "operator[]", aggTypeDeclRef); if (!lookupResult.isValid()) { goto fail; @@ -4552,7 +4552,7 @@ namespace Slang expr->Type = ExpressionType::Error; - auto lookupResult = LookUp(expr->name, expr->scope); + auto lookupResult = LookUp(this, expr->name, expr->scope); if (lookupResult.isValid()) { return createLookupResultExpr( @@ -4795,6 +4795,38 @@ namespace Slang baseScalarType, 1); } + else if(auto typeType = baseType->As<TypeType>()) + { + // We are looking up a member inside a type. + // We want to be careful here because we should only find members + // that are implicitly or explicitly `static`. + // + // TODO: this duplicates a *lot* of logic with the case below. + // We need to fix that. + auto type = typeType->type; + if(auto declRefType = type->AsDeclRefType()) + { + if (auto aggTypeDeclRef = declRefType->declRef.As<AggTypeDecl>()) + { + // Checking of the type must be complete before we can reference its members safely + EnsureDecl(aggTypeDeclRef.getDecl(), DeclCheckState::Checked); + + LookupResult lookupResult = LookUpLocal(this, expr->name, aggTypeDeclRef); + if (!lookupResult.isValid()) + { + goto fail; + } + + // TODO: need to filter for declarations that are valid to refer + // to in this context... + + return createLookupResultExpr( + lookupResult, + expr->BaseExpression, + expr); + } + } + } else if (auto declRefType = baseType->AsDeclRefType()) { if (auto aggTypeDeclRef = declRefType->declRef.As<AggTypeDecl>()) @@ -4802,8 +4834,7 @@ namespace Slang // Checking of the type must be complete before we can reference its members safely EnsureDecl(aggTypeDeclRef.getDecl(), DeclCheckState::Checked); - - LookupResult lookupResult = LookUpLocal(expr->name, aggTypeDeclRef); + LookupResult lookupResult = LookUpLocal(this, expr->name, aggTypeDeclRef); if (!lookupResult.isValid()) { goto fail; @@ -4813,88 +4844,6 @@ namespace Slang lookupResult, expr->BaseExpression, expr); -#if 0 - DeclRef<Decl> memberDeclRef(lookupResult.decl, aggTypeDeclRef.substitutions); - return ConstructDeclRefExpr(memberDeclRef, expr->BaseExpression, expr); -#endif - -#if 0 - - - // TODO(tfoley): It is unfortunate that the lookup strategy - // here isn't unified with the ordinary `Scope` case. - // In particular, if we add support for "transparent" declarations, - // etc. here then we would need to add them in ordinary lookup - // as well. - - Decl* memberDecl = nullptr; // The first declaration we found, if any - Decl* secondDecl = nullptr; // Another declaration with the same name, if any - for (auto m : aggTypeDeclRef.GetMembers()) - { - if (m.GetName() != expr->MemberName) - continue; - - if (!memberDecl) - { - memberDecl = m.getDecl(); - } - else - { - secondDecl = m.getDecl(); - break; - } - } - - // If we didn't find any member, then we signal an error - if (!memberDecl) - { - expr->Type = ExpressionType::Error; - getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->MemberName, baseType); - return expr; - } - - // If we found only a single member, then we are fine - if (!secondDecl) - { - // TODO: need to - DeclRef<Decl> memberDeclRef(memberDecl, aggTypeDeclRef.substitutions); - - expr->declRef = memberDeclRef; - expr->Type = GetTypeForDeclRef(memberDeclRef); - - // When referencing a member variable, the result is an l-value - // if and only if the base expression was. - if (auto memberVarDecl = dynamic_cast<VarDeclBase*>(memberDecl)) - { - expr->Type.IsLeftValue = expr->BaseExpression->Type.IsLeftValue; - } - return expr; - } - - // We found multiple members with the same name, and need - // to resolve the embiguity at some point... - expr->Type = ExpressionType::Error; - getSink()->diagnose(expr, Diagnostics::unimplemented, "ambiguous member reference"); - return expr; - -#endif - -#if 0 - - StructField* field = structDecl->FindField(expr->MemberName); - if (!field) - { - expr->Type = ExpressionType::Error; - getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->MemberName, baseType); - } - else - expr->Type = field->Type; - - // A reference to a struct member is an l-value if the reference to the struct - // value was also an l-value. - expr->Type.IsLeftValue = expr->BaseExpression->Type.IsLeftValue; - return expr; -#endif } // catch-all @@ -5048,4 +4997,15 @@ namespace Slang return getTypeForDeclRef(nullptr, nullptr, declRef, &typeResult); } + DeclRef<ExtensionDecl> ApplyExtensionToType( + SemanticsVisitor* semantics, + ExtensionDecl* extDecl, + RefPtr<ExpressionType> type) + { + if(!semantics) + return DeclRef<ExtensionDecl>(); + + return semantics->ApplyExtensionToType(extDecl, type); + } + } |
