summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-03-06 20:16:20 -0500
committerTim Foley <tfoleyNV@users.noreply.github.com>2019-03-06 17:16:20 -0800
commitc850ba44164ac2bee895137abdd184beb4123090 (patch)
treef6e42ce5998038a1162e95c2a879bb7b06d0573f /source
parent87610f6def3e3dceac0082c1b60abbe2aee09014 (diff)
* Add support for enum and type lookup via :: (scope operator) (#882)
* Added test for scope operator
Diffstat (limited to 'source')
-rw-r--r--source/slang/check.cpp162
-rw-r--r--source/slang/parser.cpp29
2 files changed, 126 insertions, 65 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 37c0d5baf..91bbd694a 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -8843,63 +8843,14 @@ namespace Slang
}
}
- RefPtr<Expr> visitStaticMemberExpr(StaticMemberExpr* /*expr*/)
+ // Look up a static member
+ // @param expr Can be StaticMemberExpr or MemberExpr
+ // @param baseExpression Is the underlying type expression determined from resolving expr
+ RefPtr<Expr> _lookupStaticMember(RefPtr<DeclRefExpr> expr, RefPtr<Expr> baseExpression)
{
- // StaticMemberExpr means it is already checked
- SLANG_UNEXPECTED("should not occur in unchecked AST");
- UNREACHABLE_RETURN(nullptr);
- }
-
- RefPtr<Expr> lookupResultFailure(
- MemberExpr* expr,
- QualType const& baseType)
- {
- getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->name, baseType);
- expr->type = QualType(getSession()->getErrorType());
- return expr;
-
- }
-
- RefPtr<Expr> visitMemberExpr(MemberExpr * expr)
- {
- expr->BaseExpression = CheckExpr(expr->BaseExpression);
-
- expr->BaseExpression = MaybeDereference(expr->BaseExpression);
+ auto& baseType = baseExpression->type;
- // If the base of the member lookup has an interface type
- // *without* a suitable this-type substitution, then we are
- // trying to perform lookup on a value of existential type,
- // and we should "open" the existential here so that we
- // can expose its structure.
- //
- expr->BaseExpression = maybeOpenExistential(expr->BaseExpression);
-
- auto & baseType = expr->BaseExpression->type;
-
- // Note: Checking for vector types before declaration-reference types,
- // because vectors are also declaration reference types...
- //
- // Also note: the way this is done right now means that the ability
- // to swizzle vectors interferes with any chance of looking up
- // members via extension, for vector or scalar types.
- //
- // TODO: Matrix swizzles probably need to be handled at some point.
- if (auto baseVecType = as<VectorExpressionType>(baseType))
- {
- return CheckSwizzleExpr(
- expr,
- baseVecType->elementType,
- baseVecType->elementCount);
- }
- else if(auto baseScalarType = as<BasicExpressionType>(baseType))
- {
- // Treat scalar like a 1-element vector when swizzling
- return CheckSwizzleExpr(
- expr,
- baseScalarType,
- 1);
- }
- else if(auto typeType = as<TypeType>(baseType))
+ if (auto typeType = as<TypeType>(baseType))
{
// We are looking up a member inside a type.
// We want to be careful here because we should only find members
@@ -8921,7 +8872,7 @@ namespace Slang
type);
if (!lookupResult.isValid())
{
- return lookupResultFailure(expr, baseType);
+ return lookupMemberResultFailure(expr, baseType);
}
// We need to confirm that whatever member we
@@ -8947,13 +8898,13 @@ namespace Slang
// For now let's just be expedient and disallow all of that, because
// we can always add it back in later.
- if(!lookupResult.isOverloaded())
+ if (!lookupResult.isOverloaded())
{
// The non-overloaded case is relatively easy. We just want
// to look at the member being referenced, and check if
// it is allowed in a `static` context:
//
- if(!isUsableAsStaticMember(lookupResult.item))
+ if (!isUsableAsStaticMember(lookupResult.item))
{
getSink()->diagnose(
expr->loc,
@@ -8972,10 +8923,10 @@ namespace Slang
// are non-static.
bool anyNonStatic = false;
List<LookupResultItem> staticItems;
- for(auto item : lookupResult.items)
+ for (auto item : lookupResult.items)
{
// Is this item usable as a static member?
- if(isUsableAsStaticMember(item))
+ if (isUsableAsStaticMember(item))
{
// If yes, then it will be part of the output.
staticItems.Add(item);
@@ -8988,11 +8939,11 @@ namespace Slang
}
// Was there anything non-static in the list?
- if(anyNonStatic)
+ if (anyNonStatic)
{
// If we had some static items, then that's okay,
// we just want to use our newly-filtered list.
- if(staticItems.Count())
+ if (staticItems.Count())
{
lookupResult.items = staticItems;
}
@@ -9012,13 +8963,96 @@ namespace Slang
return createLookupResultExpr(
lookupResult,
- expr->BaseExpression,
+ baseExpression,
expr->loc);
}
else if (as<ErrorType>(baseType))
{
return CreateErrorExpr(expr);
}
+
+ // Failure
+ return lookupMemberResultFailure(expr, baseType);
+ }
+
+ RefPtr<Expr> visitStaticMemberExpr(StaticMemberExpr* expr)
+ {
+ expr->BaseExpression = CheckExpr(expr->BaseExpression);
+
+ // Not sure this is needed -> but guess someone could do
+ expr->BaseExpression = MaybeDereference(expr->BaseExpression);
+
+ // If the base of the member lookup has an interface type
+ // *without* a suitable this-type substitution, then we are
+ // trying to perform lookup on a value of existential type,
+ // and we should "open" the existential here so that we
+ // can expose its structure.
+ //
+
+ expr->BaseExpression = maybeOpenExistential(expr->BaseExpression);
+ // Do a static lookup
+ return _lookupStaticMember(expr, expr->BaseExpression);
+ }
+
+ RefPtr<Expr> lookupMemberResultFailure(
+ DeclRefExpr* expr,
+ QualType const& baseType)
+ {
+ // Check it's a member expression
+ SLANG_ASSERT(as<StaticMemberExpr>(expr) || as<MemberExpr>(expr));
+
+ getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->name, baseType);
+ expr->type = QualType(getSession()->getErrorType());
+ return expr;
+ }
+
+ RefPtr<Expr> visitMemberExpr(MemberExpr * expr)
+ {
+ expr->BaseExpression = CheckExpr(expr->BaseExpression);
+
+ expr->BaseExpression = MaybeDereference(expr->BaseExpression);
+
+ // If the base of the member lookup has an interface type
+ // *without* a suitable this-type substitution, then we are
+ // trying to perform lookup on a value of existential type,
+ // and we should "open" the existential here so that we
+ // can expose its structure.
+ //
+ expr->BaseExpression = maybeOpenExistential(expr->BaseExpression);
+
+ auto & baseType = expr->BaseExpression->type;
+
+ // Note: Checking for vector types before declaration-reference types,
+ // because vectors are also declaration reference types...
+ //
+ // Also note: the way this is done right now means that the ability
+ // to swizzle vectors interferes with any chance of looking up
+ // members via extension, for vector or scalar types.
+ //
+ // TODO: Matrix swizzles probably need to be handled at some point.
+ if (auto baseVecType = as<VectorExpressionType>(baseType))
+ {
+ return CheckSwizzleExpr(
+ expr,
+ baseVecType->elementType,
+ baseVecType->elementCount);
+ }
+ else if(auto baseScalarType = as<BasicExpressionType>(baseType))
+ {
+ // Treat scalar like a 1-element vector when swizzling
+ return CheckSwizzleExpr(
+ expr,
+ baseScalarType,
+ 1);
+ }
+ else if(auto typeType = as<TypeType>(baseType))
+ {
+ return _lookupStaticMember(expr, expr->BaseExpression);
+ }
+ else if (as<ErrorType>(baseType))
+ {
+ return CreateErrorExpr(expr);
+ }
else
{
LookupResult lookupResult = lookUpMember(
@@ -9028,7 +9062,7 @@ namespace Slang
baseType.Ptr());
if (!lookupResult.isValid())
{
- return lookupResultFailure(expr, baseType);
+ return lookupMemberResultFailure(expr, baseType);
}
// TODO: need to filter for declarations that are valid to refer
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index a7ccb7b8a..5cb712489 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -1738,8 +1738,10 @@ namespace Slang
}
static RefPtr<Expr> parseMemberType(Parser * parser, RefPtr<Expr> base)
{
+ // When called the :: or . have been consumed, so don't need to consume here.
+
RefPtr<MemberExpr> memberExpr = new MemberExpr();
- parser->ReadToken(TokenType::Dot);
+
parser->FillPosition(memberExpr.Ptr());
memberExpr->BaseExpression = base;
memberExpr->name = expectIdentifier(parser).name;
@@ -1853,7 +1855,12 @@ namespace Slang
case TokenType::OpLess:
typeExpr = parseGenericApp(parser, typeExpr);
break;
+ case TokenType::Scope:
+ parser->ReadToken(TokenType::Scope);
+ typeExpr = parseMemberType(parser, typeExpr);
+ break;
case TokenType::Dot:
+ parser->ReadToken(TokenType::Dot);
typeExpr = parseMemberType(parser, typeExpr);
break;
default:
@@ -4192,6 +4199,26 @@ namespace Slang
}
break;
+ // Scope access `x::m`
+ case TokenType::Scope:
+ {
+ RefPtr<StaticMemberExpr> staticMemberExpr = new StaticMemberExpr();
+
+ // TODO(tfoley): why would a member expression need this?
+ staticMemberExpr->scope = parser->currentScope.Ptr();
+
+ parser->FillPosition(staticMemberExpr.Ptr());
+ staticMemberExpr->BaseExpression = expr;
+ parser->ReadToken(TokenType::Scope);
+ staticMemberExpr->name = expectIdentifier(parser).name;
+
+ if (peekTokenType(parser) == TokenType::OpLess)
+ expr = maybeParseGenericApp(parser, staticMemberExpr);
+ else
+ expr = staticMemberExpr;
+
+ break;
+ }
// Member access `x.m`
case TokenType::Dot:
{