diff options
| author | Yong He <yonghe@outlook.com> | 2025-07-14 18:51:57 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-15 01:51:57 +0000 |
| commit | 37143802781d8d480361d7c23202347ae3acf094 (patch) | |
| tree | 300a6f60f2ddd3a0d7f14ab07665dfff5d67f31c | |
| parent | db06fbb163877b8823507b162ee7f2dfca8520f0 (diff) | |
Fix language server crash. (#7756)
* Fix language server crash.
* Fix tests.
* Fix.
* Revert changes.
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 82 | ||||
| -rw-r--r-- | source/slang/slang-syntax.cpp | 8 | ||||
| -rw-r--r-- | tests/bugs/generic-type-arg-overloaded.slang | 3 | ||||
| -rw-r--r-- | tests/bugs/generic-type-arg-overloaded.slang.expected | 23 | ||||
| -rw-r--r-- | tests/language-server/robustness-9.slang | 137 |
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 |
