dotnet / dotnet/fsharp

Module and partially qualified namespace type shadowing interaction

Open
#13,535 2 comments 0 reactions 0 assignees View on GitHub
Area-Compiler-Service Feature Request Needs-design
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 22h
Merged PRs (30d)
144

Description

We shadow quite some things in FSharp.Core, either to poison them (compiler message to point to an alternative) or replace them with our own implementations. This is not really uncommon and a good open source example is the Prelude in Dark https://github.com/darklang/dark/blob/main/fsharp-backend/src/Prelude/Prelude.fs

In our case, probably less common, we're also aliasing Option to ValueOption, and precisely around shadowed types and aliases is where things break down a bit.

Reading the following example I would expect only the inner module 'Core' to be opened. Instead F# also opens the namespace Core (from Microsoft.FSharp.Core) and loads its types and aliases again :/

```fs
namespace Repro

module Common =
type Option<'T> = ValueOption<'T>

module SomeModule =

open Common

module Core =
let maybeTest (x: Option) = ()

open Core
// Have to re-open Common which Rider doesn't even see as a used import.
//open Common

// This expression was expected to have type 'Repro.Common.Option' but here has type 'Microsoft.FSharp.Core.Option'
let maybeSomething (x: Option) = maybeTest x
```

https://sharplab.io/#v2:DYLgZgzgNAJiDUAfAdgQwLYFMIAdUGNMACAJUxwCcB7AWACh70qYBXYYgYSvSeSIF4i9IiKIAXAJ45iAeRxiAllWQAeAOQAVAHwCiANVTAWmOYuXrt9RszbEAyt0wBZG+11W6oolWl8uPZQ8vJlY3LgpiQWEvUXYxInRUCQAjTA1seIAKAA8QIlMlVQgxCgVkAHMtAEpdTKqg0R9MPyoI6JEAeg6iAAlUADdiMSoiCIBaJpaAvgB3AAsFfDmiTBgFYYoIIhhlNXjMQb4ITGJULdQiFmOYIgV0HFaxADp2oi7Jon9eBs7ujQWtphspRsBBCkQZmcVsDMPgxKtxCM5gMhlJiGoyJQqE8vsongVzMVShUtGoiMkWPE5pgIkRkVtJNIiGonItqBAqGBngAxOzIig4HGtTD4+SFFREsqVNSvOIJJKpBxYMQLCpEHJ5AlFEpS6q6RIpNIZIjZIA===

Interestingly, this behavior only seems to be triggered without error if there is a shadowing module in scope:

```fs
namespace Sample

module SomeModule =

// error FS0893: This declaration opens the namespace or module 'Microsoft.FSharp.Core'
// through a partially qualified path. Adjust this code to use the full path of the namespace.
// This change will make your code more robust as new constructs are added to the F# and CLI libraries.
open Core

module Core =
let test() = ()

// Allowed because new module Core is in scope but additionally opens Microsoft.FSharp.Core through a partially qualified path without error.
open Core

```

Given that partially qualified opening of namespaces:
- Has produced an error since F# 1.0.
- Can only be triggered via an edge case.
- The implications of an open like this also doesn't flow through FCS or other tooling properly, given this re-import is seen as unused in Rider (can somebody try the repro in VS?).

Could we remove the behavior of re-opening namespaces via a partially qualified path entirely @dsyme?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.