summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-07-14 18:51:57 -0700
committerGitHub <noreply@github.com>2025-07-15 01:51:57 +0000
commit37143802781d8d480361d7c23202347ae3acf094 (patch)
tree300a6f60f2ddd3a0d7f14ab07665dfff5d67f31c
parentdb06fbb163877b8823507b162ee7f2dfca8520f0 (diff)
Fix language server crash. (#7756)
* Fix language server crash. * Fix tests. * Fix. * Revert changes.
-rw-r--r--source/slang/slang-check-decl.cpp3
-rw-r--r--source/slang/slang-parser.cpp82
-rw-r--r--source/slang/slang-syntax.cpp8
-rw-r--r--tests/bugs/generic-type-arg-overloaded.slang3
-rw-r--r--tests/bugs/generic-type-arg-overloaded.slang.expected23
-rw-r--r--tests/language-server/robustness-9.slang137
6 files changed, 185 insertions, 71 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index e67962ca3..584b1f081 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -9672,9 +9672,8 @@ void SemanticsVisitor::checkForRedeclaration(Decl* decl)
// Sanity check: there should always be a parent declaration.
//
- SLANG_ASSERT(parentDecl);
if (!parentDecl)
- return;
+ SLANG_ABORT_COMPILATION("decl has no parent.");
// If the declaration is the "inner" declaration of a generic,
// then we actually want to look one level up, because the
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 6401b3d06..0efa6a4b3 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -1859,53 +1859,46 @@ static Stmt* parseOptBody(Parser* parser)
}
}
- if (parser->getStage() == ParsingStage::Decl)
- {
- // If we are at the initial parsing stage, just collect the tokens
- // without actually parsing them.
- if (peekTokenType(parser) != TokenType::LBrace)
- {
- return parser->parseBlockStatement();
- }
- auto unparsedStmt = parser->astBuilder->create<UnparsedStmt>();
- unparsedStmt->currentScope = parser->currentScope;
- unparsedStmt->outerScope = parser->outerScope;
- unparsedStmt->sourceLanguage = parser->getSourceLanguage();
- unparsedStmt->isInVariadicGenerics = parser->isInVariadicGenerics;
- parser->FillPosition(unparsedStmt);
- List<Token>& tokens = unparsedStmt->tokens;
- int braceDepth = 0;
- for (;;)
+ // If we are at the initial parsing stage, just collect the tokens
+ // without actually parsing them.
+ if (peekTokenType(parser) != TokenType::LBrace)
+ {
+ return parser->parseBlockStatement();
+ }
+ auto unparsedStmt = parser->astBuilder->create<UnparsedStmt>();
+ unparsedStmt->currentScope = parser->currentScope;
+ unparsedStmt->outerScope = parser->outerScope;
+ unparsedStmt->sourceLanguage = parser->getSourceLanguage();
+ unparsedStmt->isInVariadicGenerics = parser->isInVariadicGenerics;
+ parser->FillPosition(unparsedStmt);
+ List<Token>& tokens = unparsedStmt->tokens;
+ int braceDepth = 0;
+ for (;;)
+ {
+ auto token = parser->ReadToken();
+ if (token.type == TokenType::EndOfFile)
{
- auto token = parser->ReadToken();
- if (token.type == TokenType::EndOfFile)
- {
- break;
- }
- if (token.type == TokenType::LBrace)
- {
- braceDepth++;
- }
- else if (token.type == TokenType::RBrace)
- {
- braceDepth--;
- }
- tokens.add(token);
- if (braceDepth == 0)
- {
- break;
- }
+ break;
+ }
+ if (token.type == TokenType::LBrace)
+ {
+ braceDepth++;
+ }
+ else if (token.type == TokenType::RBrace)
+ {
+ braceDepth--;
+ }
+ tokens.add(token);
+ if (braceDepth == 0)
+ {
+ break;
}
- Token eofToken;
- eofToken.type = TokenType::EndOfFile;
- eofToken.loc = parser->tokenReader.peekLoc();
- tokens.add(eofToken);
- return unparsedStmt;
}
-
- // If we are in the second stage of parsing, then we need to actually
- // parse the block statement for real.
- return parser->parseBlockStatement();
+ Token eofToken;
+ eofToken.type = TokenType::EndOfFile;
+ eofToken.loc = parser->tokenReader.peekLoc();
+ tokens.add(eofToken);
+ return unparsedStmt;
}
/// Complete parsing of a function using traditional (C-like) declarator syntax
@@ -5500,7 +5493,6 @@ static EnumCaseDecl* parseEnumCaseDecl(Parser* parser)
static Decl* parseEnumDecl(Parser* parser)
{
EnumDecl* decl = parser->astBuilder->create<EnumDecl>();
-
parser->ReadToken("enum");
// HACK: allow the user to write `enum class` in case
diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp
index bb5b574bb..67d562f0f 100644
--- a/source/slang/slang-syntax.cpp
+++ b/source/slang/slang-syntax.cpp
@@ -912,11 +912,19 @@ FuncType* getFuncType(ASTBuilder* astBuilder, DeclRef<CallableDecl> const& declR
{
List<Type*> paramTypes;
auto resultType = getResultType(astBuilder, declRef);
+
+ if (!resultType)
+ resultType = astBuilder->getErrorType();
+
auto errorType = getErrorCodeType(astBuilder, declRef);
auto visitParamDecl = [&](DeclRef<ParamDecl> paramDeclRef)
{
auto paramDecl = paramDeclRef.getDecl();
auto paramType = getParamType(astBuilder, paramDeclRef);
+ if (!paramType)
+ {
+ paramType = astBuilder->getErrorType();
+ }
if (paramDecl->findModifier<RefModifier>())
{
paramType = astBuilder->getRefType(paramType, AddressSpace::Generic);
diff --git a/tests/bugs/generic-type-arg-overloaded.slang b/tests/bugs/generic-type-arg-overloaded.slang
index 99150d2f0..d21ba0732 100644
--- a/tests/bugs/generic-type-arg-overloaded.slang
+++ b/tests/bugs/generic-type-arg-overloaded.slang
@@ -1,6 +1,6 @@
// generic-type-arg-overloaded.slang
-//DIAGNOSTIC_TEST:SIMPLE:
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
// Regression test to confirm that type checker
// doesn't crash when an overloaded identifier
@@ -11,6 +11,7 @@ interface IThing { int getVal(); }
struct Stuff : IThing { int getVal() { return 1; } }
// Conflicting declaration:
+//CHECK: ([[# @LINE+1]]): error 30200:
struct Stuff {}
int util<T : IThing>() { return 1; }
diff --git a/tests/bugs/generic-type-arg-overloaded.slang.expected b/tests/bugs/generic-type-arg-overloaded.slang.expected
deleted file mode 100644
index 1c41da717..000000000
--- a/tests/bugs/generic-type-arg-overloaded.slang.expected
+++ /dev/null
@@ -1,23 +0,0 @@
-result code = -1
-standard error = {
-tests/bugs/generic-type-arg-overloaded.slang(14): error 30200: declaration of 'Stuff' conflicts with existing declaration
-struct Stuff {}
- ^~~~~
-tests/bugs/generic-type-arg-overloaded.slang(11): note: see previous declaration of 'Stuff'
-struct Stuff : IThing { int getVal() { return 1; } }
- ^~~~~
-tests/bugs/generic-type-arg-overloaded.slang(26): error 39999: ambiguous reference to 'Stuff'
- return util<Stuff>()
- ^~~~~
-tests/bugs/generic-type-arg-overloaded.slang(14): note 39999: candidate: struct Stuff
-struct Stuff {}
- ^~~~~
-tests/bugs/generic-type-arg-overloaded.slang(11): note 39999: candidate: struct Stuff
-struct Stuff : IThing { int getVal() { return 1; } }
- ^~~~~
-tests/bugs/generic-type-arg-overloaded.slang(32): error 39999: expected a generic when using '<...>' (found: '() -> int')
- + nonGeneric<G>();
- ^~~~~~~~~~
-}
-standard output = {
-}
diff --git a/tests/language-server/robustness-9.slang b/tests/language-server/robustness-9.slang
new file mode 100644
index 000000000..daf6b9edb
--- /dev/null
+++ b/tests/language-server/robustness-9.slang
@@ -0,0 +1,137 @@
+//TEST:LANG_SERVER(filecheck=CHECK):
+
+RWTexture2D<float4> texFrame; // Output texture
+uniform float iTime;
+// In seconds
+uniform float2 iResolution; // Screen size
+
+static const float kInfinity = asfloat(0x7f800000);
+static const uint32_t kIdNone = 0xFFFFFFFF;
+
+struct Intersection
+{
+ float t = kInfinity;
+ uint32_t id = kIdNone;
+
+ bool missed() {
+ return id == kIdNone;
+ }
+
+ [mutating]
+ void update(uint32_t newId, float newT)
+ {
+ if(newT >= 0 && newT < t)
+ {
+ t = newT;
+ id = newId;
+ }
+ }
+};
+
+struct Ray
+{
+ float3 origin;
+ float3 direction;
+ float3 at(float t)
+ {
+ return mad(origin, direction, float3(t));
+ }
+};
+
+// Returns the t-value of the intersection of the infinite line
+// with the plane given by
+// `dot(planeNormal, p) == planeDist`.
+float intersectPlane(Ray ray, float3 planeNormal, float planeDist)
+{
+ // dot(planeNormal, o + d * t) == planeDist
+ // -> dot(planeNormal, o) + t * dot(planeNormal, d) == planeDist
+ // -> t = (planeDist - dot(planeNormal, o)) / dot(planeNormal, d)
+ return (planeDist - dot(planeNormal, ray.origin))
+ / dot(planeNormal, ray.direction);
+}
+
+float2 sortLoHi(float2 v)
+{
+
+
+struct OBB
+{
+ // Note that these are more parameters than we need;
+ // technically, the sides of an OBB must all be perpendicular,
+ // so there's only 3 (position) + 3 (side lengths) + 3 (rotation)
+ // degrees of freedom.
+ float3 corner;
+ float3 edges[3];
+
+ // Returns the t-value of the intersection of the OBB with
+ // the ray.
+ // The returned t-value may be negative; i.e. this assumes
+ // the camera is outside of the box.
+ // On miss, returns infinity.
+ float intersect(Ray ray)
+ {
+ ray.origin -= corner;
+
+ float2 tCloseFar;
+ float tFar;
+ [ForceUnroll]
+ for(int i = 0; i < 3; i++)
+ {
+ const float3 edge = edges[i];
+ const float edgeDist = dot(edge, ray.origin);
+ const float factor = rcp(dot(edge, ray.direction));
+ float2 slab = (float2(0, dot(edge, edge)) - edgeDist)
+ * factor;
+ slab =
+ if(i == 0)
+ {
+ tClose = min(slab.x, slab.y);
+ tFar = max(slab.x, slab.y);
+ }
+ else
+ {
+ tClose = min3(tClose, slab.x, slab.y);
+ tFar = max3(tFar, slab.x, slab.y);
+ }
+ thisSlab = sortLoHi(thisSlab);
+ tCloseFar.x =
+ }
+ return kInfinity;
+ }
+};
+
+[shader("compute")]
+[numthreads(16, 16, 1)]
+void main(uint2 thread: SV_DispatchThreadID)
+{
+ float2 uv = (2.0 * float2(thread) - iResolution.xy) / iResolution.y;
+
+ // Right-handed Z-up coordinate system, same as Blender's
+ Ray ray;
+ ray.origin = float3(0, -4, 4);
+ static const float kSqrtP5 = sqrt(.5);
+ ray.direction = float3(
+ uv.x,
+ kSqrtP5 -kSqrtP5 * uv.y,
+ -kSqrtP5 -kSqrtP5 * uv.y
+ );
+
+ Intersection intersection;
+ intersection.update(0, intersectPlane(ray, float3(0,0,1), 0));
+ OBB obb = OBB(float3(-1,-1,-1),{float3(2,0,0),float3(0,2,0), float3(0,0,2)});
+ intersection.update(1, obb.intersect(ray));
+
+ float3 color;
+ if(intersection.missed())
+ {
+ color = float3(0.0, 0.0, 1.0);
+ }
+ else
+ {
+ color = float3(intersection.t / 10.0);
+ }
+//COMPLETE:134,31
+ texFrame[thread] = float4(color, 1.0);
+}
+
+// CHECK: color