Skip to content
Draft
Show file tree
Hide file tree
Changes from 18 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/10.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Add support for `when 'T : Enum` library-only static optimization constraint. ([PR #18546](https://github.com/dotnet/fsharp/pull/18546))
* Add support for tail calls in computation expressions ([PR #18804](https://github.com/dotnet/fsharp/pull/18804))
* Add `--typecheck-only` flag support for F# Interactive (FSI) scripts to type-check without execution. ([Issue #18686](https://github.com/dotnet/fsharp/issues/18686))
* Allow opens in expression/type scoped. ([Suggestion](https://github.com/fsharp/fslang-suggestions/issues/96), [PR #18814](https://github.com/dotnet/fsharp/pull/18814))

### Fixed

Expand Down
1 change: 1 addition & 0 deletions docs/release-notes/.Language/preview.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Allow `let!`, `use!`, `and!` type annotations without requiring parentheses (([PR #18508](https://github.com/dotnet/fsharp/pull/18508) and [PR #18682](https://github.com/dotnet/fsharp/pull/18682)))
* Exception names are now validated for illegal characters using the same mechanism as types/modules/namespaces ([Issue #18763](https://github.com/dotnet/fsharp/issues/18763))
* Support tail calls in computation expressions ([PR #18804](https://github.com/dotnet/fsharp/pull/18804))
* Allow opens in expression/type scoped. ([Suggestion](https://github.com/fsharp/fslang-suggestions/issues/96), [PR #18814](https://github.com/dotnet/fsharp/pull/18814))

### Fixed

Expand Down
91 changes: 91 additions & 0 deletions src/Compiler/Checking/CheckBasics.fs
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,94 @@ type TcFileState =
}

override _.ToString() = "<cenv>"

open FSharp.Compiler.AttributeChecking
open FSharp.Compiler.Features
open FSharp.Compiler.Syntax.PrettyNaming
open FSharp.Compiler.Text.Range
open FSharp.Compiler.TypedTreeBasics

let CheckNamespaceModuleOrTypeName (g: TcGlobals) (id: Ident) =
// type names '[]' etc. are used in fslib
if not g.compilingFSharpCore && id.idText.IndexOfAny IllegalCharactersInTypeAndNamespaceNames <> -1 then
errorR(Error(FSComp.SR.tcInvalidNamespaceModuleTypeUnionName(), id.idRange))

/// Adjust the TcEnv to account for opening the set of modules or namespaces implied by an `open` declaration
let OpenModuleOrNamespaceRefs tcSink g amap scopem root env mvvs openDeclaration =
let env =
if isNil mvvs then env else
{ env with eNameResEnv = AddModuleOrNamespaceRefsContentsToNameEnv g amap env.eAccessRights scopem root env.eNameResEnv mvvs }
CallEnvSink tcSink (scopem, env.NameEnv, env.eAccessRights)
CallOpenDeclarationSink tcSink openDeclaration
env

//-------------------------------------------------------------------------
// Bind 'open' declarations
//-------------------------------------------------------------------------

let TcOpenLidAndPermitAutoResolve tcSink (env: TcEnv) amap (longId : Ident list) =
let ad = env.AccessRights
match longId with
| [] -> []
| id :: rest ->
let m = longId |> List.map (fun id -> id.idRange) |> List.reduce unionRanges
match ResolveLongIdentAsModuleOrNamespace tcSink amap m true OpenQualified env.NameEnv ad id rest true ShouldNotifySink.Yes with
| Result res -> res
| Exception err ->
errorR(err); []

let TcOpenModuleOrNamespaceDecl tcSink g amap scopem env (longId, m) =
match TcOpenLidAndPermitAutoResolve tcSink env amap longId with
| [] -> env, []
| modrefs ->

// validate opened namespace names
for id in longId do
if id.idText <> MangledGlobalName then
CheckNamespaceModuleOrTypeName g id

let IsPartiallyQualifiedNamespace (modref: ModuleOrNamespaceRef) =
let (CompPath(_, _, p)) = modref.CompilationPath
// Bug FSharp 1.0 3274: FSI paths don't count when determining this warning
let p =
match p with
| [] -> []
| (h, _) :: t -> if h.StartsWithOrdinal FsiDynamicModulePrefix then t else p

// 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
errorR(Error(FSComp.SR.tcModuleRequiresQualifiedAccess(fullDisplayTextOfModRef modref), m)))

// Bug FSharp 1.0 3133: 'open Lexing'. Skip this warning if we successfully resolved to at least a module name
if not (modrefs |> List.exists (fun (_, modref, _) -> modref.IsModule && not (HasFSharpAttribute g g.attrib_RequireQualifiedAccessAttribute modref.Attribs))) then
modrefs |> List.iter (fun (_, modref, _) ->
if IsPartiallyQualifiedNamespace modref then
errorR(Error(FSComp.SR.tcOpenUsedWithPartiallyQualifiedPath(fullDisplayTextOfModRef modref), m)))

let modrefs = List.map p23 modrefs
modrefs |> List.iter (fun modref -> CheckEntityAttributes g modref m |> CommitOperationResult)

let openDecl = OpenDeclaration.Create (SynOpenDeclTarget.ModuleOrNamespace (SynLongIdent(longId, [], []), m), modrefs, [], scopem, false)
let env = OpenModuleOrNamespaceRefs tcSink g amap scopem false env modrefs openDecl
env, [openDecl]
9 changes: 9 additions & 0 deletions src/Compiler/Checking/CheckBasics.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -358,3 +358,12 @@ type TcFileState =
-> range * Expr * TType * SynExpr
-> Expr * UnscopedTyparEnv) ->
TcFileState

val TcOpenModuleOrNamespaceDecl:
tcSink: TcResultsSink ->
g: TcGlobals ->
amap: Import.ImportMap ->
scopem: range ->
env: TcEnv ->
longId: LongIdent * m: range ->
TcEnv * OpenDeclaration list
Loading
Loading