Skip to content
Open
Show file tree
Hide file tree
Changes from all 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/11.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
* Fix FSI pretty printing to distinguish anonymous records (`{| ... |}`) from nominal records (`{ ... }`). ([Issue #6116](https://github.com/dotnet/fsharp/issues/6116), [PR #19919](https://github.com/dotnet/fsharp/pull/19919))
* Fix dot-completion after indexed expressions (`a.[0].Data.`, `a[0].Data.`, `[1;2].Length.`) returning unrelated global completions instead of expression-typings members. ([Issue #4966](https://github.com/dotnet/fsharp/issues/4966), [PR #19934](https://github.com/dotnet/fsharp/pull/19934))
* Quotations of `match s with "" -> _` no longer leak the `s <> null && s.Length = 0` lowering; the empty-string optimization moved from pattern-match compilation to the optimizer so quoted expressions keep `op_Equality(s, "")`. ([Issue #19873](https://github.com/dotnet/fsharp/issues/19873))
* Parser: recover on unfinished abstract members ([PR #20070](https://github.com/dotnet/fsharp/pull/20070))

### Added

Expand Down
21 changes: 10 additions & 11 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3723,17 +3723,16 @@ module EstablishTypeDefinitionCores =

let abstractSlots =
[ for synValSig, memberFlags in slotsigs do

let (SynValSig(range=m)) = synValSig

CheckMemberFlags None NewSlotsOK OverridesOK memberFlags m

let slots = fst (TcAndPublishValSpec (cenv, envinner, containerInfo, ModuleOrMemberBinding, Some memberFlags, tpenv, synValSig))
// Multiple slots may be returned, e.g. for
// abstract P: int with get, set

for slot in slots do
yield mkLocalValRef slot ]
let (SynValSig(ident = (SynIdent(id, _)); range = m)) = synValSig
if id.idText <> "" then
CheckMemberFlags None NewSlotsOK OverridesOK memberFlags m

let slots = fst (TcAndPublishValSpec (cenv, envinner, containerInfo, ModuleOrMemberBinding, Some memberFlags, tpenv, synValSig))
// Multiple slots may be returned, e.g. for
// abstract P: int with get, set

for slot in slots do
yield mkLocalValRef slot ]

let kind =
match kind with
Expand Down
62 changes: 62 additions & 0 deletions src/Compiler/SyntaxTree/ParseHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1136,3 +1136,65 @@ let mkLetBangExpression
Trivia = { InKeyword = mIn }
IsFromSource = true // User-written let!/use! bindings
}

let mkAbstractMember
parseState
attrs
(accessBeforeKeyword: SynAccess option)
memberFlags
(accessBeforeId: SynAccess option)
mInline
id
typeParams
typeWithConstraints
accessors
=
if Option.isSome accessBeforeKeyword then
errorR (Error(FSComp.SR.parsVisibilityDeclarationsShouldComePriorToIdentifier (), rhs parseState 2))

let (ty: SynType), arity = typeWithConstraints

let isInline, doc, explicitValTyparDecls =
Option.isSome mInline, grabXmlDoc (parseState, attrs, 1), typeParams

let mWith, (getSet, getSetRangeOpt: GetSetKeywords option, getterAccess, setterAccess) =
accessors

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

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

let mkFlags, leadingKeyword = memberFlags

let trivia =
{
LeadingKeyword = leadingKeyword
InlineKeyword = mInline
WithKeyword = mWith
EqualsRange = None
}

let vis2 = SynValSigAccess.Single None

let valSpfn =
SynValSig(attrs, id, explicitValTyparDecls, ty, arity, isInline, false, doc, vis2, None, mWhole, trivia)

let trivia: SynMemberDefnAbstractSlotTrivia = { GetSetKeywords = getSetRangeOpt }

[
SynMemberDefn.AbstractSlot(valSpfn, mkFlags (getSetAdjuster arity), mWhole, trivia)
]
13 changes: 13 additions & 0 deletions src/Compiler/SyntaxTree/ParseHelpers.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,16 @@ val mkSynField:
SynField

val leadingKeywordIsAbstract: SynLeadingKeyword -> bool

val mkAbstractMember:
parseState: IParseState ->
attrs: SynAttributeList list ->
accessBeforeKeyword: SynAccess option ->
abstractMemberFlags: (SynMemberKind -> SynMemberFlags) * SynLeadingKeyword ->
accessBeforeId: SynAccess option ->
mInline: range option ->
id: SynIdent ->
typeParams: SynValTyparDecls ->
typeWithConstraints: SynType * SynValInfo ->
accessors: range option * (SynMemberKind * GetSetKeywords option * SynAccess option * SynAccess option) ->
SynMemberDefn list
48 changes: 27 additions & 21 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -2058,27 +2058,33 @@ classDefnMember:
[ SynMemberDefn.Interface(ty, None, None, rhs2 parseState 1 3) ] }

| 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

[ $2; $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 = $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 }
[ SynMemberDefn.AbstractSlot(valSpfn, mkFlags (getSetAdjuster arity), mWhole, trivia) ] }
{ mkAbstractMember parseState $1 $2 $3 $4 $5 $6 $7 $9 $10 }

| opt_attributes opt_access abstractMemberFlags opt_access opt_inline nameop opt_explicitValTyparDecls COLON recover opt_ODECLEND
{ let id = $6
let typeWithConstraints = SynType.FromParseError(id.Range.EndRange), SynValInfo([], SynInfo.unnamedRetVal)
let accessors = None, (SynMemberKind.Member, None, None, None)
mkAbstractMember parseState $1 $2 $3 $4 $5 id $7 typeWithConstraints accessors }

| opt_attributes opt_access abstractMemberFlags opt_access opt_inline nameop opt_explicitValTyparDecls recover opt_ODECLEND
{ let id = $6
let typeWithConstraints = SynType.FromParseError(id.Range.EndRange), SynValInfo([], SynInfo.unnamedRetVal)
let accessors = None, (SynMemberKind.Member, None, None, None)
mkAbstractMember parseState $1 $2 $3 $4 $5 id $7 typeWithConstraints accessors }

| opt_attributes opt_access abstractMemberFlags opt_access opt_inline recover opt_ODECLEND
{ let mBeforeId =
match $2 with
| Some access -> access.Range
| _ ->
let _, leadingKeyword = $3
leadingKeyword.Range

let id = SynIdent(mkSynId mBeforeId.EndRange "", None)
let typeParams = SynValTyparDecls(None, true)
let typeWithConstraints = SynType.FromParseError(id.Range.EndRange), SynValInfo([], SynInfo.unnamedRetVal)
let accessors = None, (SynMemberKind.Member, None, None, None)
mkAbstractMember parseState $1 $2 $3 $4 $5 id typeParams typeWithConstraints accessors }

| opt_attributes opt_access inheritsDefn
{ if not (isNil $1) then errorR(Error(FSComp.SR.parsAttributesIllegalOnInherit(), rhs parseState 1))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

type T =
abstract M: unit -> unit

()
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
ImplFile
(ParsedImplFileInput
("/root/Member/Abstract - Method 01.fs", false, QualifiedNameOfFile Module,
[],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Types
([SynTypeDefn
(SynComponentInfo
([], None, [], [T],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (3,5--3,6)),
ObjectModel
(Unspecified,
[AbstractSlot
(SynValSig
([], SynIdent (M, None),
SynValTyparDecls (None, true),
Fun
(LongIdent (SynLongIdent ([unit], [], [None])),
LongIdent (SynLongIdent ([unit], [], [None])),
(4,16--4,28), { ArrowRange = (4,21--4,23) }),
SynValInfo
([[SynArgInfo ([], false, None)]],
SynArgInfo ([], false, None)), false, false,
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
Single None, None, (4,4--4,28),
{ LeadingKeyword = Abstract (4,4--4,12)
InlineKeyword = None
WithKeyword = None
EqualsRange = None }),
{ IsInstance = true
IsDispatchSlot = true
IsOverrideOrExplicitImpl = false
IsFinal = false
GetterOrSetterIsCompilerGenerated = false
MemberKind = Member }, (4,4--4,28),
{ GetSetKeywords = None })], (4,4--4,28)), [], None,
(3,5--4,28), { LeadingKeyword = Type (3,0--3,4)
EqualsRange = Some (3,7--3,8)
WithKeyword = None })], (3,0--4,28));
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
WarnDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

type T =
abstract M: unit ->

()
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
ImplFile
(ParsedImplFileInput
("/root/Member/Abstract - Method 02.fs", false, QualifiedNameOfFile Module,
[],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Types
([SynTypeDefn
(SynComponentInfo
([], None, [], [T],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (3,5--3,6)),
ObjectModel
(Unspecified,
[AbstractSlot
(SynValSig
([], SynIdent (M, None),
SynValTyparDecls (None, true),
Fun
(LongIdent (SynLongIdent ([unit], [], [None])),
FromParseError (4,23--4,23), (4,16--6,1),
{ ArrowRange = (4,21--4,23) }),
SynValInfo
([[SynArgInfo ([], false, None)]],
SynArgInfo ([], false, None)), false, false,
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
Single None, None, (4,4--6,1),
{ LeadingKeyword = Abstract (4,4--4,12)
InlineKeyword = None
WithKeyword = None
EqualsRange = None }),
{ IsInstance = true
IsDispatchSlot = true
IsOverrideOrExplicitImpl = false
IsFinal = false
GetterOrSetterIsCompilerGenerated = false
MemberKind = Member }, (4,4--6,1),
{ GetSetKeywords = None })], (4,4--6,1)), [], None,
(3,5--6,1), { LeadingKeyword = Type (3,0--3,4)
EqualsRange = Some (3,7--3,8)
WithKeyword = None })], (3,0--6,1));
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
WarnDirectives = []
CodeComments = [] }, set []))

(6,0)-(6,1) parse error Incomplete structured construct at or before this point in member definition
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

type T =
abstract P:

()
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
ImplFile
(ParsedImplFileInput
("/root/Member/Abstract - Property 06.fs", false,
QualifiedNameOfFile Module, [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Types
([SynTypeDefn
(SynComponentInfo
([], None, [], [T],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (3,5--3,6)),
ObjectModel
(Unspecified,
[AbstractSlot
(SynValSig
([], SynIdent (P, None),
SynValTyparDecls (None, true),
FromParseError (4,14--4,14),
SynValInfo ([], SynArgInfo ([], false, None)), false,
false,
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
Single None, None, (4,4--4,14),
{ LeadingKeyword = Abstract (4,4--4,12)
InlineKeyword = None
WithKeyword = None
EqualsRange = None }),
{ IsInstance = true
IsDispatchSlot = true
IsOverrideOrExplicitImpl = false
IsFinal = false
GetterOrSetterIsCompilerGenerated = false
MemberKind = PropertyGet }, (4,4--4,14),
{ GetSetKeywords = None })], (4,4--4,14)), [], None,
(3,5--4,14), { LeadingKeyword = Type (3,0--3,4)
EqualsRange = Some (3,7--3,8)
WithKeyword = None })], (3,0--4,14));
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
WarnDirectives = []
CodeComments = [] }, set []))

(6,0)-(6,1) parse error Incomplete structured construct at or before this point in member definition
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

type T =
abstract P

()
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
ImplFile
(ParsedImplFileInput
("/root/Member/Abstract - Property 07.fs", false,
QualifiedNameOfFile Module, [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Types
([SynTypeDefn
(SynComponentInfo
([], None, [], [T],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (3,5--3,6)),
ObjectModel
(Unspecified,
[AbstractSlot
(SynValSig
([], SynIdent (P, None),
SynValTyparDecls (None, true),
FromParseError (4,14--4,14),
SynValInfo ([], SynArgInfo ([], false, None)), false,
false,
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
Single None, None, (4,4--4,14),
{ LeadingKeyword = Abstract (4,4--4,12)
InlineKeyword = None
WithKeyword = None
EqualsRange = None }),
{ IsInstance = true
IsDispatchSlot = true
IsOverrideOrExplicitImpl = false
IsFinal = false
GetterOrSetterIsCompilerGenerated = false
MemberKind = PropertyGet }, (4,4--4,14),
{ GetSetKeywords = None })], (4,4--4,14)), [], None,
(3,5--4,14), { LeadingKeyword = Type (3,0--3,4)
EqualsRange = Some (3,7--3,8)
WithKeyword = None })], (3,0--4,14));
Expr (Const (Unit, (6,0--6,2)), (6,0--6,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
WarnDirectives = []
CodeComments = [] }, set []))

(6,0)-(6,1) parse error Incomplete structured construct at or before this point in member definition. Expected ':' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

type T =
abstract

()
Loading
Loading