From f5d0fbfe7af809b1e4d43a171dbbac98c4a7a8d0 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 25 May 2026 08:04:05 +0200 Subject: [PATCH 1/3] Fix colorization of type name in MyType.S (#18009) Accept ItemOccurrence.InvalidUse in LegitTypeOccurrence so that the type-name span in expressions like MyType.S - which name resolution flags as InvalidUse via isWrongItemInExpr - is still classified as a ReferenceType, matching the behavior for the unqualified form MyType.S. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Service/SemanticClassification.fs | 1 + .../SemanticClassificationRegressions.fs | 71 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/Compiler/Service/SemanticClassification.fs b/src/Compiler/Service/SemanticClassification.fs index 8fe61e20dd..5dbce47dc6 100644 --- a/src/Compiler/Service/SemanticClassification.fs +++ b/src/Compiler/Service/SemanticClassification.fs @@ -151,6 +151,7 @@ module TcResolutionsExtensions = | ItemOccurrence.UseInType | ItemOccurrence.UseInAttribute | ItemOccurrence.Use + | ItemOccurrence.InvalidUse | ItemOccurrence.Binding | ItemOccurrence.Pattern | ItemOccurrence.Open -> Some() diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/SemanticClassificationRegressions.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/SemanticClassificationRegressions.fs index 8af90a38e5..84aff53a4f 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/SemanticClassificationRegressions.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/SemanticClassificationRegressions.fs @@ -136,3 +136,74 @@ type Animal = (7, 2, 8) // s.IsCircle && s.IsSquare — two on same line (12, 1, 7) // t.IsIdent — RequireQualifiedAccess (17, 1, 5) ] // this.IsCat — self-referential member + +/// (#18009 regression) Static method on a generic type with a *qualified* type argument +/// must still classify the type name as a type. +[] +let ``Static method on generic type should classify type name as type`` () = + let source = + """ +module Test + +type MyType<'T> = + static member S = 1 + +let _ = MyType.S +let _ = MyType.S +""" + + let items = getClassifications source + + let isMyTypeRefOnLine line (item: SemanticClassificationItem) = + item.Type = SemanticClassificationType.ReferenceType + && item.Range.StartLine = line + && item.Range.StartColumn = 8 + && item.Range.EndColumn = 14 + + let unqualified = items |> Array.filter (isMyTypeRefOnLine 7) + Assert.True( + unqualified.Length = 1, + sprintf + "Expected exactly one ReferenceType classification for MyType on line 7, got: %A" + (items |> Array.filter (fun i -> i.Range.StartLine = 7) + |> Array.map (fun i -> i.Range.StartColumn, i.Range.EndColumn, i.Type)) + ) + + let qualified = items |> Array.filter (isMyTypeRefOnLine 8) + Assert.True( + qualified.Length = 1, + sprintf + "Expected exactly one ReferenceType classification for MyType on line 8, got: %A" + (items |> Array.filter (fun i -> i.Range.StartLine = 8) + |> Array.map (fun i -> i.Range.StartColumn, i.Range.EndColumn, i.Type)) + ) + +/// (#18009 follow-up) Accepting ItemOccurrence.InvalidUse in LegitTypeOccurrence must +/// not cause unresolved identifiers to be classified as types. +[] +let ``Undeclared identifier in expression position is not classified as a type`` () = + let source = + """ +module Test + +let _ = NotDeclaredAnywhere.S +""" + + let items = getClassifications source + + let badSpans = + items + |> Array.filter (fun item -> + item.Range.StartLine = 4 + && item.Range.StartColumn = 8 + && item.Range.EndColumn = 27 + && (item.Type = SemanticClassificationType.ReferenceType + || item.Type = SemanticClassificationType.ValueType + || item.Type = SemanticClassificationType.Type)) + + Assert.True( + badSpans.Length = 0, + sprintf + "Undeclared identifier should not be classified as a type, but found: %A" + (badSpans |> Array.map (fun i -> i.Range.StartColumn, i.Range.EndColumn, i.Type)) + ) From 2e24ca91a819bc91abb71b84c8c7a541d825bd20 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 25 May 2026 08:35:57 +0200 Subject: [PATCH 2/3] Apply remaining changes --- .executor-pid | 1 + 1 file changed, 1 insertion(+) create mode 100644 .executor-pid diff --git a/.executor-pid b/.executor-pid new file mode 100644 index 0000000000..876998c761 --- /dev/null +++ b/.executor-pid @@ -0,0 +1 @@ +33492 \ No newline at end of file From de3dd994f1c81319516fdf4afdb28a768129f104 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 26 May 2026 14:30:44 +0200 Subject: [PATCH 3/3] Remove executor artifact --- .executor-pid | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .executor-pid diff --git a/.executor-pid b/.executor-pid deleted file mode 100644 index 876998c761..0000000000 --- a/.executor-pid +++ /dev/null @@ -1 +0,0 @@ -33492 \ No newline at end of file