From 855b1a262f3a769d44765e78f94e566d875b9286 Mon Sep 17 00:00:00 2001 From: Yong He Date: Tue, 29 Jul 2025 07:35:58 -0700 Subject: [Language Server]: Show signature help on generic parameters. (#7913) * Show signature help on generic parameters. * Fix. * Update tests. * slang-test: make vvl error go through stderr. * update slang-rhi * Update slang-rhi --- source/slang/slang-language-server.cpp | 59 +++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) (limited to 'source/slang/slang-language-server.cpp') diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp index 048fcb44b..dcf7419bd 100644 --- a/source/slang/slang-language-server.cpp +++ b/source/slang/slang-language-server.cpp @@ -160,6 +160,7 @@ SlangResult LanguageServer::parseNextMessage() caps.semanticTokensProvider.full = true; caps.semanticTokensProvider.range = false; caps.signatureHelpProvider.triggerCharacters.add("("); + caps.signatureHelpProvider.triggerCharacters.add("<"); caps.signatureHelpProvider.triggerCharacters.add(","); caps.signatureHelpProvider.retriggerCharacters.add(","); for (auto tokenType : kSemanticTokenTypes) @@ -1705,14 +1706,33 @@ LanguageServerResult LanguageServerCore:: bool useOriginalExpr = true; if (auto originalDeclRefExpr = as(appExpr->originalFunctionExpr)) { + // If the original expr doesn't map to a valid declref, we will use the checked + // func expr instead. if (!originalDeclRefExpr->declRef) { useOriginalExpr = false; } } + if (as(appExpr->originalFunctionExpr)) + { + if (as(funcExpr)) + { + // If the original function is a fully specialized generic app, use the checked func + // expr for signature help. + useOriginalExpr = false; + } + } if (useOriginalExpr) funcExpr = appExpr->originalFunctionExpr; } + if (auto partialGenAppExpr = as(funcExpr)) + { + funcExpr = partialGenAppExpr->originalExpr; + } + if (auto genAppExpr = as(funcExpr)) + { + funcExpr = genAppExpr->functionExpr; + } if (!funcExpr) { return std::nullopt; @@ -1741,6 +1761,22 @@ LanguageServerResult LanguageServerCore:: if (!declRef.getDecl()) return; + // If funcExpr is a direct reference to a generic, we should either + // show the generic signature if we are inside `<>`, or show the function + // parameter signature if we are inside `()`. If we are inside `()`, we will + // need to form a decl ref to the inner decl and show its signature. + if (!as(appExpr)) + { + if (auto genDeclRef = as(declRef)) + { + declRef = createDefaultSubstitutionsIfNeeded( + version->linkage->getASTBuilder(), + &semanticsVisitor, + version->linkage->getASTBuilder()->getMemberDeclRef( + declRef, + genDeclRef.getDecl()->inner)); + } + } // If we have a better match than the current best, we will update response.activeSignature // to this signature. if (auto callableDeclRef = declRef.as()) @@ -1832,12 +1868,20 @@ LanguageServerResult LanguageServerCore:: { if (auto typeType = as(declRefExpr->type.type)) { - // Look for initializers - auto ctors = - semanticsVisitor.lookupConstructorsInType(typeType->getType(), declRefExpr->scope); - for (auto ctor : ctors) + if (as(typeType->getType())) { - addDeclRef(ctor.declRef); + addDeclRef(declRefExpr->declRef); + } + else + { + // Look for initializers + auto ctors = semanticsVisitor.lookupConstructorsInType( + typeType->getType(), + declRefExpr->scope); + for (auto ctor : ctors) + { + addDeclRef(ctor.declRef); + } } } else @@ -1847,8 +1891,13 @@ LanguageServerResult LanguageServerCore:: } else if (auto overloadedExpr = as(funcExpr)) { + bool isGenApp = as(appExpr) != nullptr; for (auto item : overloadedExpr->lookupResult2) { + // Skip non-generic candidates if we are inside a generic app expr (e.g. + // `f`). + if (isGenApp && !as(item.declRef)) + continue; addDeclRef(item.declRef); } } -- cgit v1.2.3