Skip to content

[automated] Merge branch 'main' => 'feature/lsp' #18515

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

Open
wants to merge 8 commits into
base: feature/lsp
Choose a base branch
from
Open
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
6 changes: 6 additions & 0 deletions docs/release-notes/.FSharp.Compiler.Service/9.0.300.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@
* Fixed [#18433](https://github.com/dotnet/fsharp/issues/18433), a rare case of an internal error in xml comment processing. ([PR #18436](https://github.com/dotnet/fsharp/pull/18436))
* 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))
* Fix range of SynPat.Named doesn't include accessibility ([PR #18526](https://github.com/dotnet/fsharp/pull/18526))
* Allow `_` in `use!` bindings values (lift FS1228 restriction) ([PR #18487](https://github.com/dotnet/fsharp/pull/18487))
* 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))
* Code completion: fix getting qualifier expression in do statements in type decls ([PR #18524](https://github.com/dotnet/fsharp/pull/18524))
* Fixed: [#18441](https://github.com/dotnet/fsharp/issues/18441) FSI multi-emit unstable. ([PR #18465](https://github.com/dotnet/fsharp/pull/18465))

### Added
* Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241))
Expand All @@ -37,6 +42,7 @@
* Type parameter constraint `null` in generic code will now automatically imply `not struct` ([Issue #18320](https://github.com/dotnet/fsharp/issues/18320), [PR #18323](https://github.com/dotnet/fsharp/pull/18323))
* Add a switch to determine whether to generate a default implementation body for overridden method when completing. [PR #18341](https://github.com/dotnet/fsharp/pull/18341)
* Use a more accurate range for CE Combine methods. [PR #18394](https://github.com/dotnet/fsharp/pull/18394)
* Enable TypeSubsumptionCache for IDE use. [PR #18499](https://github.com/dotnet/fsharp/pull/18499)


### Changed
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 @@ -4,6 +4,7 @@
* Deprecate places where `seq` can be omitted. ([Language suggestion #1033](https://github.com/fsharp/fslang-suggestions/issues/1033), [PR #17772](https://github.com/dotnet/fsharp/pull/17772))
* Added type conversions cache, only enabled for compiler runs ([PR#17668](https://github.com/dotnet/fsharp/pull/17668))
* Support ValueOption + Struct attribute as optional parameter for methods ([Language suggestion #1136](https://github.com/fsharp/fslang-suggestions/issues/1136), [PR #18098](https://github.com/dotnet/fsharp/pull/18098))
* Allow `_` in `use!` bindings values (lift FS1228 restriction) ([PR #18487](https://github.com/dotnet/fsharp/pull/18487))
* Warn when `unit` is passed to an `obj`-typed argument ([PR #18330](https://github.com/dotnet/fsharp/pull/18330))

### Fixed
Expand Down
8 changes: 4 additions & 4 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="9.0.0-beta.25208.6">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="9.0.0-beta.25225.6">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>aa61e8c20a869bcc994f8b29eb07d927d2bec6f4</Sha>
<Sha>bfbc858ba868b60fffaf7b2150f1d2165b01e786</Sha>
</Dependency>
<!-- Intermediate is necessary for source build. -->
<Dependency Name="Microsoft.SourceBuild.Intermediate.arcade" Version="9.0.0-beta.25208.6">
<Dependency Name="Microsoft.SourceBuild.Intermediate.arcade" Version="9.0.0-beta.25225.6">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>aa61e8c20a869bcc994f8b29eb07d927d2bec6f4</Sha>
<Sha>bfbc858ba868b60fffaf7b2150f1d2165b01e786</Sha>
<SourceBuild RepoName="arcade" ManagedOnly="true" />
</Dependency>
<Dependency Name="optimization.windows_nt-x64.MIBC.Runtime" Version="1.0.0-prerelease.24462.2">
Expand Down
2 changes: 1 addition & 1 deletion eng/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ function Test() {
projectname="${projectname%.*}"
testlogpath="$artifacts_dir/TestResults/$configuration/${projectname}_$targetframework.xml"
args="test \"$testproject\" --no-restore --no-build -c $configuration -f $targetframework --test-adapter-path . --logger \"xunit;LogFilePath=$testlogpath\" --blame-hang-timeout 5minutes --results-directory $artifacts_dir/TestResults/$configuration -p:vstestusemsbuildoutput=false"
args+=" -- xUnit.MaxParallelThreads=1"

"$DOTNET_INSTALL_DIR/dotnet" $args || exit $?
}

Expand Down
4 changes: 2 additions & 2 deletions eng/common/core-templates/job/source-index-stage1.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
parameters:
runAsPublic: false
sourceIndexUploadPackageVersion: 2.0.0-20240522.1
sourceIndexProcessBinlogPackageVersion: 1.0.1-20240522.1
sourceIndexUploadPackageVersion: 2.0.0-20250425.2
sourceIndexProcessBinlogPackageVersion: 1.0.1-20250425.2
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
preSteps: []
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"perl": "5.38.2.2"
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25208.6",
"Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.25225.6",
"Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23255.2"
}
}
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/// with generalization at appropriate points.
module internal FSharp.Compiler.CheckComputationExpressions

open FSharp.Compiler.TcGlobals
open Internal.Utilities.Library
open FSharp.Compiler.AccessibilityLogic
open FSharp.Compiler.AttributeChecking
Expand Down Expand Up @@ -1783,12 +1784,33 @@ let rec TryTranslateComputationExpression
if ceenv.isQuery then
error (Error(FSComp.SR.tcBindMayNotBeUsedInQueries (), mBind))

match pat, andBangs with
| (SynPat.Named(ident = SynIdent(id, _); isThisVal = false) | SynPat.LongIdent(longDotId = SynLongIdent(id = [ id ]))), [] ->
match andBangs with
| [] ->
// Valid pattern case - handle with Using + Bind
requireBuilderMethod "Using" mBind cenv ceenv.env ceenv.ad ceenv.builderTy mBind
requireBuilderMethod "Bind" mBind cenv ceenv.env ceenv.ad ceenv.builderTy mBind

let supportsUseBangBindingValueDiscard =
ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.UseBangBindingValueDiscard

// use! x = ...
// use! (x) = ...
// use! (__) = ...
// use! _ = ...
// use! (_) = ...
let rec extractIdentifierFromPattern pat =
match pat with
| SynPat.Named(ident = SynIdent(id, _); isThisVal = false) -> id, pat
| SynPat.LongIdent(longDotId = SynLongIdent(id = [ id ])) -> id, pat
| SynPat.Wild(m) when supportsUseBangBindingValueDiscard ->
// To properly call the Using(disposable) CE member, we need to convert the wildcard to a SynPat.Named
let tmpIdent = mkSynId m "_"
tmpIdent, SynPat.Named(SynIdent(tmpIdent, None), false, None, m)
| SynPat.Paren(pat = pat) -> extractIdentifierFromPattern pat
| _ -> error (Error(FSComp.SR.tcInvalidUseBangBinding (), pat.Range))

let ident, pat = extractIdentifierFromPattern pat

let bindExpr =
let consumeExpr =
SynExpr.MatchLambda(
Expand All @@ -1809,14 +1831,14 @@ let rec TryTranslateComputationExpression
)

let consumeExpr =
mkSynCall "Using" mBind [ SynExpr.Ident id; consumeExpr ] ceenv.builderValName
mkSynCall "Using" mBind [ SynExpr.Ident ident; consumeExpr ] ceenv.builderValName

let consumeExpr =
SynExpr.MatchLambda(
false,
mBind,
[
SynMatchClause(pat, None, consumeExpr, id.idRange, DebugPointAtTarget.No, SynMatchClauseTrivia.Zero)
SynMatchClause(pat, None, consumeExpr, ident.idRange, DebugPointAtTarget.No, SynMatchClauseTrivia.Zero)
],
DebugPointAtBinding.NoneAtInvisible,
mBind
Expand All @@ -1829,8 +1851,7 @@ let rec TryTranslateComputationExpression
|> addBindDebugPoint spBind

Some(translatedCtxt bindExpr)
| _pat, [] -> error (Error(FSComp.SR.tcInvalidUseBangBinding (), mBind))
| _pat, _ands ->
| _ ->
// Has andBangs
let m =
match andBangs with
Expand Down
8 changes: 4 additions & 4 deletions src/Compiler/Checking/TypeRelations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ let TypesFeasiblyEquivStripMeasures g amap m ty1 ty2 =
TypesFeasiblyEquivalent true 0 g amap m ty1 ty2

let inline TryGetCachedTypeSubsumption (g: TcGlobals) (amap: ImportMap) key =
if g.compilationMode = CompilationMode.OneOff && g.langVersion.SupportsFeature LanguageFeature.UseTypeSubsumptionCache then
if g.langVersion.SupportsFeature LanguageFeature.UseTypeSubsumptionCache then
match amap.TypeSubsumptionCache.TryGetValue(key) with
| true, subsumes ->
ValueSome subsumes
Expand All @@ -112,8 +112,8 @@ let inline TryGetCachedTypeSubsumption (g: TcGlobals) (amap: ImportMap) key =
ValueNone

let inline UpdateCachedTypeSubsumption (g: TcGlobals) (amap: ImportMap) key subsumes : unit =
if g.compilationMode = CompilationMode.OneOff && g.langVersion.SupportsFeature LanguageFeature.UseTypeSubsumptionCache then
amap.TypeSubsumptionCache[key] <- subsumes
if g.langVersion.SupportsFeature LanguageFeature.UseTypeSubsumptionCache then
amap.TypeSubsumptionCache.TryAdd(key, subsumes) |> ignore

/// The feasible coercion relation. Part of the language spec.
let rec TypeFeasiblySubsumesType ndeep (g: TcGlobals) (amap: ImportMap) m (ty1: TType) (canCoerce: CanCoerce) (ty2: TType) =
Expand All @@ -125,7 +125,7 @@ let rec TypeFeasiblySubsumesType ndeep (g: TcGlobals) (amap: ImportMap) m (ty1:
let ty2 = stripTyEqns g ty2

// Check if language feature supported
let key = TTypeCacheKey.FromStrippedTypes (ty1, ty2, canCoerce, g)
let key = TTypeCacheKey.FromStrippedTypes (ty1, ty2, canCoerce)

match TryGetCachedTypeSubsumption g amap key with
| ValueSome subsumes ->
Expand Down
42 changes: 22 additions & 20 deletions src/Compiler/Checking/import.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,25 @@ module internal FSharp.Compiler.Import
open System.Collections.Concurrent
open System.Collections.Generic
open System.Collections.Immutable
open FSharp.Compiler.Text.Range
open System.Diagnostics

open Internal.Utilities.Library
open Internal.Utilities.Library.Extras
open Internal.Utilities.TypeHashing
open Internal.Utilities.TypeHashing.HashTypes

open FSharp.Compiler
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.CompilerGlobalState
open FSharp.Compiler.DiagnosticsLogger
open FSharp.Compiler.SyntaxTreeOps
open FSharp.Compiler.Text
open FSharp.Compiler.Text.Range
open FSharp.Compiler.Xml
open FSharp.Compiler.TypedTree
open FSharp.Compiler.TypedTreeBasics
open FSharp.Compiler.TypedTreeOps
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Caches

#if !NO_TYPEPROVIDERS
open FSharp.Compiler.TypeProviders
Expand Down Expand Up @@ -52,18 +55,18 @@ type CanCoerce =
| CanCoerce
| NoCoerce

type [<Struct; NoComparison; CustomEquality>] TTypeCacheKey =
[<Struct; NoComparison; CustomEquality; DebuggerDisplay("{ToString()}")>]
type TTypeCacheKey =

val ty1: TType
val ty2: TType
val canCoerce: CanCoerce
val tcGlobals: TcGlobals

private new (ty1, ty2, canCoerce, tcGlobals) =
{ ty1 = ty1; ty2 = ty2; canCoerce = canCoerce; tcGlobals = tcGlobals }
private new (ty1, ty2, canCoerce) =
{ ty1 = ty1; ty2 = ty2; canCoerce = canCoerce }

static member FromStrippedTypes (ty1, ty2, canCoerce, tcGlobals) =
TTypeCacheKey(ty1, ty2, canCoerce, tcGlobals)
static member FromStrippedTypes (ty1, ty2, canCoerce) =
TTypeCacheKey(ty1, ty2, canCoerce)

interface System.IEquatable<TTypeCacheKey> with
member this.Equals other =
Expand All @@ -72,23 +75,24 @@ type [<Struct; NoComparison; CustomEquality>] TTypeCacheKey =
elif this.ty1 === other.ty1 && this.ty2 === other.ty2 then
true
else
stampEquals this.tcGlobals this.ty1 other.ty1
&& stampEquals this.tcGlobals this.ty2 other.ty2
HashStamps.stampEquals this.ty1 other.ty1
&& HashStamps.stampEquals this.ty2 other.ty2

override this.Equals(other:objnull) =
match other with
| :? TTypeCacheKey as p -> (this :> System.IEquatable<TTypeCacheKey>).Equals p
| _ -> false

override this.GetHashCode() : int =
let g = this.tcGlobals

let ty1Hash = combineHash (hashStamp g this.ty1) (hashTType g this.ty1)
let ty2Hash = combineHash (hashStamp g this.ty2) (hashTType g this.ty2)
override this.GetHashCode () : int =
HashStamps.hashTType this.ty1
|> pipeToHash (HashStamps.hashTType this.ty2)
|> pipeToHash (hash this.canCoerce)

let combined = combineHash (combineHash ty1Hash ty2Hash) (hash this.canCoerce)
override this.ToString () = $"{this.ty1.DebugText}-{this.ty2.DebugText}"

combined
let typeSubsumptionCache =
// Leave most of the capacity in reserve for bursts.
lazy Cache.Create<TTypeCacheKey, bool>({ TotalCapacity = 131072; HeadroomPercentage = 75 }, name = "TypeSubsumptionCache")

//-------------------------------------------------------------------------
// Import an IL types as F# types.
Expand All @@ -106,15 +110,13 @@ type [<Struct; NoComparison; CustomEquality>] TTypeCacheKey =
type ImportMap(g: TcGlobals, assemblyLoader: AssemblyLoader) =
let typeRefToTyconRefCache = ConcurrentDictionary<ILTypeRef, TyconRef>()

let typeSubsumptionCache = ConcurrentDictionary<TTypeCacheKey, bool>(System.Environment.ProcessorCount, 1024)

member _.g = g

member _.assemblyLoader = assemblyLoader

member _.ILTypeRefToTyconRefCache = typeRefToTyconRefCache

member _.TypeSubsumptionCache = typeSubsumptionCache
member val TypeSubsumptionCache: Cache<TTypeCacheKey, bool> = typeSubsumptionCache.Value

let CanImportILScopeRef (env: ImportMap) m scoref =

Expand Down
12 changes: 5 additions & 7 deletions src/Compiler/Checking/import.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ module internal FSharp.Compiler.Import

open Internal.Utilities.Library
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.Caches
open FSharp.Compiler.TcGlobals
open FSharp.Compiler.Text
open FSharp.Compiler.Xml
open FSharp.Compiler.TypedTree

open System.Collections.Concurrent

#if !NO_TYPEPROVIDERS
open FSharp.Compiler.TypeProviders
#endif
Expand Down Expand Up @@ -45,15 +44,14 @@ type CanCoerce =
[<Struct; NoComparison; CustomEquality>]
type TTypeCacheKey =
interface System.IEquatable<TTypeCacheKey>
private new: ty1: TType * ty2: TType * canCoerce: CanCoerce * tcGlobals: TcGlobals -> TTypeCacheKey
private new: ty1: TType * ty2: TType * canCoerce: CanCoerce -> TTypeCacheKey

static member FromStrippedTypes:
ty1: TType * ty2: TType * canCoerce: CanCoerce * tcGlobals: TcGlobals -> TTypeCacheKey
static member FromStrippedTypes: ty1: TType * ty2: TType * canCoerce: CanCoerce -> TTypeCacheKey

val ty1: TType
val ty2: TType
val canCoerce: CanCoerce
val tcGlobals: TcGlobals

override GetHashCode: unit -> int

/// Represents a context used for converting AbstractIL .NET and provided types to F# internal compiler data structures.
Expand All @@ -73,7 +71,7 @@ type ImportMap =
member g: TcGlobals

/// Type subsumption cache
member TypeSubsumptionCache: ConcurrentDictionary<TTypeCacheKey, bool>
member TypeSubsumptionCache: Cache<TTypeCacheKey, bool>

module Nullness =

Expand Down
Loading
Loading