summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-ast-expr.h6
-rw-r--r--source/slang/slang-check-expr.cpp24
-rw-r--r--source/slang/slang-check-impl.h2
-rw-r--r--source/slang/slang-diagnostic-defs.h1
-rw-r--r--source/slang/slang-language-server.cpp29
-rw-r--r--source/slang/slang-parser.cpp13
6 files changed, 56 insertions, 19 deletions
diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h
index 3331b288e..56ac83f80 100644
--- a/source/slang/slang-ast-expr.h
+++ b/source/slang/slang-ast-expr.h
@@ -238,6 +238,12 @@ class MemberExpr: public DeclRefExpr
SourceLoc memberOperatorLoc;
};
+// Member expression that is dereferenced, e.g. `a->b`.
+class DerefMemberExpr : public MemberExpr
+{
+ SLANG_AST_CLASS(DerefMemberExpr)
+};
+
// Member looked up on a type, rather than a value
class StaticMemberExpr: public DeclRefExpr
{
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index f238550fd..dc7a2d35b 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -1918,7 +1918,8 @@ namespace Slang
Expr* SemanticsExprVisitor::visitIndexExpr(IndexExpr* subscriptExpr)
{
- auto baseExpr = checkBaseForMemberExpr(subscriptExpr->baseExpression);
+ bool needDeref = false;
+ auto baseExpr = checkBaseForMemberExpr(subscriptExpr->baseExpression, needDeref);
// If the base expression is a type, it means that this is an array declaration,
// then we should disable short-circuit in case there is logical expression in
@@ -3833,13 +3834,18 @@ namespace Slang
return expr;
}
- Expr* SemanticsVisitor::checkBaseForMemberExpr(Expr* inBaseExpr)
+ Expr* SemanticsVisitor::checkBaseForMemberExpr(Expr* inBaseExpr, bool& outNeedDeref)
{
auto baseExpr = inBaseExpr;
baseExpr = CheckTerm(baseExpr);
- baseExpr = MaybeDereference(baseExpr);
+ auto derefExpr = MaybeDereference(baseExpr);
+
+ if (derefExpr != baseExpr)
+ outNeedDeref = true;
+
+ baseExpr = derefExpr;
// If the base of the member lookup has an interface type
// *without* a suitable this-type substitution, then we are
@@ -3889,7 +3895,17 @@ namespace Slang
Expr* SemanticsExprVisitor::visitMemberExpr(MemberExpr * expr)
{
- expr->baseExpression = checkBaseForMemberExpr(expr->baseExpression);
+ bool needDeref = false;
+ expr->baseExpression = checkBaseForMemberExpr(expr->baseExpression, needDeref);
+
+ if (!needDeref && as<DerefMemberExpr>(expr) && !as<PtrType>(expr->baseExpression->type))
+ {
+ // The user is trying to use the `->` operator on something that can't be
+ // dereferenced, so we should diagnose that.
+ if (!as<ErrorType>(expr->baseExpression->type))
+ getSink()->diagnose(expr->memberOperatorLoc, Diagnostics::cannotDereferenceType, expr->baseExpression->type);
+ }
+
auto baseType = expr->baseExpression->type;
// If we are looking up through a modified type, just pass straight
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index cff5b7028..b928a39f0 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -2505,7 +2505,7 @@ namespace Slang
Expr* visitStaticMemberExpr(StaticMemberExpr* expr);
/// Perform checking operations required for the "base" expression of a member-reference like `base.someField`
- Expr* checkBaseForMemberExpr(Expr* baseExpr);
+ Expr* checkBaseForMemberExpr(Expr* baseExpr, bool& outNeedDeref);
Expr* lookupMemberResultFailure(
DeclRefExpr* expr,
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 6299d6666..757ce94ee 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -327,6 +327,7 @@ DIAGNOSTIC(30068, Warning, mutatingMethodOnFunctionInputParameterWarning, "mutat
DIAGNOSTIC(30070, Error, unsizedMemberMustAppearLast, "unsized member can only appear as the last member in a composite type.")
DIAGNOSTIC(30100, Error, staticRefToNonStaticMember, "type '$0' cannot be used to refer to non-static member '$1'")
+DIAGNOSTIC(30101, Error, cannotDereferenceType, "cannot dereference type '$0', do you mean to use '.'?")
DIAGNOSTIC(30200, Error, redeclaration, "declaration of '$0' conflicts with existing declaration")
DIAGNOSTIC(30201, Error, functionRedefinition, "function '$0' already has a body")
diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp
index b8ebf8e08..9cfef50a0 100644
--- a/source/slang/slang-language-server.cpp
+++ b/source/slang/slang-language-server.cpp
@@ -125,6 +125,7 @@ SlangResult LanguageServer::parseNextMessage()
caps.documentOnTypeFormattingProvider.moreTriggerCharacter.add("{");
caps.documentRangeFormattingProvider = true;
caps.completionProvider.triggerCharacters.add(".");
+ caps.completionProvider.triggerCharacters.add(">");
caps.completionProvider.triggerCharacters.add(":");
caps.completionProvider.triggerCharacters.add("[");
caps.completionProvider.triggerCharacters.add(" ");
@@ -931,17 +932,25 @@ SlangResult LanguageServer::completion(
return SLANG_OK;
}
- // Don't show completion at case label.
+ // Don't show completion at case label or after single '>' operator.
if (args.context.triggerKind ==
- LanguageServerProtocol::kCompletionTriggerKindTriggerCharacter &&
- args.context.triggerCharacter == ":")
- {
- auto line = doc->getLine((Int)args.position.line + 1);
- auto prevCharPos = args.position.character - 2;
- if (prevCharPos >= 0 && prevCharPos < line.getLength() && line[prevCharPos] != ':')
- {
- m_connection->sendResult(NullResponse::get(), responseId);
- return SLANG_OK;
+ LanguageServerProtocol::kCompletionTriggerKindTriggerCharacter)
+ {
+ char requiredPrevChar = 0;
+ if (args.context.triggerCharacter == ":")
+ requiredPrevChar = ':';
+ else if (args.context.triggerCharacter == ">")
+ requiredPrevChar = '-';
+ if (requiredPrevChar != 0)
+ {
+ // Check if the previous character is the required character (':' or '-'
+ auto line = doc->getLine((Int)args.position.line + 1);
+ auto prevCharPos = args.position.character - 2;
+ if (prevCharPos >= 0 && prevCharPos < line.getLength() && line[prevCharPos] != requiredPrevChar)
+ {
+ m_connection->sendResult(NullResponse::get(), responseId);
+ return SLANG_OK;
+ }
}
}
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index ab69b66d8..d64329add 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -6884,7 +6884,8 @@ namespace Slang
auto expr = parseAtomicExpr(parser);
for(;;)
{
- switch( peekTokenType(parser) )
+ auto nextTokenType = peekTokenType(parser);
+ switch (nextTokenType)
{
default:
return expr;
@@ -6976,16 +6977,20 @@ namespace Slang
break;
}
- // Member access `x.m`
+ // Member access `x.m` or `x->m`
case TokenType::Dot:
+ case TokenType::RightArrow:
{
- MemberExpr* memberExpr = parser->astBuilder->create<MemberExpr>();
+
+ MemberExpr* memberExpr = nextTokenType == TokenType::Dot
+ ? parser->astBuilder->create<MemberExpr>()
+ : parser->astBuilder->create<DerefMemberExpr>();
// TODO(tfoley): why would a member expression need this?
memberExpr->scope = parser->currentScope;
memberExpr->memberOperatorLoc = parser->tokenReader.peekLoc();
memberExpr->baseExpression = expr;
- parser->ReadToken(TokenType::Dot);
+ parser->ReadToken(nextTokenType);
parser->FillPosition(memberExpr);
memberExpr->name = expectIdentifier(parser).name;