summaryrefslogtreecommitdiffstats
path: root/source/slang/check.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-06-21 10:43:25 -0700
committerTim Foley <tfoley@nvidia.com>2017-06-21 11:59:51 -0700
commit7f7864e80e8b5631ba5ec1aa9657fdaf1b4adb06 (patch)
treea9d0bc921e9ead73e5ec9491c4f3925c041cdbf5 /source/slang/check.cpp
parent5148c594c19da9466b151ab3b6b11441f265823e (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.cpp132
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);
+ }
+
}