diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 084ce71ec..bda0692f1 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -1,4 +1,4 @@
-FROM mcr.microsoft.com/dotnet/sdk:8.0.300
+FROM mcr.microsoft.com/dotnet/sdk:8.0.400
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 62c59b864..356ba2f48 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 7.0.0-alpha-001 - 2024-09-16
+
+### Added
+* Add initial support for Nullness syntax. [#3118](https://github.com/fsprojects/fantomas/pull/3118)
+
+### Changed
+* Update FCS to 'Add trivia to Nullness nodes in SyntaxTree', commit 836d4e0603442d6053c8d439993a022501cae494 [#3118](https://github.com/fsprojects/fantomas/pull/3118)
+
## 6.3.15 - 2024-09-14
### Fixed
diff --git a/Directory.Build.props b/Directory.Build.props
index 7c22db742..26e34508a 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -40,12 +40,12 @@ Some common use cases include:
true
true
- $(OtherFlags) --test:GraphBasedChecking --test:ParallelOptimization --test:ParallelIlxGen --strict-indentation+
+ $(OtherFlags) --test:GraphBasedChecking --test:ParallelOptimization --test:ParallelIlxGen --strict-indentation+ --realsig+
- 836d4e0603442d6053c8d439993a022501cae494
+ e668b90e3c087e5fba8a855e502af60bf35be45e
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 12d2619ec..37b265adc 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,6 +1,7 @@
true
+ true
@@ -18,6 +19,7 @@
+
diff --git a/build.fsx b/build.fsx
index bd18e4e44..49be79b35 100644
--- a/build.fsx
+++ b/build.fsx
@@ -194,6 +194,8 @@ let updateFileRaw (file: FileInfo) =
|> Array.map (fun line ->
if line.Contains("FSharp.Compiler") then
line.Replace("FSharp.Compiler", "Fantomas.FCS")
+ elif line.Contains("[]") then
+ line.Replace("[]", "[]")
else
line)
File.WriteAllLines(file.FullName, updatedLines)
@@ -228,6 +230,7 @@ pipeline "Init" {
run (fun _ ->
[| "src/Compiler/FSComp.txt"
"src/Compiler/FSStrings.resx"
+ "src/Compiler/Utilities/NullnessShims.fs"
"src/Compiler/Utilities/Activity.fsi"
"src/Compiler/Utilities/Activity.fs"
"src/Compiler/Utilities/sformat.fsi"
diff --git a/global.json b/global.json
index 8d0a1c0ac..6f6aff9de 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.300",
- "rollForward": "latestMinor"
+ "version": "8.0.400",
+ "rollForward": "latestPatch"
}
}
\ No newline at end of file
diff --git a/src/Fantomas.Client.Tests/packages.lock.json b/src/Fantomas.Client.Tests/packages.lock.json
index 995df0067..c3cc3d7db 100644
--- a/src/Fantomas.Client.Tests/packages.lock.json
+++ b/src/Fantomas.Client.Tests/packages.lock.json
@@ -91,8 +91,8 @@
},
"Microsoft.NETCore.Targets": {
"type": "Transitive",
- "resolved": "1.1.0",
- "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg=="
+ "resolved": "1.1.3",
+ "contentHash": "3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ=="
},
"Microsoft.TestPlatform.ObjectModel": {
"type": "Transitive",
@@ -166,11 +166,6 @@
"System.Runtime.CompilerServices.Unsafe": "4.7.1"
}
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
"NuGet.Frameworks": {
"type": "Transitive",
"resolved": "6.5.0",
@@ -765,6 +760,12 @@
"StreamJsonRpc": "[2.8.28, )"
}
},
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"SemanticVersioning": {
"type": "CentralTransitive",
"requested": "[2.0.2, )",
@@ -796,29 +797,29 @@
"System.Collections.Immutable": {
"type": "CentralTransitive",
"requested": "[7.0.0, )",
- "resolved": "5.0.0",
- "contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g=="
+ "resolved": "7.0.0",
+ "contentHash": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ=="
},
"System.Diagnostics.DiagnosticSource": {
"type": "CentralTransitive",
"requested": "[7.0.0, )",
- "resolved": "5.0.1",
- "contentHash": "uXQEYqav2V3zP6OwkOKtLv+qIi6z3m1hsGyKwXX7ZA7htT4shoVccGxnJ9kVRFPNAsi1ArZTq2oh7WOto6GbkQ=="
+ "resolved": "7.0.0",
+ "contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw=="
},
"System.Memory": {
"type": "CentralTransitive",
"requested": "[4.5.5, )",
- "resolved": "4.5.4",
- "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw=="
+ "resolved": "4.5.5",
+ "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw=="
},
"System.Runtime": {
"type": "CentralTransitive",
"requested": "[4.3.1, )",
- "resolved": "4.3.0",
- "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
+ "resolved": "4.3.1",
+ "contentHash": "abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
"dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0"
+ "Microsoft.NETCore.Platforms": "1.1.1",
+ "Microsoft.NETCore.Targets": "1.1.3"
}
}
}
diff --git a/src/Fantomas.Client/packages.lock.json b/src/Fantomas.Client/packages.lock.json
index 484f33f58..57fc70151 100644
--- a/src/Fantomas.Client/packages.lock.json
+++ b/src/Fantomas.Client/packages.lock.json
@@ -121,8 +121,8 @@
},
"Microsoft.NETCore.Targets": {
"type": "Transitive",
- "resolved": "1.1.0",
- "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg=="
+ "resolved": "1.1.3",
+ "contentHash": "3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ=="
},
"Microsoft.SourceLink.AzureRepos.Git": {
"type": "Transitive",
@@ -221,11 +221,6 @@
"System.Runtime.CompilerServices.Unsafe": "4.7.1"
}
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "12.0.2",
- "contentHash": "rTK0s2EKlfHsQsH6Yx2smvcTCeyoDNgCW7FEYyV01drPlh2T243PR2DiDXqtC5N4GDm4Ma/lkxfW5a/4793vbA=="
- },
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
"type": "Transitive",
"resolved": "4.3.2",
@@ -584,8 +579,8 @@
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
- "resolved": "5.0.0",
- "contentHash": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA=="
+ "resolved": "6.0.0",
+ "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
},
"System.Runtime.Extensions": {
"type": "Transitive",
@@ -830,30 +825,37 @@
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
}
},
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"System.Collections.Immutable": {
"type": "CentralTransitive",
"requested": "[7.0.0, )",
- "resolved": "5.0.0",
- "contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==",
+ "resolved": "7.0.0",
+ "contentHash": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==",
"dependencies": {
- "System.Memory": "4.5.4"
+ "System.Memory": "4.5.5",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Diagnostics.DiagnosticSource": {
"type": "CentralTransitive",
"requested": "[7.0.0, )",
- "resolved": "5.0.1",
- "contentHash": "uXQEYqav2V3zP6OwkOKtLv+qIi6z3m1hsGyKwXX7ZA7htT4shoVccGxnJ9kVRFPNAsi1ArZTq2oh7WOto6GbkQ==",
+ "resolved": "7.0.0",
+ "contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==",
"dependencies": {
- "System.Memory": "4.5.4",
- "System.Runtime.CompilerServices.Unsafe": "5.0.0"
+ "System.Memory": "4.5.5",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Memory": {
"type": "CentralTransitive",
"requested": "[4.5.5, )",
- "resolved": "4.5.4",
- "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==",
+ "resolved": "4.5.5",
+ "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
"dependencies": {
"System.Buffers": "4.5.1",
"System.Numerics.Vectors": "4.4.0",
@@ -863,11 +865,11 @@
"System.Runtime": {
"type": "CentralTransitive",
"requested": "[4.3.1, )",
- "resolved": "4.3.0",
- "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
+ "resolved": "4.3.1",
+ "contentHash": "abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
"dependencies": {
- "Microsoft.NETCore.Platforms": "1.1.0",
- "Microsoft.NETCore.Targets": "1.1.0"
+ "Microsoft.NETCore.Platforms": "1.1.1",
+ "Microsoft.NETCore.Targets": "1.1.3"
}
}
}
diff --git a/src/Fantomas.Core.Tests/AutoPropertiesTests.fs b/src/Fantomas.Core.Tests/AutoPropertiesTests.fs
new file mode 100644
index 000000000..ab6a962df
--- /dev/null
+++ b/src/Fantomas.Core.Tests/AutoPropertiesTests.fs
@@ -0,0 +1,95 @@
+module Fantomas.Core.Tests.AutoPropertiesTests
+
+open NUnit.Framework
+open FsUnit
+open Fantomas.Core.Tests.TestHelpers
+
+[]
+let ``public get, private set`` () =
+ formatSourceString
+ """
+type X() =
+ member val Y: int = 7 with public get, private set
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+type X() =
+ member val Y: int = 7 with public get, private set
+"""
+
+[]
+let ``plain get, private set`` () =
+ formatSourceString
+ """
+type X() =
+ member val Y: int = 7 with get, private set
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+type X() =
+ member val Y: int = 7 with get, private set
+"""
+
+[]
+let ``internal get, plain set`` () =
+ formatSourceString
+ """
+type X() =
+ member val Y: int = 7 with internal get, set
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+type X() =
+ member val Y: int = 7 with internal get, set
+"""
+
+[]
+let ``public get, private set in signature`` () =
+ formatSignatureString
+ """
+module A
+
+type X =
+ new: unit -> X
+ member internal Y: int with public get, private set
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+module A
+
+type X =
+ new: unit -> X
+ member internal Y: int with public get, private set
+"""
+
+[]
+let ``abstract member with public get, private set`` () =
+ formatSignatureString
+ """
+namespace Meh
+
+type X =
+ abstract Y: int with public get, private set
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+namespace Meh
+
+type X =
+ abstract Y: int with public get, private set
+"""
diff --git a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj
index 78718e432..f764d1de9 100644
--- a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj
+++ b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj
@@ -132,6 +132,8 @@
+
+
diff --git a/src/Fantomas.Core.Tests/NullnessTests.fs b/src/Fantomas.Core.Tests/NullnessTests.fs
new file mode 100644
index 000000000..2f80450a3
--- /dev/null
+++ b/src/Fantomas.Core.Tests/NullnessTests.fs
@@ -0,0 +1,150 @@
+module Fantomas.Core.Tests.NullnessTests
+
+open NUnit.Framework
+open FsUnit
+open Fantomas.Core.Tests.TestHelpers
+
+[]
+let ``du case of string or null`` () =
+ formatSourceString
+ """
+type DU = MyCase of (string | null)
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+type DU = MyCase of (string | null)
+"""
+
+[]
+let ``multiple or type`` () =
+ formatSourceString
+ """
+let myFunc ("abc" | "" : string | null | "123") = 15
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+let myFunc ("abc" | "": string | null | "123") = 15
+"""
+
+[]
+let ``null type constraint`` () =
+ formatSourceString
+ """
+let myFunc() : 'T when 'T : not struct and 'T:null = null
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+let myFunc () : 'T when 'T: not struct and 'T: null = null
+"""
+
+[]
+let ``not null type constraint`` () =
+ formatSourceString
+ """
+let myFunc (x: 'T when 'T: not null) = 42
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+let myFunc (x: 'T when 'T: not null) = 42
+"""
+
+[]
+let ``not null in type constraints`` () =
+ formatSourceString
+ """
+type C<'T when 'T: not null> = class end
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+type C<'T when 'T: not null> = class end
+"""
+
+[]
+let ``or null pattern`` () =
+ formatSourceString
+ """
+match x with
+| :? string | null -> ()
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+match x with
+| :? string
+| null -> ()
+"""
+
+[]
+let ``nullness in signature file`` () =
+ formatSignatureString
+ """
+namespace Meh
+
+type DU = MyCase of (string | null)
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+namespace Meh
+
+type DU = MyCase of (string | null)
+"""
+
+[]
+let ``trivia in SynType.WithNull`` () =
+ formatSourceString
+ """
+type DU = MyCase of (string
+ | // but why?
+ null)
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+type DU =
+ | MyCase of
+ (string | // but why?
+ null)
+"""
+
+[]
+let ``trivia in SynTypeConstraint.WhereTyparNotSupportsNull`` () =
+ formatSourceString
+ """
+type C<'T when
+ 'T
+ : // comment 1
+ not // comment 2
+ null> = class end
+"""
+ config
+ |> prepend newline
+ |> should
+ equal
+ """
+type C<'T
+ when 'T: // comment 1
+ not // comment 2
+ null> = class end
+"""
diff --git a/src/Fantomas.Core.Tests/packages.lock.json b/src/Fantomas.Core.Tests/packages.lock.json
index 4a095303b..9da29aaa1 100644
--- a/src/Fantomas.Core.Tests/packages.lock.json
+++ b/src/Fantomas.Core.Tests/packages.lock.json
@@ -109,11 +109,6 @@
"Newtonsoft.Json": "13.0.1"
}
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
"NuGet.Frameworks": {
"type": "Transitive",
"resolved": "6.5.0",
@@ -163,6 +158,12 @@
"System.Runtime": "[4.3.1, )"
}
},
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"System.Collections.Immutable": {
"type": "CentralTransitive",
"requested": "[7.0.0, )",
diff --git a/src/Fantomas.Core/ASTTransformer.fs b/src/Fantomas.Core/ASTTransformer.fs
index 5544c7022..93240f743 100644
--- a/src/Fantomas.Core/ASTTransformer.fs
+++ b/src/Fantomas.Core/ASTTransformer.fs
@@ -78,6 +78,16 @@ let mkSynAccess (vis: SynAccess option) =
| Some(SynAccess.Private range) -> Some(stn "private" range)
| Some(SynAccess.Public range) -> Some(stn "public" range)
+let (|AccessSynValSigAccess|) (valSigAccess: SynValSigAccess) =
+ match valSigAccess with
+ | SynValSigAccess.Single(accessibility = vis)
+ | SynValSigAccess.GetSet(accessibility = vis) -> vis
+
+let (|SynValSigAccessAll|) (valSigAccess: SynValSigAccess) =
+ match valSigAccess with
+ | SynValSigAccess.Single(vis) -> vis, None, None
+ | SynValSigAccess.GetSet(vis, g, s) -> vis, g, s
+
let parseExpressionInSynBinding returnInfo expr =
match returnInfo, expr with
| Some(SynBindingReturnInfo(typeName = t1)), SynExpr.Typed(e, t2, _) when RangeHelpers.rangeEq t1.Range t2.Range ->
@@ -329,15 +339,18 @@ let rec collectComputationExpressionStatements
let andBangs =
andBangs
- |> List.map (fun (SynExprAndBang(_, _, _, ap, ae, StartRange 4 (mAnd, m), trivia)) ->
- ExprAndBang(
- stn "and!" mAnd,
- mkPat creationAide ap,
- stn "=" trivia.EqualsRange,
- mkExpr creationAide ae,
- m
- )
- |> ComputationExpressionStatement.AndBangStatement)
+ |> List.map
+ (fun
+ (SynExprAndBang(_,
+ _,
+ _,
+ ap,
+ ae,
+ m,
+ { AndBangKeyword = mAnd
+ EqualsRange = mEq })) ->
+ ExprAndBang(stn "and!" mAnd, mkPat creationAide ap, stn "=" mEq, mkExpr creationAide ae, m)
+ |> ComputationExpressionStatement.AndBangStatement)
collectComputationExpressionStatements creationAide body (fun bodyStatements ->
[ letOrUseBang; yield! andBangs; yield! bodyStatements ] |> finalContinuation)
@@ -2168,6 +2181,9 @@ let mkSynTypeConstraint (creationAide: CreationAide) (tc: SynTypeConstraint) : T
TypeConstraintEnumOrDelegateNode(mkSynTypar tp, "delegate", List.map (mkType creationAide) ts, m)
|> TypeConstraint.EnumOrDelegate
| SynTypeConstraint.WhereSelfConstrained(t, _) -> mkType creationAide t |> TypeConstraint.WhereSelfConstrained
+ | SynTypeConstraint.WhereTyparNotSupportsNull(typar, EndRange 4 (mNull, m), { ColonRange = mColon; NotRange = mNot }) ->
+ TypeConstraintWhereNotSupportsNull(mkSynTypar typar, stn ":" mColon, stn "not" mNot, stn "null" mNull, m)
+ |> TypeConstraint.WhereNotSupportsNull
// Arrow type is right-associative
let rec (|TFuns|_|) =
@@ -2309,6 +2325,12 @@ let mkType (creationAide: CreationAide) (t: SynType) : Type =
yield Choice1Of2(mkType creationAide t) ]
TypeIntersectionNode(typesAndSeparators, m) |> Type.Intersection
+ | SynType.StaticConstantNull(m) -> stn "null" m |> Type.Var
+ // string | null
+ | SynType.WithNull(innerType, _, EndRange 4 (mNull, m), { BarRange = mBar }) ->
+ let nullType = stn "null" mNull |> Type.Var
+
+ TypeOrNode(mkType creationAide innerType, stn "|" mBar, nullType, m) |> Type.Or
| t -> failwith $"unexpected type: %A{t}"
let rec (|OpenL|_|) =
@@ -2632,20 +2654,44 @@ let mkTypeDefn
TypeDefnRegularNode(typeNameNode, allMembers, typeDefnRange) |> TypeDefn.Regular
| _ -> failwithf "Could not create a TypeDefn for %A" typeRepr
-let mkWithGetSet (withKeyword: range option) (getSet: GetSetKeywords option) =
+let mkWithGetSet
+ (withKeyword: range option)
+ (getSet: GetSetKeywords option)
+ (visGet: SynAccess option)
+ (visSet: SynAccess option)
+ =
match withKeyword, getSet with
| Some mWith, Some gs ->
let withNode = stn "with" mWith
let m = unionRanges mWith gs.Range
+ let visNodes vis = Option.toList (mkSynAccess vis)
match gs with
- | GetSetKeywords.Get mGet -> Some(MultipleTextsNode([ withNode; stn "get" mGet ], m))
- | GetSetKeywords.Set mSet -> Some(MultipleTextsNode([ withNode; stn "set" mSet ], m))
+ | GetSetKeywords.Get mGet -> Some(MultipleTextsNode([ withNode; yield! visNodes visGet; stn "get" mGet ], m))
+ | GetSetKeywords.Set mSet -> Some(MultipleTextsNode([ withNode; yield! visNodes visSet; stn "set" mSet ], m))
| GetSetKeywords.GetSet(mGet, mSet) ->
if rangeBeforePos mGet mSet.Start then
- Some(MultipleTextsNode([ withNode; stn "get," mGet; stn "set" mSet ], m))
+ Some(
+ MultipleTextsNode(
+ [ withNode
+ yield! visNodes visGet
+ stn "get," mGet
+ yield! visNodes visSet
+ stn "set" mSet ],
+ m
+ )
+ )
else
- Some(MultipleTextsNode([ withNode; stn "set," mSet; stn "get" mGet ], m))
+ Some(
+ MultipleTextsNode(
+ [ withNode
+ yield! visNodes visSet
+ stn "set," mSet
+ yield! visNodes visGet
+ stn "get" mGet ],
+ m
+ )
+ )
| _ -> None
let mkPropertyGetSetBinding
@@ -2826,35 +2872,41 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
memberDefinitionRange
)
|> MemberDefn.Interface
- | SynMemberDefn.AutoProperty(ats,
- _isStatic,
- ident,
- typeOpt,
- _,
- _,
- _,
- px,
- ao,
- e,
- _,
- { LeadingKeyword = lk
- EqualsRange = Some mEq
- WithKeyword = mWith
- GetSetKeywords = mGS }) ->
+ | SynMemberDefn.AutoProperty(
+ attributes = ats
+ ident = ident
+ typeOpt = typeOpt
+ xmlDoc = px
+ accessibility = SynValSigAccessAll(vis, getVis, setVis)
+ synExpr = e
+ trivia = { LeadingKeyword = lk
+ EqualsRange = Some mEq
+ WithKeyword = mWith
+ GetSetKeywords = mGS }) ->
+
MemberDefnAutoPropertyNode(
mkXmlDoc px,
mkAttributes creationAide ats,
mkSynLeadingKeyword lk,
- mkSynAccess ao,
+ mkSynAccess vis,
mkIdent ident,
Option.map (mkType creationAide) typeOpt,
stn "=" mEq,
mkExpr creationAide e,
- mkWithGetSet mWith mGS,
+ mkWithGetSet mWith mGS getVis setVis,
memberDefinitionRange
)
|> MemberDefn.AutoProperty
- | SynMemberDefn.AbstractSlot(SynValSig(ats, ident, tds, t, _, _, _, px, _ao, _, _, trivia), _, _, abstractSlotTrivia) ->
+ | SynMemberDefn.AbstractSlot(
+ slotSig = SynValSig(
+ attributes = ats
+ ident = ident
+ explicitTypeParams = tds
+ synType = t
+ xmlDoc = px
+ accessibility = SynValSigAccessAll(_ao, visGet, visSet)
+ trivia = trivia)
+ trivia = abstractSlotTrivia) ->
MemberDefnAbstractSlotNode(
mkXmlDoc px,
mkAttributes creationAide ats,
@@ -2862,7 +2914,7 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
mkSynIdent ident,
mkSynValTyparDecls creationAide (Some tds),
mkType creationAide t,
- mkWithGetSet trivia.WithKeyword abstractSlotTrivia.GetSetKeywords,
+ mkWithGetSet trivia.WithKeyword abstractSlotTrivia.GetSetKeywords visGet visSet,
memberDefinitionRange
)
|> MemberDefn.AbstractSlot
@@ -3014,7 +3066,7 @@ let mkMemberDefn (creationAide: CreationAide) (md: SynMemberDefn) =
let mkVal
(creationAide: CreationAide)
- (SynValSig(ats, synIdent, vtd, t, _vi, _isInline, isMutable, px, ao, eo, range, trivia))
+ (SynValSig(ats, synIdent, vtd, t, _vi, _isInline, isMutable, px, AccessSynValSigAccess(ao), eo, range, trivia))
: ValNode =
let lk =
match trivia.LeadingKeyword with
@@ -3041,11 +3093,12 @@ let mkMemberSig (creationAide: CreationAide) (ms: SynMemberSig) =
match ms with
| SynMemberSig.Member(vs, _, _, memberTrivia) ->
- let (SynValSig(trivia = trivia)) = vs
+ let (SynValSig(trivia = trivia; accessibility = SynValSigAccessAll(_ao, visGet, visSet))) =
+ vs
MemberDefnSigMemberNode(
mkVal creationAide vs,
- mkWithGetSet trivia.WithKeyword memberTrivia.GetSetKeywords,
+ mkWithGetSet trivia.WithKeyword memberTrivia.GetSetKeywords visGet visSet,
memberSigRange
)
|> MemberDefn.SigMember
diff --git a/src/Fantomas.Core/CodePrinter.fs b/src/Fantomas.Core/CodePrinter.fs
index 357eaf63a..bcddf6700 100644
--- a/src/Fantomas.Core/CodePrinter.fs
+++ b/src/Fantomas.Core/CodePrinter.fs
@@ -3155,6 +3155,27 @@ let genTypeConstraint (tc: TypeConstraint) =
+> !- ">"
|> genNode node
| TypeConstraint.WhereSelfConstrained t -> genType t
+ | TypeConstraint.WhereNotSupportsNull node ->
+ let short =
+ genSingleTextNode node.Typar
+ +> onlyIfCtx (fun ctx -> ctx.Config.SpaceBeforeColon) sepSpace
+ +> genSingleTextNode node.Colon
+ +> sepSpace
+ +> genSingleTextNode node.Not
+ +> sepSpace
+ +> genSingleTextNode node.Null
+
+ let long =
+ genSingleTextNode node.Typar
+ +> onlyIfCtx (fun ctx -> ctx.Config.SpaceBeforeColon) sepSpace
+ +> genSingleTextNode node.Colon
+ +> indentSepNlnUnindent (
+ genSingleTextNode node.Not
+ +> sepNlnWhenWriteBeforeNewlineNotEmptyOr sepSpace
+ +> genSingleTextNode node.Null
+ )
+
+ expressionFitsOnRestOfLine short long |> genNode node
let genTypeConstraints (tcs: TypeConstraint list) =
let short = colPre (sepSpace +> !- "when ") wordAnd tcs genTypeConstraint
@@ -3292,12 +3313,20 @@ let genType (t: Type) =
+> autoIndentAndNlnIfExpressionExceedsPageWidth (genType node.Type)
|> genNode node
| Type.Or node ->
- genType node.LeftHandSide
- +> sepSpace
- +> genSingleTextNode node.Or
- +> sepSpace
- +> genType node.RightHandSide
- |> genNode node
+ let short =
+ genType node.LeftHandSide
+ +> sepSpace
+ +> genSingleTextNode node.Or
+ +> sepSpace
+ +> genType node.RightHandSide
+
+ let long =
+ genType node.LeftHandSide
+ +> sepSpace
+ +> genSingleTextNode node.Or
+ +> indentSepNlnUnindent (genType node.RightHandSide)
+
+ expressionFitsOnRestOfLine short long |> genNode node
| Type.LongIdentApp node ->
genType node.AppType +> sepDot +> genIdentListNode node.LongIdent
|> genNode node
diff --git a/src/Fantomas.Core/SyntaxOak.fs b/src/Fantomas.Core/SyntaxOak.fs
index 5d2de5a89..c15dc6f0d 100644
--- a/src/Fantomas.Core/SyntaxOak.fs
+++ b/src/Fantomas.Core/SyntaxOak.fs
@@ -2787,6 +2787,17 @@ type TypeConstraintEnumOrDelegateNode(typar: SingleTextNode, verb: string, ts: T
member val Verb = verb
member val Types = ts
+/// `'T: not null` in `type C<'T when 'T: not null> = class end`
+type TypeConstraintWhereNotSupportsNull
+ (typar: SingleTextNode, colon: SingleTextNode, notNode: SingleTextNode, nullNode: SingleTextNode, range) =
+ inherit NodeBase(range)
+
+ override val Children: Node array = [| yield typar; yield colon; yield notNode; yield nullNode |]
+ member val Typar = typar
+ member val Colon = colon
+ member val Not = notNode
+ member val Null = nullNode
+
[]
type TypeConstraint =
| Single of TypeConstraintSingleNode
@@ -2795,6 +2806,7 @@ type TypeConstraint =
| SupportsMember of TypeConstraintSupportsMemberNode
| EnumOrDelegate of TypeConstraintEnumOrDelegateNode
| WhereSelfConstrained of Type
+ | WhereNotSupportsNull of TypeConstraintWhereNotSupportsNull
static member Node(tc: TypeConstraint) : Node =
match tc with
@@ -2804,6 +2816,7 @@ type TypeConstraint =
| SupportsMember n -> n
| EnumOrDelegate n -> n
| WhereSelfConstrained t -> Type.Node t
+ | WhereNotSupportsNull n -> n
type UnitOfMeasureNode(lessThan: SingleTextNode, measure: Measure, greaterThan: SingleTextNode, range) =
inherit NodeBase(range)
diff --git a/src/Fantomas.FCS/Fantomas.FCS.fsproj b/src/Fantomas.FCS/Fantomas.FCS.fsproj
index 0b8e460ff..db012a03f 100644
--- a/src/Fantomas.FCS/Fantomas.FCS.fsproj
+++ b/src/Fantomas.FCS/Fantomas.FCS.fsproj
@@ -6,7 +6,7 @@
$(NoWarn);57;
$(NoWarn);1204
$(NoWarn);1178
- $(DefineConstants);COMPILER;FSHARPCORE_USE_PACKAGE
+ $(DefineConstants);COMPILER;FSHARPCORE_USE_PACKAGE;NO_CHECKNULLS
generated\$(TargetFramework)\
generated\$(TargetFramework)\
true
@@ -16,6 +16,7 @@
+
FSComp.txt
@@ -23,6 +24,9 @@
FSStrings.resx
FSStrings.resources
+
+ Utilities\NullnessShims.fs
+
Utilities\Activity.fsi
diff --git a/src/Fantomas.FCS/TailCall.fs b/src/Fantomas.FCS/TailCall.fs
new file mode 100644
index 000000000..5088f93a3
--- /dev/null
+++ b/src/Fantomas.FCS/TailCall.fs
@@ -0,0 +1,7 @@
+module Microsoft.FSharp.Core
+
+open System
+
+[]
+type TailCallAttribute() =
+ inherit Attribute()
diff --git a/src/Fantomas.Tests/packages.lock.json b/src/Fantomas.Tests/packages.lock.json
index 781cd7336..2d6c37764 100644
--- a/src/Fantomas.Tests/packages.lock.json
+++ b/src/Fantomas.Tests/packages.lock.json
@@ -196,11 +196,6 @@
"System.Runtime.CompilerServices.Unsafe": "4.7.1"
}
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.1",
- "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
- },
"NuGet.Frameworks": {
"type": "Transitive",
"resolved": "6.5.0",
@@ -887,6 +882,12 @@
"resolved": "0.1.50",
"contentHash": "nr7/KaY5KP9QvCEf478w1k9Yz+dXQZKLEAsjfhIjuneScmyLvMKoItPL6OfkNODeCrINtHEBt8A7q7yETS1PQQ=="
},
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"SemanticVersioning": {
"type": "CentralTransitive",
"requested": "[2.0.2, )",
diff --git a/src/Fantomas/EditorConfig.fs b/src/Fantomas/EditorConfig.fs
index f362fe4ba..87af71998 100644
--- a/src/Fantomas/EditorConfig.fs
+++ b/src/Fantomas/EditorConfig.fs
@@ -16,7 +16,7 @@ module Reflection =
DisplayName: string option
Description: string option }
- let inline getCustomAttribute<'t, 'v when 't :> Attribute and 't: null>
+ let inline getCustomAttribute<'t, 'v when 't :> Attribute and 't: null and 't: not struct>
(projection: 't -> 'v)
(property: PropertyInfo)
: 'v option =
diff --git a/src/Fantomas/Fantomas.fsproj b/src/Fantomas/Fantomas.fsproj
index 6210ac75a..08a87ac2b 100644
--- a/src/Fantomas/Fantomas.fsproj
+++ b/src/Fantomas/Fantomas.fsproj
@@ -1,7 +1,7 @@
Exe
- net6.0
+ net8.0
en
diff --git a/src/Fantomas/Logging.fs b/src/Fantomas/Logging.fs
index c6ebda69a..c5a4d53be 100644
--- a/src/Fantomas/Logging.fs
+++ b/src/Fantomas/Logging.fs
@@ -20,15 +20,13 @@ let initLogger (level: VerbosityLevel) : VerbosityLevel =
Log.Logger <- logger
level
-let logger = Log.Logger
-
/// log a message
-let stdlog (s: string) = logger.Information(s)
+let stdlog (s: string) = Log.Logger.Information(s)
/// log an error
-let elog (s: string) = logger.Error(s)
+let elog (s: string) = Log.Logger.Error(s)
/// log a message if the verbosity level is >= Detailed
-let logGrEqDetailed s = logger.Debug(s)
+let logGrEqDetailed s = Log.Logger.Debug(s)
let closeAndFlushLog () = Log.CloseAndFlush()
diff --git a/src/Fantomas/packages.lock.json b/src/Fantomas/packages.lock.json
index 5a219fa80..d0d3541ea 100644
--- a/src/Fantomas/packages.lock.json
+++ b/src/Fantomas/packages.lock.json
@@ -1,7 +1,7 @@
{
"version": 2,
"dependencies": {
- "net6.0": {
+ "net8.0": {
"Argu": {
"type": "Direct",
"requested": "[6.2.4, )",
@@ -285,11 +285,6 @@
"System.Runtime.CompilerServices.Unsafe": "4.7.1"
}
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "12.0.2",
- "contentHash": "rTK0s2EKlfHsQsH6Yx2smvcTCeyoDNgCW7FEYyV01drPlh2T243PR2DiDXqtC5N4GDm4Ma/lkxfW5a/4793vbA=="
- },
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
"type": "Transitive",
"resolved": "4.3.2",
@@ -630,8 +625,8 @@
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
- "resolved": "6.0.0",
- "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ "resolved": "4.7.1",
+ "contentHash": "zOHkQmzPCn5zm/BH+cxC1XbUS3P4Yoi3xzW7eRgVpDR2tPGSzyMZ17Ig1iRkfJuY0nhxkQQde8pgePNiA7z7TQ=="
},
"System.Runtime.Extensions": {
"type": "Transitive",
@@ -917,6 +912,12 @@
"System.Runtime": "[4.3.1, )"
}
},
+ "Newtonsoft.Json": {
+ "type": "CentralTransitive",
+ "requested": "[13.0.3, )",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
"SemanticVersioning": {
"type": "CentralTransitive",
"requested": "[2.0.2, )",
@@ -927,19 +928,13 @@
"type": "CentralTransitive",
"requested": "[7.0.0, )",
"resolved": "7.0.0",
- "contentHash": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==",
- "dependencies": {
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
+ "contentHash": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ=="
},
"System.Diagnostics.DiagnosticSource": {
"type": "CentralTransitive",
"requested": "[7.0.0, )",
"resolved": "7.0.0",
- "contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==",
- "dependencies": {
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
- }
+ "contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw=="
},
"System.Memory": {
"type": "CentralTransitive",