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

Disallow abstract member with access modifiers in sig file #17802

Merged
merged 17 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
3 changes: 2 additions & 1 deletion docs/release-notes/.FSharp.Compiler.Service/9.0.200.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
* Fix false negatives for passing null to "obj" arguments. Only "obj | null" can now subsume any type ([PR #17757](https://github.com/dotnet/fsharp/pull/17757))
* Fix internal error when calling 'AddSingleton' and other overloads only differing in generic arity ([PR #17804](https://github.com/dotnet/fsharp/pull/17804))
* Fix extension methods support for non-reference system assemblies ([PR #17799](https://github.com/dotnet/fsharp/pull/17799))
* Ensure `frameworkTcImportsCache` mutations are thread-safe. ([PR #17795](https://github.com/dotnet/fsharp/pull/17795))
* Ensure `frameworkTcImportsCache` mutations are threadsafe. ([PR #17795](https://github.com/dotnet/fsharp/pull/17795))
* Disallow abstract member with access modifiers in sig file. ([PR #17802](https://github.com/dotnet/fsharp/pull/17802))
* Fix concurrency issue in `ILPreTypeDefImpl` ([PR #17812](https://github.com/dotnet/fsharp/pull/17812))

### Added
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Service/FSharpSource.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type internal FSharpSource =
abstract TimeStamp: DateTime

/// Gets the internal text container. Text may be on-disk, in a stream, or a source text.
abstract internal GetTextContainer: unit -> Async<TextContainer>
abstract GetTextContainer: unit -> Async<TextContainer>

/// Creates a FSharpSource from disk. Only used internally.
static member internal CreateFromFile: filePath: string -> FSharpSource
Expand Down
8 changes: 8 additions & 0 deletions src/Compiler/SyntaxTree/ParseHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1228,3 +1228,11 @@ let mkValField
mkSynField parseState idOpt typ isMutable access attribs mStaticOpt rangeStart (Some leadingKeyword)

SynMemberDefn.ValField(field, field.Range)

let leadingKeywordIsAbstract =
function
| SynLeadingKeyword.Abstract _
| SynLeadingKeyword.AbstractMember _
| SynLeadingKeyword.StaticAbstract _
| SynLeadingKeyword.StaticAbstractMember _ -> true
| _ -> false
2 changes: 2 additions & 0 deletions src/Compiler/SyntaxTree/ParseHelpers.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,5 @@ val mkSynField:
rangeStart: range ->
leadingKeyword: SynLeadingKeyword option ->
SynField

val leadingKeywordIsAbstract: SynLeadingKeyword -> bool
23 changes: 15 additions & 8 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -985,8 +985,12 @@ classMemberSpfn:
match optLiteralValue with
| None -> m
| Some e -> unionRanges m e.Range

let flags, leadingKeyword = $3
if leadingKeywordIsAbstract leadingKeyword then
[ $5; getterAccess; setterAccess ]
|> List.iter (function None -> () | Some access -> errorR(Error(FSComp.SR.parsAccessibilityModsIllegalForAbstract(), access.Range)))

let flags = flags (getSetAdjuster arity)
let trivia = { LeadingKeyword = leadingKeyword; InlineKeyword = $4; WithKeyword = mWith; EqualsRange = mEquals }
let valSpfn = SynValSig($1, id, explicitValTyparDecls, ty, arity, isInline, false, doc, vis2, optLiteralValue, mWhole, trivia)
Expand Down Expand Up @@ -2046,21 +2050,24 @@ classDefnMember:
let ty = SynType.FromParseError(mInterface.EndRange)
[ SynMemberDefn.Interface(ty, None, None, rhs2 parseState 1 3) ] }

| opt_attributes opt_access abstractMemberFlags opt_inline nameop opt_explicitValTyparDecls COLON topTypeWithTypeConstraints classMemberSpfnGetSet opt_ODECLEND
{ let ty, arity = $8
let isInline, doc, id, explicitValTyparDecls = (Option.isSome $4), grabXmlDoc(parseState, $1, 1), $5, $6
let mWith, (getSet, getSetRangeOpt, getterAccess, setterAccess) = $9
| opt_attributes opt_access abstractMemberFlags opt_access opt_inline nameop opt_explicitValTyparDecls COLON topTypeWithTypeConstraints classMemberSpfnGetSet opt_ODECLEND
{ if Option.isSome $2 then errorR(Error(FSComp.SR.parsVisibilityDeclarationsShouldComePriorToIdentifier(), rhs parseState 2))
let ty, arity = $9
let isInline, doc, id, explicitValTyparDecls = (Option.isSome $5), grabXmlDoc(parseState, $1, 1), $6, $7
let mWith, (getSet, getSetRangeOpt, getterAccess, setterAccess) = $10
let getSetAdjuster arity = match arity, getSet with SynValInfo([], _), SynMemberKind.Member -> SynMemberKind.PropertyGet | _ -> getSet
let mWhole =
let m = rhs parseState 1
match getSetRangeOpt with
| None -> unionRanges m ty.Range
| Some gs -> unionRanges m gs.Range
|> unionRangeWithXmlDoc doc
if Option.isSome $2 || Option.isSome getterAccess || Option.isSome setterAccess
then errorR(Error(FSComp.SR.parsAccessibilityModsIllegalForAbstract(), mWhole))

[ $4; getterAccess; setterAccess ]
|> List.iter (function None -> () | Some access -> errorR(Error(FSComp.SR.parsAccessibilityModsIllegalForAbstract(), access.Range)))

let mkFlags, leadingKeyword = $3
let trivia = { LeadingKeyword = leadingKeyword; InlineKeyword = $4; WithKeyword = mWith; EqualsRange = None }
let trivia = { LeadingKeyword = leadingKeyword; InlineKeyword = $5; WithKeyword = mWith; EqualsRange = None }
let vis2 = SynValSigAccess.Single(None)
let valSpfn = SynValSig($1, id, explicitValTyparDecls, ty, arity, isInline, false, doc, vis2, None, mWhole, trivia)
let trivia: SynMemberDefnAbstractSlotTrivia = { GetSetKeywords = getSetRangeOpt }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,30 @@ module AccessibilityAnnotations_PermittedLocations =
|> withDiagnostics [
(Error 531, Line 8, Col 13, Line 8, Col 20, "Accessibility modifiers should come immediately prior to the identifier naming a construct")
]

[<Fact>]
let ``Signature File Test: abstract member cannot have access modifiers`` () =
Fsi """module Program

type A =
abstract internal B: int ->int
abstract member internal E: int ->int
abstract member C: int with internal get, private set
abstract internal D: int with get, set
static abstract internal B2: int ->int
static abstract member internal E2: int ->int
static abstract member C2: int with internal get, private set
static abstract internal D2: int with get, set"""
|> withOptions ["--nowarn:3535"]
|> verifyCompile
|> shouldFail
|> withDiagnostics [
(Error 0561, Line 4, Col 5, Line 4, Col 35, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.")
(Error 0561, Line 5, Col 5, Line 5, Col 42, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.")
(Error 0561, Line 6, Col 5, Line 6, Col 58, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.")
(Error 0561, Line 7, Col 5, Line 7, Col 43, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.")
(Error 0561, Line 8, Col 5, Line 8, Col 43, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.")
(Error 0561, Line 9, Col 5, Line 9, Col 50, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.")
(Error 0561, Line 10, Col 5, Line 10, Col 66, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.")
(Error 0561, Line 11, Col 5, Line 11, Col 51, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.")
]
ijklam marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ type A =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
(Error 240, Line 1, Col 1, Line 9, Col 42, "The signature file 'Program' does not have a corresponding implementation file. If an implementation file exists then check the 'module' and 'namespace' declarations in the signature and implementation files match.")
(Error 0561, Line 9, Col 5, Line 9, Col 42, "Accessibility modifiers are not allowed on this member. Abstract slots always have the same visibility as the enclosing type.")
]

[<Fact>]
Expand Down
Loading