diff options
| author | Yong He <yonghe@outlook.com> | 2024-03-21 17:19:03 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-21 17:19:03 -0700 |
| commit | 7a8ef896196ad0d7095412d8558dd9a2542874c8 (patch) | |
| tree | deef82a216f468fd57164f94700f2624164c7ca9 /source | |
| parent | dd32414bd7332c55dc37ea2972ffcca73328d834 (diff) | |
Support arrow operator `->` on pointers. (#3812)
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-ast-expr.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 24 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-language-server.cpp | 29 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 13 |
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; |
