diff --git a/eng/Versions.props b/eng/Versions.props
index 4d4f0b03af3..7d714d3ceb6 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -97,7 +97,7 @@
4.3.0
4.5.0
- 3.9.0-1.20512.2
+ 3.9.0-2.20516.5
$(RoslynVersion)
$(RoslynVersion)
$(RoslynVersion)
diff --git a/global.json b/global.json
index 5fed4a7295e..c2dea3f313b 100644
--- a/global.json
+++ b/global.json
@@ -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": [
diff --git a/src/fsharp/NicePrint.fs b/src/fsharp/NicePrint.fs
index cdfbf1ee89a..23282e25dd5 100755
--- a/src/fsharp/NicePrint.fs
+++ b/src/fsharp/NicePrint.fs
@@ -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()
@@ -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
diff --git a/src/fsharp/TypedTreeOps.fs b/src/fsharp/TypedTreeOps.fs
index 8ce4839b3da..464d6c6fa1d 100644
--- a/src/fsharp/TypedTreeOps.fs
+++ b/src/fsharp/TypedTreeOps.fs
@@ -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
diff --git a/src/fsharp/service/ServiceParamInfoLocations.fs b/src/fsharp/service/ServiceParamInfoLocations.fs
index d70052a74c1..0585c921242 100755
--- a/src/fsharp/service/ServiceParamInfoLocations.fs
+++ b/src/fsharp/service/ServiceParamInfoLocations.fs
@@ -6,8 +6,19 @@ open FSharp.Compiler.SyntaxTree
open FSharp.Compiler.SyntaxTreeOps
open FSharp.Compiler.Range
+type TupledArgumentLocation = { IsNamedArgument: bool; ArgumentRange: range }
+
[]
-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
@@ -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
[]
module internal NoteworthyParamInfoLocationsImpl =
@@ -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) =
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
| _ ->
@@ -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
| _ ->
@@ -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
@@ -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) ->
@@ -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
@@ -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
@@ -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
@@ -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
diff --git a/src/fsharp/service/ServiceParamInfoLocations.fsi b/src/fsharp/service/ServiceParamInfoLocations.fsi
index 618ced81d12..4ce27fc0169 100755
--- a/src/fsharp/service/ServiceParamInfoLocations.fsi
+++ b/src/fsharp/service/ServiceParamInfoLocations.fsi
@@ -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
[]
type public FSharpNoteworthyParamInfoLocations =
@@ -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
diff --git a/src/fsharp/service/ServiceUntypedParse.fs b/src/fsharp/service/ServiceUntypedParse.fs
index bd24fef3fad..3228be7e5cd 100755
--- a/src/fsharp/service/ServiceUntypedParse.fs
+++ b/src/fsharp/service/ServiceUntypedParse.fs
@@ -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() =
diff --git a/src/fsharp/service/ServiceUntypedParse.fsi b/src/fsharp/service/ServiceUntypedParse.fsi
index b88bc0efec3..2cf813b884f 100755
--- a/src/fsharp/service/ServiceUntypedParse.fsi
+++ b/src/fsharp/service/ServiceUntypedParse.fsi
@@ -22,11 +22,20 @@ type public FSharpParseFileResults =
/// Notable parse info for ParameterInfo at a given location
member FindNoteworthyParamInfoLocations : pos:pos -> FSharpNoteworthyParamInfoLocations option
+ /// Gets the ranges of all arguments, if they can be found, for a function application at the given position.
+ member GetAllArgumentsForFunctionApplicationAtPostion: pos: pos -> range list option
+
+ /// Determines if the expression or pattern at the given position has a type annotation
+ member IsTypeAnnotationGivenAtPosition: pos -> bool
+
+ /// Determines if the binding at the given position is bound to a lambda expression
+ member IsBindingALambdaAtPosition: pos -> bool
+
/// Name of the file for which this information were created
- member FileName : string
+ member FileName: string
/// Get declared items and the selected item at the specified location
- member GetNavigationItems : unit -> FSharpNavigationItems
+ member GetNavigationItems: unit -> FSharpNavigationItems
/// Return the inner-most range associated with a possible breakpoint location
member ValidateBreakpointLocation : pos:pos -> range option
diff --git a/src/fsharp/symbols/Symbols.fs b/src/fsharp/symbols/Symbols.fs
index 59b36bcc0d4..d1919bb6717 100644
--- a/src/fsharp/symbols/Symbols.fs
+++ b/src/fsharp/symbols/Symbols.fs
@@ -1645,6 +1645,11 @@ type FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) =
| M m | C m -> m.IsDispatchSlot
| V v -> v.IsDispatchSlot
+ member _.IsMethod =
+ match d with
+ | M _ -> true
+ | _ -> false
+
member x.IsProperty =
match d with
| P _ -> true
@@ -2062,6 +2067,11 @@ type FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) =
| V valRef -> not (SymbolHelpers.isFunction cenv.g valRef.Type)
| _ -> false
+ member x.IsFunction =
+ match d with
+ | V valRef -> SymbolHelpers.isFunction cenv.g valRef.Type
+ | _ -> false
+
override x.Equals(other: obj) =
box x === other ||
match other with
@@ -2082,10 +2092,10 @@ type FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) =
prefix + x.LogicalName
with _ -> "??"
- member x.FormatLayout (context:FSharpDisplayContext) =
+ member x.FormatLayout (displayContext: FSharpDisplayContext) =
match x.IsMember, d with
| true, V v ->
- NicePrint.prettyLayoutOfMemberNoInstShort { (context.Contents cenv.g) with showMemberContainers=true } v.Deref
+ NicePrint.prettyLayoutOfMemberNoInstShort { (displayContext.Contents cenv.g) with showMemberContainers=true } v.Deref
| _,_ ->
checkIsResolved()
let ty =
@@ -2097,8 +2107,26 @@ type FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) =
let argtysl = m.GetParamTypes(cenv.amap, range0, m.FormalMethodInst)
mkIteratedFunTy (List.map (mkRefTupledTy cenv.g) argtysl) rty
| V v -> v.TauType
- NicePrint.prettyLayoutOfTypeNoCx (context.Contents cenv.g) ty
+ NicePrint.prettyLayoutOfTypeNoCx (displayContext.Contents cenv.g) ty
+ member x.GetReturnTypeLayout (displayContext: FSharpDisplayContext) =
+ match x.IsMember, d with
+ | true, _ ->
+ None
+ | false, _ ->
+ checkIsResolved()
+ match d with
+ | E _
+ | P _
+ | C _ -> None
+ | M m ->
+ let rty = m.GetFSharpReturnTy(cenv.amap, range0, m.FormalMethodInst)
+ NicePrint.layoutType (displayContext.Contents cenv.g) rty
+ |> Some
+ | V v ->
+ NicePrint.layoutOfValReturnType (displayContext.Contents cenv.g) v
+ |> Some
+
member x.GetWitnessPassingInfo() =
let witnessInfos =
match d with
diff --git a/src/fsharp/symbols/Symbols.fsi b/src/fsharp/symbols/Symbols.fsi
index f364f2c1f36..cb21f5a0791 100644
--- a/src/fsharp/symbols/Symbols.fsi
+++ b/src/fsharp/symbols/Symbols.fsi
@@ -772,6 +772,9 @@ type FSharpMemberOrFunctionOrValue =
/// Indicates if this is a property member
member IsProperty: bool
+ /// Indicates if this is a method member
+ member IsMethod : bool
+
/// Indicates if this is a property and there exists an associated getter method
member HasGetterMethod: bool
@@ -858,7 +861,13 @@ type FSharpMemberOrFunctionOrValue =
/// Get the name as presented in F# error messages and documentation
member DisplayName: string
- member CurriedParameterGroups: IList>
+ /// List of list of parameters, where each nested item represents a defined parameter
+ ///
+ /// Typically, there is only one nested list.
+ /// However, code such as 'f (a, b) (c, d)' contains two groups, each with two parameters.
+ /// In that example, there is a list made up of two lists, each with a parameter.
+ ///
+ member CurriedParameterGroups : IList>
/// Gets the overloads for the current method
/// matchParameterNumber indicates whether to filter the overloads to match the number of parameters in the current symbol
@@ -900,13 +909,19 @@ type FSharpMemberOrFunctionOrValue =
/// Indicated if this is a value
member IsValue: bool
+
+ /// Indicated if this is a function
+ member IsFunction : bool
/// Indicates if this is a constructor.
member IsConstructor: bool
/// Format the type using the rules of the given display context
- member FormatLayout: context: FSharpDisplayContext -> Layout
-
+ member FormatLayout: displayContext: FSharpDisplayContext -> Layout
+
+ /// Format the type using the rules of the given display context
+ member GetReturnTypeLayout: displayContext: FSharpDisplayContext -> Layout option
+
/// Check if this method has an entrpoint that accepts witness arguments and if so return
/// the name of that entrypoint and information about the additional witness arguments
member GetWitnessPassingInfo: unit -> (string * IList) option
diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs
index 1f94595981f..52220db873b 100644
--- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs
+++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs
@@ -22437,11 +22437,13 @@ FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsOver
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsProperty
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsPropertyGetterMethod
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsPropertySetterMethod
+FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsMethod
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsSetterMethod
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsTypeFunction
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsUnresolved
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsValCompiledAsMethod
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsValue
+FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean IsFunction
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_EventIsStandard()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_HasGetterMethod()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_HasSetterMethod()
@@ -22470,11 +22472,13 @@ FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_Is
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsProperty()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsPropertyGetterMethod()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsPropertySetterMethod()
+FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsMethod()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsSetterMethod()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsTypeFunction()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsUnresolved()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsValCompiledAsMethod()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsValue()
+FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Boolean get_IsFunction()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: FSharp.Compiler.SourceCodeServices.FSharpAccessibility Accessibility
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: FSharp.Compiler.SourceCodeServices.FSharpAccessibility get_Accessibility()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: FSharp.Compiler.SourceCodeServices.FSharpAssembly Assembly
@@ -22500,6 +22504,7 @@ FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: FSharp.Compile
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Int32 GetEffectivelySameAsHash()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Int32 GetHashCode()
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Internal.Utilities.StructuredFormat.Layout FormatLayout(FSharp.Compiler.SourceCodeServices.FSharpDisplayContext)
+FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Microsoft.FSharp.Core.FSharpOption`1[Internal.Utilities.StructuredFormat.Layout] GetReturnTypeLayout(FSharp.Compiler.SourceCodeServices.FSharpDisplayContext)
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Range+range] DeclarationLocation
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Range+range] ImplementationLocation
FSharp.Compiler.SourceCodeServices.FSharpMemberOrFunctionOrValue: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Range+range] SignatureLocation
@@ -22672,6 +22677,19 @@ FSharp.Compiler.SourceCodeServices.FSharpNoteworthyParamInfoLocations: pos get_L
FSharp.Compiler.SourceCodeServices.FSharpNoteworthyParamInfoLocations: pos get_OpenParenLocation()
FSharp.Compiler.SourceCodeServices.FSharpNoteworthyParamInfoLocations: pos[] TupleEndLocations
FSharp.Compiler.SourceCodeServices.FSharpNoteworthyParamInfoLocations: pos[] get_TupleEndLocations()
+FSharp.Compiler.SourceCodeServices.FSharpNoteworthyParamInfoLocations: FSharp.Compiler.SourceCodeServices.TupledArgumentLocation[] ArgumentLocations
+FSharp.Compiler.SourceCodeServices.FSharpNoteworthyParamInfoLocations: FSharp.Compiler.SourceCodeServices.TupledArgumentLocation[] get_ArgumentLocations()
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: Boolean Equals(FSharp.Compiler.SourceCodeServices.TupledArgumentLocation)
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: Boolean Equals(System.Object)
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: Boolean IsNamedArgument
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: Boolean get_IsNamedArgument()
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: Int32 GetHashCode()
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: Int32 GetHashCode(System.Collections.IEqualityComparer)
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: System.String ToString()
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: Void .ctor(Boolean, range)
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: range ArgumentRange
+FSharp.Compiler.SourceCodeServices.TupledArgumentLocation: range get_ArgumentRange()
FSharp.Compiler.SourceCodeServices.FSharpObjectExprOverride: FSharp.Compiler.SourceCodeServices.FSharpAbstractSignature Signature
FSharp.Compiler.SourceCodeServices.FSharpObjectExprOverride: FSharp.Compiler.SourceCodeServices.FSharpAbstractSignature get_Signature()
FSharp.Compiler.SourceCodeServices.FSharpObjectExprOverride: FSharp.Compiler.SourceCodeServices.FSharpExpr Body
@@ -22737,6 +22755,9 @@ FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: FSharp.Compiler.Sourc
FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: FSharp.Compiler.SourceCodeServices.FSharpNavigationItems GetNavigationItems()
FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Range+range] ValidateBreakpointLocation(pos)
FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.SourceCodeServices.FSharpNoteworthyParamInfoLocations] FindNoteworthyParamInfoLocations(pos)
+FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Boolean IsTypeAnnotationGivenAtPosition(pos)
+FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Boolean IsBindingALambdaAtPosition(pos)
+FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Range+range]] GetAllArgumentsForFunctionApplicationAtPostion(pos)
FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.SyntaxTree+ParsedInput] ParseTree
FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.SyntaxTree+ParsedInput] get_ParseTree()
FSharp.Compiler.SourceCodeServices.FSharpParseFileResults: System.String FileName
diff --git a/tests/service/ServiceUntypedParseTests.fs b/tests/service/ServiceUntypedParseTests.fs
index 18c7f7318d1..86185b69e51 100644
--- a/tests/service/ServiceUntypedParseTests.fs
+++ b/tests/service/ServiceUntypedParseTests.fs
@@ -305,3 +305,506 @@ type T =
new (x:int) = ()
"""
getTypeMemberRange source |> shouldEqual [ (3, 4), (3, 20) ]
+
+module FunctionApplicationArguments =
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - Single arg``() =
+ let source = """
+let f x = ()
+f 12
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 2)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - Multi arg``() =
+ let source = """
+let f x y z = ()
+f 1 2 3
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 2); (3, 4); (3, 6)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - Multi arg parentheses``() =
+ let source = """
+let f x y z = ()
+f (1) (2) (3)
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 2); (3, 6); (3, 10)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - Multi arg nested parentheses``() =
+ let source = """
+let f x y z = ()
+f ((1)) (((2))) ((((3))))
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 3); (3, 10); (3, 19)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - unit``() =
+ let source = """
+let f () = ()
+f ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ Assert.IsTrue(res.IsNone, "Found argument for unit-accepting function, which shouldn't be the case.")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - curried function``() =
+ let source = """
+let f x y = x + y
+f 12
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 2)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - tuple value``() =
+ let source = """
+let f (t: int * int) = ()
+let t = (1, 2)
+f t
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 4 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(4, 2)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - tuple literal``() =
+ let source = """
+let f (t: int * int) = ()
+f (1, 2)
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 3); (3, 6)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - tuple value with definition that has explicit names``() =
+ let source = """
+let f ((x, y): int * int) = ()
+let t = (1, 2)
+f t
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 4 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(4, 2)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - tuple literal inside parens``() =
+ let source = """
+let f (x, y) = ()
+f ((1, 2))
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 4); (3, 7)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - tuples with elements as arguments``() =
+ let source = """
+let f (a, b) = ()
+f (1, 2)
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 3); (3, 6)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - top-level arguments with nested function call``() =
+ let source = """
+let f x y = x + y
+f (f 1 2) 3
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 0)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 2); (3, 10)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - nested function argument positions``() =
+ let source = """
+let f x y = x + y
+f (f 1 2) 3
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 3 3)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(3, 5); (3, 7)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - nested function application in infix expression``() =
+ let source = """
+let addStr x y = string x + y
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 2 17)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(2, 24)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - nested function application outside of infix expression``() =
+ let source = """
+let addStr x y = x + string y
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 2 21)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(2, 28)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+ []
+ let ``GetAllArgumentsForFunctionApplicationAtPostion - nested function applications both inside and outside of infix expression``() =
+ let source = """
+let addStr x y = string x + string y
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 2 17)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(2, 24)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+
+ let res = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion (mkPos 2 28)
+ match res with
+ | Some res ->
+ res
+ |> List.map (tups >> fst)
+ |> shouldEqual [(2, 35)]
+ | None ->
+ Assert.Fail("No arguments found in source code")
+
+module TypeAnnotations =
+ []
+ let ``IsTypeAnnotationGivenAtPosition - function - no annotation``() =
+ let source = """
+let f x = ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 6), "Expected no annotation for argument 'x'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - function - single arg annotation``() =
+ let source = """
+let f (x: int) = ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 7), "Expected annotation for argument 'x'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - function - first arg annotated``() =
+ let source = """
+let f (x: int) y = ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 7), "Expected annotation for argument 'x'")
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 15), "Expected no annotation for argument 'x'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - function - second arg annotated``() =
+ let source = """
+let f x (y: string) = ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.False(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 7), "Expected no annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 9), "Expected annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - function - all args annotated``() =
+ let source = """
+let f (x: int) (y: string) = ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 7), "Expected annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 16), "Expected annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - lambda function - all args annotated``() =
+ let source = """
+let f = fun (x: int) (y: string) -> ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 13), "Expected a annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 22), "Expected a annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - constuctor - arg no annotations``() =
+ let source = """
+type C(x) = class end
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 7), "Expected no annotation for argument 'x'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - constuctor - first arg unannotated``() =
+ let source = """
+type C(x, y: string) = class end
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 7), "Expected no annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 10), "Expected annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - constuctor - second arg unannotated``() =
+ let source = """
+type C(x: int, y) = class end
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 7), "Expected annotation for argument 'x'")
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 15), "Expected no annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - constuctor - both args annotated``() =
+ let source = """
+type C(x: int, y: int) = class end
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 7), "Expected annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 15), "Expected annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - method - args no unannotions``() =
+ let source = """
+type C() =
+ member _.M(x, y) = ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 15), "Expected no annotation for argument 'x'")
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 18), "Expected no annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - method - first arg annotated``() =
+ let source = """
+type C() =
+ member _.M(x: int, y) = ()
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 15), "Expected annotation for argument 'x'")
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 23), "Expected no annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - method - second arg annotated``() =
+ let source = """
+type C() =
+ member _.M(x, y: int) = ()
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 15), "Expected no annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 18), "Expected annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - method - both args annotated``() =
+ let source = """
+type C() =
+ member _.M(x: int, y: string) = ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 15), "Expected annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 23), "Expected annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - method currying - args no unannotions``() =
+ let source = """
+type C() =
+ member _.M x y = ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 15), "Expected no annotation for argument 'x'")
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 17), "Expected no annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - method currying - first arg annotated``() =
+ let source = """
+type C() =
+ member _.M (x: int) y = ()
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 16), "Expected annotation for argument 'x'")
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 24), "Expected no annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - method currying - second arg annotated``() =
+ let source = """
+type C() =
+ member _.M x (y: int) = ()
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 16), "Expected no annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 18), "Expected annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - method currying - both args annotated``() =
+ let source = """
+type C() =
+ member _.M (x: int) (y: string) = ()
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 16), "Expected annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 25), "Expected annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - method - only return type annotated``() =
+ let source = """
+type C() =
+ member _.M(x): string = "hello" + x
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 3 15), "Expected no annotation for argument 'x'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - tuple - no annotations``() =
+ let source = """
+let (x, y) = (12, "hello")
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 5), "Expected no annotation for value 'x'")
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 8), "Expected no annotation for value 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - tuple - first value annotated``() =
+ let source = """
+let (x: int, y) = (12, "hello")
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 5), "Expected annotation for argument 'x'")
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 13), "Expected no annotation for argument 'y'")
+
+ []
+ let ``IsTypeAnnotationGivenAtPosition - tuple - second value annotated``() =
+ let source = """
+let (x, y: string) = (12, "hello")
+"""
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 5), "Expected no annotation for argument 'x'")
+ Assert.IsTrue(parseFileResults.IsTypeAnnotationGivenAtPosition (mkPos 2 8), "Expected annotation for argument 'y'")
+
+module LambdaRecognition =
+ []
+ let ``IsBindingALambdaAtPosition - recognize a lambda``() =
+ let source = """
+let f = fun x y -> x + y
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsBindingALambdaAtPosition (mkPos 2 4), "Expected 'f' to be a lambda expression")
+
+ []
+ let ``IsBindingALambdaAtPosition - recognize a nested lambda``() =
+ let source = """
+let f =
+ fun x ->
+ fun y ->
+ x + y
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsBindingALambdaAtPosition (mkPos 2 4), "Expected 'f' to be a lambda expression")
+
+ []
+ let ``IsBindingALambdaAtPosition - recognize a "partial" lambda``() =
+ let source = """
+let f x =
+ fun y ->
+ x + y
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsTrue(parseFileResults.IsBindingALambdaAtPosition (mkPos 2 4), "Expected 'f' to be a lambda expression")
+
+ []
+ let ``IsBindingALambdaAtPosition - not a lambda``() =
+ let source = """
+let f x y = x + y
+ """
+ let parseFileResults, _ = getParseAndCheckResults source
+ Assert.IsFalse(parseFileResults.IsBindingALambdaAtPosition (mkPos 2 4), "'f' is not a lambda expression'")
\ No newline at end of file
diff --git a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs
index 17e2724d6ee..39c4fca7de6 100644
--- a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs
+++ b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs
@@ -10,8 +10,6 @@ open System.Threading.Tasks
open System.Linq
open Microsoft.CodeAnalysis
-open Microsoft.CodeAnalysis.Editor.Implementation.Debugging
-open Microsoft.CodeAnalysis.Host.Mef
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Implementation.Debugging
diff --git a/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs b/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs
index cf37cf08aa6..a69b9106bc4 100644
--- a/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs
+++ b/vsintegration/src/FSharp.Editor/Debugging/LanguageDebugInfoService.fs
@@ -2,7 +2,6 @@
namespace Microsoft.VisualStudio.FSharp.Editor
-open System
open System.Composition
open System.Collections.Generic
open System.Threading
@@ -10,8 +9,6 @@ open System.Threading.Tasks
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Classification
-open Microsoft.CodeAnalysis.Editor.Implementation.Debugging
-open Microsoft.CodeAnalysis.Host.Mef
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.Implementation.Debugging
diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
index 8bc59c35a19..d66c085a386 100644
--- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
+++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
@@ -84,6 +84,7 @@
+
diff --git a/vsintegration/src/FSharp.Editor/InlineHints/InlineHints.fs b/vsintegration/src/FSharp.Editor/InlineHints/InlineHints.fs
new file mode 100644
index 00000000000..fc8035597a7
--- /dev/null
+++ b/vsintegration/src/FSharp.Editor/InlineHints/InlineHints.fs
@@ -0,0 +1,150 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+namespace Microsoft.VisualStudio.FSharp.Editor
+
+open System
+open System.Collections.Immutable
+open System.Threading
+open System.ComponentModel.Composition
+
+open Microsoft.CodeAnalysis
+open Microsoft.CodeAnalysis.Text
+open Microsoft.CodeAnalysis.ExternalAccess.FSharp.InlineHints
+
+open FSharp.Compiler
+open FSharp.Compiler.SourceCodeServices
+open FSharp.Compiler.Range
+
+[)>]
+type internal FSharpInlineHintsService
+ []
+ (
+ checkerProvider: FSharpCheckerProvider,
+ projectInfoManager: FSharpProjectOptionsManager
+ ) =
+
+ static let userOpName = "FSharpInlineHints"
+
+ static let getFirstPositionAfterParen (str: string) startPos =
+ match str with
+ | null -> -1
+ | str when startPos > str.Length -> -1
+ | str ->
+ str.IndexOf('(') + 1
+
+ interface IFSharpInlineHintsService with
+ member _.GetInlineHintsAsync(document: Document, textSpan: TextSpan, cancellationToken: CancellationToken) =
+ asyncMaybe {
+ do! Option.guard (not (isSignatureFile document.FilePath))
+
+ let! _, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
+ let! sourceText = document.GetTextAsync(cancellationToken)
+ let! parseFileResults, _, checkFileResults = checkerProvider.Checker.ParseAndCheckDocument(document, projectOptions, userOpName)
+ let range = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, textSpan, sourceText)
+ let symbolUses =
+ checkFileResults.GetAllUsesOfAllSymbolsInFile(cancellationToken)
+ |> Seq.filter (fun su -> rangeContainsRange range su.RangeAlternate)
+
+ let typeHints = ImmutableArray.CreateBuilder()
+ let parameterHints = ImmutableArray.CreateBuilder()
+
+ let isValidForTypeHint (funcOrValue: FSharpMemberOrFunctionOrValue) (symbolUse: FSharpSymbolUse) =
+ let isLambdaIfFunction =
+ funcOrValue.IsFunction &&
+ parseFileResults.IsBindingALambdaAtPosition symbolUse.RangeAlternate.Start
+
+ (funcOrValue.IsValue || isLambdaIfFunction) &&
+ not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.RangeAlternate.Start) &&
+ symbolUse.IsFromDefinition &&
+ not funcOrValue.IsMember &&
+ not funcOrValue.IsMemberThisValue &&
+ not funcOrValue.IsConstructorThisValue &&
+ not (PrettyNaming.IsOperatorName funcOrValue.DisplayName)
+
+ for symbolUse in symbolUses do
+ match symbolUse.Symbol with
+ | :? FSharpMemberOrFunctionOrValue as funcOrValue when isValidForTypeHint funcOrValue symbolUse ->
+ let typeInfo = ResizeArray()
+
+ let layout =
+ funcOrValue.GetReturnTypeLayout symbolUse.DisplayContext
+ |> Option.defaultValue Layout.emptyL
+
+ layout
+ |> Layout.renderL (Layout.taggedTextListR typeInfo.Add)
+ |> ignore
+
+ let displayParts = ImmutableArray.CreateBuilder()
+ displayParts.Add(TaggedText(TextTags.Text, ": "))
+
+ for tt in typeInfo do
+ displayParts.Add(TaggedText(RoslynHelpers.roslynTag tt.Tag, tt.Text))
+
+ let symbolSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate)
+
+ let hint = FSharpInlineHint(TextSpan(symbolSpan.End, 0), displayParts.ToImmutableArray())
+ typeHints.Add(hint)
+
+ | :? FSharpMemberOrFunctionOrValue as func when func.IsFunction && not symbolUse.IsFromDefinition ->
+ let appliedArgRangesOpt = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion symbolUse.RangeAlternate.Start
+ match appliedArgRangesOpt with
+ | None -> ()
+ | Some [] -> ()
+ | Some appliedArgRanges ->
+ let parameters = func.CurriedParameterGroups |> Seq.concat
+ let appliedArgRanges = appliedArgRanges |> Array.ofList
+ let definitionArgs = parameters |> Array.ofSeq
+
+ for idx = 0 to appliedArgRanges.Length - 1 do
+ let appliedArgRange = appliedArgRanges.[idx]
+ let definitionArgName = definitionArgs.[idx].DisplayName
+ if not (String.IsNullOrWhiteSpace(definitionArgName)) then
+ let appliedArgSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, appliedArgRange)
+ let displayParts = ImmutableArray.Create(TaggedText(TextTags.Text, definitionArgName + " ="))
+ let hint = FSharpInlineHint(TextSpan(appliedArgSpan.Start, 0), displayParts)
+ parameterHints.Add(hint)
+
+ | :? FSharpMemberOrFunctionOrValue as methodOrConstructor when methodOrConstructor.IsMethod || methodOrConstructor.IsConstructor ->
+ let endPosForMethod = symbolUse.RangeAlternate.End
+ let line, _ = Pos.toZ endPosForMethod
+ let afterParenPosInLine = getFirstPositionAfterParen (sourceText.Lines.[line].ToString()) (endPosForMethod.Column)
+ let tupledParamInfos = parseFileResults.FindNoteworthyParamInfoLocations(Pos.fromZ line afterParenPosInLine)
+ let appliedArgRanges = parseFileResults.GetAllArgumentsForFunctionApplicationAtPostion symbolUse.RangeAlternate.Start
+ match tupledParamInfos, appliedArgRanges with
+ | None, None -> ()
+
+ // Prefer looking at the "tupled" view if it exists, even if the other ranges exist.
+ // M(1, 2) can give results for both, but in that case we want the "tupled" view.
+ | Some tupledParamInfos, _ ->
+ let parameters = methodOrConstructor.CurriedParameterGroups |> Seq.concat |> Array.ofSeq
+ for idx = 0 to parameters.Length - 1 do
+ let paramLocationInfo = tupledParamInfos.ArgumentLocations.[idx]
+ let paramName = parameters.[idx].DisplayName
+ if not paramLocationInfo.IsNamedArgument && not (String.IsNullOrWhiteSpace(paramName)) then
+ let appliedArgSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, paramLocationInfo.ArgumentRange)
+ let displayParts = ImmutableArray.Create(TaggedText(TextTags.Text, paramName + " ="))
+ let hint = FSharpInlineHint(TextSpan(appliedArgSpan.Start, 0), displayParts)
+ parameterHints.Add(hint)
+
+ // This will only happen for curried methods defined in F#.
+ | _, Some appliedArgRanges ->
+ let parameters = methodOrConstructor.CurriedParameterGroups |> Seq.concat
+ let appliedArgRanges = appliedArgRanges |> Array.ofList
+ let definitionArgs = parameters |> Array.ofSeq
+
+ for idx = 0 to appliedArgRanges.Length - 1 do
+ let appliedArgRange = appliedArgRanges.[idx]
+ let definitionArgName = definitionArgs.[idx].DisplayName
+ if not (String.IsNullOrWhiteSpace(definitionArgName)) then
+ let appliedArgSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, appliedArgRange)
+ let displayParts = ImmutableArray.Create(TaggedText(TextTags.Text, definitionArgName + " ="))
+ let hint = FSharpInlineHint(TextSpan(appliedArgSpan.Start, 0), displayParts)
+ parameterHints.Add(hint)
+ | _ -> ()
+
+ let typeHints = typeHints.ToImmutableArray()
+ let parameterHints = parameterHints.ToImmutableArray()
+
+ return typeHints.AddRange(parameterHints)
+ }
+ |> Async.map (Option.defaultValue ImmutableArray<_>.Empty)
+ |> RoslynHelpers.StartAsyncAsTask(cancellationToken)