Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .executor-pid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
13284
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### Fixed

* Fix missing FS1182 ("unused binding") warning for unused `let` function bindings inside class types. ([Issue #13849](https://github.com/dotnet/fsharp/issues/13849))
* Honor `--nowarn` and `--warnaserror` for warnings emitted during command-line option parsing ([Issue #19576](https://github.com/dotnet/fsharp/issues/19576), [PR #19776](https://github.com/dotnet/fsharp/pull/19776))
* Fix `[<return: X>]` prefix attributes being silently dropped on class members, and fix false-positive `AllowMultiple=false` errors when `[<X>]` and `[<return: X>]` are applied to the same binding. ([Issue #17904](https://github.com/dotnet/fsharp/issues/17904), [Issue #19020](https://github.com/dotnet/fsharp/issues/19020), [PR #19738](https://github.com/dotnet/fsharp/pull/19738))
* Fix attributes on return type of unparenthesized tuple methods being silently dropped from IL. ([Issue #462](https://github.com/dotnet/fsharp/issues/462), [PR #19714](https://github.com/dotnet/fsharp/pull/19714))
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/CheckIncrementalClasses.fs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ type IncrClassReprInfo =
nm, takenFieldNames.Add nm

let reportIfUnused() =
if not v.HasBeenReferenced && not v.IsCompiledAsTopLevel && not (v.DisplayName.StartsWithOrdinal("_")) && not v.IsCompilerGenerated then
if not v.HasBeenReferenced && not (v.DisplayName.StartsWithOrdinal("_")) && not v.IsCompilerGenerated then
warning (Error(FSComp.SR.chkUnusedValue(v.DisplayName), v.Range))

let repr =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,154 @@ type System.Int32 with
|> compile
|> shouldSucceed
|> ignore

// -------------------------------------------------------------------------
// FS1182 tests for `let`-bound functions inside class types (issue #13849).
// Today, FS1182 fires for unused `let`-bound values inside classes, but not
// for unused `let`-bound functions inside classes. These tests pin the
// expected post-fix behavior. The tests marked "RED" must FAIL today and
// pass once the fix lands; the tests marked "GUARD" must already pass.
// -------------------------------------------------------------------------

// RED: primary repro from the issue.
[<Fact>]
let ``Unused let function in class reports FS1182`` () =
FSharp """
module M
type T() =
let f _ = ()
"""
|> withOptions ["--warnon:FS1182"]
|> asLibrary
|> compile
|> withWarningCode 1182
|> withDiagnosticMessageMatches "The value 'f' is unused"
|> ignore

// RED: variants of unused let-function in classes.
// Note: the recursive variant (`let rec f x = ... f (x-1)`) is intentionally
// omitted from this Theory because F# treats the self-reference inside a
// `rec` binding as a use, so it does not warn; that behavior is unchanged by
// the fix and is covered separately below as a negative regression guard.
[<Theory>]
[<InlineData("module M\ntype T() = let f x = x + 1")>]
[<InlineData("module M\ntype T() = let f (x:int) (y:int) = x + y")>]
[<InlineData("module M\ntype T() = let f x y = x + y")>]
let ``Unused let function variants in class report FS1182`` (source: string) =
FSharp source
|> withOptions ["--warnon:FS1182"]
|> asLibrary
|> compile
|> withWarningCode 1182
|> withDiagnosticMessageMatches "The value 'f' is unused"
|> ignore

// GUARD: a recursive let-function in a class that only references itself.
// F# considers the self-reference inside `let rec` as a use, so no FS1182
// is expected (today and after the fix). Documented as a regression guard.
[<Fact>]
let ``Recursive let function in class with only self-reference does NOT report FS1182`` () =
FSharp """
module M
type T() =
let rec f x = if x = 0 then 1 else f (x-1)
"""
|> withOptions ["--warnon:FS1182"]
|> asLibrary
|> compile
|> shouldSucceed
|> withDiagnostics []
|> ignore

// GUARD: used let-function in a class must not warn (today and after fix).
[<Fact>]
let ``Used let function in class does NOT report FS1182`` () =
FSharp """
module M
type T() =
let f x = x + 1
member _.GetValue() = f 42
"""
|> withOptions ["--warnon:FS1182"]
|> asLibrary
|> compile
|> shouldSucceed
|> withDiagnostics []
|> ignore

// GUARD: unused let-value in a class already warns today.
[<Fact>]
let ``Unused let value in class still reports FS1182`` () =
FSharp """
module M
type T() =
let x = 42
"""
|> withOptions ["--warnon:FS1182"]
|> asLibrary
|> compile
|> withWarningCode 1182
|> withDiagnosticMessageMatches "The value 'x' is unused"
|> ignore

// GUARD: module-level unused functions must NOT warn (they are public surface).
// This guards against accidentally widening the fix beyond class-let bindings.
[<Fact>]
let ``Module-level unused function does not get new false positive`` () =
FSharp """
module M
let f x = x + 1
"""
|> withOptions ["--warnon:FS1182"]
|> asLibrary
|> compile
|> shouldSucceed
|> withDiagnostics []
|> ignore

// GUARD: underscore-prefixed unused let-function in a class must NOT warn.
[<Fact>]
let ``Underscore-prefixed let function in class does NOT report FS1182`` () =
FSharp """
module M
type T() =
let _f x = x + 1
"""
|> withOptions ["--warnon:FS1182"]
|> asLibrary
|> compile
|> shouldSucceed
|> withDiagnostics []
|> ignore

// RED: mixed used/unused let-functions in a class - only unused one warns.
[<Fact>]
let ``Mixed used and unused let functions in class`` () =
FSharp """
module M
type T() =
let used x = x + 1
let unused x = x * 2
member _.GetValue() = used 42
"""
|> withOptions ["--warnon:FS1182"]
|> asLibrary
|> compile
|> withWarningCode 1182
|> withDiagnosticMessageMatches "The value 'unused' is unused"
|> ignore

// RED: static let function in a class - same code path with isStatic=true.
[<Fact>]
let ``Unused static let function in class reports FS1182`` () =
FSharp """
module M
type T() =
static let f x = x + 1
"""
|> withOptions ["--warnon:FS1182"]
|> asLibrary
|> compile
|> withWarningCode 1182
|> withDiagnosticMessageMatches "The value 'f' is unused"
|> ignore
Loading