From 3feb36b77d5e904efb5cbb51667febb811abc79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Mon, 28 Jul 2025 15:47:31 +0200 Subject: [PATCH 1/4] Limit TypeUtils.resolveTypeForPipeCompletion to 10 recursive calls to prevent infinite loops --- analysis/src/TypeUtils.ml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/analysis/src/TypeUtils.ml b/analysis/src/TypeUtils.ml index e6c7e8bc71..df38d88aec 100644 --- a/analysis/src/TypeUtils.ml +++ b/analysis/src/TypeUtils.ml @@ -526,7 +526,7 @@ let rec digToRelevantTemplateNameType ~env ~package ?(suffix = "") | _ -> (t, suffix, env)) | _ -> (t, suffix, env) -let rec resolveTypeForPipeCompletion ~env ~package ~lhsLoc ~full +let rec resolveTypeForPipeCompletion ~env ~package ~lhsLoc ~full ?(depth = 0) (t : Types.type_expr) = (* If the type we're completing on is a type parameter, we won't be able to do completion unless we know what that type parameter is compiled as. @@ -540,7 +540,11 @@ let rec resolveTypeForPipeCompletion ~env ~package ~lhsLoc ~full in match typFromLoc with | Some typFromLoc -> - typFromLoc |> resolveTypeForPipeCompletion ~lhsLoc ~env ~package ~full + if depth > 10 then (env, typFromLoc) + else + typFromLoc + |> resolveTypeForPipeCompletion ~lhsLoc ~env ~package ~full + ~depth:(depth + 1) | None -> let rec digToRelevantType ~env ~package (t : Types.type_expr) = match t.desc with From 6266549d9d8195fc8919f225b4bc2cd110303acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Mon, 28 Jul 2025 20:47:46 +0200 Subject: [PATCH 2/4] Add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 896e9282ff..7de6834e2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ #### :bug: Bug fix - Fix error message that falsely suggested using coercion when it wouldn't work. https://github.com/rescript-lang/rescript/pull/7721 +- Fix hang in `rescript-editor-analysis.exe codeAction` that sometimes prevented ReScript files from being saved in VS Code. https://github.com/rescript-lang/rescript/pull/7731 # 12.0.0-beta.3 From cc9987e52b9176080288705519e30cfe31dabcb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Wed, 30 Jul 2025 12:10:40 +0200 Subject: [PATCH 3/4] Add comment explaining why TypeUtils.resolveTypeForPipeCompletion enforces a maximum iteration count and add TODO about fixing the root of the issue --- analysis/src/TypeUtils.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/analysis/src/TypeUtils.ml b/analysis/src/TypeUtils.ml index df38d88aec..04b971b5a3 100644 --- a/analysis/src/TypeUtils.ml +++ b/analysis/src/TypeUtils.ml @@ -540,6 +540,10 @@ let rec resolveTypeForPipeCompletion ~env ~package ~lhsLoc ~full ?(depth = 0) in match typFromLoc with | Some typFromLoc -> + (* Prevent infinite loops when `typFromLoc` is a type variable by bailing out after + 10 iterations. + TODO: fix the root of the issue (probably in `findReturnTypeOfFunctionAtLoc`) + instead of enforcing a maximum number of iterations. *) if depth > 10 then (env, typFromLoc) else typFromLoc From 44c403099ea17d543a17f374adc2f2fa5b02e237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Wed, 30 Jul 2025 14:13:46 +0200 Subject: [PATCH 4/4] Prevent infinite recursion in TypeUtils.resolveTypeForPipeCompletion by not looping over type variables --- analysis/src/TypeUtils.ml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/analysis/src/TypeUtils.ml b/analysis/src/TypeUtils.ml index 04b971b5a3..b066a62cc0 100644 --- a/analysis/src/TypeUtils.ml +++ b/analysis/src/TypeUtils.ml @@ -526,7 +526,7 @@ let rec digToRelevantTemplateNameType ~env ~package ?(suffix = "") | _ -> (t, suffix, env)) | _ -> (t, suffix, env) -let rec resolveTypeForPipeCompletion ~env ~package ~lhsLoc ~full ?(depth = 0) +let rec resolveTypeForPipeCompletion ~env ~package ~lhsLoc ~full (t : Types.type_expr) = (* If the type we're completing on is a type parameter, we won't be able to do completion unless we know what that type parameter is compiled as. @@ -539,16 +539,9 @@ let rec resolveTypeForPipeCompletion ~env ~package ~lhsLoc ~full ?(depth = 0) | _ -> None in match typFromLoc with + | Some ({desc = Tvar _} as t) -> (env, t) | Some typFromLoc -> - (* Prevent infinite loops when `typFromLoc` is a type variable by bailing out after - 10 iterations. - TODO: fix the root of the issue (probably in `findReturnTypeOfFunctionAtLoc`) - instead of enforcing a maximum number of iterations. *) - if depth > 10 then (env, typFromLoc) - else - typFromLoc - |> resolveTypeForPipeCompletion ~lhsLoc ~env ~package ~full - ~depth:(depth + 1) + typFromLoc |> resolveTypeForPipeCompletion ~lhsLoc ~env ~package ~full | None -> let rec digToRelevantType ~env ~package (t : Types.type_expr) = match t.desc with