From 7c2e9734415e157caf575604dbb78a8f1a5972ec Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Sat, 8 Feb 2025 14:05:17 -0500 Subject: [PATCH 1/7] Resolve `nameof` in `nameof<'T>` --- src/Compiler/Checking/Expressions/CheckExpressions.fs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index d34d9cf2978..3f6b7529f4a 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -9270,6 +9270,13 @@ and TcValueItemThen cenv overallTy env vref tpenv mItem afterResolution delayed let _tpR, tpenv = TcTypeOrMeasureParameter None cenv env ImplicitlyBoundTyparsAllowed.NoNewTypars tpenv tp let vExpr = TcNameOfExprResult cenv id mExprAndTypeArgs let vexpFlex = MakeApplicableExprNoFlex cenv vExpr + + // Record the resolution of the `nameof` usage so that we can classify it correctly later. + do + match afterResolution with + | AfterResolution.RecordResolution (_, callSink, _, _) -> callSink emptyTyparInst + | AfterResolution.DoNothing -> () + PropagateThenTcDelayed cenv overallTy env tpenv mExprAndTypeArgs vexpFlex g.string_ty ExprAtomicFlag.Atomic otherDelayed | _ -> error (Error(FSComp.SR.expressionHasNoName(), mExprAndTypeArgs)) From dd1465f174f03a630aaef113ce41466a5e75b3dc Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Sat, 8 Feb 2025 14:06:46 -0500 Subject: [PATCH 2/7] =?UTF-8?q?Resolve=20`nameof`=20in=20`match=20?= =?UTF-8?q?=E2=80=A6=20with=20nameof=20ident=20->=20=E2=80=A6`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Compiler/Checking/CheckPatterns.fs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Compiler/Checking/CheckPatterns.fs b/src/Compiler/Checking/CheckPatterns.fs index 5d447da6021..cdffd9acb7f 100644 --- a/src/Compiler/Checking/CheckPatterns.fs +++ b/src/Compiler/Checking/CheckPatterns.fs @@ -583,7 +583,10 @@ and TcPatLongIdentNewDef warnOnUpperForId warnOnUpper (cenv: cenv) env ad valRep | [arg] when g.langVersion.SupportsFeature LanguageFeature.NameOf && IsNameOf cenv env ad m id -> match TcNameOfExpr cenv env tpenv (ConvSynPatToSynExpr arg) with - | Expr.Const(Const.String s, m, _) -> TcConstPat warnOnUpper cenv env vFlags patEnv ty (SynConst.String(s, SynStringKind.Regular, m)) m + | Expr.Const(Const.String s, m, _) -> + // Record the resolution of the `nameof` usage so that we can classify it correctly later. + CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, Item.Value g.nameof_vref, emptyTyparInst, ItemOccurrence.Use, env.eAccessRights) + TcConstPat warnOnUpper cenv env vFlags patEnv ty (SynConst.String(s, SynStringKind.Regular, m)) m | _ -> failwith "Impossible: TcNameOfExpr must return an Expr.Const of type string" | _ -> From 8a5e2819f7daede59bb062c6baf2f46ab93047c4 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Sat, 8 Feb 2025 14:07:45 -0500 Subject: [PATCH 3/7] Add `nameof` classification tests --- .../SemanticClassificationServiceTests.fs | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs index 64313dd6bd5..b1fa4554462 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs @@ -43,8 +43,12 @@ type SemanticClassificationServiceTests() = match ranges |> List.tryFind (fun item -> Range.rangeContainsPos item.Range markerPos) with | None -> failwith "Cannot find colorization data for end of marker" | Some item -> - FSharpClassificationTypes.getClassificationTypeName item.Type - |> Assert.shouldBeEqualWith classificationType "Classification data doesn't match for end of marker" + let actual = FSharpClassificationTypes.getClassificationTypeName item.Type + + actual + |> Assert.shouldBeEqualWith + classificationType + $"Classification data doesn't match for end of marker: {classificationType} ≠ {actual} ({item.Type})" let verifyNoClassificationDataAtEndOfMarker (fileContents: string, marker: string, classificationType: string) = let text = SourceText.From(fileContents) @@ -183,3 +187,48 @@ let g() = """ verifyNoClassificationDataAtEndOfMarker (sourceText, marker, classificationType) + + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + [] + member _.``nameof ident, nameof<'T>, match … with nameof ident``(marker: string, classificationType: string) = + let sourceText = + """ +module ``Normal usage of nameof should show up as a keyword`` = + let f x = (*1*)nameof x + let g (x : 'T) = (*2*)nameof<'T> + let h x y = match x with (*3*)nameof y -> () | _ -> () + +module ``Redefined nameof should shadow the intrinsic one`` = + let f x = match x with (*4*)nameof -> () | _ -> () + let f (*5*)nameof = (*6*)nameof + let (*7*)nameof = "redefined" + let _ = (*8*)nameof + + type (*9*)nameof () = class end + let _ = (*10*)nameof () + let _ = new (*11*)nameof () + + module (*12*)nameof = + let f x = x + + let _ = (*13*)nameof.f 3 + + let f (x : '(*14*)nameof) = x + let g (x : (*15*)'nameof) = x +""" + + verifyClassificationAtEndOfMarker (sourceText, marker, classificationType) From d2e22891e630378037ce3c7f13c0f2793e68e82a Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Sat, 8 Feb 2025 14:20:21 -0500 Subject: [PATCH 4/7] Update release notes --- docs/release-notes/.FSharp.Compiler.Service/9.0.300.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index a6d29f078d4..4a94774a0b7 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -1,4 +1,5 @@ ### Fixed +* Fix classification of `nameof` in `nameof<'T>`, `match … with nameof ident -> …`. ([Issue #10026](https://github.com/dotnet/fsharp/issues/10026), [PR #18300](https://github.com/dotnet/fsharp/pull/18300)) * Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877)) * Fix optimizer internal error for records with static fields ([Issue #18165](https://github.com/dotnet/fsharp/issues/18165), [PR #18280](https://github.com/dotnet/fsharp/pull/18280)) * Fix nullness warning with flexible types ([Issue #18056](https://github.com/dotnet/fsharp/issues/18056), [PR #18266](https://github.com/dotnet/fsharp/pull/18266)) @@ -22,4 +23,4 @@ * Remove `Cancellable.UsingToken` from tests ([PR #18276](https://github.com/dotnet/fsharp/pull/18276)) ### Breaking Changes -* Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877)) \ No newline at end of file +* Struct unions with overlapping fields now generate mappings needed for reading via reflection ([Issue #18121](https://github.com/dotnet/fsharp/issues/17797), [PR #18274](https://github.com/dotnet/fsharp/pull/17877)) From 74eea31868152c5b66827288104c8204181c1657 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Sat, 8 Feb 2025 14:38:38 -0500 Subject: [PATCH 5/7] Might as well make them compilable --- .../SemanticClassificationServiceTests.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs index b1fa4554462..d8401a833b3 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs @@ -213,8 +213,8 @@ module ``Normal usage of nameof should show up as a keyword`` = let h x y = match x with (*3*)nameof y -> () | _ -> () module ``Redefined nameof should shadow the intrinsic one`` = - let f x = match x with (*4*)nameof -> () | _ -> () - let f (*5*)nameof = (*6*)nameof + let a x = match x with (*4*)nameof -> () | _ -> () + let b (*5*)nameof = (*6*)nameof let (*7*)nameof = "redefined" let _ = (*8*)nameof @@ -227,8 +227,8 @@ module ``Redefined nameof should shadow the intrinsic one`` = let _ = (*13*)nameof.f 3 - let f (x : '(*14*)nameof) = x - let g (x : (*15*)'nameof) = x + let c (x : '(*14*)nameof) = x + let d (x : (*15*)'nameof) = x """ verifyClassificationAtEndOfMarker (sourceText, marker, classificationType) From 3f91e70c1252c19c9026a74d7bc674950505c92f Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Sat, 8 Feb 2025 15:03:14 -0500 Subject: [PATCH 6/7] =?UTF-8?q?Show=20`nameof`=20as=20keyword=20in=20`name?= =?UTF-8?q?of<=E2=80=A6>`=20even=20when=20the=20type=20parameter=20is=20in?= =?UTF-8?q?valid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Checking/Expressions/CheckExpressions.fs | 13 ++++++------- .../SemanticClassificationServiceTests.fs | 10 +++++++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 3f6b7529f4a..d80470b9e53 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -9265,18 +9265,17 @@ and TcValueItemThen cenv overallTy env vref tpenv mItem afterResolution delayed // Allow `nameof<'T>` for a generic parameter match vref with | _ when isNameOfValRef g vref && g.langVersion.SupportsFeature LanguageFeature.NameOf -> + // Record the resolution of the `nameof` usage so that we can classify it correctly later. + do + match afterResolution with + | AfterResolution.RecordResolution (_, callSink, _, _) -> callSink emptyTyparInst + | AfterResolution.DoNothing -> () + match tys with | [SynType.Var(SynTypar(id, _, false) as tp, _m)] -> let _tpR, tpenv = TcTypeOrMeasureParameter None cenv env ImplicitlyBoundTyparsAllowed.NoNewTypars tpenv tp let vExpr = TcNameOfExprResult cenv id mExprAndTypeArgs let vexpFlex = MakeApplicableExprNoFlex cenv vExpr - - // Record the resolution of the `nameof` usage so that we can classify it correctly later. - do - match afterResolution with - | AfterResolution.RecordResolution (_, callSink, _, _) -> callSink emptyTyparInst - | AfterResolution.DoNothing -> () - PropagateThenTcDelayed cenv overallTy env tpenv mExprAndTypeArgs vexpFlex g.string_ty ExprAtomicFlag.Atomic otherDelayed | _ -> error (Error(FSComp.SR.expressionHasNoName(), mExprAndTypeArgs)) diff --git a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs index d8401a833b3..6e3666d726d 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs @@ -204,13 +204,16 @@ let g() = [] [] [] + [] + [] + [] member _.``nameof ident, nameof<'T>, match … with nameof ident``(marker: string, classificationType: string) = let sourceText = """ module ``Normal usage of nameof should show up as a keyword`` = let f x = (*1*)nameof x let g (x : 'T) = (*2*)nameof<'T> - let h x y = match x with (*3*)nameof y -> () | _ -> () + let h x y = match x with (*3*)nameof y -> () module ``Redefined nameof should shadow the intrinsic one`` = let a x = match x with (*4*)nameof -> () | _ -> () @@ -229,6 +232,11 @@ module ``Redefined nameof should shadow the intrinsic one`` = let c (x : '(*14*)nameof) = x let d (x : (*15*)'nameof) = x + +module ``It should still show up as a keyword even if the type parameter is invalid`` = + let _ = (*16*)nameof<> + let a (x : 'a) (y : 'b) = (*17*)nameof<'c> // FS0039: The type parameter 'c is not defined. + let _ = (*18*)nameof // FS3250: Expression does not have a name. """ verifyClassificationAtEndOfMarker (sourceText, marker, classificationType) From 96783dcba0c8f857c635fe1c8de5f4271aa66a4a Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Sat, 8 Feb 2025 15:07:23 -0500 Subject: [PATCH 7/7] Touchup --- .../FSharp.Editor.Tests/SemanticClassificationServiceTests.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs index 6e3666d726d..eae06773f68 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/SemanticClassificationServiceTests.fs @@ -213,10 +213,10 @@ let g() = module ``Normal usage of nameof should show up as a keyword`` = let f x = (*1*)nameof x let g (x : 'T) = (*2*)nameof<'T> - let h x y = match x with (*3*)nameof y -> () + let h x y = match x with (*3*)nameof y -> () | _ -> () module ``Redefined nameof should shadow the intrinsic one`` = - let a x = match x with (*4*)nameof -> () | _ -> () + let a x = match x with (*4*)nameof -> () let b (*5*)nameof = (*6*)nameof let (*7*)nameof = "redefined" let _ = (*8*)nameof