Skip to content

Commit

Permalink
Update FCS
Browse files Browse the repository at this point in the history
GitOrigin-RevId: 11a997867fed14546d1c67461130af8446a548ff
  • Loading branch information
auduchinok committed Jan 15, 2025
1 parent 245e875 commit 0d2fb46
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<ItemGroup>
<PackageLock Include="FSharp.Core" Version="9.0.100-beta.24466.6" />
<PackageLock Include="JetBrains.Annotations" Version="2024.3.0" />
<PackageLock Include="JetBrains.FSharp.Compiler.Service" Version="2024.3.2" />
<PackageLock Include="JetBrains.FSharp.Compiler.Service" Version="2025.1.0" />
<PackageLock Include="JetBrains.Lifetimes" Version="2024.3.0" />
<PackageLock Include="JetBrains.RdFramework" Version="2024.3.0" />
<PackageLock Include="Microsoft.NETCore.Platforms" Version="1.1.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,13 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
let mutable isInvalidating = false

let mutable isDirty = false
let mutable upToDateChecked = null

/// The types that have already been checked in isUpToDate check
let mutable upToDateCheckedTypes = null

/// Set together with `upToDateChecked` set.
/// It's placed outside `isUpToDate` to keep its state if an interruption happens during checking.
let mutable seenOutdatedTypes = false

let mutable moduleDef: (ILModuleDef * ILPreTypeDef[]) option = None
let mutable realModuleReader: ILModuleReader option = realReader
Expand Down Expand Up @@ -155,7 +161,7 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC

// The whole FCS request could've been cancelled and the call above silently exited.
// We need to throw the exception to make FCS handle it properly.
Cancellable.CheckAndThrow()
Cancellable.TryCheckAndThrow()
logger.Trace("readData: after CheckAndThrow");

let isDll (project: IProject) (targetFrameworkId: TargetFrameworkId) =
Expand Down Expand Up @@ -184,13 +190,13 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
let mkDummyTypeDef (name: string) =
let attributes = enum 0
let layout = ILTypeDefLayout.Auto
let implements = emptyILInterfaceImpls
let implements = []
let genericParams = []
let extends = None
let nestedTypes = emptyILTypeDefs

ILTypeDef(name, attributes, layout, emptyILInterfaceImpls, genericParams, extends, emptyILMethods, nestedTypes,
emptyILFields, emptyILMethodImpls, emptyILEvents, emptyILProperties, ILTypeDefAdditionalFlags.None,
ILTypeDef(name, attributes, layout, implements, genericParams, extends, emptyILMethods, nestedTypes,
emptyILFields, emptyILMethodImpls, emptyILEvents, emptyILProperties,
emptyILSecurityDecls, emptyILCustomAttrsStored)

let mkTypeAccessRights (typeElement: ITypeElement): TypeAttributes =
Expand Down Expand Up @@ -1163,17 +1169,20 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
(expected.Value, actual)
||> List.forall2 (fun i1 i2 -> i1.Type = i2.Type)

let isUpToDateBaseType (typeDef: ILTypeDef) typeElement =
not typeDef.Extends.IsValueCreated ||

let actualBaseType = mkTypeDefExtends typeElement
actualBaseType = typeDef.Extends.Value

let rec isUpToDateTypeDef (typeElement: ITypeElement) (fcsTypeDef: FcsTypeDef) =
let typeDef = fcsTypeDef.TypeDef

let extends = mkTypeDefExtends typeElement
extends = typeDef.Extends &&

isUpToDateBaseType typeDef typeElement &&
isUpToDateInterfaceImpls typeElement typeDef &&

isUpToDateTypeParamDefs typeElement.TypeParameters typeDef.GenericParams &&
isUpToDateTypeDefCustomAttributes typeElement typeDef &&
isUpToDateNestedMembers typeElement fcsTypeDef.Members
isUpToDateNestedTypesAndMembers typeElement fcsTypeDef.Members

and isUpToDateNestedTypeDefs (preTypeDefs: ILPreTypeDef[]) =
isNull preTypeDefs ||
Expand All @@ -1188,7 +1197,7 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
let typeElement = symbolScope.GetTypeElementByCLRName(clrTypeName).NotNull("IsUpToDate: nested type")
isUpToDateTypeDef typeElement typeDef)

and isUpToDateNestedMembers (typeElement: ITypeElement) (members: FcsTypeDefMembers) =
and isUpToDateNestedTypesAndMembers (typeElement: ITypeElement) (members: FcsTypeDefMembers) =
isNull members ||

isUpToDateNestedTypeDefs members.NestedTypes &&
Expand Down Expand Up @@ -1216,42 +1225,43 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC

if not isDirty then true else

if isNull upToDateChecked then
upToDateChecked <- HashSet()
if isNull upToDateCheckedTypes then
upToDateCheckedTypes <- HashSet()
seenOutdatedTypes <- false

use cookie = ReadLockCookie.Create()
use compilationCookie = CompilationContextCookie.GetOrCreate(psiModule.GetContextFromModule())

let mutable isUpToDate = true

match moduleDef with
| None -> ()
| Some(_, oldPreTypeDefs) ->
let newPreTypeDefs = mkPreTypeDefs reader
let preTypeDefsUpToDate =
oldPreTypeDefs.Length = newPreTypeDefs.Length &&

// todo: can the order change? Do we want to support it, if yes?
(oldPreTypeDefs, newPreTypeDefs) ||> Array.forall2 (fun oldPreTypeDef newPreTypeDef ->
oldPreTypeDef.Name = newPreTypeDef.Name &&
oldPreTypeDef.Namespace = newPreTypeDef.Namespace
)

if not preTypeDefsUpToDate then
isUpToDate <- false
seenOutdatedTypes <- true

for KeyValue(clrTypeName, fcsTypeDef) in List.ofSeq typeDefs do
Interruption.Current.CheckAndThrow()

if upToDateChecked.Contains(clrTypeName) then () else
if upToDateCheckedTypes.Contains(clrTypeName) then () else

if not (isUpToDateTypeDef clrTypeName fcsTypeDef) then
typeDefs.TryRemove(clrTypeName) |> ignore
isUpToDate <- false
seenOutdatedTypes <- true

upToDateChecked.Add(clrTypeName) |> ignore
upToDateCheckedTypes.Add(clrTypeName) |> ignore

isDirty <- false
isUpToDate
upToDateCheckedTypes <- null
seenOutdatedTypes

member this.CreateTypeDef(clrTypeName: IClrTypeName) =
use lock = usingWriteLock ()
Expand All @@ -1275,7 +1285,7 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
| typeElement ->
let name = mkTypeDefName typeElement clrTypeName
let typeAttributes = mkTypeAttributes typeElement
let extends = mkTypeDefExtends typeElement
let extends = InterruptibleLazy(fun _ -> usingTypeElement clrTypeName None mkTypeDefExtends)
let genericParams = mkGenericParamDefs typeElement

// todo: pass this table in nested types too?
Expand All @@ -1292,9 +1302,17 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
usingTypeElement clrTypeName [||] mkTypeDefCustomAttrs
)

let typeKind =
match typeElement with
| :? IEnum -> ILTypeDefAdditionalFlags.Enum
| :? IStruct -> ILTypeDefAdditionalFlags.ValueType
| :? IDelegate -> ILTypeDefAdditionalFlags.Delegate
| :? IInterface -> ILTypeDefAdditionalFlags.Interface
| _ -> ILTypeDefAdditionalFlags.Class

let additionalFlags =
if hasExtensions then ILTypeDefAdditionalFlags.CanContainExtensionMethods
else ILTypeDefAdditionalFlags.None
if hasExtensions then ILTypeDefAdditionalFlags.CanContainExtensionMethods ||| typeKind
else typeKind

let typeDef =
ILTypeDef(name, typeAttributes, ILTypeDefLayout.Auto, implements,
Expand Down Expand Up @@ -1415,7 +1433,8 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
for clrTypeName in clrNamesByShortNames.GetValuesSafe(shortName) do
this.InvalidateTypeDef(clrTypeName)
isDirty <- true
upToDateChecked <- null
upToDateCheckedTypes <- null
seenOutdatedTypes <- false
finally
isInvalidating <- false

Expand All @@ -1425,6 +1444,8 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
if isUpToDate this then
shim.Logger.Trace("Up to date: {0}", path) else

upToDateCheckedTypes <- null
seenOutdatedTypes <- false
moduleDef <- None
timestamp <- DateTime.UtcNow
shim.Logger.Trace("New timestamp: {0}: {1}", path, timestamp)
Expand All @@ -1436,7 +1457,8 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
use _ = usingWriteLock ()
shim.Logger.Trace("Mark dirty: {0}", path)
isDirty <- true
upToDateChecked <- null
upToDateCheckedTypes <- null
seenOutdatedTypes <- false
finally
isInvalidating <- false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static void UsingReadLockInsideFcs(IShellLocks locks, Action action, Func
// Capture FCS cancellation token so we can propagate cancellation in cases like F#->C#->F#,
// where the last FCS request is initiated from inside reading the C# metadata,
// and the initial request may get cancelled
var fcsToken = Cancellable.Token;
var fcsToken = Cancellable.HasCancellationToken ? Cancellable.Token : CancellationToken.None;
using var _ = Interruption.Current.Add(new LifetimeInterruptionSource(fcsToken));

// Try to acquire read lock on the current thread.
Expand Down Expand Up @@ -76,7 +76,7 @@ public static void UsingReadLockInsideFcs(IShellLocks locks, Action action, Func
// To ensure FCS metadata consistency, we retry cancelled requests in this loop.
// This may happen when R# read lock is cancelled, but the corresponding FCS request in not (yet).
// We should check the FCS request cancellation separately via its cancellation token.
if (Cancellable.Token.IsCancellationRequested)
if (Cancellable.HasCancellationToken && Cancellable.Token.IsCancellationRequested)
{
logger.Trace("UsingReadLockInsideFcs: FCS token is cancelled");
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ type FSharpImplTreeBuilder(lexer, document, decls, lifetime, path, projectedOffs

let memberType =
match typeMember with
| SynMemberDefn.ImplicitInherit(baseType, args, _, _) ->
| SynMemberDefn.ImplicitInherit(baseType, args, _, _, _) ->
x.ProcessTypeAsTypeReferenceName(baseType)
x.MarkChameleonExpression(args)
ElementType.TYPE_INHERIT
Expand All @@ -225,8 +225,9 @@ type FSharpImplTreeBuilder(lexer, document, decls, lifetime, path, projectedOffs
ElementType.INTERFACE_IMPLEMENTATION

| SynMemberDefn.Inherit(baseType, _, _, _) ->
try x.ProcessTypeAsTypeReferenceName(baseType)
with _ -> () // Getting type range throws an exception if base type lid is empty.
match baseType with
| Some baseType -> x.ProcessTypeAsTypeReferenceName(baseType)
| None -> ()
ElementType.INTERFACE_INHERIT

| SynMemberDefn.GetSetMember(getBinding, setBinding, range, trivia) ->
Expand Down
2 changes: 1 addition & 1 deletion ReSharper.FSharp/src/FSharp/PackagesLock.targets
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<PackageLock Include="FSharp.Core" Version="9.0.100-beta.24466.6" />
<PackageLock Include="JetBrains.Annotations" Version="2024.3.0" />
<PackageLock Include="JetBrains.Build.Platform.DistributedCache" Version="1.1.20241202.225" />
<PackageLock Include="JetBrains.FSharp.Compiler.Service" Version="2024.3.2" />
<PackageLock Include="JetBrains.FSharp.Compiler.Service" Version="2025.1.0" />
<PackageLock Include="JetBrains.HabitatDetector" Version="1.4.3" />
<PackageLock Include="JetBrains.Lifetimes" Version="2024.3.0" />
<PackageLock Include="JetBrains.NuGet.Packaging" Version="6.12.20241210.146" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
||(0)module Module
module Module

type T() =
||inherit|(1)|(2)
||inherit|(0)|(1)
---------------------------------------------------------
(0): ReSharper Underlined Error Highlighting: internal error: rangeOfLidwd
(1): ReSharper Underlined Error Highlighting: This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.
(2): ReSharper Underlined Error Highlighting: Type name cannot be empty.
(0): ReSharper Underlined Error Highlighting: This 'inherit' declaration specifies the inherited type but no arguments. Consider supplying arguments, e.g. 'inherit BaseType(args)'.
(1): ReSharper Underlined Error Highlighting: Type name cannot be empty.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ParameterInfo is available
--- All invocables: ----
(int) : string
Parameter: 0 'int'
(x: int) : string
Parameter: 0 'x: int'

--- Accepted invocables: ---
(int) : string
(x: int) : string
2 changes: 1 addition & 1 deletion ReSharper.FSharp/test/src/PackagesLock.targets
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<ItemGroup>
<PackageLock Include="Fantomas.Core" Version="6.3.15" />
<PackageLock Include="FSharp.Core" Version="9.0.100-beta.24466.6" />
<PackageLock Include="JetBrains.FSharp.Compiler.Service" Version="2024.3.2" />
<PackageLock Include="JetBrains.FSharp.Compiler.Service" Version="2025.1.0" />
<PackageLock Include="JetBrains.Lifetimes" Version="2024.3.0" />
<PackageLock Include="JetBrains.NuGet.Frameworks" Version="6.12.20241210.146" />
<PackageLock Include="JetBrains.NuGet.Packaging" Version="6.12.20241210.146" />
Expand Down

0 comments on commit 0d2fb46

Please sign in to comment.