Skip to content

Checker: don't capture environment for checked modules #18519

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/9.0.300.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* Fix confusing type inference error in task expression ([Issue #13789](https://github.com/dotnet/fsharp/issues/13789), [PR #18450](https://github.com/dotnet/fsharp/pull/18450))
* Fix missing `null` highlighting in tooltips ([PR #18457](https://github.com/dotnet/fsharp/pull/18457))
* Make `[<CallerMemberName; Struct>]` combination work([PR #18444](https://github.com/dotnet/fsharp/pull/18444/))
* Fix code completion considers types from own namespace non-imported ([PR #18518](https://github.com/dotnet/fsharp/issues/18518))

### Added
* Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241))
Expand Down
11 changes: 5 additions & 6 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ let AddNonLocalCcu g amap scopem env assemblyName (ccu: CcuThunk, internalsVisib
env

/// Adjust the TcEnv to account for a fully processed "namespace" declaration in this file
let AddLocalRootModuleOrNamespace tcSink g amap scopem env (moduleTy: ModuleOrNamespaceType) =
let AddLocalRootModuleOrNamespace g amap scopem env (moduleTy: ModuleOrNamespaceType) =
// Compute the top-rooted module or namespace references
let modrefs = moduleTy.ModuleAndNamespaceDefinitions |> List.map mkLocalModuleRef
// Compute the top-rooted type definitions
Expand All @@ -350,7 +350,6 @@ let AddLocalRootModuleOrNamespace tcSink g amap scopem env (moduleTy: ModuleOrNa
let env = { env with
eNameResEnv = if isNil tcrefs then env.eNameResEnv else AddTyconRefsToNameEnv BulkAdd.No false g amap env.eAccessRights scopem true env.eNameResEnv tcrefs
eUngeneralizableItems = addFreeItemOfModuleTy moduleTy env.eUngeneralizableItems }
CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
env

/// Inside "namespace X.Y.Z" there is an implicit open of "X.Y.Z"
Expand Down Expand Up @@ -4978,7 +4977,7 @@ let rec TcSignatureElementNonMutRec (cenv: cenv) parent typeNames endm (env: TcE
CallNameResolutionSink cenv.tcSink (moduleEntity.Range, env.NameEnv, item, emptyTyparInst, ItemOccurrence.Binding, env.AccessRights))

// For 'namespace rec' and 'module rec' we add the thing being defined
let envNS = if isRec then AddLocalRootModuleOrNamespace cenv.tcSink g cenv.amap m envNS modTyRoot else envNS
let envNS = if isRec then AddLocalRootModuleOrNamespace g cenv.amap m envNS modTyRoot else envNS
let nsInfo = Some (modulNSOpt, envNS.eModuleOrNamespaceTypeAccumulator)
let mutRecNSInfo = if isRec then nsInfo else None

Expand All @@ -4990,7 +4989,7 @@ let rec TcSignatureElementNonMutRec (cenv: cenv) parent typeNames endm (env: TcE
if isNil enclosingNamespacePath then
envAtEnd
else
let env = AddLocalRootModuleOrNamespace cenv.tcSink g cenv.amap m env modTyRoot
let env = AddLocalRootModuleOrNamespace g cenv.amap m env modTyRoot

// If the namespace is an interactive fragment e.g. FSI_0002, then open FSI_0002 in the subsequent environment.
let env, _openDecls =
Expand Down Expand Up @@ -5440,7 +5439,7 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
CallNameResolutionSink cenv.tcSink (moduleEntity.Range, env.NameEnv, item, emptyTyparInst, ItemOccurrence.Binding, env.AccessRights))

// For 'namespace rec' and 'module rec' we add the thing being defined
let envNS = if isRec then AddLocalRootModuleOrNamespace cenv.tcSink g cenv.amap m envNS modTyRoot else envNS
let envNS = if isRec then AddLocalRootModuleOrNamespace g cenv.amap m envNS modTyRoot else envNS
let nsInfo = Some (modulNSOpt, envNS.eModuleOrNamespaceTypeAccumulator)
let mutRecNSInfo = if isRec then nsInfo else None

Expand All @@ -5453,7 +5452,7 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
if isNil enclosingNamespacePath then
envAtEnd, []
else
let env = AddLocalRootModuleOrNamespace cenv.tcSink g cenv.amap m env modTyRoot
let env = AddLocalRootModuleOrNamespace g cenv.amap m env modTyRoot

// If the namespace is an interactive fragment e.g. FSI_0002, then open FSI_0002 in the subsequent environment
let env, openDecls =
Expand Down
3 changes: 1 addition & 2 deletions src/Compiler/Checking/CheckDeclarations.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Text
open FSharp.Compiler.TypedTree

val AddLocalRootModuleOrNamespace:
TcResultsSink -> TcGlobals -> ImportMap -> range -> TcEnv -> ModuleOrNamespaceType -> TcEnv
val AddLocalRootModuleOrNamespace: TcGlobals -> ImportMap -> range -> TcEnv -> ModuleOrNamespaceType -> TcEnv

val CreateInitialTcEnv:
TcGlobals * ImportMap * range * assemblyName: string * (CcuThunk * string list * string list) list ->
Expand Down
6 changes: 3 additions & 3 deletions src/Compiler/Driver/ParseAndCheckInputs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1198,14 +1198,14 @@ let AddCheckResultsToTcState

// Add the implementation as to the implementation env
let tcImplEnv =
AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcImplEnv implFileSigType
AddLocalRootModuleOrNamespace tcGlobals amap m tcImplEnv implFileSigType

// Add the implementation as to the signature env (unless it had an explicit signature)
let tcSigEnv =
if hadSig then
tcState.tcsTcSigEnv
else
AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcState.tcsTcSigEnv implFileSigType
AddLocalRootModuleOrNamespace tcGlobals amap m tcState.tcsTcSigEnv implFileSigType

// Open the prefixPath for fsi.exe (tcImplEnv)
let tcImplEnv, openDecls =
Expand Down Expand Up @@ -1563,7 +1563,7 @@ let CheckOneInputWithCallback
let rootSigs = Zmap.add qualNameOfFile sigFileType tcState.tcsRootSigs

let tcSigEnv =
AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcState.tcsTcSigEnv sigFileType
AddLocalRootModuleOrNamespace tcGlobals amap m tcState.tcsTcSigEnv sigFileType

// Add the signature to the signature env (unless it had an explicit signature)
let ccuSigForFile = CombineCcuContentFragments [ sigFileType; tcState.tcsCcuSig ]
Expand Down
64 changes: 64 additions & 0 deletions tests/FSharp.Compiler.Service.Tests/CompletionTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,67 @@ let f (s: string) =
()
"""
assertHasItemWithNames ["Length"] info


[<Fact>]
let ``Import - Ns 01`` () =
let info =
getCompletionInfo "let _: R " (14, 12) """
namespace Ns

type Rec1 = { F: int }


namespace Ns

type Rec2 = { F: int }

module M =

type Rec3 = { F: int }

let _: R = ()
"""
assertHasItemWithNames ["Rec1"; "Rec2"; "Rec3"] info

[<Fact>]
let ``Import - Ns 02 - Rec`` () =
let info =
getCompletionInfo "let _: R " (14, 12) """
namespace Ns

type Rec1 = { F: int }


namespace rec Ns

type Rec2 = { F: int }

module M =

type Rec3 = { F: int }

let _: R = ()
"""
assertHasItemWithNames ["Rec1"; "Rec2"; "Rec3"] info

[<Fact>]
let ``Import - Ns 03 - Rec`` () =
let info =
getCompletionInfo "let _: R " (14, 12) """
namespace Ns

type Rec1 = { F: int }


namespace rec Ns

type Rec2 = { F: int }

module rec M =

type Rec3 = { F: int }

let _: R = ()
"""
assertHasItemWithNames ["Rec1"; "Rec2"; "Rec3"] info