Skip to content
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

Improve completion after method/property override #17292

Merged
merged 34 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
03e7cab
show related completion after = or <> like C#
ijklam May 25, 2024
ed3db60
fix bug; format
ijklam May 25, 2024
1994e63
try fix
ijklam May 25, 2024
4375a4d
fix build
ijklam May 25, 2024
0a204bb
improve class member override completion
ijklam May 26, 2024
a0cccec
support override completion for interface implementation and obj expr
ijklam May 26, 2024
3aa34f8
fix #14375
ijklam May 27, 2024
2ab0062
field completion in method parameter list
ijklam Jun 1, 2024
0636a80
Merge branch 'main' into completion-after-op-improve
ijklam Jun 4, 2024
fc599c1
sync with main
ijklam Jun 4, 2024
e8351b9
sync with main
ijklam Jun 4, 2024
1578994
make override completion of property correctly
ijklam Jun 5, 2024
74967ba
for accessing base method, only write `base`
ijklam Jun 5, 2024
f820edc
exclude implemented method/prop from interface implement of class
ijklam Jun 5, 2024
a0d28a6
simplify completionitem construct
ijklam Jun 6, 2024
0589485
parameter completion on currying function
ijklam Jun 6, 2024
d087238
format code
ijklam Jun 6, 2024
38faffa
fix test
ijklam Jun 6, 2024
4900fd7
Merge branch 'main' into completion-after-op-improve
ijklam Jun 6, 2024
fadd943
Merge branch 'completion-after-op-improve' of https://github.com/Tang…
ijklam Jun 6, 2024
8ba8b4d
Merge from completion-after-op-improve
ijklam Jun 6, 2024
19e678e
fix indexer generation
ijklam Jun 7, 2024
6207dff
update baseline
ijklam Jun 7, 2024
56ab9aa
format; release note
ijklam Jun 7, 2024
92e0255
fix test
ijklam Jun 7, 2024
8160e50
fix tests
ijklam Jun 9, 2024
0531a33
static member completion after the method name
ijklam Jun 9, 2024
d9b5394
format
ijklam Jun 10, 2024
7cf8d41
Merge branch 'main' into completion-after-override
ijklam Jun 10, 2024
67049f6
Fix completion for partial implemented property
ijklam Jun 11, 2024
943b018
fix _.ImplementedSlotSignatures maybe failed
ijklam Jun 11, 2024
48535d3
fix parser
ijklam Jun 26, 2024
7b0b5cc
Merge branch 'main' into completion-after-override
vzarytovskii Jun 26, 2024
f5fe776
fixed typo
psfinaki Jun 27, 2024
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/8.0.400.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@
* Reduce allocations in compiler checking via `ValueOption` usage ([PR #16822](https://github.com/dotnet/fsharp/pull/16822))
* Use AsyncLocal instead of ThreadStatic to hold Cancellable.Token ([PR #17156](https://github.com/dotnet/fsharp/pull/17156))
* Showing and inserting correct name of entities from unopened namespace/module ([Issue #14375](https://github.com/dotnet/fsharp/issues/14375), [PR #17261](https://github.com/dotnet/fsharp/pull/17261))
* Improve completion after method/property override ([PR #17292](https://github.com/dotnet/fsharp/pull/17292))
77 changes: 65 additions & 12 deletions src/Compiler/Checking/InfoReader.fs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ open FSharp.Compiler.TypeHierarchy
open FSharp.Compiler.TypeRelations

/// Use the given function to select some of the member values from the members of an F# type
let SelectImmediateMemberVals g optFilter f (tcref: TyconRef) =
let SelectImmediateMemberVals g optFilter f withExplicitImpl (tcref: TyconRef) =
let chooser (vref: ValRef) =
match vref.MemberInfo with
// The 'when' condition is a workaround for the fact that values providing
// override and interface implementations are published in inferred module types
// These cannot be selected directly via the "." notation.
// However, it certainly is useful to be able to publish these values, as we can in theory
// optimize code to make direct calls to these methods.
| Some membInfo when not (ValRefIsExplicitImpl g vref) ->
| Some membInfo when withExplicitImpl || not (ValRefIsExplicitImpl g vref) ->
f membInfo vref
| _ ->
None
Expand All @@ -53,7 +53,7 @@ let TrySelectMemberVal g optFilter ty pri _membInfo (vref: ValRef) =
else
None

let rec GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m origTy metadataTy =
let rec GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy metadataTy =

let minfos =
match metadataOfTy g metadataTy with
Expand All @@ -77,25 +77,28 @@ let rec GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m origTy
// In this case convert to the .NET Tuple type that carries metadata and try again
if isAnyTupleTy g metadataTy then
let betterMetadataTy = convertToTypeWithMetadataIfPossible g metadataTy
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m origTy betterMetadataTy
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy betterMetadataTy
// Function types support methods FSharpFunc<_, _>.FromConverter and friends from .NET metadata,
// but not instance methods (you can't write "f.Invoke(x)", you have to write "f x")
elif isFunTy g metadataTy then
let betterMetadataTy = convertToTypeWithMetadataIfPossible g metadataTy
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m origTy betterMetadataTy
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy betterMetadataTy
|> List.filter (fun minfo -> not minfo.IsInstance)
else
match tryTcrefOfAppTy g metadataTy with
| ValueNone -> []
| ValueSome tcref ->
SelectImmediateMemberVals g optFilter (TrySelectMemberVal g optFilter origTy None) tcref
SelectImmediateMemberVals g optFilter (TrySelectMemberVal g optFilter origTy None) withExplicitImpl tcref
let minfos = minfos |> List.filter (IsMethInfoAccessible amap m ad)
minfos

/// Query the immediate methods of an F# type, not taking into account inherited methods. The optFilter
/// parameter is an optional name to restrict the set of properties returned.
let GetImmediateIntrinsicMethInfosOfType (optFilter, ad) g amap m ty =
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m ty ty
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m false ty ty

let GetImmediateIntrinsicMethInfosWithExplicitImplOfType (optFilter, ad) g amap m ty =
GetImmediateIntrinsicMethInfosOfTypeAux (optFilter, ad) g amap m true ty ty

/// Query the immediate methods of an F# type, not taking into account inherited methods. The optFilter
/// parameter is an optional name to restrict the set of properties returned.
Expand Down Expand Up @@ -185,7 +188,7 @@ type PropertyCollector(g, amap, m, ty, optFilter, ad) =

member _.Close() = [ for KeyValue(_, pinfo) in props -> pinfo ]

let rec GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m origTy metadataTy =
let rec GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy metadataTy =

let pinfos =
match metadataOfTy g metadataTy with
Expand Down Expand Up @@ -216,22 +219,25 @@ let rec GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m origTy
// In this case convert to the .NET Tuple type that carries metadata and try again
if isAnyTupleTy g metadataTy || isFunTy g metadataTy then
let betterMetadataTy = convertToTypeWithMetadataIfPossible g metadataTy
GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m origTy betterMetadataTy
GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m withExplicitImpl origTy betterMetadataTy
else
match tryTcrefOfAppTy g metadataTy with
| ValueNone -> []
| ValueSome tcref ->
let propCollector = PropertyCollector(g, amap, m, origTy, optFilter, ad)
SelectImmediateMemberVals g None (fun membInfo vref -> propCollector.Collect(membInfo, vref); None) tcref |> ignore
SelectImmediateMemberVals g None (fun membInfo vref -> propCollector.Collect(membInfo, vref); None) withExplicitImpl tcref |> ignore
propCollector.Close()

let pinfos = pinfos |> List.filter (IsPropInfoAccessible g amap m ad)
pinfos

/// Query the immediate properties of an F# type, not taking into account inherited properties. The optFilter
/// parameter is an optional name to restrict the set of properties returned.
let rec GetImmediateIntrinsicPropInfosOfType (optFilter, ad) g amap m ty =
GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m ty ty
let GetImmediateIntrinsicPropInfosOfType (optFilter, ad) g amap m ty =
GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m false ty ty

let GetImmediateIntrinsicPropInfosWithExplicitImplOfType (optFilter, ad) g amap m ty =
GetImmediateIntrinsicPropInfosOfTypeAux (optFilter, ad) g amap m true ty ty

// Checks whether the given type has an indexer property.
let IsIndexerType g amap ty =
Expand Down Expand Up @@ -655,6 +661,44 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this =
PropInfosEquivByNameAndSig EraseNone g amap m,
(fun pinfo -> pinfo.PropertyName))

//type A() =
// abstract E: int with get, set
// default val E = 0 with get
// Will get (A::E with get, A::E with get, set)
// -----
//type A() =
// member val A = 0 with get, set
//type B() =
// inherit A()
// static member val A = 0
// Will get (static B::A, None)
static let FilterOverridesOfPropInfosWithOverridenProp findFlag g amap m props =
let checkProp prop prop2 =
not(obj.ReferenceEquals(prop, prop2)) &&
PropInfosEquivByNameAndSig EraseNone g amap m prop prop2 &&
if prop.HasGetter && prop.HasSetter then false
elif prop.HasGetter then prop2.HasSetter
elif prop.HasSetter then prop2.HasGetter
else false

let rec findPropBefore prop hasMetTheProp =
function
| props :: t when hasMetTheProp ->
match props |> List.tryFind (checkProp prop) with
| Some p -> ValueSome p
| None -> findPropBefore prop true t
| props :: t ->
if props |> List.exists (fun i -> obj.ReferenceEquals(prop, i)) then
match props |> List.tryFind (checkProp prop) with
| Some p -> ValueSome p
| None -> findPropBefore prop true t
else findPropBefore prop false t
| _ -> ValueNone

props
|> FilterOverridesOfPropInfos findFlag g amap m
|> List.map (List.map (fun prop -> struct(prop, if findFlag = FindMemberFlag.IgnoreOverrides || prop.IsNewSlot then ValueNone else findPropBefore prop false props)))

/// Exclude methods from super types which have the same signature as a method in a more specific type.
static let ExcludeHiddenOfMethInfosImpl g amap m (minfos: MethInfo list list) =
minfos
Expand Down Expand Up @@ -905,6 +949,12 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this =
member infoReader.GetIntrinsicPropInfosOfType optFilter ad allowMultiIntfInst findFlag m ty =
infoReader.GetIntrinsicPropInfoSetsOfType optFilter ad allowMultiIntfInst findFlag m ty |> List.concat

/// Get the flattened list of intrinsic properties in the hierarchy
member infoReader.GetIntrinsicPropInfoWithOverriddenPropOfType optFilter ad allowMultiIntfInst findFlag m ty =
infoReader.GetRawIntrinsicPropertySetsOfType(optFilter, ad, allowMultiIntfInst, m, ty)
|> FilterOverridesOfPropInfosWithOverridenProp findFlag infoReader.g infoReader.amap m
|> List.concat

member _.GetTraitInfosInType optFilter ty =
GetImmediateTraitsInfosOfType optFilter g ty

Expand Down Expand Up @@ -958,6 +1008,9 @@ let GetIntrinsicMethInfosOfType (infoReader: InfoReader) optFilter ad allowMulti
let GetIntrinsicPropInfosOfType (infoReader: InfoReader) optFilter ad allowMultiIntfInst findFlag m ty =
infoReader.GetIntrinsicPropInfosOfType optFilter ad allowMultiIntfInst findFlag m ty

let GetIntrinsicPropInfoWithOverriddenPropOfType (infoReader: InfoReader) optFilter ad allowMultiIntfInst findFlag m ty =
infoReader.GetIntrinsicPropInfoWithOverriddenPropOfType optFilter ad allowMultiIntfInst findFlag m ty

let TryFindIntrinsicNamedItemOfType (infoReader: InfoReader) (nm, ad, includeConstraints) findFlag m ty =
infoReader.TryFindIntrinsicNamedItemOfType (nm, ad, includeConstraints) findFlag m ty

Expand Down
31 changes: 31 additions & 0 deletions src/Compiler/Checking/InfoReader.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ val GetImmediateIntrinsicMethInfosOfType:
ty: TType ->
MethInfo list

/// Query the immediate methods of an F# type, not taking into account inherited methods. The optFilter
/// parameter is an optional name to restrict the set of properties returned.
val GetImmediateIntrinsicMethInfosWithExplicitImplOfType:
optFilter: string option * ad: AccessorDomain ->
g: TcGlobals ->
amap: ImportMap ->
m: range ->
ty: TType ->
MethInfo list

/// A helper type to help collect properties.
///
/// Join up getters and setters which are not associated in the F# data structure
Expand All @@ -55,6 +65,16 @@ val GetImmediateIntrinsicPropInfosOfType:
ty: TType ->
PropInfo list

/// Query the immediate properties of an F# type, not taking into account inherited properties. The optFilter
/// parameter is an optional name to restrict the set of properties returned.
val GetImmediateIntrinsicPropInfosWithExplicitImplOfType:
optFilter: string option * ad: AccessorDomain ->
g: TcGlobals ->
amap: ImportMap ->
m: range ->
ty: TType ->
PropInfo list

/// Checks whether the given type has an indexer property.
val IsIndexerType: g: TcGlobals -> amap: ImportMap -> ty: TType -> bool

Expand Down Expand Up @@ -261,6 +281,17 @@ val GetIntrinsicPropInfosOfType:
ty: TType ->
PropInfo list

/// Get the flattened list of intrinsic properties in the hierarchy. If the PropInfo is get-only or set-only, try to find its setter or getter from the hierarchy.
val GetIntrinsicPropInfoWithOverriddenPropOfType:
infoReader: InfoReader ->
optFilter: string option ->
ad: AccessorDomain ->
allowMultiIntfInst: AllowMultiIntfInstantiations ->
findFlag: FindMemberFlag ->
m: range ->
ty: TType ->
struct (PropInfo * PropInfo voption) list

/// Perform type-directed name resolution of a particular named member in an F# type
val TryFindIntrinsicNamedItemOfType:
infoReader: InfoReader ->
Expand Down
Loading
Loading