Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3567144
Initial skeleton + dependencies updates
cartermp Oct 16, 2020
8b4b8cb
Initial proof of concept
cartermp Oct 21, 2020
6b36be5
Cleanup, tag interfaces correctly, surface area
cartermp Oct 21, 2020
b67ebdb
Basic, buggy support for parameter names
cartermp Oct 22, 2020
7f09a76
Preliminary support for not adding hints to already-annotated values
cartermp Oct 23, 2020
e129f58
don't show for typed value decls
cartermp Oct 23, 2020
fcc4be6
No sig files, handle more typed cases
cartermp Oct 23, 2020
626f7ff
Be precise about type annotations when looking for them in the syntax…
cartermp Oct 23, 2020
1c9afe6
More annotations fixity
cartermp Oct 23, 2020
57f8246
Hints show only the return type for functions
cartermp Oct 24, 2020
7dfc1b8
Cleanup and surface tests
cartermp Oct 24, 2020
47ed27a
Match names
cartermp Oct 24, 2020
51dcd6f
Basic tests for arg names
cartermp Oct 24, 2020
d2502db
Fix issues with nested functions + more tests
cartermp Oct 26, 2020
a964414
More testing and fix a bug with annotating return types for methods
cartermp Oct 27, 2020
3169656
Add failing test for infix exprs
cartermp Oct 27, 2020
b565539
Tests and fixes for exprs in infix operators
cartermp Oct 27, 2020
a8e289b
QuickInfo is scoped out + surface area
cartermp Oct 27, 2020
16c0b93
Add IsMethod and change parameter name hints to be more like names pa…
cartermp Oct 28, 2020
7e9eded
Only show type hints for lambdas + tests + surface
cartermp Oct 28, 2020
0ce8403
Preliminary support for labels for methods
cartermp Oct 29, 2020
50e7d9d
Cleanup, handle method params properly, constructors
cartermp Oct 30, 2020
258aa23
Feedback
cartermp Nov 2, 2020
86c25b9
Param names
cartermp Nov 4, 2020
2fef548
Update with latest
cartermp Nov 6, 2020
feaacf7
Update src/fsharp/symbols/Symbols.fsi
cartermp Nov 16, 2020
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
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
<SystemThreadingThreadPoolVersion>4.3.0</SystemThreadingThreadPoolVersion>
<SystemValueTupleVersion>4.5.0</SystemValueTupleVersion>
<!-- Roslyn packages -->
<RoslynVersion>3.9.0-1.20512.2</RoslynVersion>
<RoslynVersion>3.9.0-2.20516.5</RoslynVersion>
<MicrosoftCodeAnalysisEditorFeaturesVersion>$(RoslynVersion)</MicrosoftCodeAnalysisEditorFeaturesVersion>
<MicrosoftCodeAnalysisEditorFeaturesTextVersion>$(RoslynVersion)</MicrosoftCodeAnalysisEditorFeaturesTextVersion>
<MicrosoftCodeAnalysisEditorFeaturesWpfVersion>$(RoslynVersion)</MicrosoftCodeAnalysisEditorFeaturesWpfVersion>
Expand Down
5 changes: 2 additions & 3 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{
"sdk": {
"version": "3.1.302",
"rollForward": "minor"
"version": "3.1.403"
},
"tools": {
"dotnet": "3.1.302",
"dotnet": "3.1.403",
"vs": {
"version": "16.4",
"components": [
Expand Down
17 changes: 15 additions & 2 deletions src/fsharp/NicePrint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,18 @@ module private PrintTypes =

let prettyLayoutOfTypeNoConstraints denv ty =
let ty, _cxs = PrettyTypes.PrettifyType denv.g ty
layoutTypeWithInfoAndPrec denv SimplifyTypes.typeSimplificationInfo0 5 ty
layoutTypeWithInfoAndPrec denv SimplifyTypes.typeSimplificationInfo0 5 ty

let layoutOfValReturnType denv (v: ValRef) =
match v.ValReprInfo with
| None ->
let _, tau = v.TypeScheme
let _argtysl, rty = stripFunTy denv.g tau
layoutReturnType denv SimplifyTypes.typeSimplificationInfo0 rty
| Some (ValReprInfo(_typars, argInfos, _retInfo)) ->
let tau = v.TauType
let _c, rty = GetTopTauTypeInFSharpForm denv.g argInfos tau Range.range0
layoutReturnType denv SimplifyTypes.typeSimplificationInfo0 rty

let layoutAssemblyName _denv (ty: TType) =
ty.GetAssemblyName()
Expand Down Expand Up @@ -2223,7 +2234,9 @@ let prettyLayoutOfValOrMember denv typarInst v = PrintTastMemberOrVals.prettyLay

let prettyLayoutOfValOrMemberNoInst denv v = PrintTastMemberOrVals.prettyLayoutOfValOrMemberNoInst denv v

let prettyLayoutOfMemberNoInstShort denv v = PrintTastMemberOrVals.prettyLayoutOfMemberNoInstShort denv v
let prettyLayoutOfMemberNoInstShort denv v = PrintTastMemberOrVals.prettyLayoutOfMemberNoInstShort denv v

let layoutOfValReturnType denv x = x |> PrintTypes.layoutOfValReturnType denv

let prettyLayoutOfInstAndSig denv x = PrintTypes.prettyLayoutOfInstAndSig denv x

Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/TypedTreeOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2844,7 +2844,7 @@ let tagEntityRefName (xref: EntityRef) name =
elif xref.IsFSharpDelegateTycon then tagDelegate name
elif xref.IsILEnumTycon || xref.IsFSharpEnumTycon then tagEnum name
elif xref.IsStructOrEnumTycon then tagStruct name
elif xref.IsFSharpInterfaceTycon then tagInterface name
elif isInterfaceTyconRef xref then tagInterface name
elif xref.IsUnionTycon then tagUnion name
elif xref.IsRecordTycon then tagRecord name
else tagClass name
Expand Down
105 changes: 89 additions & 16 deletions src/fsharp/service/ServiceParamInfoLocations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,19 @@ open FSharp.Compiler.SyntaxTree
open FSharp.Compiler.SyntaxTreeOps
open FSharp.Compiler.Range

type TupledArgumentLocation = { IsNamedArgument: bool; ArgumentRange: range }

[<Sealed>]
type FSharpNoteworthyParamInfoLocations(longId: string list, longIdRange: range, openParenLocation: pos, tupleEndLocations: pos list, isThereACloseParen: bool, namedParamNames: string option list) =
type FSharpNoteworthyParamInfoLocations
(
longId: string list,
longIdRange: range,
openParenLocation: pos,
argRanges: TupledArgumentLocation list,
tupleEndLocations: pos list,
isThereACloseParen: bool,
namedParamNames: string option list
) =

let tupleEndLocations = Array.ofList tupleEndLocations
let namedParamNames = Array.ofList namedParamNames
Expand All @@ -28,6 +39,7 @@ type FSharpNoteworthyParamInfoLocations(longId: string list, longIdRange: range,
member this.TupleEndLocations = tupleEndLocations
member this.IsThereACloseParen = isThereACloseParen
member this.NamedParamNames = namedParamNames
member this.ArgumentLocations = argRanges |> Array.ofList

[<AutoOpen>]
module internal NoteworthyParamInfoLocationsImpl =
Expand All @@ -50,7 +62,7 @@ module internal NoteworthyParamInfoLocationsImpl =
| _ -> None

type FindResult =
| Found of openParen: pos * commasAndCloseParen: (pos * string option) list * hasClosedParen: bool
| Found of openParen: pos * argRanges: TupledArgumentLocation list * commasAndCloseParen: (pos * string option) list * hasClosedParen: bool
| NotFound

let digOutIdentFromStaticArg (StripParenTypes synType) =
Expand Down Expand Up @@ -86,7 +98,8 @@ module internal NoteworthyParamInfoLocationsImpl =
match inner with
| None ->
if AstTraversal.rangeContainsPosLeftEdgeExclusiveAndRightEdgeInclusive parenRange pos then
Found (parenRange.Start, [(parenRange.End, getNamedParamName synExpr)], rpRangeOpt.IsSome), None
let argRanges = [{ IsNamedArgument = (getNamedParamName synExpr).IsSome; ArgumentRange = synExpr.Range }]
Found (parenRange.Start, argRanges, [(parenRange.End, getNamedParamName synExpr)], rpRangeOpt.IsSome), None
else
NotFound, None
| _ -> NotFound, None
Expand All @@ -103,8 +116,12 @@ module internal NoteworthyParamInfoLocationsImpl =
match inner with
| None ->
if AstTraversal.rangeContainsPosLeftEdgeExclusiveAndRightEdgeInclusive parenRange pos then
// argRange, isNamed
let argRanges =
synExprList
|> List.map (fun e -> { IsNamedArgument = (getNamedParamName e).IsSome; ArgumentRange = e.Range })
let commasAndCloseParen = ((synExprList, commaRanges@[parenRange]) ||> List.map2 (fun e c -> c.End, getNamedParamName e))
let r = Found (parenRange.Start, commasAndCloseParen, rpRangeOpt.IsSome)
let r = Found (parenRange.Start, argRanges, commasAndCloseParen, rpRangeOpt.IsSome)
r, None
else
NotFound, None
Expand All @@ -123,14 +140,14 @@ module internal NoteworthyParamInfoLocationsImpl =

| SynExpr.ArbitraryAfterError (_debugStr, range) -> // single argument when e.g. after open paren you hit EOF
if AstTraversal.rangeContainsPosEdgesExclusive range pos then
let r = Found (range.Start, [(range.End, None)], false)
let r = Found (range.Start, [], [(range.End, None)], false)
r, None
else
NotFound, None

| SynExpr.Const (SynConst.Unit, unitRange) ->
if AstTraversal.rangeContainsPosEdgesExclusive unitRange pos then
let r = Found (unitRange.Start, [(unitRange.End, None)], true)
let r = Found (unitRange.Start, [], [(unitRange.End, None)], true)
r, None
else
NotFound, None
Expand All @@ -141,7 +158,7 @@ module internal NoteworthyParamInfoLocationsImpl =
| None ->
if AstTraversal.rangeContainsPosEdgesExclusive e.Range pos then
// any other expression doesn't start with parens, so if it was the target of an App, then it must be a single argument e.g. "f x"
Found (e.Range.Start, [ (e.Range.End, None) ], false), Some inner
Found (e.Range.Start, [], [ (e.Range.End, None) ], false), Some inner
else
NotFound, Some inner
| _ -> NotFound, Some inner
Expand All @@ -153,7 +170,7 @@ module internal NoteworthyParamInfoLocationsImpl =
let betweenTheBrackets = mkRange wholem.FileName openm.Start wholem.End
if AstTraversal.rangeContainsPosEdgesExclusive betweenTheBrackets pos && args |> List.forall isStaticArg then
let commasAndCloseParen = [ for c in commas -> c.End ] @ [ wholem.End ]
Some (FSharpNoteworthyParamInfoLocations(pathOfLid lid, lidm, openm.Start, commasAndCloseParen, closemOpt.IsSome, args |> List.map digOutIdentFromStaticArg))
Some (FSharpNoteworthyParamInfoLocations(pathOfLid lid, lidm, openm.Start, [], commasAndCloseParen, closemOpt.IsSome, args |> List.map digOutIdentFromStaticArg))
else
None
| _ ->
Expand All @@ -169,9 +186,9 @@ module internal NoteworthyParamInfoLocationsImpl =
| SynExpr.New (_, synType, synExpr, _) ->
let constrArgsResult, cacheOpt = searchSynArgExpr traverseSynExpr pos synExpr
match constrArgsResult, cacheOpt with
| Found(parenLoc, args, isThereACloseParen), _ ->
| Found(parenLoc, argRanges, commasAndCloseParen, isThereACloseParen), _ ->
let typeName = getTypeName synType
Some (FSharpNoteworthyParamInfoLocations(typeName, synType.Range, parenLoc, args |> List.map fst, isThereACloseParen, args |> List.map snd))
Some (FSharpNoteworthyParamInfoLocations(typeName, synType.Range, parenLoc, argRanges, commasAndCloseParen |> List.map fst, isThereACloseParen, commasAndCloseParen |> List.map snd))
| NotFound, Some cache ->
cache
| _ ->
Expand All @@ -190,7 +207,7 @@ module internal NoteworthyParamInfoLocationsImpl =
if AstTraversal.rangeContainsPosEdgesExclusive typeArgsm pos then
// We found it, dig out ident
match digOutIdentFromFuncExpr synExpr with
| Some(lid, lidRange) -> Some (FSharpNoteworthyParamInfoLocations(lid, lidRange, op.idRange.Start, [ wholem.End ], false, []))
| Some(lid, lidRange) -> Some (FSharpNoteworthyParamInfoLocations(lid, lidRange, op.idRange.Start, [], [ wholem.End ], false, []))
| None -> None
else
None
Expand All @@ -205,7 +222,7 @@ module internal NoteworthyParamInfoLocationsImpl =
// Search the argument
let xResult, cacheOpt = searchSynArgExpr traverseSynExpr pos synExpr2
match xResult, cacheOpt with
| Found(parenLoc, args, isThereACloseParen), _ ->
| Found(parenLoc, argRanges, commasAndCloseParen, isThereACloseParen), _ ->
// We found it, dig out ident
match digOutIdentFromFuncExpr synExpr with
| Some(lid, lidRange) ->
Expand All @@ -215,7 +232,7 @@ module internal NoteworthyParamInfoLocationsImpl =
// For now, we don't support infix operators.
None
else
Some (FSharpNoteworthyParamInfoLocations(lid, lidRange, parenLoc, args |> List.map fst, isThereACloseParen, args |> List.map snd))
Some (FSharpNoteworthyParamInfoLocations(lid, lidRange, parenLoc, argRanges, commasAndCloseParen |> List.map fst, isThereACloseParen, commasAndCloseParen |> List.map snd))
| None -> None
| NotFound, Some cache -> cache
| _ -> traverseSynExpr synExpr2
Expand All @@ -228,7 +245,8 @@ module internal NoteworthyParamInfoLocationsImpl =
let typeArgsm = mkRange openm.FileName openm.Start wholem.End
if AstTraversal.rangeContainsPosEdgesExclusive typeArgsm pos && tyArgs |> List.forall isStaticArg then
let commasAndCloseParen = [ for c in commas -> c.End ] @ [ wholem.End ]
let r = FSharpNoteworthyParamInfoLocations(["dummy"], synExpr.Range, openm.Start, commasAndCloseParen, closemOpt.IsSome, tyArgs |> List.map digOutIdentFromStaticArg)
let argRanges = tyArgs |> List.map (fun tyarg -> { IsNamedArgument = false; ArgumentRange = tyarg.Range })
let r = FSharpNoteworthyParamInfoLocations(["dummy"], synExpr.Range, openm.Start, argRanges, commasAndCloseParen, closemOpt.IsSome, tyArgs |> List.map digOutIdentFromStaticArg)
Some r
else
None
Expand All @@ -249,10 +267,10 @@ module internal NoteworthyParamInfoLocationsImpl =
// inherit ty(expr) --- treat it like an application (constructor call)
let xResult, _cacheOpt = searchSynArgExpr defaultTraverse pos expr
match xResult with
| Found(parenLoc, args, isThereACloseParen) ->
| Found(parenLoc, argRanges, commasAndCloseParen, isThereACloseParen) ->
// we found it, dig out ident
let typeName = getTypeName ty
let r = FSharpNoteworthyParamInfoLocations(typeName, ty.Range, parenLoc, args |> List.map fst, isThereACloseParen, args |> List.map snd)
let r = FSharpNoteworthyParamInfoLocations(typeName, ty.Range, parenLoc, argRanges, commasAndCloseParen |> List.map fst, isThereACloseParen, commasAndCloseParen |> List.map snd)
Some r
| NotFound -> None
else None
Expand All @@ -272,3 +290,58 @@ type FSharpNoteworthyParamInfoLocations with
r
| _ -> None

module internal SynExprAppLocationsImpl =
let rec private searchSynArgExpr traverseSynExpr expr ranges =
match expr with
| SynExpr.Const(SynConst.Unit, _) ->
None, None

| SynExprParen(SynExpr.Tuple (_, exprs, _commas, _tupRange), _, _, _parenRange) ->
let rec loop (exprs: SynExpr list) ranges =
match exprs with
| [] -> ranges
| h::t ->
loop t (h.Range :: ranges)

let res = loop exprs ranges
Some (res), None

| SynExprParen(SynExprParen(_, _, _, _) as synExpr, _, _, _parenRange) ->
let r, _cacheOpt = searchSynArgExpr traverseSynExpr synExpr ranges
r, None

| SynExprParen(SynExpr.App (_, _isInfix, _, _, _range), _, _, parenRange) ->
Some (parenRange :: ranges), None

| e ->
let inner = traverseSynExpr e
match inner with
| None ->
Some (e.Range :: ranges), Some inner
| _ -> None, Some inner

let getAllCurriedArgsAtPosition pos parseTree =
AstTraversal.Traverse(pos, parseTree, { new AstTraversal.AstVisitorBase<_>() with
member _.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) =
match expr with
| SynExpr.App (_exprAtomicFlag, _isInfix, funcExpr, argExpr, range) when posEq pos range.Start ->
let isInfixFuncExpr =
match funcExpr with
| SynExpr.App (_, isInfix, _, _, _) -> isInfix
| _ -> false

if isInfixFuncExpr then
traverseSynExpr funcExpr
else
let workingRanges =
match traverseSynExpr funcExpr with
| Some ranges -> ranges
| None -> []

let xResult, cacheOpt = searchSynArgExpr traverseSynExpr argExpr workingRanges
match xResult, cacheOpt with
| Some ranges, _ -> Some ranges
| None, Some cache -> cache
| _ -> traverseSynExpr argExpr
| _ -> defaultTraverse expr })
|> Option.map List.rev
10 changes: 9 additions & 1 deletion src/fsharp/service/ServiceParamInfoLocations.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ namespace FSharp.Compiler.SourceCodeServices
open FSharp.Compiler.Range
open FSharp.Compiler.SyntaxTree

/// Represents the location of a tupled argument, which can optionally be a named argument.
type TupledArgumentLocation = { IsNamedArgument: bool; ArgumentRange: range }

/// Represents the locations relevant to activating parameter info in an IDE
[<Sealed>]
type public FSharpNoteworthyParamInfoLocations =
Expand All @@ -33,8 +36,13 @@ type public FSharpNoteworthyParamInfoLocations =
member IsThereACloseParen : bool

/// Either empty or a name if an actual named parameter; f(0,a=4,?b=None) would be [|None; Some "a"; Some "b"|]
member NamedParamNames : string option []
member NamedParamNames : string option []

/// Array of locations for each argument, and a flag if that argument is named
member ArgumentLocations: TupledArgumentLocation []

/// Find the information about parameter info locations at a particular source location
static member Find : pos * ParsedInput -> FSharpNoteworthyParamInfoLocations option

module internal SynExprAppLocationsImpl =
val getAllCurriedArgsAtPosition: pos: pos -> parseTree: ParsedInput -> range list option
55 changes: 55 additions & 0 deletions src/fsharp/service/ServiceUntypedParse.fs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,61 @@ type FSharpParseFileResults(errors: FSharpErrorInfo[], input: ParsedInput option
match input with
| Some input -> FSharpNoteworthyParamInfoLocations.Find(pos, input)
| _ -> None

member scope.GetAllArgumentsForFunctionApplicationAtPostion pos =
match input with
| Some input -> SynExprAppLocationsImpl.getAllCurriedArgsAtPosition pos input
| None -> None

member scope.IsTypeAnnotationGivenAtPosition pos =
match input with
| Some parseTree ->
let res =
AstTraversal.Traverse(pos, parseTree, { new AstTraversal.AstVisitorBase<_>() with
member _.VisitExpr(_path, _traverseSynExpr, defaultTraverse, expr) =
match expr with
| SynExpr.Typed (_expr, _typeExpr, range) when posEq range.Start pos ->
Some range
| _ -> defaultTraverse expr

override _.VisitSimplePats(pats) =
match pats with
| [] -> None
| _ ->
let exprFunc pat =
match pat with
| SynSimplePat.Typed (_pat, _targetExpr, range) when posEq range.Start pos ->
Some range
| _ ->
None

pats |> List.tryPick exprFunc

override _.VisitPat(defaultTraverse, pat) =
match pat with
| SynPat.Typed (_pat, _targetType, range) when posEq range.Start pos ->
Some range
| _ -> defaultTraverse pat })
res.IsSome
| None -> false

member scope.IsBindingALambdaAtPosition pos =
match input with
| Some parseTree ->
let res =
AstTraversal.Traverse(pos, parseTree, { new AstTraversal.AstVisitorBase<_>() with
member _.VisitExpr(_path, _traverseSynExpr, defaultTraverse, expr) =
defaultTraverse expr

override _.VisitBinding(defaultTraverse, binding) =
match binding with
| SynBinding.Binding(_, _, _, _, _, _, _, _, _, expr, range, _) when posEq range.Start pos ->
match expr with
| SynExpr.Lambda _ -> Some range
| _ -> None
| _ -> defaultTraverse binding })
res.IsSome
| None -> false

/// Get declared items and the selected item at the specified location
member private scope.GetNavigationItemsImpl() =
Expand Down
Loading