This tutorial demonstrates how to work with symbols provided by the F# compiler. See also project wide analysis for information on symbol references.
NOTE: The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published.
As usual we start by referencing FSharp.Compiler.Service.dll
, opening the relevant namespace and creating an instance of FSharpChecker
:
// Reference F# compiler API
#r "FSharp.Compiler.Service.dll"
open System
open System.IO
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Symbols
open FSharp.Compiler.Text
// Create an interactive checker instance
let checker = FSharpChecker.Create()
We now perform type checking on the specified input:
let parseAndTypeCheckSingleFile (file, input) =
// Get context representing a stand-alone (script) file
let projOptions, errors =
checker.GetProjectOptionsFromScript(file, input, assumeDotNetFramework=false)
|> Async.RunSynchronously
let parseFileResults, checkFileResults =
checker.ParseAndCheckFileInProject(file, 0, input, projOptions)
|> Async.RunSynchronously
// Wait until type checking succeeds (or 100 attempts)
match checkFileResults with
| FSharpCheckFileAnswer.Succeeded(res) -> parseFileResults, res
| res -> failwithf "Parsing did not finish... (%A)" res
let file = "/home/user/Test.fsx"
Getting resolved signature information about the file
After type checking a file, you can access the inferred signature of a project up to and including the checking of the given file through the PartialAssemblySignature
property of the TypeCheckResults
.
The full signature information is available for modules, types, attributes, members, values, functions, union cases, record types, units of measure and other F# language constructs.
The typed expression trees are also available, see typed tree tutorial.
let input2 =
"""
[<System.CLSCompliant(true)>]
let foo(x, y) =
let msg = String.Concat("Hello"," ","world")
if true then
printfn "x = %d, y = %d" x y
printfn "%s" msg
type C() =
member x.P = 1
"""
let parseFileResults, checkFileResults =
parseAndTypeCheckSingleFile(file, SourceText.ofString input2)
Now get the partial assembly signature for the code:
let partialAssemblySignature = checkFileResults.PartialAssemblySignature
partialAssemblySignature.Entities.Count = 1 // one entity
Now get the entity that corresponds to the module containing the code:
let moduleEntity = partialAssemblySignature.Entities.[0]
moduleEntity.DisplayName = "Test"
Now get the entity that corresponds to the type definition in the code:
let classEntity = moduleEntity.NestedEntities.[0]
Now get the value that corresponds to the function defined in the code:
let fnVal = moduleEntity.MembersFunctionsAndValues.[0]
Now look around at the properties describing the function value:
fnVal.Attributes.Count // 1
fnVal.CurriedParameterGroups.Count // 1
fnVal.CurriedParameterGroups.[0].Count // 2
fnVal.CurriedParameterGroups.[0].[0].Name // Some "x"
fnVal.CurriedParameterGroups.[0].[1].Name // Some "y"
fnVal.DeclarationLocation.StartLine // 3
fnVal.DisplayName // "foo"
fnVal.DeclaringEntity.Value.DisplayName // "Test"
fnVal.DeclaringEntity.Value.DeclarationLocation.StartLine // 1
fnVal.GenericParameters.Count // 0
fnVal.InlineAnnotation // FSharpInlineAnnotation.OptionalInline
fnVal.IsActivePattern // false
fnVal.IsCompilerGenerated // false
fnVal.IsDispatchSlot // false
fnVal.IsExtensionMember // false
fnVal.IsPropertyGetterMethod // false
fnVal.IsImplicitConstructor // false
fnVal.IsInstanceMember // false
fnVal.IsMember // false
fnVal.IsModuleValueOrMember // true
fnVal.IsMutable // false
fnVal.IsPropertySetterMethod // false
fnVal.IsTypeFunction // false
Now look at the type of the function if used as a first class value. (Aside: the CurriedParameterGroups
property contains more information like the names of the arguments.)
fnVal.FullType // int * int -> unit
fnVal.FullType.IsFunctionType // int * int -> unit
fnVal.FullType.GenericArguments.[0] // int * int
fnVal.FullType.GenericArguments.[0].IsTupleType // int * int
let argTy1 = fnVal.FullType.GenericArguments.[0].GenericArguments.[0]
argTy1.TypeDefinition.DisplayName // int
OK, so we got an object representation of the type int * int -> unit
, and we have seen the first 'int'. We can find out more about the type 'int' as follows, determining that it is a named type, which is an F# type abbreviation, type int = int32
:
argTy1.HasTypeDefinition
argTy1.TypeDefinition.IsFSharpAbbreviation // "int"
We can now look at the right-hand-side of the type abbreviation, which is the type int32
:
let argTy1b = argTy1.TypeDefinition.AbbreviatedType
argTy1b.TypeDefinition.Namespace // Some "Microsoft.FSharp.Core"
argTy1b.TypeDefinition.CompiledName // "int32"
Again we can now look through the type abbreviation type int32 = System.Int32
to get the full information about the type:
let argTy1c = argTy1b.TypeDefinition.AbbreviatedType
argTy1c.TypeDefinition.Namespace // Some "SystemCore"
argTy1c.TypeDefinition.CompiledName // "Int32"
The type checking results for a file also contain information extracted from the project (or script) options used in the compilation, called the ProjectContext
:
let projectContext = checkFileResults.ProjectContext
for assembly in projectContext.GetReferencedAssemblies() do
match assembly.FileName with
| None -> printfn "compilation referenced an assembly without a file"
| Some s -> printfn "compilation references assembly '%s'" s
Notes:
To check whole projects, create a checker, then call parseAndCheckScript
. In this case, we just check the project for a single script. By specifying a different "projOptions" you can create a specification of a larger project.
let parseAndCheckScript (file, input) =
let projOptions, errors =
checker.GetProjectOptionsFromScript(file, input, assumeDotNetFramework=false)
|> Async.RunSynchronously
checker.ParseAndCheckProject(projOptions) |> Async.RunSynchronously
Now do it for a particular input:
let tmpFile = Path.ChangeExtension(System.IO.Path.GetTempFileName() , "fs")
File.WriteAllText(tmpFile, input2)
let projectResults = parseAndCheckScript(tmpFile, SourceText.ofString input2)
Now look at the results:
let assemblySig = projectResults.AssemblySignature
printfn $"#entities = {assemblySig.Entities.Count}" // 1
printfn $"namespace = {assemblySig.Entities.[0].Namespace}" // one entity
printfn $"entity name = {assemblySig.Entities.[0].DisplayName}" // "Tmp28D0"
printfn $"#members = {assemblySig.Entities.[0].MembersFunctionsAndValues.Count}" // 1
printfn $"member name = {assemblySig.Entities.[0].MembersFunctionsAndValues.[0].DisplayName}" // "foo"
namespace System
namespace System.IO
Multiple items
namespace FSharp
--------------------
namespace Microsoft.FSharp
namespace FSharp.Compiler
namespace FSharp.Compiler.CodeAnalysis
namespace FSharp.Compiler.Symbols
Multiple items
namespace FSharp
--------------------
namespace Microsoft.FSharp
--------------------
type FSharpAttribute = member Format: context: FSharpDisplayContext -> string member IsAttribute: unit -> bool member AttributeType: FSharpEntity with get member ConstructorArguments: IList<FSharpType * objnull> with get member IsUnresolved: bool with get member NamedArguments: IList<FSharpType * string * bool * objnull> with get member Range: range with get
namespace FSharp.Compiler.Text
val checker: FSharpChecker
type FSharpChecker = member CheckFileInProject: parseResults: FSharpParseFileResults * fileName: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * ?userOpName: string -> Async<FSharpCheckFileAnswer> member ClearCache: options: FSharpProjectOptions seq * ?userOpName: string -> unit + 1 overload member ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients: unit -> unit member Compile: argv: string array * ?userOpName: string -> Async<FSharpDiagnostic array * exn option> member FindBackgroundReferencesInFile: fileName: string * options: FSharpProjectOptions * symbol: FSharpSymbol * ?canInvalidateProject: bool * [<Experimental ("This FCS API is experimental and subject to change.")>] ?fastCheck: bool * ?userOpName: string -> Async<range seq> + 1 overload member GetBackgroundCheckResultsForFileInProject: fileName: string * options: FSharpProjectOptions * ?userOpName: string -> Async<FSharpParseFileResults * FSharpCheckFileResults> member GetBackgroundParseResultsForFileInProject: fileName: string * options: FSharpProjectOptions * ?userOpName: string -> Async<FSharpParseFileResults> member GetBackgroundSemanticClassificationForFile: fileName: string * options: FSharpProjectOptions * ?userOpName: string -> Async<SemanticClassificationView option> + 1 overload member GetParsingOptionsFromCommandLineArgs: sourceFiles: string list * argv: string list * ?isInteractive: bool * ?isEditing: bool -> FSharpParsingOptions * FSharpDiagnostic list + 1 overload member GetParsingOptionsFromProjectOptions: options: FSharpProjectOptions -> FSharpParsingOptions * FSharpDiagnostic list ...
<summary> Used to parse and check F# source code. </summary>
static member FSharpChecker.Create: ?projectCacheSize: int * ?keepAssemblyContents: bool * ?keepAllBackgroundResolutions: bool * ?legacyReferenceResolver: LegacyReferenceResolver * ?tryGetMetadataSnapshot: FSharp.Compiler.AbstractIL.ILBinaryReader.ILReaderTryGetMetadataSnapshot * ?suggestNamesForErrors: bool * ?keepAllBackgroundSymbolUses: bool * ?enableBackgroundItemKeyStoreAndSemanticClassification: bool * ?enablePartialTypeChecking: bool * ?parallelReferenceResolution: bool * ?captureIdentifiersWhenParsing: bool * [<Experimental ("This parameter is experimental and likely to be removed in the future.")>] ?documentSource: DocumentSource * [<Experimental ("This parameter is experimental and likely to be removed in the future.")>] ?useTransparentCompiler: bool * [<Experimental ("This parameter is experimental and likely to be removed in the future.")>] ?transparentCompilerCacheSizes: TransparentCompiler.CacheSizes -> FSharpChecker
val parseAndTypeCheckSingleFile: file: string * input: ISourceText -> FSharpParseFileResults * FSharpCheckFileResults
val file: string
val input: ISourceText
val projOptions: FSharpProjectOptions
val errors: FSharp.Compiler.Diagnostics.FSharpDiagnostic list
member FSharpChecker.GetProjectOptionsFromScript: fileName: string * source: ISourceText * ?caret: Position * ?previewEnabled: bool * ?loadedTimeStamp: DateTime * ?otherFlags: string array * ?useFsiAuxLib: bool * ?useSdkRefs: bool * ?assumeDotNetFramework: bool * ?sdkDirOverride: string * ?optionsStamp: int64 * ?userOpName: string -> Async<FSharpProjectOptions * FSharp.Compiler.Diagnostics.FSharpDiagnostic list>
Multiple items
type Async = static member AsBeginEnd: computation: ('Arg -> Async<'T>) -> ('Arg * AsyncCallback * objnull -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit) static member AwaitEvent: event: IEvent<'Del,'T> * ?cancelAction: (unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate) static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -> Async<bool> static member AwaitTask: task: Task<'T> -> Async<'T> + 1 overload static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -> Async<bool> static member CancelDefaultToken: unit -> unit static member Catch: computation: Async<'T> -> Async<Choice<'T,exn>> static member Choice: computations: Async<'T option> seq -> Async<'T option> static member FromBeginEnd: beginAction: (AsyncCallback * objnull -> IAsyncResult) * endAction: (IAsyncResult -> 'T) * ?cancelAction: (unit -> unit) -> Async<'T> + 3 overloads static member FromContinuations: callback: (('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T> ...
--------------------
type Async<'T>
static member Async.RunSynchronously: computation: Async<'T> * ?timeout: int * ?cancellationToken: Threading.CancellationToken -> 'T
val parseFileResults: FSharpParseFileResults
val checkFileResults: FSharpCheckFileAnswer
member FSharpChecker.ParseAndCheckFileInProject: fileName: string * projectSnapshot: FSharpProjectSnapshot * ?userOpName: string -> Async<FSharpParseFileResults * FSharpCheckFileAnswer>
member FSharpChecker.ParseAndCheckFileInProject: fileName: string * fileVersion: int * sourceText: ISourceText * options: FSharpProjectOptions * ?userOpName: string -> Async<FSharpParseFileResults * FSharpCheckFileAnswer>
type FSharpCheckFileAnswer = | Aborted | Succeeded of FSharpCheckFileResults
<summary> The result of calling TypeCheckResult including the possibility of abort and background compiler not caught up. </summary>
union case FSharpCheckFileAnswer.Succeeded: FSharpCheckFileResults -> FSharpCheckFileAnswer
<summary> Success </summary>
val res: FSharpCheckFileResults
val res: FSharpCheckFileAnswer
val failwithf: format: Printf.StringFormat<'T,'Result> -> 'T
val input2: string
val checkFileResults: FSharpCheckFileResults
module SourceText from FSharp.Compiler.Text
<summary> Functions related to ISourceText objects </summary>
val ofString: string -> ISourceText
<summary> Creates an ISourceText object from the given string </summary>
val partialAssemblySignature: FSharpAssemblySignature
property FSharpCheckFileResults.PartialAssemblySignature: FSharpAssemblySignature with get
<summary> Get a view of the contents of the assembly up to and including the file just checked </summary>
property FSharpAssemblySignature.Entities: Collections.Generic.IList<FSharpEntity> with get
<summary> The (non-nested) module and type definitions in this signature </summary>
property Collections.Generic.ICollection.Count: int with get
<summary>Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary>
<returns>The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.</returns>
val moduleEntity: FSharpEntity
property FSharpEntity.DisplayName: string with get
<summary> Get the name of the type or module as displayed in F# code </summary>
val classEntity: FSharpEntity
property FSharpEntity.NestedEntities: Collections.Generic.IList<FSharpEntity> with get
<summary> Get the modules and types defined in a module, or the nested types of a type </summary>
val fnVal: FSharpMemberOrFunctionOrValue
property FSharpEntity.MembersFunctionsAndValues: Collections.Generic.IList<FSharpMemberOrFunctionOrValue> with get
<summary> Get the properties, events and methods of a type definitions, or the functions and values of a module </summary>
property FSharpMemberOrFunctionOrValue.Attributes: Collections.Generic.IList<FSharpAttribute> with get
<summary> Custom attributes attached to the value. These contain references to other values (i.e. constructors in types). Mutable to fixup these value references after copying a collection of values. </summary>
property FSharpMemberOrFunctionOrValue.CurriedParameterGroups: Collections.Generic.IList<Collections.Generic.IList<FSharpParameter>> with get
<summary>List of list of parameters, where each nested item represents a defined parameter</summary>
<remarks> 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. </remarks>
property FSharpMemberOrFunctionOrValue.DeclarationLocation: range with get
<summary> Get the declaration location of the member, function or value </summary>
property Range.StartLine: int with get
<summary> The start line of the range </summary>
property FSharpMemberOrFunctionOrValue.DisplayName: string with get
<summary> Get the name as presented in F# error messages and documentation </summary>
property FSharpMemberOrFunctionOrValue.DeclaringEntity: FSharpEntity option with get
<summary> Get the enclosing entity for the definition </summary>
property Option.Value: FSharpEntity with get
property FSharpEntity.DeclarationLocation: range with get
<summary> Get the declaration location for the type constructor </summary>
property FSharpMemberOrFunctionOrValue.GenericParameters: Collections.Generic.IList<FSharpGenericParameter> with get
<summary> Get the typars of the member, function or value </summary>
property FSharpMemberOrFunctionOrValue.InlineAnnotation: FSharpInlineAnnotation with get
<summary> Get a result indicating if this is a must-inline value </summary>
property FSharpMemberOrFunctionOrValue.IsActivePattern: bool with get
<summary> Indicates if this value or member is an F# active pattern </summary>
property FSharpMemberOrFunctionOrValue.IsCompilerGenerated: bool with get
<summary> Indicates if this is a compiler generated value </summary>
property FSharpMemberOrFunctionOrValue.IsDispatchSlot: bool with get
<summary> Indicates if this is an abstract member? </summary>
property FSharpMemberOrFunctionOrValue.IsExtensionMember: bool with get
<summary> Indicates if this is an extension member? </summary>
property FSharpMemberOrFunctionOrValue.IsPropertyGetterMethod: bool with get
<summary> Indicates if this is a getter method for a property, or a use of a property in getter mode </summary>
property FSharpMemberOrFunctionOrValue.IsImplicitConstructor: bool with get
<summary> Indicates if this is an implicit constructor? </summary>
property FSharpMemberOrFunctionOrValue.IsInstanceMember: bool with get
<summary> Indicates if this is an instance member, when seen from F#? </summary>
property FSharpMemberOrFunctionOrValue.IsMember: bool with get
<summary> Indicates if this is a member, including extension members? </summary>
property FSharpMemberOrFunctionOrValue.IsModuleValueOrMember: bool with get
<summary> Indicates if this is a module or member value </summary>
property FSharpMemberOrFunctionOrValue.IsMutable: bool with get
<summary> Indicates if this is a mutable value </summary>
property FSharpMemberOrFunctionOrValue.IsPropertySetterMethod: bool with get
<summary> Indicates if this is a setter method for a property, or a use of a property in setter mode </summary>
property FSharpMemberOrFunctionOrValue.IsTypeFunction: bool with get
<summary> Indicates if this is an F# type function </summary>
property FSharpMemberOrFunctionOrValue.FullType: FSharpType with get
<summary> Get the full type of the member, function or value when used as a first class value </summary>
property FSharpType.IsFunctionType: bool with get
<summary> Indicates if the type is a function type. The GenericArguments property returns the domain and range of the function type. </summary>
property FSharpType.GenericArguments: Collections.Generic.IList<FSharpType> with get
<summary> Get the generic arguments for a tuple type, a function type or a type constructed using a named entity </summary>
val argTy1: FSharpType
property FSharpType.TypeDefinition: FSharpEntity with get
<summary> Get the type definition for a type </summary>
property FSharpType.HasTypeDefinition: bool with get
<summary> Indicates if the type is constructed using a named entity, including array and byref types </summary>
property FSharpEntity.IsFSharpAbbreviation: bool with get
<summary> Indicates if the entity is a measure, type or exception abbreviation </summary>
val argTy1b: FSharpType
property FSharpEntity.AbbreviatedType: FSharpType with get
<summary> Get the type abbreviated by an F# type abbreviation </summary>
property FSharpEntity.Namespace: string option with get
<summary> Get the namespace containing the type or module, if any. Use 'None' for item not in a namespace. </summary>
property FSharpEntity.CompiledName: string with get
<summary> Get the compiled name of the type or module, possibly with `n mangling. This is identical to LogicalName unless the CompiledName attribute is used. </summary>
val argTy1c: FSharpType
val projectContext: FSharpProjectContext
property FSharpCheckFileResults.ProjectContext: FSharpProjectContext with get
<summary> Get the resolution of the ProjectOptions </summary>
val assembly: FSharpAssembly
member FSharpProjectContext.GetReferencedAssemblies: unit -> FSharpAssembly list
property FSharpAssembly.FileName: string option with get
<summary> The file name for the assembly, if any </summary>
union case Option.None: Option<'T>
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
union case Option.Some: Value: 'T -> Option<'T>
val s: string
val parseAndCheckScript: file: string * input: ISourceText -> FSharpCheckProjectResults
member FSharpChecker.ParseAndCheckProject: projectSnapshot: FSharpProjectSnapshot * ?userOpName: string -> Async<FSharpCheckProjectResults>
member FSharpChecker.ParseAndCheckProject: options: FSharpProjectOptions * ?userOpName: string -> Async<FSharpCheckProjectResults>
val tmpFile: string
type Path = static member ChangeExtension: path: string * extension: string -> string static member Combine: path1: string * path2: string -> string + 4 overloads static member EndsInDirectorySeparator: path: ReadOnlySpan<char> -> bool + 1 overload static member Exists: path: string -> bool static member GetDirectoryName: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetExtension: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFileName: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFileNameWithoutExtension: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload static member GetFullPath: path: string -> string + 1 overload static member GetInvalidFileNameChars: unit -> char array ...
<summary>Performs operations on <see cref="T:System.String" /> instances that contain file or directory path information. These operations are performed in a cross-platform manner.</summary>
[<return:NotNullIfNotNullAttribute ("path")>] Path.ChangeExtension(path: string, extension: string) : string
Path.GetTempFileName() : string
type File = static member AppendAllBytes: path: string * bytes: byte array -> unit + 1 overload static member AppendAllBytesAsync: path: string * bytes: byte array * ?cancellationToken: CancellationToken -> Task + 1 overload static member AppendAllLines: path: string * contents: IEnumerable<string> -> unit + 1 overload static member AppendAllLinesAsync: path: string * contents: IEnumerable<string> * encoding: Encoding * ?cancellationToken: CancellationToken -> Task + 1 overload static member AppendAllText: path: string * contents: ReadOnlySpan<char> -> unit + 3 overloads static member AppendAllTextAsync: path: string * contents: ReadOnlyMemory<char> * encoding: Encoding * ?cancellationToken: CancellationToken -> Task + 3 overloads static member AppendText: path: string -> StreamWriter static member Copy: sourceFileName: string * destFileName: string -> unit + 1 overload static member Create: path: string -> FileStream + 2 overloads static member CreateSymbolicLink: path: string * pathToTarget: string -> FileSystemInfo ...
<summary>Provides static methods for the creation, copying, deletion, moving, and opening of a single file, and aids in the creation of <see cref="T:System.IO.FileStream" /> objects.</summary>
File.WriteAllText(path: string, contents: string) : unit
File.WriteAllText(path: string, contents: ReadOnlySpan<char>) : unit
File.WriteAllText(path: string, contents: string, encoding: Text.Encoding) : unit
File.WriteAllText(path: string, contents: ReadOnlySpan<char>, encoding: Text.Encoding) : unit
val projectResults: FSharpCheckProjectResults
val assemblySig: FSharpAssemblySignature
property FSharpCheckProjectResults.AssemblySignature: FSharpAssemblySignature with get
<summary> Get a view of the overall signature of the assembly. Only valid to use if HasCriticalErrors is false. </summary>
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4