Fix #7931: Resolve opened namespaces for attributes in recursive scopes#19502
Fix #7931: Resolve opened namespaces for attributes in recursive scopes#19502Copilot wants to merge 5 commits into
Conversation
|
@copilot Try again |
Implemented the fix in commit Root cause: In recursive scopes ( Fix: Added |
c8d283c to
676aa49
Compare
❗ Release notes required
|
b90f44e to
e59207c
Compare
Pre-process open declarations before Phase1A attribute checking in recursive scopes (namespace rec / module rec). Previously, opens were only processed in Phase1AB after module entities were built, but module attributes needed access to opened namespaces during Phase1A. The fix adds preProcessOpensForPhase1A which silently resolves opens before Phase1A, making opened namespaces available for attribute resolution on modules and types in recursive scopes. Agent-Logs-Url: https://github.com/dotnet/fsharp/sessions/20a6e4bb-a5f1-45cc-b80d-ee1110cd8812 Co-authored-by: abonie <20281641+abonie@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/fsharp/sessions/20a6e4bb-a5f1-45cc-b80d-ee1110cd8812 Co-authored-by: abonie <20281641+abonie@users.noreply.github.com>
…tive test - Narrow preProcessOpensForPhase1A to only handle SynOpenDeclTarget.ModuleOrNamespace, avoiding unnecessary processing of 'open type' declarations in incomplete recursive env. - Add negative test verifying undefined attributes still produce FS0039 in namespace rec. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ce rec Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
4af4f66 to
2b14389
Compare
…24c-befc-6bcc6711d784
| |> typecheck | ||
| |> shouldSucceed | ||
|
|
||
| // https://github.com/dotnet/fsharp/issues/5795 - Custom attribute used on type and let in rec module |
T-Gro
left a comment
There was a problem hiding this comment.
Review: Fix #7931 — Resolve opened namespaces for attributes in recursive scopes
APPROVE — This is a well-targeted fix for a real bug with sound approach and good test coverage.
Correctness Analysis
The root cause is correctly identified: in recursive scopes, open declarations are processed in Phase1AB (after Phase1A builds module/type entities), but module attributes are checked during Phase1A via TcAttributes cenv envInitial. The �nvInitial at that point doesn't include opened namespaces.
The fix introduces preProcessOpensForPhase1A which silently resolves opens before Phase1A. The dual-site application is correct:
- Top-level (TcMutRecDefns_Phase1): pre-processes top-level opens into �nvWithOpens, which flows via mapWithParent as the �nvInitial parameter to TcTyconDefnCore_Phase1A_BuildInitialModule → TcAttributes for top-level modules.
- Nested (TcTyconDefnCore_Phase1A_BuildInitialModule): pre-processes child opens into �nvForDecls, which flows via mapWithParent recursion to nested module attribute checking.
The suppressErrorReporting + TemporarilySuspendReportingTypecheckResultsToSink combination is the right pattern — errors from opens referencing not-yet-defined modules are swallowed silently, and duplicate sink entries are prevented. The proper Phase1AB processing (line 4121, via TcMutRecDefns_ComputeEnvs using the original �nvInitial) still runs with full error reporting.
Only SynOpenDeclTarget.ModuleOrNamespace is pre-processed, which is appropriate — open type declarations depend on established types and aren't relevant for attribute namespace resolution.
Tests
Good coverage with 11 test cases: core scenarios (Extension on module/type in
amespace rec, module rec, nested modules), negative tests (undefined attribute still errors, invalid open target still errors), and edge cases (multiple opens, forward-reference open, non-recursive baseline).
Minor
PR description mentions "8 test cases" but there are 11 test functions — trivial description inaccuracy.
Description
Fixes nested module attributes not being resolved in
namespace rec/module recscopes. Previously, using[<Extension>]on a module insidenamespace recwould fail withFS0039: The type 'Extension' is not defined, even whenopen System.Runtime.CompilerServiceswas in scope.Root Cause
In recursive scopes, open declarations are processed in Phase1AB — after Phase1A builds module/type entities. But module attributes are checked during Phase1A using
envInitial, which doesn't yet include the opened namespaces. In non-recursive scopes, opens are processed sequentially before module attributes are checked, so this issue doesn't occur.Changes Made
src/Compiler/Checking/CheckDeclarations.fs: AddedpreProcessOpensForPhase1Ahelper that silently resolves open declarations before Phase1A attribute checking. UsessuppressErrorReportingandTemporarilySuspendReportingTypecheckResultsToSinkto avoid duplicate diagnostics (since opens are re-processed properly in Phase1AB). Applied at two levels:TcMutRecDefns_Phase1(fixesnamespace reccase)TcTyconDefnCore_Phase1A_BuildInitialModule(fixes nested module case)AttributeResolutionInRecursiveScopes.fscovering the issue scenarios (Extension attribute on modules/types innamespace rec, nested modules, multiple opens,module rec, and non-recursive baseline).docs/release-notes/.FSharp.Compiler.Service/11.0.100.md.Testing
📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.