Skip to content

Commit

Permalink
Fix 17731 - Regression, F# 9 compiler cannot find constructor for att…
Browse files Browse the repository at this point in the history
…ribute (#17746)

* Fix 17731

* fantomas

---------

Co-authored-by: Vlad Zarytovskii <[email protected]>
  • Loading branch information
KevinRansom and vzarytovskii authored Sep 16, 2024
1 parent e668b90 commit f4860a4
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 24 deletions.
28 changes: 14 additions & 14 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ module TcRecdUnionAndEnumDeclarations =
let TcFieldDecl (cenv: cenv) env parent isIncrClass tpenv (isStatic, synAttrs, id: Ident, nameGenerated, ty, isMutable, xmldoc, vis) =
let g = cenv.g
let m = id.idRange
let attrs, _ = TcAttributesWithPossibleTargets false cenv env AttributeTargets.FieldDecl synAttrs
let attrs, _ = TcAttributesWithPossibleTargets TcCanFail.ReportAllErrors cenv env AttributeTargets.FieldDecl synAttrs

let attrsForProperty, attrsForField = attrs |> List.partition (fun (attrTargets, _) -> (attrTargets &&& AttributeTargets.Property) <> enum 0)
let attrsForProperty = (List.map snd attrsForProperty)
Expand All @@ -455,7 +455,7 @@ module TcRecdUnionAndEnumDeclarations =
match parent with
| Parent tcref when useGenuineField tcref.Deref rfspec ->
// Recheck the attributes for errors if the definition only generates a field
TcAttributesWithPossibleTargets false cenv env AttributeTargets.FieldDeclRestricted synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.ReportAllErrors cenv env AttributeTargets.FieldDeclRestricted synAttrs |> ignore
| _ -> ()
rfspec

Expand Down Expand Up @@ -2909,9 +2909,9 @@ module EstablishTypeDefinitionCores =

if reportAttributeTargetsErrors then
if hasStructAttr then
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Struct synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.IgnoreMemberResoutionError cenv envinner AttributeTargets.Struct synAttrs |> ignore
else
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Class synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.IgnoreMemberResoutionError cenv envinner AttributeTargets.Class synAttrs |> ignore

// Note: the table of union cases is initially empty
Construct.MakeUnionRepr []
Expand All @@ -2934,9 +2934,9 @@ module EstablishTypeDefinitionCores =

if reportAttributeTargetsErrors then
if hasStructAttr then
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Struct synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.IgnoreMemberResoutionError cenv envinner AttributeTargets.Struct synAttrs |> ignore
else
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Class synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.IgnoreMemberResoutionError cenv envinner AttributeTargets.Class synAttrs |> ignore

// Note: the table of record fields is initially empty
TFSharpTyconRepr (Construct.NewEmptyFSharpTyconData TFSharpRecord)
Expand All @@ -2952,19 +2952,19 @@ module EstablishTypeDefinitionCores =
match kind with
| SynTypeDefnKind.Class ->
if reportAttributeTargetsErrors then
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Class synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.IgnoreMemberResoutionError cenv envinner AttributeTargets.Class synAttrs |> ignore
TFSharpClass
| SynTypeDefnKind.Interface ->
if reportAttributeTargetsErrors then
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Interface synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.IgnoreMemberResoutionError cenv envinner AttributeTargets.Interface synAttrs |> ignore
TFSharpInterface
| SynTypeDefnKind.Delegate _ ->
if reportAttributeTargetsErrors then
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Delegate synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.IgnoreMemberResoutionError cenv envinner AttributeTargets.Delegate synAttrs |> ignore
TFSharpDelegate (MakeSlotSig("Invoke", g.unit_ty, [], [], [], None))
| SynTypeDefnKind.Struct ->
if reportAttributeTargetsErrors then
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Struct synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.IgnoreMemberResoutionError cenv envinner AttributeTargets.Struct synAttrs |> ignore
TFSharpStruct
| _ -> error(InternalError("should have inferred tycon kind", m))

Expand All @@ -2973,7 +2973,7 @@ module EstablishTypeDefinitionCores =
| SynTypeDefnSimpleRepr.Enum _ ->
noCLIMutableAttributeCheck()
if reportAttributeTargetsErrors then
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Enum synAttrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.IgnoreMemberResoutionError cenv envinner AttributeTargets.Enum synAttrs |> ignore
TFSharpTyconRepr (Construct.NewEmptyFSharpTyconData TFSharpEnum)

// OK, now fill in the (partially computed) type representation
Expand Down Expand Up @@ -4035,7 +4035,7 @@ module EstablishTypeDefinitionCores =
// Phase 1B. Establish the kind of each type constructor
// Here we run InferTyconKind and record partial information about the kind of the type constructor.
// This means FSharpTyconKind is set, which means isSealedTy, isInterfaceTy etc. give accurate results.
let withAttrs =
let withAttrs =
(envMutRecPrelim, withEnvs) ||> MutRecShapes.mapTyconsWithEnv (fun envForDecls (origInfo, tyconOpt) ->
let res =
match origInfo, tyconOpt with
Expand Down Expand Up @@ -5202,7 +5202,7 @@ let TcModuleOrNamespaceElementsMutRec (cenv: cenv) parent typeNames m envInitial
let mutRecDefnsChecked, envAfter = TcDeclarations.TcMutRecDefinitions cenv envInitial parent typeNames tpenv m scopem mutRecNSInfo mutRecDefns true

// Check the assembly attributes
let attrs, _ = TcAttributesWithPossibleTargets false cenv envAfter AttributeTargets.Top synAttrs
let attrs, _ = TcAttributesWithPossibleTargets TcCanFail.ReportAllErrors cenv envAfter AttributeTargets.Top synAttrs

// Check the non-escaping condition as we build the list of module expressions on the way back up
let moduleContents = TcMutRecDefsFinish cenv mutRecDefnsChecked m
Expand Down Expand Up @@ -5279,7 +5279,7 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
return! failwith "unreachable"

| SynModuleDecl.Attributes (Attributes synAttrs, _) ->
let attrs, _ = TcAttributesWithPossibleTargets false cenv env AttributeTargets.Top synAttrs
let attrs, _ = TcAttributesWithPossibleTargets TcCanFail.ReportAllErrors cenv env AttributeTargets.Top synAttrs
return ([], [], attrs), env, env

| SynModuleDecl.HashDirective _ ->
Expand Down
17 changes: 12 additions & 5 deletions src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,13 @@ let TranslatePartialValReprInfo tps (PrelimValReprInfo (argsData, retData)) =
// Members
//-------------------------------------------------------------------------


[<RequireQualifiedAccess>]
type TcCanFail =
| IgnoreMemberResoutionError
| IgnoreAllErrors
| ReportAllErrors

let TcAddNullnessToType (warn: bool) (cenv: cenv) (env: TcEnv) nullness innerTyC m =
let g = cenv.g
if g.langFeatureNullness then
Expand Down Expand Up @@ -10869,7 +10876,7 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt
// For all but attributes positioned at the return value, disallow implicitly
// targeting the return value.
let tgtEx = if isRet then enum 0 else AttributeTargets.ReturnValue
let attrs, _ = TcAttributesMaybeFailEx false cenv envinner tgt tgtEx attrs
let attrs, _ = TcAttributesMaybeFailEx TcCanFail.ReportAllErrors cenv envinner tgt tgtEx attrs
let attrs: Attrib list = attrs
if attrTgt = enum 0 && not (isNil attrs) then
for attr in attrs do
Expand Down Expand Up @@ -11131,7 +11138,7 @@ and TcAttributeTargetsOnLetBindings (cenv: cenv) env attrs overallPatTy overallE
else
AttributeTargets.ReturnValue ||| AttributeTargets.Field ||| AttributeTargets.Property

TcAttributesWithPossibleTargets false cenv env attrTgt attrs |> ignore
TcAttributesWithPossibleTargets TcCanFail.ReportAllErrors cenv env attrTgt attrs |> ignore

and TcLiteral (cenv: cenv) overallTy env tpenv (attrs, synLiteralValExpr) =

Expand Down Expand Up @@ -11291,7 +11298,7 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn
error(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElement(), mAttr))

match ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mAttr ad ty with
| Exception _ when canFail -> [ ], true
| Exception _ when canFail = TcCanFail.IgnoreAllErrors || canFail = TcCanFail.IgnoreMemberResoutionError -> [ ], true
| res ->

let item = ForceRaise res
Expand Down Expand Up @@ -11396,11 +11403,11 @@ and TcAttributesMaybeFail canFail cenv env attrTgt synAttribs =
TcAttributesMaybeFailEx canFail cenv env attrTgt (enum 0) synAttribs

and TcAttributesCanFail cenv env attrTgt synAttribs =
let attrs, didFail = TcAttributesMaybeFail true cenv env attrTgt synAttribs
let attrs, didFail = TcAttributesMaybeFail TcCanFail.IgnoreAllErrors cenv env attrTgt synAttribs
attrs, (fun () -> if didFail then TcAttributes cenv env attrTgt synAttribs else attrs)

and TcAttributes cenv env attrTgt synAttribs =
TcAttributesMaybeFail false cenv env attrTgt synAttribs |> fst
TcAttributesMaybeFail TcCanFail.ReportAllErrors cenv env attrTgt synAttribs |> fst

//-------------------------------------------------------------------------
// TcLetBinding
Expand Down
8 changes: 7 additions & 1 deletion src/Compiler/Checking/Expressions/CheckExpressions.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,12 @@ type PostSpecialValsRecursiveBinding =
{ ValScheme: ValScheme
Binding: Binding }

[<RequireQualifiedAccess>]
type TcCanFail =
| IgnoreMemberResoutionError
| IgnoreAllErrors
| ReportAllErrors

/// Represents a recursive binding after it has been both checked and generalized, but
/// before initialization recursion has been rewritten
type PreInitializationGraphEliminationBinding =
Expand Down Expand Up @@ -598,7 +604,7 @@ val TcAttributesCanFail:

/// Check a set of attributes which can only target specific elements
val TcAttributesWithPossibleTargets:
canFail: bool ->
canFail: TcCanFail ->
cenv: TcFileState ->
env: TcEnv ->
attrTgt: AttributeTargets ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace Conformance.BasicGrammarElements

Expand Down Expand Up @@ -875,7 +875,7 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) =
(Error 948, Line 8, Col 6, Line 8, Col 24, "Interface types cannot be sealed")
(Error 942, Line 14, Col 6, Line 14, Col 33, "Delegate types are always sealed")
]

// SOURCE= E_StructLayout01.fs # E_StructLayout01.fs
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"E_StructLayout01.fs"|])>]
let ``E_StructLayout01 9.0`` compilation =
Expand All @@ -890,7 +890,7 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) =
(Error 937, Line 14, Col 6, Line 14, Col 8, "Only structs and classes without primary constructors may be given the 'StructLayout' attribute")
(Error 937, Line 17, Col 6, Line 17, Col 8, "Only structs and classes without primary constructors may be given the 'StructLayout' attribute")
]

// SOURCE=E_StructLayout01.fs # E_StructLayout01.fs
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"E_StructLayout01.fs"|])>]
let ``E_StructLayout01 preview`` compilation =
Expand All @@ -904,4 +904,32 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) =
(Error 937, Line 11, Col 6, Line 11, Col 8, "Only structs and classes without primary constructors may be given the 'StructLayout' attribute")
(Error 937, Line 14, Col 6, Line 14, Col 8, "Only structs and classes without primary constructors may be given the 'StructLayout' attribute")
(Error 937, Line 17, Col 6, Line 17, Col 8, "Only structs and classes without primary constructors may be given the 'StructLayout' attribute")
]
]

#if NETCOREAPP
let missingConstructorRepro =
"""
open System.Text.Json.Serialization
type internal ApplicationTenantJsonDerivedTypeAttribute () =
inherit JsonDerivedTypeAttribute (typeof<ApplicationTenant>, "a")
// --------------------------------------------------------------------------
// IMPORTANT: Read ReadMe before modifying this сlass and any referenced types
// --------------------------------------------------------------------------
and [<ApplicationTenantJsonDerivedType>]
ApplicationTenant
[<JsonConstructor>] (id, name, loginProvider, allowedDomains, authorizedTenants, properties) =
member _.Id = ""
"""

[<InlineData("8.0")>]
[<InlineData("preview")>]
[<Theory>]
let ``Regression for - F# 9 compiler cannot find constructor for attribute`` langVersion =
FSharp missingConstructorRepro
|> withLangVersion langVersion
|> verifyCompile
|> shouldSucceed
#endif

0 comments on commit f4860a4

Please sign in to comment.