From 9f1a533f9f072cc572dc66f9aeedf849b9be3f5c Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 18 Feb 2026 15:53:06 +0100 Subject: [PATCH 1/5] FSharpType: add more predefined type checks --- src/Compiler/Symbols/Symbols.fs | 67 ++++++++++++++++++++++---------- src/Compiler/Symbols/Symbols.fsi | 11 ++++++ 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index d7db3ecd19..bbc42d3027 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -2557,24 +2557,55 @@ type FSharpType(cenv, ty:TType) = member _.IsMeasureType = isResolved() && - protect <| fun () -> - match stripTyparEqns ty with - | TType_measure _ -> true - | _ -> false + protect <| fun () -> isMeasureTy cenv.g ty member _.IsTupleType = isResolved() && - protect <| fun () -> - match stripTyparEqns ty with - | TType_tuple _ -> true - | _ -> false + protect <| fun () -> isRefTupleTy cenv.g ty member _.IsStructTupleType = isResolved() && - protect <| fun () -> - match stripTyparEqns ty with - | TType_tuple (tupInfo, _) -> evalTupInfoIsStruct tupInfo - | _ -> false + protect <| fun () -> isStructTupleTy cenv.g ty + + member _.IsUnitType = + isResolved () && + protect <| fun () -> isUnitTy cenv.g ty + + member _.IsArrayType = + isResolved () && + protect <| fun () -> isArrayTy cenv.g ty + + member _.IsNativePointerType = + isResolved () && + protect <| fun () -> isNativePtrTy cenv.g ty + + member _.IsFSharpList = + isResolved () && + protect <| fun () -> isListTy cenv.g ty + + member _.IsFSharpChoice = + isResolved () && + protect <| fun () -> isChoiceTy cenv.g ty + + member _.IsFSharpOption = + isResolved () && + protect <| fun () -> isOptionTy cenv.g ty + + member _.IsFSharpValueOption = + isResolved () && + protect <| fun () -> isValueOptionTy cenv.g ty + + member _.IsStringType = + isResolved () && + protect <| fun () -> isStringTy cenv.g ty + + member _.IsObjectType = + isResolved () && + protect <| fun () -> isObjTyAnyNullness cenv.g ty + + member _.IsBooleanType = + isResolved () && + protect <| fun () -> isBoolTy cenv.g ty member _.TypeDefinition = protect <| fun () -> @@ -2633,17 +2664,11 @@ type FSharpType(cenv, ty:TType) = member _.IsFunctionType = isResolved() && - protect <| fun () -> - match stripTyparEqns ty with - | TType_fun _ -> true - | _ -> false + protect <| fun () -> isFunTy cenv.g ty member _.IsAnonRecordType = isResolved() && - protect <| fun () -> - match stripTyparEqns ty with - | TType_anon _ -> true - | _ -> false + protect <| fun () -> isAnonRecdTy cenv.g ty member _.AnonRecordTypeDetails = protect <| fun () -> @@ -2676,7 +2701,7 @@ type FSharpType(cenv, ty:TType) = GetSuperTypeOfType cenv.g cenv.amap range0 ty |> Option.map (fun ty -> FSharpType(cenv, ty)) - member x.ErasedType= + member x.ErasedType = FSharpType(cenv, stripTyEqnsWrtErasure EraseAll cenv.g ty) member x.BasicQualifiedName = diff --git a/src/Compiler/Symbols/Symbols.fsi b/src/Compiler/Symbols/Symbols.fsi index c416016583..1fa825b61b 100644 --- a/src/Compiler/Symbols/Symbols.fsi +++ b/src/Compiler/Symbols/Symbols.fsi @@ -1123,6 +1123,17 @@ type FSharpType = /// Indicates if the type is a struct tuple type. The GenericArguments property returns the elements of the tuple type. member IsStructTupleType: bool + member IsArrayType: bool + member IsNativePointerType: bool + member IsUnitType: bool + member IsFSharpList: bool + member IsFSharpChoice: bool + member IsFSharpOption: bool + member IsFSharpValueOption: bool + member IsStringType: bool + member IsObjectType: bool + member IsBooleanType: bool + /// Indicates if the type is a function type. The GenericArguments property returns the domain and range of the function type. member IsFunctionType: bool From 485c49f8ea7cecef2083334c402bdee405eca5da Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 18 Feb 2026 15:56:27 +0100 Subject: [PATCH 2/5] Release notes --- docs/release-notes/.FSharp.Compiler.Service/10.0.300.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md index 6a30bf5536..20e8fdda4c 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md @@ -17,6 +17,8 @@ ### Added * FSharpType: add ImportILType ([PR #19300](https://github.com/dotnet/fsharp/pull/19300)) +* FSharpType: add more predefined type checks ([PR #19325](https://github.com/dotnet/fsharp/pull/19325)) + ### Changed From ba42ccafc195351dabfb85a825a7f3b32eb2d717 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 18 Feb 2026 15:56:45 +0100 Subject: [PATCH 3/5] Release notes --- docs/release-notes/.FSharp.Compiler.Service/10.0.300.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md index 20e8fdda4c..bf8fb6612e 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md @@ -19,7 +19,6 @@ * FSharpType: add ImportILType ([PR #19300](https://github.com/dotnet/fsharp/pull/19300)) * FSharpType: add more predefined type checks ([PR #19325](https://github.com/dotnet/fsharp/pull/19325)) - ### Changed * Centralized product TFM (Target Framework Moniker) into MSBuild props file `eng/TargetFrameworks.props`. Changing the target framework now only requires editing one file, and it integrates with MSBuild's `--getProperty` for scripts. From d2356cb3ffb19eef067fb64dfe11675b950d4b69 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 18 Feb 2026 17:23:51 +0100 Subject: [PATCH 4/5] Surface area --- ...iler.Service.SurfaceArea.netstandard20.bsl | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl index 78114ab29c..6c0063e935 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl @@ -5835,23 +5835,43 @@ FSharp.Compiler.Symbols.FSharpType: Boolean HasNullAnnotation FSharp.Compiler.Symbols.FSharpType: Boolean HasTypeDefinition FSharp.Compiler.Symbols.FSharpType: Boolean IsAbbreviation FSharp.Compiler.Symbols.FSharpType: Boolean IsAnonRecordType +FSharp.Compiler.Symbols.FSharpType: Boolean IsArrayType +FSharp.Compiler.Symbols.FSharpType: Boolean IsBooleanType +FSharp.Compiler.Symbols.FSharpType: Boolean IsFSharpChoice +FSharp.Compiler.Symbols.FSharpType: Boolean IsFSharpList +FSharp.Compiler.Symbols.FSharpType: Boolean IsFSharpOption +FSharp.Compiler.Symbols.FSharpType: Boolean IsFSharpValueOption FSharp.Compiler.Symbols.FSharpType: Boolean IsFunctionType FSharp.Compiler.Symbols.FSharpType: Boolean IsGenericParameter FSharp.Compiler.Symbols.FSharpType: Boolean IsMeasureType +FSharp.Compiler.Symbols.FSharpType: Boolean IsNativePointerType FSharp.Compiler.Symbols.FSharpType: Boolean IsNullAmbivalent +FSharp.Compiler.Symbols.FSharpType: Boolean IsObjectType +FSharp.Compiler.Symbols.FSharpType: Boolean IsStringType FSharp.Compiler.Symbols.FSharpType: Boolean IsStructTupleType FSharp.Compiler.Symbols.FSharpType: Boolean IsTupleType +FSharp.Compiler.Symbols.FSharpType: Boolean IsUnitType FSharp.Compiler.Symbols.FSharpType: Boolean IsUnresolved FSharp.Compiler.Symbols.FSharpType: Boolean get_HasNullAnnotation() FSharp.Compiler.Symbols.FSharpType: Boolean get_HasTypeDefinition() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsAbbreviation() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsAnonRecordType() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsArrayType() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsBooleanType() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsFSharpChoice() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsFSharpList() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsFSharpOption() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsFSharpValueOption() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsFunctionType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsGenericParameter() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsMeasureType() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsNativePointerType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsNullAmbivalent() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsObjectType() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsStringType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsStructTupleType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsTupleType() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsUnitType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsUnresolved() FSharp.Compiler.Symbols.FSharpType: FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails AnonRecordTypeDetails FSharp.Compiler.Symbols.FSharpType: FSharp.Compiler.Symbols.FSharpAnonRecordTypeDetails get_AnonRecordTypeDetails() From d31ca9f2f8f9971288337f0be98bbd5796f14dc5 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Mon, 23 Feb 2026 17:06:59 +0100 Subject: [PATCH 5/5] Use isAnyTupleType, add IsReferenceTupleType --- src/Compiler/Symbols/Symbols.fs | 4 ++++ src/Compiler/Symbols/Symbols.fsi | 3 +++ .../FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index bbc42d3027..c44e47efd9 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -2560,6 +2560,10 @@ type FSharpType(cenv, ty:TType) = protect <| fun () -> isMeasureTy cenv.g ty member _.IsTupleType = + isResolved() && + protect <| fun () -> isAnyTupleTy cenv.g ty + + member _.IsReferenceTupleType = isResolved() && protect <| fun () -> isRefTupleTy cenv.g ty diff --git a/src/Compiler/Symbols/Symbols.fsi b/src/Compiler/Symbols/Symbols.fsi index 1fa825b61b..8c8a47a3df 100644 --- a/src/Compiler/Symbols/Symbols.fsi +++ b/src/Compiler/Symbols/Symbols.fsi @@ -1120,6 +1120,9 @@ type FSharpType = /// Indicates if the type is a tuple type (reference or struct). The GenericArguments property returns the elements of the tuple type. member IsTupleType: bool + /// Indicates if the type is a reference tuple type. The GenericArguments property returns the elements of the tuple type. + member IsReferenceTupleType: bool + /// Indicates if the type is a struct tuple type. The GenericArguments property returns the elements of the tuple type. member IsStructTupleType: bool diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl index 6c0063e935..598232aa4d 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl @@ -5847,6 +5847,7 @@ FSharp.Compiler.Symbols.FSharpType: Boolean IsMeasureType FSharp.Compiler.Symbols.FSharpType: Boolean IsNativePointerType FSharp.Compiler.Symbols.FSharpType: Boolean IsNullAmbivalent FSharp.Compiler.Symbols.FSharpType: Boolean IsObjectType +FSharp.Compiler.Symbols.FSharpType: Boolean IsReferenceTupleType FSharp.Compiler.Symbols.FSharpType: Boolean IsStringType FSharp.Compiler.Symbols.FSharpType: Boolean IsStructTupleType FSharp.Compiler.Symbols.FSharpType: Boolean IsTupleType @@ -5868,6 +5869,7 @@ FSharp.Compiler.Symbols.FSharpType: Boolean get_IsMeasureType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsNativePointerType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsNullAmbivalent() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsObjectType() +FSharp.Compiler.Symbols.FSharpType: Boolean get_IsReferenceTupleType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsStringType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsStructTupleType() FSharp.Compiler.Symbols.FSharpType: Boolean get_IsTupleType()