Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow access modifiers to auto properties getters and setters #16687

Merged
merged 22 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/8.0.300.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* Higher-order-function-based API for working with the untyped abstract syntax tree. ([PR #16462](https://github.com/dotnet/fsharp/pull/16462))
* Allow returning bool instead of unit option for partial active patterns. ([Language suggestion #1041](https://github.com/fsharp/fslang-suggestions/issues/1041), [PR #16473](https://github.com/dotnet/fsharp/pull/16473))
* Symbols: Add GenericArguments to FSharpEntity ([PR #16470](https://github.com/dotnet/fsharp/pull/16470))
* Allow access modifies to auto properties getters and setters ([PR 16687](https://github.com/dotnet/fsharp/pull/16687), [Language suggestion #430](https://github.com/fsharp/fslang-suggestions/issues/430))

### Changed

Expand Down
1 change: 1 addition & 0 deletions docs/release-notes/.Language/preview.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Bidirectional F#/C# interop for 'unmanaged' constraint. ([PR #12154](https://github.com/dotnet/fsharp/pull/12154))
* Make `.Is*` discriminated union properties visible. ([Language suggestion #222](https://github.com/fsharp/fslang-suggestions/issues/222), [PR #16341](https://github.com/dotnet/fsharp/pull/16341))
* Allow returning bool instead of unit option for partial active patterns. ([Language suggestion #1041](https://github.com/fsharp/fslang-suggestions/issues/1041), [PR #16473](https://github.com/dotnet/fsharp/pull/16473))
* Allow access modifies to auto properties getters and setters ([PR 16687](https://github.com/dotnet/fsharp/pull/16687), [Language suggestion #430](https://github.com/fsharp/fslang-suggestions/issues/430))

### Fixed

Expand Down
6 changes: 3 additions & 3 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4342,7 +4342,7 @@ module TcDeclarations =
let rec postAutoProps memb =
match memb with
| SynMemberDefn.AutoProperty(ident = id) when String.IsNullOrEmpty(id.idText) -> []
| SynMemberDefn.AutoProperty(attributes=Attributes attribs; isStatic=isStatic; ident=id; typeOpt=tyOpt; propKind=propKind; memberFlags=memberFlags; memberFlagsForSet=memberFlagsForSet; xmlDoc=xmlDoc; accessibility=access; trivia = { GetSetKeywords = mGetSetOpt }) ->
| SynMemberDefn.AutoProperty(attributes=Attributes attribs; isStatic=isStatic; ident=id; typeOpt=tyOpt; propKind=propKind; memberFlags=memberFlags; memberFlagsForSet=memberFlagsForSet; xmlDoc=xmlDoc; trivia = { GetSetKeywords = mGetSetOpt }; getterAccessibility = getterAccesss; setterAccessibility = setterAccess) ->
let mMemberPortion = id.idRange
// Only the keep the non-field-targeted attributes
let attribs = attribs |> List.filter (fun a -> match a.Target with Some t when t.idText = "field" -> false | _ -> true)
Expand All @@ -4365,7 +4365,7 @@ module TcDeclarations =
let rhsExpr = SynExpr.Ident fldId
let retInfo = match tyOpt with None -> None | Some ty -> Some (None, SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range))
let attribs = mkAttributeList attribs mMemberPortion
let binding = mkSynBinding (xmlDoc, headPat) (access, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, retInfo, rhsExpr, rhsExpr.Range, [], attribs, Some memberFlags, SynBindingTrivia.Zero)
let binding = mkSynBinding (xmlDoc, headPat) (getterAccesss, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, retInfo, rhsExpr, rhsExpr.Range, [], attribs, Some memberFlags, SynBindingTrivia.Zero)
SynMemberDefn.Member (binding, mMemberPortion)
yield getter
| _ -> ()
Expand All @@ -4377,7 +4377,7 @@ module TcDeclarations =
let vId = ident("v", mMemberPortion)
let headPat = SynPat.LongIdent (SynLongIdent(headPatIds, [], List.replicate headPatIds.Length None), None, Some noInferredTypars, SynArgPats.Pats [mkSynPatVar None vId], None, mMemberPortion)
let rhsExpr = mkSynAssign (SynExpr.Ident fldId) (SynExpr.Ident vId)
let binding = mkSynBinding (xmlDoc, headPat) (access, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, None, rhsExpr, rhsExpr.Range, [], [], Some memberFlagsForSet, SynBindingTrivia.Zero)
let binding = mkSynBinding (xmlDoc, headPat) (setterAccess, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, None, rhsExpr, rhsExpr.Range, [], [], Some memberFlagsForSet, SynBindingTrivia.Zero)
SynMemberDefn.Member (binding, mMemberPortion)
yield setter
| _ -> ()]
Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1742,4 +1742,5 @@ featureReuseSameFieldsInStructUnions,"Share underlying fields in a [<Struct>] di
3862,parsStaticMemberImcompleteSyntax,"Incomplete declaration of a static construct. Use 'static let','static do','static member' or 'static val' for declaration."
3863,parsExpectingField,"Expecting record field"
3864,tooManyMethodsInDotNetTypeWritingAssembly,"The type '%s' has too many methods. Found: '%d', maximum: '%d'"
3865,parsOnlySimplePatternsAreAllowedInConstructors,"Only simple patterns are allowed in primary constructors"
3865,parsOnlySimplePatternsAreAllowedInConstructors,"Only simple patterns are allowed in primary constructors"
featureAllowAccessModifiersToAutoPropertiesGettersAndSetters,"Allow access modifiers to auto properties getters and setters"
4 changes: 4 additions & 0 deletions src/Compiler/Facilities/LanguageFeatures.fs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type LanguageFeature =
| WarningIndexedPropertiesGetSetSameType
| WarningWhenTailCallAttrOnNonRec
| BooleanReturningAndReturnTypeDirectedPartialActivePattern
| AllowAccessModifiersToAutoPropertiesGettersAndSetters

/// LanguageVersion management
type LanguageVersion(versionText) =
Expand Down Expand Up @@ -197,6 +198,7 @@ type LanguageVersion(versionText) =
LanguageFeature.WarningWhenTailCallAttrOnNonRec, previewVersion
LanguageFeature.UnionIsPropertiesVisible, previewVersion
LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern, previewVersion
LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters, previewVersion
]

static let defaultLanguageVersion = LanguageVersion("default")
Expand Down Expand Up @@ -340,6 +342,8 @@ type LanguageVersion(versionText) =
| LanguageFeature.WarningWhenTailCallAttrOnNonRec -> FSComp.SR.featureChkTailCallAttrOnNonRec ()
| LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern ->
FSComp.SR.featureBooleanReturningAndReturnTypeDirectedPartialActivePattern ()
| LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters ->
FSComp.SR.featureAllowAccessModifiersToAutoPropertiesGettersAndSetters ()

/// Get a version string associated with the given feature.
static member GetFeatureVersionString feature =
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/Facilities/LanguageFeatures.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ type LanguageFeature =
| WarningIndexedPropertiesGetSetSameType
| WarningWhenTailCallAttrOnNonRec
| BooleanReturningAndReturnTypeDirectedPartialActivePattern
| AllowAccessModifiersToAutoPropertiesGettersAndSetters

/// LanguageVersion management
type LanguageVersion =
Expand Down
5 changes: 3 additions & 2 deletions src/Compiler/Service/ServiceNavigation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,10 @@ module NavigationImpl =
[
createMember (rcid, NavigationItemKind.Field, FSharpGlyph.Field, range, enclosingEntityKind, false, access)
]
| SynMemberDefn.AutoProperty(ident = id; accessibility = access) ->
| SynMemberDefn.AutoProperty(ident = id; getterAccessibility = getterAccessibility; setterAccessibility = setterAccessibility) ->
[
createMember (id, NavigationItemKind.Field, FSharpGlyph.Field, id.idRange, enclosingEntityKind, false, access)
createMember (id, NavigationItemKind.Field, FSharpGlyph.Field, id.idRange, enclosingEntityKind, false, getterAccessibility)
createMember (id, NavigationItemKind.Field, FSharpGlyph.Field, id.idRange, enclosingEntityKind, false, setterAccessibility)
]
| SynMemberDefn.AbstractSlot(slotSig = SynValSig(ident = SynIdent(id, _); synType = ty; accessibility = access)) ->
[
Expand Down
22 changes: 21 additions & 1 deletion src/Compiler/SyntaxTree/ParseHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1100,7 +1100,7 @@ let mkSynUnionCase attributes (access: SynAccess option) id kind mDecl (xmlDoc,
let mDecl = unionRangeWithXmlDoc xmlDoc mDecl
SynUnionCase(attributes, id, kind, xmlDoc, None, mDecl, trivia)

let mkAutoPropDefn mVal access ident typ mEquals (expr: SynExpr) accessors xmlDoc attribs flags rangeStart =
let mkAutoPropDefn mVal access ident typ mEquals (expr: SynExpr) accessors xmlDoc attribs flags rangeStart langVersion =
let mWith, (getSet, getSetOpt) = accessors

let memberRange =
Expand All @@ -1117,6 +1117,24 @@ let mkAutoPropDefn mVal access ident typ mEquals (expr: SynExpr) accessors xmlDo
let memberFlagsForSet = flags SynMemberKind.PropertySet
let isStatic = not memberFlags.IsInstance

let getterAccess, setterAccess =
match access, getSetOpt with
| Some _, Some(GetSetKeywords.GetSet(_, None, _, None)) -> access, access
| Some _, Some(GetSetKeywords.GetSet(_, Some x, _, _))
| Some _, Some(GetSetKeywords.GetSet(_, _, _, Some x)) ->
raiseParseErrorAt x.Range (FSComp.SR.parsMultipleAccessibilitiesForGetSet ())
| None, Some(GetSetKeywords.GetSet(_, getterAccess, _, setterAccess)) ->
match getterAccess, setterAccess with
| Some x, _
| _, Some x ->
checkLanguageFeatureError langVersion LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters x.Range
| None, None -> ()

getterAccess, setterAccess
| _, Some(GetSetKeywords.Get _) -> access, None
| _, Some(GetSetKeywords.Set _) -> None, access
| _ -> None, None

let trivia =
{
LeadingKeyword = leadingKeyword
Expand All @@ -1135,6 +1153,8 @@ let mkAutoPropDefn mVal access ident typ mEquals (expr: SynExpr) accessors xmlDo
memberFlagsForSet,
xmlDoc,
access,
getterAccess,
setterAccess,
expr,
memberRange,
trivia
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/SyntaxTree/ParseHelpers.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ val mkAutoPropDefn:
attribs: SynAttributes ->
flags: (SynMemberKind -> SynMemberFlags) * SynLeadingKeyword ->
rangeStart: range ->
langVersion: LanguageVersion ->
SynMemberDefn

val mkValField:
Expand Down
43 changes: 43 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,47 @@ type SynAccess =
| Internal m
| Private m -> m

[<NoEquality; NoComparison>]
type GetSetKeywords =
| Get of range
| Set of range
| GetSet of get: range * getterAccess: SynAccess option * set: range * setterAccess: SynAccess option

member x.Range =
match x with
| Get m
| Set m -> m
| GetSet(mG, _, mS, _) ->
if Range.rangeBeforePos mG mS.Start then
Range.unionRanges mG mS
else
Range.unionRanges mS mG

[<NoEquality; NoComparison>]
type SynMemberDefnAutoPropertyTrivia =
{
LeadingKeyword: SynLeadingKeyword
WithKeyword: range option
EqualsRange: range option
GetSetKeywords: GetSetKeywords option
}

[<NoEquality; NoComparison>]
type SynMemberDefnAbstractSlotTrivia =
{
GetSetKeywords: GetSetKeywords option
}

static member Zero = { GetSetKeywords = None }

[<NoEquality; NoComparison>]
type SynMemberSigMemberTrivia =
{
GetSetKeywords: GetSetKeywords option
}

static member Zero: SynMemberSigMemberTrivia = { GetSetKeywords = None }

[<RequireQualifiedAccess>]
type DebugPointAtTarget =
| Yes
Expand Down Expand Up @@ -1463,6 +1504,8 @@ type SynMemberDefn =
memberFlagsForSet: SynMemberFlags *
xmlDoc: PreXmlDoc *
accessibility: SynAccess option *
getterAccessibility: SynAccess option *
setterAccessibility: SynAccess option *
synExpr: SynExpr *
range: range *
trivia: SynMemberDefnAutoPropertyTrivia
Expand Down
48 changes: 48 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTree.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,52 @@ type SynAccess =

member Range: range

/// Represents additional information for `get, set` syntax
[<NoEquality; NoComparison; RequireQualifiedAccess>]
type GetSetKeywords =
| Get of range
| Set of range
| GetSet of get: range * getterAccess: SynAccess option * set: range * setterAccess: SynAccess option

member Range: range

/// Represents additional information for SynMemberDefn.AutoProperty
[<NoEquality; NoComparison>]
type SynMemberDefnAutoPropertyTrivia =
ijklam marked this conversation as resolved.
Show resolved Hide resolved
{
/// Used leading keyword of AutoProperty
LeadingKeyword: SynLeadingKeyword

/// The syntax range of the `with` keyword
WithKeyword: range option

/// The syntax range of the `=` token
EqualsRange: range option

/// The syntax range of 'get, set'
GetSetKeywords: GetSetKeywords option
}

/// Represents additional information for SynMemberDefn.AbstractSlot
[<NoEquality; NoComparison>]
type SynMemberDefnAbstractSlotTrivia =
{
/// The syntax range of 'get, set'
GetSetKeywords: GetSetKeywords option
}

static member Zero: SynMemberDefnAbstractSlotTrivia

/// Represents additional information for SynMemberSig.Member
[<NoEquality; NoComparison>]
type SynMemberSigMemberTrivia =
{
/// The syntax range of 'get, set'
GetSetKeywords: GetSetKeywords option
}

static member Zero: SynMemberSigMemberTrivia

/// Represents whether a debug point should be present for the target
/// of a decision tree, that is whether the construct corresponds to a debug
/// point in the original source.
Expand Down Expand Up @@ -1656,6 +1702,8 @@ type SynMemberDefn =
memberFlagsForSet: SynMemberFlags *
xmlDoc: PreXmlDoc *
accessibility: SynAccess option *
getterAccessibility: SynAccess option *
setterAccessibility: SynAccess option *
synExpr: SynExpr *
range: range *
trivia: SynMemberDefnAutoPropertyTrivia
Expand Down
41 changes: 0 additions & 41 deletions src/Compiler/SyntaxTree/SyntaxTrivia.fs
Original file line number Diff line number Diff line change
Expand Up @@ -346,39 +346,6 @@ type SynMemberDefnImplicitCtorTrivia = { AsKeyword: range option }
[<NoEquality; NoComparison>]
type SynArgPatsNamePatPairsTrivia = { ParenRange: range }

[<NoEquality; NoComparison>]
type GetSetKeywords =
| Get of range
| Set of range
| GetSet of get: range * set: range

member x.Range =
match x with
| Get m
| Set m -> m
| GetSet(mG, mS) ->
if Range.rangeBeforePos mG mS.Start then
Range.unionRanges mG mS
else
Range.unionRanges mS mG

[<NoEquality; NoComparison>]
type SynMemberDefnAutoPropertyTrivia =
{
LeadingKeyword: SynLeadingKeyword
WithKeyword: range option
EqualsRange: range option
GetSetKeywords: GetSetKeywords option
}

[<NoEquality; NoComparison>]
type SynMemberDefnAbstractSlotTrivia =
{
GetSetKeywords: GetSetKeywords option
}

static member Zero = { GetSetKeywords = None }

[<NoEquality; NoComparison>]
type SynFieldTrivia =
{
Expand All @@ -398,14 +365,6 @@ type SynTypeOrTrivia = { OrKeyword: range }
[<NoEquality; NoComparison>]
type SynBindingReturnInfoTrivia = { ColonRange: range option }

[<NoEquality; NoComparison>]
type SynMemberSigMemberTrivia =
{
GetSetKeywords: GetSetKeywords option
}

static member Zero: SynMemberSigMemberTrivia = { GetSetKeywords = None }

[<NoEquality; NoComparison>]
type SynTyparDeclTrivia =
{
Expand Down
46 changes: 0 additions & 46 deletions src/Compiler/SyntaxTree/SyntaxTrivia.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -444,42 +444,6 @@ type SynArgPatsNamePatPairsTrivia =
ParenRange: range
}

/// Represents additional information for `get, set` syntax
[<NoEquality; NoComparison; RequireQualifiedAccess>]
type GetSetKeywords =
| Get of range
| Set of range
| GetSet of get: range * set: range

member Range: range

/// Represents additional information for SynMemberDefn.AutoProperty
[<NoEquality; NoComparison>]
type SynMemberDefnAutoPropertyTrivia =
{
/// Used leading keyword of AutoProperty
LeadingKeyword: SynLeadingKeyword

/// The syntax range of the `with` keyword
WithKeyword: range option

/// The syntax range of the `=` token
EqualsRange: range option

/// The syntax range of 'get, set'
GetSetKeywords: GetSetKeywords option
}

/// Represents additional information for SynMemberDefn.AbstractSlot
[<NoEquality; NoComparison>]
type SynMemberDefnAbstractSlotTrivia =
{
/// The syntax range of 'get, set'
GetSetKeywords: GetSetKeywords option
}

static member Zero: SynMemberDefnAbstractSlotTrivia

/// Represents additional information for SynField
[<NoEquality; NoComparison>]
type SynFieldTrivia =
Expand Down Expand Up @@ -508,16 +472,6 @@ type SynBindingReturnInfoTrivia =
ColonRange: range option
}

/// Represents additional information for SynMemberSig.Member
[<NoEquality; NoComparison>]
type SynMemberSigMemberTrivia =
{
/// The syntax range of 'get, set'
GetSetKeywords: GetSetKeywords option
}

static member Zero: SynMemberSigMemberTrivia

/// Represents additional information for SynTyparDecl
[<NoEquality; NoComparison>]
type SynTyparDeclTrivia =
Expand Down
Loading
Loading