提交 b2d14fc2 编写于 作者: D Don Syme

Merge commit '30b3a8fa' into feature/nullness

# The F# compiler, F# core library, and F# editor tools
[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/fsharp/fsharp-ci?branchName=main)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=90&branchName=main)
[![Help Wanted](https://img.shields.io/github/issues/dotnet/fsharp/help%20wanted?style=flat-square&color=%232EA043&label=help%20wanted)](https://github.com/dotnet/runtime/labels/help%20wanted)
You're invited to contribute to future releases of the F# compiler, core library, and tools. Development of this repository can be done on any OS supported by [.NET](https://dotnet.microsoft.com/).
You will also need the latest .NET 6 SDK installed from [here](https://dotnet.microsoft.com/download/dotnet/6.0).
You will also need the latest .NET 7 SDK installed from [here](https://dotnet.microsoft.com/download/dotnet/7.0).
## Contributing
......@@ -54,12 +57,6 @@ After it's finished, open `FSharp.sln` in your editor of choice.
Even if you find a single-character typo, we're happy to take the change! Although the codebase can feel daunting for beginners, we and other contributors are happy to help you along.
## Build Status
| Branch | Status |
|:------:|:------:|
|main|[![Build Status](https://dev.azure.com/dnceng/public/_apis/build/status/dotnet/fsharp/fsharp-ci?branchName=main)](https://dev.azure.com/dnceng/public/_build/latest?definitionId=496&branchName=main)|
## Per-build NuGet packages
Per-build [versions](https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet-tools&view=versions&package=FSharp.Compiler.Service&protocolType=NuGet) of our NuGet packages are available via this URL: `https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json`
......
......@@ -8,14 +8,14 @@
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.22477.1">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.22480.2">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>0213f8ad31ac8c63ad41760f02a929998abf69bb</Sha>
<Sha>60e9ab3c31d68167f8dac5b8e2c536deb12ef737</Sha>
<SourceBuild RepoName="arcade" ManagedOnly="true" />
</Dependency>
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="8.0.0-beta.22477.1">
<Dependency Name="Microsoft.DotNet.Helix.Sdk" Version="8.0.0-beta.22480.2">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>0213f8ad31ac8c63ad41760f02a929998abf69bb</Sha>
<Sha>60e9ab3c31d68167f8dac5b8e2c536deb12ef737</Sha>
</Dependency>
</ToolsetDependencies>
</Dependencies>
......@@ -113,6 +113,7 @@ try {
$ToolPath = Convert-Path -Path $BinPath
Write-Host "Adding $ToolName to the path ($ToolPath)..."
Write-Host "##vso[task.prependpath]$ToolPath"
$env:PATH = "$ToolPath;$env:PATH"
$InstalledTools += @{ $ToolName = $ToolDirectory.FullName }
}
}
......
......@@ -25,6 +25,7 @@ parameters:
enablePublishTestResults: false
enablePublishUsingPipelines: false
disableComponentGovernance: false
componentGovernanceIgnoreDirectories: ''
mergeTestResults: false
testRunTitle: ''
testResultsFormat: ''
......@@ -146,6 +147,8 @@ jobs:
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), ne(parameters.disableComponentGovernance, 'true')) }}:
- task: ComponentGovernanceComponentDetection@0
continueOnError: true
inputs:
ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }}
- ${{ if eq(parameters.enableMicrobuild, 'true') }}:
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
......@@ -223,4 +226,5 @@ jobs:
parameters:
PackageVersion: ${{ parameters.packageVersion}}
BuildDropPath: ${{ parameters.buildDropPath }}
IgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }}
......@@ -14,7 +14,7 @@ parameters:
# This is the default platform provided by Arcade, intended for use by a managed-only repo.
defaultManagedPlatform:
name: 'Managed'
container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8-20220809204800-17a4aab'
container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8-latest'
# Defines the platforms on which to run build jobs. One job is created for each platform, and the
# object in this array is sent to the job template as 'platform'. If no platforms are specified,
......
......@@ -2,12 +2,14 @@
# PackageName - The name of the package this SBOM represents.
# PackageVersion - The version of the package this SBOM represents.
# ManifestDirPath - The path of the directory where the generated manifest files will be placed
# IgnoreDirectories - Directories to ignore for SBOM generation. This will be passed through to the CG component detector.
parameters:
PackageVersion: 7.0.0
BuildDropPath: '$(Build.SourcesDirectory)/artifacts'
PackageName: '.NET'
ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom
IgnoreDirectories: ''
sbomContinueOnError: true
steps:
......@@ -34,6 +36,8 @@ steps:
BuildDropPath: ${{ parameters.buildDropPath }}
PackageVersion: ${{ parameters.packageVersion }}
ManifestDirPath: ${{ parameters.manifestDirPath }}
${{ if ne(parameters.IgnoreDirectories, '') }}:
AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}'
- task: PublishPipelineArtifact@1
displayName: Publish SBOM manifest
......
......@@ -18,7 +18,7 @@
"perl": "5.32.1.1"
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.22477.1",
"Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.22477.1"
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.22480.2",
"Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.22480.2"
}
}
......@@ -471,13 +471,13 @@ and TcNullPat cenv env patEnv ty m =
and CheckNoArgsForLiteral args m =
match args with
| SynArgPats.Pats []
| SynArgPats.NamePatPairs ([], _) -> ()
| SynArgPats.NamePatPairs (pats = []) -> ()
| _ -> errorR (Error (FSComp.SR.tcLiteralDoesNotTakeArguments (), m))
and GetSynArgPatterns args =
match args with
| SynArgPats.Pats args -> args
| SynArgPats.NamePatPairs (pairs, _) -> List.map (fun (_, _, pat) -> pat) pairs
| SynArgPats.NamePatPairs (pats = pairs) -> List.map (fun (_, _, pat) -> pat) pairs
and TcArgPats warnOnUpper (cenv: cenv) env vFlags patEnv args =
let g = cenv.g
......@@ -600,7 +600,7 @@ and TcPatLongIdentUnionCaseOrExnCase warnOnUpper cenv env ad vFlags patEnv ty (m
let args, extraPatternsFromNames =
match args with
| SynArgPats.Pats args -> args, []
| SynArgPats.NamePatPairs (pairs, m) ->
| SynArgPats.NamePatPairs (pairs, m, _) ->
// rewrite patterns from the form (name-N = pat-N; ...) to (..._, pat-N, _...)
// so type T = Case of name: int * value: int
// | Case(value = v)
......
......@@ -442,6 +442,11 @@ type ILTypeInfo =
member x.IsValueType = x.RawMetadata.IsStructOrEnum
/// Indicates if the type is marked with the [<IsReadOnly>] attribute.
member x.IsReadOnly (g: TcGlobals) =
x.RawMetadata.CustomAttrs
|> TryFindILAttribute g.attrib_IsReadOnlyAttribute
member x.Instantiate inst =
let (ILTypeInfo(g, ty, tref, tdef)) = x
ILTypeInfo(g, instType inst ty, tref, tdef)
......@@ -997,15 +1002,22 @@ type MethInfo =
member x.IsStruct =
isStructTy x.TcGlobals x.ApparentEnclosingType
/// Indicates if this method is read-only; usually by the [<IsReadOnly>] attribute.
member x.IsOnReadOnlyType =
let g = x.TcGlobals
let typeInfo = ILTypeInfo.FromType g x.ApparentEnclosingType
typeInfo.IsReadOnly g
/// Indicates if this method is read-only; usually by the [<IsReadOnly>] attribute on method or struct level.
/// Must be an instance method.
/// Receiver must be a struct type.
member x.IsReadOnly =
// Perf Review: Is there a way we can cache this result?
// Perf Review: Is there a way we can cache this result?
x.IsInstance &&
x.IsStruct &&
match x with
| ILMeth (g, ilMethInfo, _) -> ilMethInfo.IsReadOnly g
| ILMeth (g, ilMethInfo, _) ->
ilMethInfo.IsReadOnly g || x.IsOnReadOnlyType
| FSMeth _ -> false // F# defined methods not supported yet. Must be a language feature.
| _ -> false
......
......@@ -2652,9 +2652,9 @@ type FSharpCheckFileResults
ToolTipText.ToolTipText
[
for kw in names do
match Tokenization.FSharpKeywords.KeywordsDescriptionLookup.TryGetValue kw with
| false, _ -> ()
| true, kwDescription ->
match Tokenization.FSharpKeywords.KeywordsDescriptionLookup kw with
| None -> ()
| Some kwDescription ->
let kwText = kw |> TaggedText.tagKeyword |> wordL |> LayoutRender.toArray
let kwTip = ToolTipElementData.Create(kwText, FSharpXmlDoc.None)
......
......@@ -39,7 +39,7 @@ type ToolTipElementData =
Remarks: TaggedText[] option
ParamName : string option }
static member Create(layout, xml, ?typeMapping, ?paramName, ?remarks) =
static member internal Create(layout, xml, ?typeMapping, ?paramName, ?remarks) =
{ MainDescription=layout; XmlDoc=xml; TypeMapping=defaultArg typeMapping []; ParamName=paramName; Remarks=remarks }
/// A single data tip display element
......
......@@ -31,7 +31,7 @@ type public ToolTipElementData =
ParamName: string option
}
static member Create: layout: TaggedText[] * xml: FSharpXmlDoc * ?typeMapping: TaggedText[] list * ?paramName: string * ?remarks: TaggedText[] -> ToolTipElementData
static member internal Create: layout: TaggedText[] * xml: FSharpXmlDoc * ?typeMapping: TaggedText[] list * ?paramName: string * ?remarks: TaggedText[] -> ToolTipElementData
/// A single tool tip display element
//
......
......@@ -1217,7 +1217,13 @@ module FSharpKeywords =
let KeywordsWithDescription = PrettyNaming.keywordsWithDescription
let KeywordsDescriptionLookup = KeywordsWithDescription |> dict
let internal KeywordsDescriptionLookup =
let d = KeywordsWithDescription |> dict
fun kw ->
match d.TryGetValue kw with
| false, _ -> None
| true, desc -> Some desc
let KeywordNames = Lexhelp.Keywords.keywordNames
......
......@@ -345,7 +345,7 @@ module FSharpKeywords =
val KeywordsWithDescription: (string * string) list
/// A lookup from keywords to their descriptions
val KeywordsDescriptionLookup: System.Collections.Generic.IDictionary<string, string>
val internal KeywordsDescriptionLookup: (string -> string option)
/// All the keywords in the F# language
val KeywordNames: string list
......
......@@ -797,7 +797,7 @@ module SyntaxTraversal =
| SynPat.LongIdent (argPats = args) ->
match args with
| SynArgPats.Pats ps -> ps |> List.tryPick (traversePat path)
| SynArgPats.NamePatPairs (ps, _) -> ps |> List.map (fun (_, _, pat) -> pat) |> List.tryPick (traversePat path)
| SynArgPats.NamePatPairs (pats = ps) -> ps |> List.map (fun (_, _, pat) -> pat) |> List.tryPick (traversePat path)
| SynPat.Typed (p, ty, _) ->
match traversePat path p with
| None -> traverseSynType path ty
......
......@@ -556,7 +556,7 @@ module ParsedInput =
let (|ConstructorPats|) pats =
match pats with
| SynArgPats.Pats ps -> ps
| SynArgPats.NamePatPairs (xs, _) -> List.map (fun (_, _, pat) -> pat) xs
| SynArgPats.NamePatPairs (pats = xs) -> List.map (fun (_, _, pat) -> pat) xs
/// A recursive pattern that collect all sequential expressions to avoid StackOverflowException
let rec (|Sequentials|_|) expr =
......@@ -1567,7 +1567,7 @@ module ParsedInput =
let (|ConstructorPats|) pats =
match pats with
| SynArgPats.Pats ps -> ps
| SynArgPats.NamePatPairs (xs, _) -> List.map (fun (_, _, pat) -> pat) xs
| SynArgPats.NamePatPairs (pats = xs) -> List.map (fun (_, _, pat) -> pat) xs
/// Returns all `Ident`s and `LongIdent`s found in an untyped AST.
let getLongIdents (parsedInput: ParsedInput) : IDictionary<pos, LongIdent> =
......
......@@ -895,12 +895,12 @@ type SynSimplePats =
type SynArgPats =
| Pats of pats: SynPat list
| NamePatPairs of pats: (Ident * range * SynPat) list * range: range
| NamePatPairs of pats: (Ident * range * SynPat) list * range: range * trivia: SynArgPatsNamePatPairsTrivia
member x.Patterns =
match x with
| Pats pats -> pats
| NamePatPairs (pats, _) -> pats |> List.map (fun (_, _, pat) -> pat)
| NamePatPairs (pats = pats) -> pats |> List.map (fun (_, _, pat) -> pat)
[<NoEquality; NoComparison; RequireQualifiedAccess>]
type SynPat =
......
......@@ -1032,7 +1032,7 @@ type SynSimplePats =
type SynArgPats =
| Pats of pats: SynPat list
| NamePatPairs of pats: (Ident * range * SynPat) list * range: range
| NamePatPairs of pats: (Ident * range * SynPat) list * range: range * trivia: SynArgPatsNamePatPairsTrivia
member Patterns: SynPat list
......
......@@ -257,3 +257,6 @@ type SynMemberGetSetTrivia =
AndKeyword: range option
SetKeyword: range option
}
[<NoEquality; NoComparison>]
type SynArgPatsNamePatPairsTrivia = { ParenRange: range }
......@@ -365,3 +365,11 @@ type SynMemberGetSetTrivia =
/// The syntax range of the `set` keyword
SetKeyword: range option
}
/// Represents additional information for SynArgPats.NamePatPairs
[<NoEquality; NoComparison>]
type SynArgPatsNamePatPairsTrivia =
{
/// The syntax range from the beginning of the `(` token till the end of the `)` token.
ParenRange: range
}
......@@ -3245,7 +3245,10 @@ constrPattern:
atomicPatsOrNamePatPairs:
| LPAREN namePatPairs rparen
{ SynArgPats.NamePatPairs $2, snd $2 }
{ let mParen = rhs2 parseState 1 3
let pats, m = $2
let trivia = { ParenRange = mParen }
SynArgPats.NamePatPairs(pats, m, trivia), snd $2 }
| atomicPatterns
{ let mParsed = rhs parseState 1
......
......@@ -70,6 +70,18 @@ module TestCompilerWarningLevel =
|> withDiagnosticMessageMatches "The value has been copied to ensure the original is not mutated by this operation or because the copy is implicit when returning a struct from a member and another member is then accessed$"
|> ignore
#if NETSTANDARD
// This test works with KeyValuePair, which is not a 'readonly struct' in net472
[<Theory; Directory(__SOURCE_DIRECTORY__ + "/../../resources/tests/CompilerOptions/fsc/warn", Includes=[|"nowarn_readonlystruct.fs"|])>]
let ``no error 52 with readonly struct`` compilation =
compilation
|> asExe
|> withOptions ["--warn:5"; "--warnaserror:52"]
|> compile
|> shouldSucceed
|> ignore
#endif
[<Theory; Directory(__SOURCE_DIRECTORY__ + "/../../resources/tests/CompilerOptions/fsc/warn", Includes=[|"warn_level6.fs"|])>]
let ``warn_level6_fs --warn:6`` compilation =
compilation
......
module FSharp.Compiler.ComponentTests.EmittedIL.StructDefensiveCopy
open Xunit
open System.IO
open FSharp.Test
open FSharp.Test.Compiler
let verifyKeyValuePairInstanceMethodCall expectedIl =
FSharp """
module StructUnion01
open System.Runtime.CompilerServices
open System.Collections.Generic
let doWork(kvp1:inref<KeyValuePair<int,int>>) =
kvp1.ToString()
"""
|> ignoreWarnings
|> compile
|> shouldSucceed
|> verifyIL expectedIl
#if NETSTANDARD
// KeyValuePair defined as a readonly struct (in C#)
[<Fact>]
let ``Defensive copy can be skipped on read-only structs``() =
verifyKeyValuePairInstanceMethodCall [""" .method public static string doWork([in] valuetype [runtime]System.Collections.Generic.KeyValuePair`2<int32,int32>& kvp1) cil managed
{
.param [1]
.custom instance void [runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 8
IL_0000: ldarg.0
IL_0001: constrained. valuetype [runtime]System.Collections.Generic.KeyValuePair`2<int32,int32>
IL_0007: callvirt instance string [runtime]System.Object::ToString()
IL_000c: ret
}
} """]
#else
// KeyValuePair just a regular struct. Notice the "ldobj" instruction
[<Fact>]
let ``Non readonly struct needs a defensive copy``() =
verifyKeyValuePairInstanceMethodCall [""" .method public static string doWork([in] valuetype [runtime]System.Collections.Generic.KeyValuePair`2<int32,int32>& kvp1) cil managed
{
.param [1]
.custom instance void [runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 3
.locals init (valuetype [runtime]System.Collections.Generic.KeyValuePair`2<int32,int32> V_0)
IL_0000: ldarg.0
IL_0001: ldobj valuetype [runtime]System.Collections.Generic.KeyValuePair`2<int32,int32>
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: constrained. valuetype [runtime]System.Collections.Generic.KeyValuePair`2<int32,int32>
IL_000f: callvirt instance string [runtime]System.Object::ToString()
IL_0014: ret
} """]
#endif
let verifyDateTimeExtensionMethodCall expectedIl =
FSharp """
module DateTimeExtensionMethod
open System
open System.Collections.Generic
open System.Runtime.CompilerServices
[<Extension>]
type DateTimeExtensions =
[<Extension>]
static member PrintDate(d: inref<DateTime>) = d.ToString()
let doWork(dt:inref<DateTime>) =
dt.PrintDate()
"""
|> ignoreWarnings
|> compile
|> shouldSucceed
|> verifyIL expectedIl
#if NETSTANDARD
// DateTime defined as a readonly struct (in C#)
[<Fact>]
let ``Defensive copy can be skipped for extension methods on read-only structs``() =
verifyDateTimeExtensionMethodCall [""" .method public static string doWork([in] valuetype [runtime]System.DateTime& dt) cil managed
{
.param [1]
.custom instance void [runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 8
IL_0000: ldarg.0
IL_0001: constrained. [runtime]System.DateTime
IL_0007: callvirt instance string [runtime]System.Object::ToString()
IL_000c: ret
} """]
#else
// DateTime just a regular struct. Notice the "ldobj" instruction
[<Fact>]
let ``Non readonly struct needs a defensive copy when its extension method is called``() =
verifyDateTimeExtensionMethodCall [""" .method public static string doWork([in] valuetype [runtime]System.DateTime& dt) cil managed
{
.param [1]
.custom instance void [runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 3
.locals init (valuetype [runtime]System.DateTime& V_0,
valuetype [runtime]System.DateTime V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: ldobj [runtime]System.DateTime
IL_0008: stloc.1
IL_0009: ldloca.s V_1
IL_000b: constrained. [runtime]System.DateTime
IL_0011: callvirt instance string [runtime]System.Object::ToString()
IL_0016: ret
} """]
#endif
#if NETSTANDARD
[<Fact>]
#endif
let ``Csharp extension method on a readonly struct does not need defensive copy``() =
let csLib =
CSharp """
using System;
public static class DateTimeExtensionMethod
{
public static string CustomPrintDate(this in DateTime d)
{
return d.Date.ToShortDateString();
}
}""" |> withName "CsLib"
FSharp """
module DateTimeDefinedInCsharpUsage
open System
let doWork(dt:inref<DateTime>) =
dt.CustomPrintDate()
"""
|> withReferences [csLib]
|> ignoreWarnings
|> compile
|> shouldSucceed
|> verifyIL [""" .method public static string doWork([in] valuetype [runtime]System.DateTime& dt) cil managed
{
.param [1]
.custom instance void [runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 8
IL_0000: ldarg.0
IL_0001: call string [CsLib]DateTimeExtensionMethod::CustomPrintDate(valuetype [runtime]System.DateTime&)
IL_0006: ret
} """]
......@@ -134,6 +134,7 @@
<Compile Include="EmittedIL\Structure\Structure.fs" />
<Compile Include="EmittedIL\TestFunctions\TestFunctions.fs" />
<Compile Include="EmittedIL\Tuples\Tuples.fs" />
<Compile Include="EmittedIL\StructDefensiveCopy\StructDefensiveCopy.fs" />
<Compile Include="ErrorMessages\UnsupportedAttributes.fs" />
<Compile Include="ErrorMessages\TypeEqualsMissingTests.fs" />
<Compile Include="ErrorMessages\AccessOfTypeAbbreviationTests.fs" />
......
// #Regression #NoMT #CompilerOptions
// See DevDiv:364238
open System.Collections.Generic
let x : IEnumerator<KeyValuePair<int, int>> = failwith ""
printfn "%A" x.Current.Key // no defensive copy needed, because KeyValuePair is a "readonly struct"
let y : list<KeyValuePair<int, int>> = failwith "" // KeyValuePair<int, int>
printfn "%A" y.[0].Key // no defensive copy needed, because KeyValuePair is a "readonly struct"
......@@ -2,8 +2,12 @@
// See DevDiv:364238
open System.Collections.Generic
let x : IEnumerator<KeyValuePair<int, int>> = failwith ""
printfn "%A" x.Current.Key // defensive copy
[<Struct>]
type NonReadOnlyStruct=
member val Property = "" with get, set
let y : list<KeyValuePair<int, int>> = failwith ""
printfn "%A" y.[0].Key // defensive copy
let x : IEnumerator<NonReadOnlyStruct> = failwith ""
printfn "%A" x.Current.Property // defensive copy
let y : list<NonReadOnlyStruct> = failwith "" // KeyValuePair<int, int>
printfn "%A" y.[0].Property // defensive copy
......@@ -3977,7 +3977,6 @@ FSharp.Compiler.EditorServices.ToolTipElementData
FSharp.Compiler.EditorServices.ToolTipElementData: Boolean Equals(FSharp.Compiler.EditorServices.ToolTipElementData)
FSharp.Compiler.EditorServices.ToolTipElementData: Boolean Equals(System.Object)
FSharp.Compiler.EditorServices.ToolTipElementData: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
FSharp.Compiler.EditorServices.ToolTipElementData: FSharp.Compiler.EditorServices.ToolTipElementData Create(FSharp.Compiler.Text.TaggedText[], FSharp.Compiler.Symbols.FSharpXmlDoc, Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Text.TaggedText[]]], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.TaggedText[]])
FSharp.Compiler.EditorServices.ToolTipElementData: FSharp.Compiler.Symbols.FSharpXmlDoc XmlDoc
FSharp.Compiler.EditorServices.ToolTipElementData: FSharp.Compiler.Symbols.FSharpXmlDoc get_XmlDoc()
FSharp.Compiler.EditorServices.ToolTipElementData: FSharp.Compiler.Text.TaggedText[] MainDescription
......@@ -5830,6 +5829,8 @@ FSharp.Compiler.Syntax.SynArgInfo: Microsoft.FSharp.Core.FSharpOption`1[FSharp.C
FSharp.Compiler.Syntax.SynArgInfo: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident] ident
FSharp.Compiler.Syntax.SynArgInfo: System.String ToString()
FSharp.Compiler.Syntax.SynArgPats
FSharp.Compiler.Syntax.SynArgPats+NamePatPairs: FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia get_trivia()
FSharp.Compiler.Syntax.SynArgPats+NamePatPairs: FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia trivia
FSharp.Compiler.Syntax.SynArgPats+NamePatPairs: FSharp.Compiler.Text.Range get_range()
FSharp.Compiler.Syntax.SynArgPats+NamePatPairs: FSharp.Compiler.Text.Range range
FSharp.Compiler.Syntax.SynArgPats+NamePatPairs: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Syntax.Ident,FSharp.Compiler.Text.Range,FSharp.Compiler.Syntax.SynPat]] get_pats()
......@@ -5842,7 +5843,7 @@ FSharp.Compiler.Syntax.SynArgPats: Boolean IsNamePatPairs
FSharp.Compiler.Syntax.SynArgPats: Boolean IsPats
FSharp.Compiler.Syntax.SynArgPats: Boolean get_IsNamePatPairs()
FSharp.Compiler.Syntax.SynArgPats: Boolean get_IsPats()
FSharp.Compiler.Syntax.SynArgPats: FSharp.Compiler.Syntax.SynArgPats NewNamePatPairs(Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Syntax.Ident,FSharp.Compiler.Text.Range,FSharp.Compiler.Syntax.SynPat]], FSharp.Compiler.Text.Range)
FSharp.Compiler.Syntax.SynArgPats: FSharp.Compiler.Syntax.SynArgPats NewNamePatPairs(Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`3[FSharp.Compiler.Syntax.Ident,FSharp.Compiler.Text.Range,FSharp.Compiler.Syntax.SynPat]], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia)
FSharp.Compiler.Syntax.SynArgPats: FSharp.Compiler.Syntax.SynArgPats NewPats(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynPat])
FSharp.Compiler.Syntax.SynArgPats: FSharp.Compiler.Syntax.SynArgPats+NamePatPairs
FSharp.Compiler.Syntax.SynArgPats: FSharp.Compiler.Syntax.SynArgPats+Pats
......@@ -9396,6 +9397,11 @@ FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia: Microsoft.FSharp.Collecti
FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia] get_ConditionalDirectives()
FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia: System.String ToString()
FSharp.Compiler.SyntaxTrivia.ParsedSigFileInputTrivia: Void .ctor(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTrivia.ConditionalDirectiveTrivia], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.SyntaxTrivia.CommentTrivia])
FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia
FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia: FSharp.Compiler.Text.Range ParenRange
FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia: FSharp.Compiler.Text.Range get_ParenRange()
FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia: System.String ToString()
FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia: Void .ctor(FSharp.Compiler.Text.Range)
FSharp.Compiler.SyntaxTrivia.SynBindingTrivia
FSharp.Compiler.SyntaxTrivia.SynBindingTrivia: FSharp.Compiler.SyntaxTrivia.SynBindingTrivia Zero
FSharp.Compiler.SyntaxTrivia.SynBindingTrivia: FSharp.Compiler.SyntaxTrivia.SynBindingTrivia get_Zero()
......@@ -9901,8 +9907,6 @@ FSharp.Compiler.Tokenization.FSharpKeywords: Microsoft.FSharp.Collections.FSharp
FSharp.Compiler.Tokenization.FSharpKeywords: Microsoft.FSharp.Collections.FSharpList`1[System.String] get_KeywordNames()
FSharp.Compiler.Tokenization.FSharpKeywords: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] KeywordsWithDescription
FSharp.Compiler.Tokenization.FSharpKeywords: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.String,System.String]] get_KeywordsWithDescription()
FSharp.Compiler.Tokenization.FSharpKeywords: System.Collections.Generic.IDictionary`2[System.String,System.String] KeywordsDescriptionLookup
FSharp.Compiler.Tokenization.FSharpKeywords: System.Collections.Generic.IDictionary`2[System.String,System.String] get_KeywordsDescriptionLookup()
FSharp.Compiler.Tokenization.FSharpKeywords: System.String NormalizeIdentifierBackticks(System.String)
FSharp.Compiler.Tokenization.FSharpLexer
FSharp.Compiler.Tokenization.FSharpLexer: Void Tokenize(FSharp.Compiler.Text.ISourceText, Microsoft.FSharp.Core.FSharpFunc`2[FSharp.Compiler.Tokenization.FSharpToken,Microsoft.FSharp.Core.Unit], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[System.String]], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Tokenization.FSharpLexerFlags], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpMap`2[System.String,System.String]], Microsoft.FSharp.Core.FSharpOption`1[System.Threading.CancellationToken])
......
......@@ -97,4 +97,28 @@ match x with
)
]) ])) ->
Assert.AreEqual("op_ColonColon", opColonColonIdent.idText)
| _ -> Assert.Fail $"Could not get valid AST, got {parseResults}"
\ No newline at end of file
| _ -> Assert.Fail $"Could not get valid AST, got {parseResults}"
[<Test>]
let ``Parentheses of SynArgPats.NamePatPairs`` () =
let parseResults =
getParseResults
"""
match data with
| OnePartData( // foo
part1 = p1
(* bar *) ) -> p1
| _ -> failwith "todo"
"""
match parseResults with
| ParsedInput.ImplFile (ParsedImplFileInput (contents = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = [
SynModuleDecl.Expr(
expr = SynExpr.Match(clauses = [
SynMatchClause(pat = SynPat.LongIdent(argPats = SynArgPats.NamePatPairs(trivia = trivia)))
_
])
)
]) ])) ->
assertRange (3, 13) (5, 13) trivia.ParenRange
| _ -> Assert.Fail $"Could not get valid AST, got {parseResults}"
......@@ -28,51 +28,43 @@ type internal CodeLensProvider
settings: EditorOptions
) =
let lineLensProvider = ResizeArray()
let tryGetTextDocument (buffer: ITextBuffer) (factory: ITextDocumentFactoryService) =
match factory.TryGetTextDocument buffer with
| true, document -> Some document
| _ -> None
let taggers = ResizeArray()
let lineLensProviders = ResizeArray()
let componentModel = Package.GetGlobalService(typeof<ComponentModelHost.SComponentModel>) :?> ComponentModelHost.IComponentModel
let workspace = componentModel.GetService<VisualStudioWorkspace>()
/// Returns an provider for the textView if already one has been created. Else create one.
let addCodeLensProviderOnce wpfView buffer =
let res = taggers |> Seq.tryFind(fun (view, _) -> view = wpfView)
match res with
| Some (_, (tagger, _)) -> tagger
| None ->
let documentId =
lazy (
match textDocumentFactory.TryGetTextDocument(buffer) with
| true, textDocument ->
Seq.tryHead (workspace.CurrentSolution.GetDocumentIdsWithFilePath(textDocument.FilePath))
| _ -> None
|> Option.get
)
let tagger = CodeLensGeneralTagger(wpfView, buffer)
let service = FSharpCodeLensService(serviceProvider, workspace, documentId, buffer, metadataAsSource, componentModel.GetService(), typeMap, tagger, settings)
let provider = (wpfView, (tagger, service))
wpfView.Closed.Add (fun _ -> taggers.Remove provider |> ignore)
taggers.Add((wpfView, (tagger, service)))
tagger
let tryGetCodeLensTagger wpfView buffer =
taggers
|> Seq.tryFind (fun (view, _) -> view = wpfView)
|> Option.map (fun (_, (tagger, _)) -> tagger)
|> Option.orElse
(textDocumentFactory
|> tryGetTextDocument buffer
|> Option.map (fun document -> workspace.CurrentSolution.GetDocumentIdsWithFilePath document.FilePath)
|> Option.bind Seq.tryHead
|> Option.map (fun documentId ->
let tagger = CodeLensGeneralTagger(wpfView, buffer)
let service = FSharpCodeLensService(serviceProvider, workspace, documentId, buffer, metadataAsSource, componentModel.GetService(), typeMap, tagger, settings)
let provider = (wpfView, (tagger, service))
wpfView.Closed.Add (fun _ -> taggers.Remove provider |> ignore)
taggers.Add provider
tagger))
/// Returns an provider for the textView if already one has been created. Else create one.
let addLineLensProviderOnce wpfView buffer =
let res = lineLensProvider |> Seq.tryFind(fun (view, _) -> view = wpfView)
match res with
| None ->
let documentId =
lazy (
match textDocumentFactory.TryGetTextDocument(buffer) with
| true, textDocument ->
Seq.tryHead (workspace.CurrentSolution.GetDocumentIdsWithFilePath(textDocument.FilePath))
| _ -> None
|> Option.get
)
let addLineLensProvider wpfView buffer =
textDocumentFactory
|> tryGetTextDocument buffer
|> Option.map (fun document -> workspace.CurrentSolution.GetDocumentIdsWithFilePath(document.FilePath))
|> Option.bind Seq.tryHead
|> Option.map (fun documentId ->
let service = FSharpCodeLensService(serviceProvider, workspace, documentId, buffer, metadataAsSource, componentModel.GetService(), typeMap, LineLensDisplayService(wpfView, buffer), settings)
let provider = (wpfView, service)
wpfView.Closed.Add (fun _ -> lineLensProvider.Remove provider |> ignore)
lineLensProvider.Add(provider)
| _ -> ()
wpfView.Closed.Add (fun _ -> lineLensProviders.Remove provider |> ignore)
lineLensProviders.Add(provider))
[<Export(typeof<AdornmentLayerDefinition>); Name("CodeLens");
Order(Before = PredefinedAdornmentLayers.Text);
......@@ -92,11 +84,18 @@ type internal CodeLensProvider
| :? IWpfTextView as view -> view
| _ -> failwith "error"
box(addCodeLensProviderOnce wpfView buffer) :?> _
match tryGetCodeLensTagger wpfView buffer with
| Some tagger -> box tagger :?> _
| None -> null
else
null
interface IWpfTextViewCreationListener with
override _.TextViewCreated view =
if settings.CodeLens.Enabled && settings.CodeLens.ReplaceWithLineLens then
addLineLensProviderOnce view (view.TextBuffer) |> ignore
\ No newline at end of file
let provider =
lineLensProviders
|> Seq.tryFind (fun (v, _) -> v = view)
if provider.IsNone then
addLineLensProvider view (view.TextBuffer) |> ignore
\ No newline at end of file
......@@ -42,7 +42,7 @@ type internal FSharpCodeLensService
(
serviceProvider: IServiceProvider,
workspace: Workspace,
documentId: Lazy<DocumentId>,
documentId: DocumentId,
buffer: ITextBuffer,
metadataAsSource: FSharpMetadataAsSourceService,
classificationFormatMapService: IClassificationFormatMapService,
......@@ -153,7 +153,7 @@ type internal FSharpCodeLensService
#if DEBUG
logInfof "Rechecking code due to buffer edit!"
#endif
let! document = workspace.CurrentSolution.GetDocument(documentId.Value) |> Option.ofObj
let! document = workspace.CurrentSolution.GetDocument documentId |> Option.ofObj
let! parseFileResults, checkFileResults = document.GetFSharpParseAndCheckResultsAsync(nameof(FSharpUseMutationWhenValueIsMutableFixProvider)) |> liftAsync
let parsedInput = parseFileResults.ParseTree
#if DEBUG
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册