From 016b04c56830631eb8fcbcb466ca2132692ddf84 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Tue, 16 Sep 2025 17:58:47 +0200 Subject: [PATCH 1/4] Checker: fix declaring type for abbreviated types extensions --- src/Compiler/Checking/CheckDeclarations.fs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index e6a39af0a7b..7d1c875e25c 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -4250,11 +4250,15 @@ module TcDeclarations = // a) For interfaces, only if it is in the original defn. // Augmentations to interfaces via partial type defns will always be extensions, e.g. extension members on interfaces. // b) For other types, if the type is isInSameModuleOrNamespace - let declKind, typars = - if isAtOriginalTyconDefn then - ModuleOrMemberBinding, reqTypars + if isAtOriginalTyconDefn then + ModuleOrMemberBinding, tcref, reqTypars + else + match tcref.TypeAbbrev |> Option.toValueOption |> ValueOption.bind (tryTcrefOfAppTy g) with + | ValueSome abbrTcref -> + errorR (Error(FSComp.SR.tcTypeAbbreviationsCannotHaveAugmentations(), m)) + ExtrinsicExtensionBinding, abbrTcref, abbrTcref.TyparsNoRange + | _ -> - else let isInSameModuleOrNamespace = match envForDecls.eModuleOrNamespaceTypeAccumulator.Value.TypesByMangledName.TryGetValue tcref.LogicalName with | true, tycon -> tyconOrder.Compare(tcref.Deref, tycon) = 0 @@ -4277,7 +4281,7 @@ module TcDeclarations = if not (typarsAEquiv g (TypeEquivEnv.EmptyWithNullChecks g) reqTypars declaredTypars) then warning(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m)) // Note we return 'reqTypars' for intrinsic extensions since we may only have given warnings - IntrinsicExtensionBinding, reqTypars + IntrinsicExtensionBinding, tcref, reqTypars else if isInSameModuleOrNamespace && isDelegateOrEnum then errorR(Error(FSComp.SR.tcMembersThatExtendInterfaceMustBePlacedInSeparateModule(), tcref.Range)) @@ -4285,10 +4289,7 @@ module TcDeclarations = error(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m)) if not (typarsAEquiv g (TypeEquivEnv.EmptyWithNullChecks g) reqTypars declaredTypars) then errorR(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m)) - ExtrinsicExtensionBinding, declaredTypars - - - declKind, tcref, typars + ExtrinsicExtensionBinding, tcref, declaredTypars let private isAugmentationTyconDefnRepr = function SynTypeDefnSimpleRepr.General(kind=SynTypeDefnKind.Augmentation _) -> true | _ -> false @@ -4608,9 +4609,6 @@ module TcDeclarations = if (declKind = ExtrinsicExtensionBinding) && isByrefTyconRef g tcref then error(Error(FSComp.SR.tcByrefsMayNotHaveTypeExtensions(), tyDeclRange)) - if not (isNil members) && tcref.IsTypeAbbrev then - errorR(Error(FSComp.SR.tcTypeAbbreviationsCannotHaveAugmentations(), tyDeclRange)) - let (SynComponentInfo (attributes, _, _, _, _, _, _, _)) = synTyconInfo if not (List.isEmpty attributes) && (declKind = ExtrinsicExtensionBinding || declKind = IntrinsicExtensionBinding) then let attributeRange = (List.head attributes).Range From 795c03a1f842765104a94c5174a4d6f116de3437 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 17 Sep 2025 12:39:05 +0200 Subject: [PATCH 2/4] Fix type parameters --- src/Compiler/Checking/CheckDeclarations.fs | 11 +++++------ .../ErrorMessages/AbbreviationTests.fs | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 7d1c875e25c..be30d8a0abb 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -4253,12 +4253,6 @@ module TcDeclarations = if isAtOriginalTyconDefn then ModuleOrMemberBinding, tcref, reqTypars else - match tcref.TypeAbbrev |> Option.toValueOption |> ValueOption.bind (tryTcrefOfAppTy g) with - | ValueSome abbrTcref -> - errorR (Error(FSComp.SR.tcTypeAbbreviationsCannotHaveAugmentations(), m)) - ExtrinsicExtensionBinding, abbrTcref, abbrTcref.TyparsNoRange - | _ -> - let isInSameModuleOrNamespace = match envForDecls.eModuleOrNamespaceTypeAccumulator.Value.TypesByMangledName.TryGetValue tcref.LogicalName with | true, tycon -> tyconOrder.Compare(tcref.Deref, tycon) = 0 @@ -4274,6 +4268,11 @@ module TcDeclarations = let _tpenv = TcTyparConstraints cenv NoNewTypars CheckCxs ItemOccurrence.UseInType envForTycon emptyUnscopedTyparEnv synTyparCxs declaredTypars |> List.iter (SetTyparRigid envForDecls.DisplayEnv m) + if tcref.TypeAbbrev.IsSome then + errorR (Error(FSComp.SR.tcTypeAbbreviationsCannotHaveAugmentations(), m)) + ExtrinsicExtensionBinding, tcref, declaredTypars + else + if isInSameModuleOrNamespace && not isInterfaceOrDelegateOrEnum then // For historical reasons we only give a warning for incorrect type parameters on intrinsic extensions if nReqTypars <> synTypars.Length then diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/AbbreviationTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/AbbreviationTests.fs index 26966e72782..41d7a86677a 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/AbbreviationTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/AbbreviationTests.fs @@ -54,6 +54,23 @@ type FloatAlias with (Error 909, Line 6, Col 15, Line 6, Col 34, "All implemented interfaces should be declared on the initial declaration of the type") ] +[] +let ``Members 04 - Error in expr`` () = + Fsx """ +type StringAlias = string + +type StringAlias with + member x.Length = x.Length + "" + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 964, Line 4, Col 6, Line 4, Col 17, "Type abbreviations cannot have augmentations") + (Error 895, Line 5, Col 5, Line 5, Col 36, "Type abbreviations cannot have members") + (Error 1, Line 5, Col 34, Line 5, Col 36, "The type 'string' does not match the type 'int'") + (Error 43, Line 5, Col 32, Line 5, Col 33, "The type 'string' does not match the type 'int'") + ] + [] let ``Multiple types 01`` () = Fsx """ From dbee7599fe2b7e260f243823d99a8da701a11d19 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 17 Sep 2025 12:46:54 +0200 Subject: [PATCH 3/4] Release notes --- docs/release-notes/.FSharp.Compiler.Service/10.0.100.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md index c87819d01ba..1419988c5e6 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md @@ -26,6 +26,7 @@ * Fix nullable types formatting in `FSharpType.Format` and tooltips to include parentheses. ([PR #18842](https://github.com/dotnet/fsharp/pull/18842)) * TypeMismatchDiagnosticExtendedData: fix expected and actual types calculation. ([Issue ](https://github.com/dotnet/fsharp/pull/18851)) * Parser: fix range for computed binding expressions ([PR #18903](https://github.com/dotnet/fsharp/pull/18903)) +* Checker: fix declaring type for abbreviated types extensions ([PR #18909](https://github.com/dotnet/fsharp/pull/18909)) ### Changed * Use `errorR` instead of `error` in `CheckDeclarations.fs` when possible. ([PR #18645](https://github.com/dotnet/fsharp/pull/18645)) From 48dfdad73375c1eaaa74411f2b00f74c60e782e6 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 17 Sep 2025 12:49:47 +0200 Subject: [PATCH 4/4] Minimize diff --- src/Compiler/Checking/CheckDeclarations.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index be30d8a0abb..cbf79fbdfb3 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -4269,11 +4269,8 @@ module TcDeclarations = declaredTypars |> List.iter (SetTyparRigid envForDecls.DisplayEnv m) if tcref.TypeAbbrev.IsSome then - errorR (Error(FSComp.SR.tcTypeAbbreviationsCannotHaveAugmentations(), m)) ExtrinsicExtensionBinding, tcref, declaredTypars - else - - if isInSameModuleOrNamespace && not isInterfaceOrDelegateOrEnum then + elif isInSameModuleOrNamespace && not isInterfaceOrDelegateOrEnum then // For historical reasons we only give a warning for incorrect type parameters on intrinsic extensions if nReqTypars <> synTypars.Length then errorR(Error(FSComp.SR.tcDeclaredTypeParametersForExtensionDoNotMatchOriginal(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m)) @@ -4608,6 +4605,9 @@ module TcDeclarations = if (declKind = ExtrinsicExtensionBinding) && isByrefTyconRef g tcref then error(Error(FSComp.SR.tcByrefsMayNotHaveTypeExtensions(), tyDeclRange)) + if not (isNil members) && tcref.IsTypeAbbrev then + errorR(Error(FSComp.SR.tcTypeAbbreviationsCannotHaveAugmentations(), tyDeclRange)) + let (SynComponentInfo (attributes, _, _, _, _, _, _, _)) = synTyconInfo if not (List.isEmpty attributes) && (declKind = ExtrinsicExtensionBinding || declKind = IntrinsicExtensionBinding) then let attributeRange = (List.head attributes).Range