Skip to content

Module and partially qualified namespace type shadowing interaction #13535

Open
@NinoFloris

Description

@NinoFloris

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 :/

namespace Repro

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

module SomeModule = 

    open Common

    module Core = 
        let maybeTest (x: Option<string>) = ()

    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<string>' but here has type 'Microsoft.FSharp.Core.Option<string>'
    let maybeSomething (x: Option<string>) = 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:

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?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    New

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions