Skip to content

Commit

Permalink
Make Microsoft optional in namepsace paths from FSharp.Core
Browse files Browse the repository at this point in the history
commit 4273c5af3e9d5ff60e9eca2d60c92c06c87ebdeb
Merge: df8b476 d301929
Author: latkin <latkin@microsoft.com>
Date:   Thu Jan 8 13:07:38 2015 -0800

    Merge branch 'msft-optional' of https://git01.codeplex.com/forks/dsyme/cleanup into msftnamespace

commit d301929def6926050c8b6e33dd2f621398162784
Author: Don Syme <dsyme@microsoft.com>
Date:   Tue Dec 2 15:10:33 2014 +0000

    add more tests

commit 5e2731b91bd6bc67c1d0252a4de9aade2d2e2809
Author: Don Syme <dsyme@microsoft.com>
Date:   Tue Dec 2 15:07:43 2014 +0000

    update code comment

commit 72c3bf1facd8c0684be838396b7d627e61959bc5
Author: Don Syme <dsyme@microsoft.com>
Date:   Tue Sep 16 16:18:51 2014 +0100

    Make Microsoft optional in namepsace paths from FSharp.Core
  • Loading branch information
dsyme authored and latkin committed Jan 8, 2015
1 parent df8b476 commit 51d7b62
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 27 deletions.
10 changes: 5 additions & 5 deletions src/fsharp/nameres.fs
Original file line number Diff line number Diff line change
Expand Up @@ -671,13 +671,13 @@ let rec AddModuleOrNamespaceRefsToNameEnv g amap m root ad nenv (modrefs: Module
let nenv =
(nenv,modrefs) ||> List.fold (fun nenv modref ->
if modref.IsModule && TryFindFSharpBoolAttribute g g.attrib_AutoOpenAttribute modref.Attribs = Some true then
AddModuleOrNamespaceContentsToNameEnv g amap ad m nenv modref
AddModuleOrNamespaceContentsToNameEnv g amap ad m false nenv modref
else
nenv)
nenv

/// Add the contents of a module or namespace to the name resolution environment
and AddModuleOrNamespaceContentsToNameEnv (g:TcGlobals) amap (ad:AccessorDomain) m nenv (modref:ModuleOrNamespaceRef) =
and AddModuleOrNamespaceContentsToNameEnv (g:TcGlobals) amap (ad:AccessorDomain) m root nenv (modref:ModuleOrNamespaceRef) =
let pri = NextExtensionMethodPriority()
let mty = modref.ModuleOrNamespaceType
let tycons = mty.TypeAndExceptionDefinitions
Expand All @@ -695,7 +695,7 @@ and AddModuleOrNamespaceContentsToNameEnv (g:TcGlobals) amap (ad:AccessorDomain)
else None)
|> FlatList.toArray
let nenv = AddValRefsToNameEnvWithPriority BulkAdd.Yes pri nenv vrefs
let nenv = (nenv,MakeNestedModuleRefs modref) ||> AddModuleOrNamespaceRefsToNameEnv g amap m false ad
let nenv = (nenv,MakeNestedModuleRefs modref) ||> AddModuleOrNamespaceRefsToNameEnv g amap m root ad
nenv

/// Add a set of modules or namespaces to the name resolution environment
Expand All @@ -706,8 +706,8 @@ and AddModuleOrNamespaceContentsToNameEnv (g:TcGlobals) amap (ad:AccessorDomain)
// open M1
//
// The list contains [M1b; M1a]
and AddModulesAndNamespacesContentsToNameEnv g amap ad m nenv modrefs =
(modrefs, nenv) ||> List.foldBack (fun modref acc -> AddModuleOrNamespaceContentsToNameEnv g amap ad m acc modref)
and AddModulesAndNamespacesContentsToNameEnv g amap ad m root nenv modrefs =
(modrefs, nenv) ||> List.foldBack (fun modref acc -> AddModuleOrNamespaceContentsToNameEnv g amap ad m root acc modref)

/// Add a single modules or namespace to the name resolution environment
let AddModuleOrNamespaceRefToNameEnv g amap m root ad nenv (modref:EntityRef) =
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/nameres.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ val internal AddModuleOrNamespaceRefsToNameEnv : TcGlobals ->
val internal AddModuleOrNamespaceRefToNameEnv : TcGlobals -> ImportMap -> range -> bool -> AccessorDomain -> NameResolutionEnv -> ModuleOrNamespaceRef -> NameResolutionEnv

/// Add a list of modules or namespaces to the name resolution environment
val internal AddModulesAndNamespacesContentsToNameEnv : TcGlobals -> ImportMap -> AccessorDomain -> range -> NameResolutionEnv -> ModuleOrNamespaceRef list -> NameResolutionEnv
val internal AddModulesAndNamespacesContentsToNameEnv : TcGlobals -> ImportMap -> AccessorDomain -> range -> bool -> NameResolutionEnv -> ModuleOrNamespaceRef list -> NameResolutionEnv

/// A flag which indicates if it is an error to have two declared type parameters with identical names
/// in the name resolution environment.
Expand Down
73 changes: 52 additions & 21 deletions src/fsharp/tc.fs
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,8 @@ let AddLocalTyconsAndReport tcSink g amap scopem tycons env =
// Open a structure or an IL namespace
//-------------------------------------------------------------------------

let OpenModulesOrNamespaces tcSink g amap scopem env mvvs =
let env = ModifyNameResEnv (fun nenv -> AddModulesAndNamespacesContentsToNameEnv g amap env.eAccessRights scopem nenv mvvs) env
let OpenModulesOrNamespaces tcSink g amap scopem root env mvvs =
let env = ModifyNameResEnv (fun nenv -> AddModulesAndNamespacesContentsToNameEnv g amap env.eAccessRights scopem root nenv mvvs) env
CallEnvSink tcSink (scopem,env.NameEnv,env.eAccessRights)
env

Expand Down Expand Up @@ -613,7 +613,7 @@ let ImplicitlyOpenOwnNamespace tcSink g amap scopem enclosingNamespacePath env =
else
let ad = env.eAccessRights
match ResolveLongIndentAsModuleOrNamespace amap scopem OpenQualified env.eNameResEnv ad enclosingNamespacePath with
| Result modrefs -> OpenModulesOrNamespaces tcSink g amap scopem env (List.map p23 modrefs)
| Result modrefs -> OpenModulesOrNamespaces tcSink g amap scopem false env (List.map p23 modrefs)
| Exception _ -> env


Expand Down Expand Up @@ -11138,7 +11138,27 @@ let TcOpenDecl tcSink g amap m scopem env (longId : Ident list) =
match p with
| [] -> []
| (h,_):: t -> if h.StartsWith(FsiDynamicModulePrefix,System.StringComparison.Ordinal) then t else p
modref.IsNamespace && p.Length >= longId.Length

// See https://fslang.uservoice.com/forums/245727-f-language/suggestions/6107641-make-microsoft-prefix-optional-when-using-core-f
let isFSharpCoreSpecialCase =
match ccuOfTyconRef modref with
| None -> false
| Some ccu ->
ccuEq ccu g.fslibCcu &&
// Check if we're using a reference one string shorter than what we expect.
//
// "p" is the fully qualified path _containing_ the thing we're opening, e.g. "Microsoft.FSharp" when opening "Microsoft.FSharp.Data"
// "longId" is the text being used, e.g. "FSharp.Data"
// Length of thing being opened = p.Length + 1
// Length of reference = longId.Length
// So the reference is a "shortened" reference if (p.Length + 1) - 1 = longId.Length
(p.Length + 1) - 1 = longId.Length &&
fst p.[0] = "Microsoft"

modref.IsNamespace &&
p.Length >= longId.Length &&
not isFSharpCoreSpecialCase
// Allow "open Foo" for "Microsoft.Foo" from FSharp.Core

modrefs |> List.iter (fun (_,modref,_) ->
if modref.IsModule && HasFSharpAttribute g g.attrib_RequireQualifiedAccessAttribute modref.Attribs then
Expand All @@ -11152,7 +11172,7 @@ let TcOpenDecl tcSink g amap m scopem env (longId : Ident list) =

modrefs |> List.iter (fun (_,modref,_) -> CheckEntityAttributes g modref m |> CommitOperationResult)

let env = OpenModulesOrNamespaces tcSink g amap scopem env (List.map p23 modrefs)
let env = OpenModulesOrNamespaces tcSink g amap scopem false env (List.map p23 modrefs)
env


Expand Down Expand Up @@ -15303,25 +15323,36 @@ and TcModuleOrNamespace cenv env (id,isModule,defs,xml,modAttrs,vis,m:range) =
// TypecheckOneImplFile - Typecheck all the namespace fragments in a file.
//--------------------------------------------------------------------------


let ApplyAssemblyLevelAutoOpenAttributeToTcEnv g amap (ccu: CcuThunk) scopem env (p, root) =
let warn() =
warning(Error(FSComp.SR.tcAttributeAutoOpenWasIgnored(p, ccu.AssemblyName),scopem))
env
let p = splitNamespace p
if isNil p then warn() else
let h,t = List.frontAndBack p
let modref = mkNonLocalTyconRef (mkNonLocalEntityRef ccu (Array.ofList h)) t
match modref.TryDeref with
| None -> warn()
| Some _ -> OpenModulesOrNamespaces TcResultsSink.NoSink g amap scopem root env [modref]

// Add the CCU and apply the "AutoOpen" attributes
let AddCcuToTcEnv(g,amap,scopem,env,ccu,autoOpens,internalsVisible) =
let env = AddNonLocalCcu g amap scopem env (ccu,internalsVisible)

#if AUTO_OPEN_ATTRIBUTES_AS_OPEN
let env = List.fold (fun env p -> TcOpenDecl tcSink g amap scopem scopem env (pathToSynLid scopem (splitNamespace p))) env autoOpens
#else
let env =
(env,autoOpens) ||> List.fold (fun env p ->
let warn() =
warning(Error(FSComp.SR.tcAttributeAutoOpenWasIgnored(p, ccu.AssemblyName),scopem))
env
let p = splitNamespace p
if isNil p then warn() else
let h,t = List.frontAndBack p
let modref = mkNonLocalTyconRef (mkNonLocalEntityRef ccu (Array.ofList h)) t
match modref.TryDeref with
| None -> warn()
| Some _ -> OpenModulesOrNamespaces TcResultsSink.NoSink g amap scopem env [modref])
#endif
// See https://fslang.uservoice.com/forums/245727-f-language/suggestions/6107641-make-microsoft-prefix-optional-when-using-core-f
// "Microsoft" is opened by default in FSharp.Core
let autoOpens =
let autoOpens = autoOpens |> List.map (fun p -> (p,false))
if ccuEq ccu g.fslibCcu then
// Auto open 'Microsoft' in FSharp.Core.dll. Even when using old versions of FSharp.Core.dll that do
// not have this attribute. The 'true' means 'treat all namespaces so revealed as "roots" accessible via
// global, e.g. global.FSharp.Collections'
("Microsoft", true) :: autoOpens
else
autoOpens

let env = (env,autoOpens) ||> List.fold (ApplyAssemblyLevelAutoOpenAttributeToTcEnv g amap ccu scopem)
env

let CreateInitialTcEnv(g,amap,scopem,ccus) =
Expand Down
20 changes: 20 additions & 0 deletions tests/fsharp/typecheck/sigs/build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ call %~d0%~p0..\..\..\config.bat
call ..\..\single-neg-test.bat neg91
@if ERRORLEVEL 1 goto Error

"%FSC%" %fsc_flags% --target:exe -o:pos19.exe pos19.fs
@if ERRORLEVEL 1 goto Error

"%PEVERIFY%" pos19.exe
@if ERRORLEVEL 1 goto Error

pos19.exe
@if ERRORLEVEL 1 goto Error


"%FSC%" %fsc_flags% --target:exe -o:pos18.exe pos18.fs
@if ERRORLEVEL 1 goto Error

"%PEVERIFY%" pos18.exe
@if ERRORLEVEL 1 goto Error

pos18.exe
@if ERRORLEVEL 1 goto Error


"%FSC%" %fsc_flags% --target:exe -o:pos16.exe pos16.fs
@if ERRORLEVEL 1 goto Error

Expand Down
35 changes: 35 additions & 0 deletions tests/fsharp/typecheck/sigs/pos18.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// This test is related to F# 4.0+ design change "https://fslang.uservoice.com/forums/245727-f-language/suggestions/6107641-make-microsoft-prefix-optional-when-using-core-f"
//
// In this test, we check we can do basic operations like "open FSharp.Collections" without needing the "Microsoft" prefix

module Pos18 =
// Check we can open 'FSharp.Collections' unqualified, without warning
open FSharp.Collections

// Check we can open 'FSharp.Quotations' unqualified, without warning
open FSharp.Quotations

let v = Expr.Value 3

// Check we can access 'FSharp.Quotations' via full path
let v2 = FSharp.Quotations.Expr.Value 3

// Check we can access 'FSharp.Quotations' via 'global'
let v3 = global.FSharp.Quotations.Expr.Value 3

module Pos18b =
open Microsoft // Adding "open Microsoft" shouldn't trigger additional warnings

// Check we can open 'FSharp.Collections' unqualified, without warning
open FSharp.Collections

// Check we can open 'FSharp.Quotations' unqualified, without warning
open FSharp.Quotations

let v = Expr.Value 3

// Check we can access 'FSharp.Quotations' via full path
let v2 = FSharp.Quotations.Expr.Value 3

// Check we can access 'FSharp.Quotations' via 'global'
let v3 = global.FSharp.Quotations.Expr.Value 3
79 changes: 79 additions & 0 deletions tests/fsharp/typecheck/sigs/pos19.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

// This test is related to F# 4.0+ design change "https://fslang.uservoice.com/forums/245727-f-language/suggestions/6107641-make-microsoft-prefix-optional-when-using-core-f"
//
// In this test, we simulate user code that has defined types in FSharp.Collections. We check that the resolution
// of types in FSharp.Collections proceeds as previously for user-defined types.

namespace FSharp.Collections

type List<'T> = A | B
type Map<'T> = C | D


namespace Pos19

module N =
open FSharp.Collections

// check "List" resolves to the FSharp.Collections.List defined above
let f (x: List<int>) =
match x with
| A -> 1
| B -> 2

let y = f A

namespace Test3

module N =
open FSharp.Collections

// check "List" resolves to the FSharp.Collections.List defined above
let f1 (x: List<int>) =
match x with
| A -> 1
| B -> 2

let y1 = f1 A

// check "List" resolves to the FSharp.Collections.List defined above
let f2 (x: global.FSharp.Collections.List<int>) =
match x with
| A -> 1
| B -> 2

let y2 = f2 A

// check "List" resolves to the FSharp.Collections.List defined above
let f3 (x: FSharp.Collections.List<int>) =
match x with
| A -> 1
| B -> 2

let y3 = f3 A


// check "Map" resolves to the FSharp.Collections.List defined above
let g1 (x: Map<int>) =
match x with
| C -> 1
| D -> 2

let z1 = g1 C

// check "List" resolves to the FSharp.Collections.List defined above
let g2 (x: global.FSharp.Collections.Map<int>) =
match x with
| C -> 1
| D -> 2

let z2 = g2 C


// check "List" resolves to the FSharp.Collections.List defined above
let g3 (x: FSharp.Collections.Map<int>) =
match x with
| C -> 1
| D -> 2

let z3 = g3 C

0 comments on commit 51d7b62

Please sign in to comment.