Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"type": "coreclr",
"request": "launch",
// TODO: Shall we assume that it's already been built, or build it every time we debug?
// "preLaunchTask": "Build (Debug)",
"preLaunchTask": "Build (Debug)",
// If you have changed target frameworks, make sure to update the program p
"program": "${workspaceFolder}/artifacts/bin/fsi/Debug/net8.0/fsi.dll",
"args": [
Expand Down Expand Up @@ -50,7 +50,7 @@
"type": "coreclr",
"request": "launch",
// TODO: Shall we assume that it's already been built, or build it every time we debug?
// "preLaunchTask": "Build (Debug)",
"preLaunchTask": "Build (Debug)",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/artifacts/bin/fsc/Debug/net8.0/fsc.dll",
"args": [
Expand Down
21 changes: 17 additions & 4 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,18 @@
"-c",
"Debug",
"FSharp.Compiler.Service.sln"
],
]
},
"options": {
"env": {
"UpdateXlfOnBuild": "true"
}
},
"problemMatcher": "$msCompile",
"group": "build",
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "Build (Release)",
Expand All @@ -53,10 +61,15 @@
"-c",
"Release",
"FSharp.Compiler.Service.sln"
],
]
},
"options": {
"env": {
"UpdateXlfOnBuild": "true"
}
},
"problemMatcher": "$msCompile",
"group": "build",
"group": "build"
},
{
"label": "Update xlf files",
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4418,7 +4418,7 @@ module TcDeclarations =
let isAtOriginalTyconDefn = true
let core = MutRecDefnsPhase1DataForTycon(synTyconInfo, SynTypeDefnSimpleRepr.Exception r, implements1, false, false, isAtOriginalTyconDefn)
core, extra_vals_Inherits_Abstractslots @ extraMembers

//-------------------------------------------------------------------------

/// Bind a collection of mutually recursive definitions in an implementation file
Expand Down
16 changes: 12 additions & 4 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7022,7 +7022,7 @@ and TcObjectExpr (cenv: cenv) env tpenv (objTy, realObjTy, argopt, binds, extraI
let overrides' =
[ for overrideMeth in overrides do
let overrideInfo, (_, thisVal, methodVars, bindingAttribs, bindingBody) = overrideMeth
let (Override(_, _, id, mtps, _, _, _, isFakeEventProperty, _)) = overrideInfo
let (Override(_, _, id, mtps, _, _, _, isFakeEventProperty, _, _)) = overrideInfo

if not isFakeEventProperty then
let searchForOverride =
Expand Down Expand Up @@ -11241,7 +11241,11 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (_: Val option) (a
let uniqueAbstractMethSigs =
match dispatchSlots with
| [] ->
errorR(Error(FSComp.SR.tcNoMemberFoundForOverride(), memberId.idRange))
let instanceExpected = memberFlags.IsInstance
if instanceExpected then
errorR(Error(FSComp.SR.tcNoMemberFoundForOverride(), memberId.idRange))
else
errorR (Error(FSComp.SR.tcNoStaticMemberFoundForOverride (), memberId.idRange))
[]

| slot :: _ as slots ->
Expand Down Expand Up @@ -11300,7 +11304,7 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (_: Val option) (a

| SynMemberKind.PropertyGet
| SynMemberKind.PropertySet as k ->
let dispatchSlots = GetAbstractPropInfosForSynPropertyDecl(cenv.infoReader, ad, memberId, m, typToSearchForAbstractMembers)
let dispatchSlots = GetAbstractPropInfosForSynPropertyDecl(cenv.infoReader, ad, memberId, m, typToSearchForAbstractMembers, memberFlags)

// Only consider those abstract slots where the get/set flags match the value we're defining
let dispatchSlots =
Expand All @@ -11313,7 +11317,11 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (_: Val option) (a
let uniqueAbstractPropSigs =
match dispatchSlots with
| [] when not (CompileAsEvent g attribs) ->
errorR(Error(FSComp.SR.tcNoPropertyFoundForOverride(), memberId.idRange))
let instanceExpected = memberFlags.IsInstance
if instanceExpected then
errorR(Error(FSComp.SR.tcNoPropertyFoundForOverride(), memberId.idRange))
else
errorR (Error(FSComp.SR.tcNoStaticPropertyFoundForOverride (), memberId.idRange))
[]
| [uniqueAbstractProp] -> [uniqueAbstractProp]
| _ ->
Expand Down
42 changes: 24 additions & 18 deletions src/Compiler/Checking/MethodOverrides.fs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ type OverrideInfo =
argTypes: TType list list *
returnType: TType option *
isFakeEventProperty: bool *
isCompilerGenerated: bool
isCompilerGenerated: bool *
isInstance: bool


member x.CanImplement = let (Override(canImplement=a)) = x in a

Expand All @@ -61,6 +63,9 @@ type OverrideInfo =
member x.ReturnType = let (Override(returnType=b)) = x in b

member x.IsCompilerGenerated = let (Override(isCompilerGenerated=b)) = x in b

member x.IsInstance = let (Override(isInstance=b)) = x in b


type RequiredSlot =
| RequiredSlot of methodInfo: MethInfo * isOptional: bool
Expand Down Expand Up @@ -104,7 +109,7 @@ exception OverrideDoesntOverride of DisplayEnv * OverrideInfo * MethInfo option
module DispatchSlotChecking =

/// Print the signature of an override to a buffer as part of an error message
let PrintOverrideToBuffer denv os (Override(_, _, id, methTypars, memberToParentInst, argTys, retTy, _, _)) =
let PrintOverrideToBuffer denv os (Override(_, _, id, methTypars, memberToParentInst, argTys, retTy, _, _, _)) =
let denv = { denv with showTyparBinding = true }
let retTy = (retTy |> GetFSharpViewOfReturnType denv.g)
let argInfos =
Expand Down Expand Up @@ -136,7 +141,7 @@ module DispatchSlotChecking =
let (CompiledSig (argTys, retTy, fmethTypars, ttpinst)) = CompiledSigOfMeth g amap m minfo

let isFakeEventProperty = minfo.IsFSharpEventPropertyMethod
Override(parentType, minfo.ApparentEnclosingTyconRef, mkSynId m nm, fmethTypars, ttpinst, argTys, retTy, isFakeEventProperty, false)
Override(parentType, minfo.ApparentEnclosingTyconRef, mkSynId m nm, fmethTypars, ttpinst, argTys, retTy, isFakeEventProperty, false, minfo.IsInstance)

/// Get the override info for a value being used to implement a dispatch slot.
let GetTypeMemberOverrideInfo g reqdTy (overrideBy: ValRef) =
Expand Down Expand Up @@ -175,7 +180,7 @@ module DispatchSlotChecking =
//CanImplementAnySlot <<----- Change to this to enable implicit interface implementation

let isFakeEventProperty = overrideBy.IsFSharpEventProperty(g)
Override(implKind, overrideBy.MemberApparentEntity, mkSynId overrideBy.Range nm, memberMethodTypars, memberToParentInst, argTys, retTy, isFakeEventProperty, overrideBy.IsCompilerGenerated)
Override(implKind, overrideBy.MemberApparentEntity, mkSynId overrideBy.Range nm, memberMethodTypars, memberToParentInst, argTys, retTy, isFakeEventProperty, overrideBy.IsCompilerGenerated, overrideBy.IsInstanceMember)

/// Get the override information for an object expression method being used to implement dispatch slots
let GetObjectExprOverrideInfo g amap (implTy, id: Ident, memberFlags, ty, arityInfo, bindingAttribs, rhsExpr) =
Expand All @@ -200,7 +205,7 @@ module DispatchSlotChecking =
CanImplementAnyClassHierarchySlot
//CanImplementAnySlot <<----- Change to this to enable implicit interface implementation
let isFakeEventProperty = CompileAsEvent g bindingAttribs
let overrideByInfo = Override(implKind, tcrefOfAppTy g implTy, id, tps, [], argTys, retTy, isFakeEventProperty, false)
let overrideByInfo = Override(implKind, tcrefOfAppTy g implTy, id, tps, [], argTys, retTy, isFakeEventProperty, false, memberFlags.IsInstance)
overrideByInfo, (baseValOpt, thisv, vs, bindingAttribs, rhsExpr)
| _ ->
error(InternalError("Unexpected shape for object expression override", id.idRange))
Expand All @@ -227,7 +232,7 @@ module DispatchSlotChecking =

/// Check if an override is a partial match for the requirements for a dispatch slot except for the name.
let IsSigPartialMatch g (dispatchSlot: MethInfo) compiledSig overrideBy =
let (Override(_, _, _, methTypars, _, argTys, _retTy, _, _)) = overrideBy
let (Override(_, _, _, methTypars, _, argTys, _retTy, _, _, _)) = overrideBy
let (CompiledSig (vargTys, _, fvmethTypars, _)) = compiledSig
methTypars.Length = fvmethTypars.Length &&
IsTyparKindMatch compiledSig overrideBy &&
Expand All @@ -249,7 +254,7 @@ module DispatchSlotChecking =

/// Check if an override exactly matches the requirements for a dispatch slot except for the name.
let IsSigExactMatch g amap m dispatchSlot overrideBy =
let (Override(_, _, _, methTypars, memberToParentInst, argTys, retTy, _, _)) = overrideBy
let (Override(_, _, _, methTypars, memberToParentInst, argTys, retTy, _, _, _)) = overrideBy
let compiledSig = CompiledSigOfMeth g amap m dispatchSlot
IsSigPartialMatch g dispatchSlot compiledSig overrideBy &&
let (CompiledSig (vargTys, vrty, fvmethTypars, ttpinst)) = compiledSig
Expand Down Expand Up @@ -300,7 +305,8 @@ module DispatchSlotChecking =
/// Check if an override exactly matches the requirements for a dispatch slot.
let IsExactMatch g amap m dispatchSlot overrideBy =
IsNameMatch dispatchSlot overrideBy &&
IsSigExactMatch g amap m dispatchSlot overrideBy
IsSigExactMatch g amap m dispatchSlot overrideBy &&
dispatchSlot.IsInstance = overrideBy.IsInstance

/// Check if an override implements a dispatch slot
let OverrideImplementsDispatchSlot g amap m dispatchSlot availPriorOverride =
Expand All @@ -321,7 +327,7 @@ module DispatchSlotChecking =
reqdTy,
dispatchSlots: RequiredSlot list,
availPriorOverrides: OverrideInfo list,
overrides: OverrideInfo list) =
overrides: OverrideInfo list) =
let g = infoReader.g
let amap = infoReader.amap

Expand Down Expand Up @@ -353,8 +359,8 @@ module DispatchSlotChecking =
|> List.filter (OverrideImplementsDispatchSlot g amap m dispatchSlot)

match maybeResolvedSlot with
| [ovd] ->
if not ovd.IsCompilerGenerated then
| [ovd] ->
if not ovd.IsCompilerGenerated then
let item = Item.MethodGroup(ovd.LogicalName, [dispatchSlot],None)
CallNameResolutionSink sink (ovd.Range, nenv, item, dispatchSlot.FormalMethodTyparInst, ItemOccurence.Implemented, AccessorDomain.AccessibleFromSomewhere)
| [] ->
Expand Down Expand Up @@ -386,7 +392,7 @@ module DispatchSlotChecking =
noimpl()
| [ overrideBy ] ->

let (Override(_, _, _, methTypars, _, argTys, _, _, _)) = overrideBy
let (Override(_, _, _, methTypars, _, argTys, _, _, _, _)) = overrideBy

let moreThanOnePossibleDispatchSlot =
dispatchSlots
Expand Down Expand Up @@ -612,7 +618,8 @@ module DispatchSlotChecking =
if dispatchSlot.IsFinal && (isObjExpr || not (typeEquiv g reqdTy dispatchSlot.ApparentEnclosingType)) then
errorR(Error(FSComp.SR.typrelMethodIsSealed(NicePrint.stringOfMethInfo infoReader m denv dispatchSlot), m))
| dispatchSlots ->
match dispatchSlots |> List.filter (fun dispatchSlot ->
match dispatchSlots |> List.filter (fun dispatchSlot ->
(dispatchSlot.IsInstance = overrideBy.IsInstance) &&
isInterfaceTy g dispatchSlot.ApparentEnclosingType ||
not (DispatchSlotIsAlreadyImplemented g amap m availPriorOverridesKeyed dispatchSlot)) with
| h1 :: h2 :: _ ->
Expand Down Expand Up @@ -812,7 +819,7 @@ module DispatchSlotChecking =
// We don't give missing method errors for abstract classes

if isImplementation && not (isInterfaceTy g overallTy) then
let overrides = allImmediateMembersThatMightImplementDispatchSlots |> List.map snd
let overrides = allImmediateMembersThatMightImplementDispatchSlots |> List.map snd
let allCorrect = CheckDispatchSlotsAreImplemented (denv, infoReader, m, nenv, sink, tcaug.tcaug_abstract, reqdTy, dispatchSlots, availPriorOverrides, overrides)

// Tell the user to mark the thing abstract if it was missing implementations
Expand Down Expand Up @@ -940,7 +947,7 @@ let GetAbstractMethInfosForSynMethodDecl(infoReader: InfoReader, ad, memberName:
NameMultiMap.find memberName.idText dispatchSlotsKeyed |> List.map (fun reqdSlot -> reqdSlot.MethodInfo)
| ty, None ->
GetIntrinsicMethInfosOfType infoReader (Some memberName.idText) ad AllowMultiIntfInstantiations.Yes findFlag bindm ty
let dispatchSlots = minfos |> List.filter (fun minfo -> minfo.IsDispatchSlot)
let dispatchSlots = minfos |> List.filter (fun minfo -> minfo.IsDispatchSlot && minfo.IsInstance = memberFlags.IsInstance)
let valReprSynArities = SynInfo.AritiesOfArgs valSynData

// We only return everything if it's empty or if it's a non-instance member.
Expand All @@ -955,14 +962,13 @@ let GetAbstractMethInfosForSynMethodDecl(infoReader: InfoReader, ad, memberName:

/// Get the properties relevant to determining if a uniquely-identified-override exists based on the syntactic information
/// at the member signature prior to type inference. This is used to pre-assign type information if it does
let GetAbstractPropInfosForSynPropertyDecl(infoReader: InfoReader, ad, memberName: Ident, bindm, typToSearchForAbstractMembers) =
let GetAbstractPropInfosForSynPropertyDecl(infoReader: InfoReader, ad, memberName: Ident, bindm, typToSearchForAbstractMembers, memberFlags: SynMemberFlags) =
let pinfos =
match typToSearchForAbstractMembers with
| _, Some(SlotImplSet(_, _, _, reqdProps)) ->
reqdProps |> List.filter (fun pinfo -> pinfo.PropertyName = memberName.idText)
| ty, None ->
GetIntrinsicPropInfosOfType infoReader (Some memberName.idText) ad AllowMultiIntfInstantiations.Yes IgnoreOverrides bindm ty

let dispatchSlots = pinfos |> List.filter (fun pinfo -> pinfo.IsVirtualProperty)
let dispatchSlots = pinfos |> List.filter (fun pinfo -> pinfo.IsVirtualProperty && (not pinfo.IsStatic) = memberFlags.IsInstance)
dispatchSlots

8 changes: 6 additions & 2 deletions src/Compiler/Checking/MethodOverrides.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ type OverrideInfo =
argTypes: TType list list *
returnType: TType option *
isFakeEventProperty: bool *
isCompilerGenerated: bool
isCompilerGenerated: bool *
isInstance: bool

member ArgTypes: TType list list

Expand All @@ -42,6 +43,8 @@ type OverrideInfo =

member IsCompilerGenerated: bool

member IsInstance: bool

member IsFakeEventProperty: bool

member LogicalName: string
Expand Down Expand Up @@ -167,5 +170,6 @@ val GetAbstractPropInfosForSynPropertyDecl:
ad: AccessorDomain *
memberName: Ident *
bindm: range *
typToSearchForAbstractMembers: (TType * SlotImplSet option) ->
typToSearchForAbstractMembers: (TType * SlotImplSet option) *
memberFlags: SynMemberFlags ->
PropInfo list
10 changes: 10 additions & 0 deletions src/Compiler/Driver/CompilerDiagnostics.fs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,8 @@ module OldStyleMessages =
let OverrideDoesntOverride2E () = Message("OverrideDoesntOverride2", "%s")
let OverrideDoesntOverride3E () = Message("OverrideDoesntOverride3", "%s")
let OverrideDoesntOverride4E () = Message("OverrideDoesntOverride4", "%s")
let OverrideShouldBeStatic () = Message("OverrideShouldBeStatic", "")
let OverrideShouldBeInstance () = Message("OverrideShouldBeInstance", "")
let UnionCaseWrongArgumentsE () = Message("UnionCaseWrongArguments", "%d%d")
let UnionPatternsBindDifferentNamesE () = Message("UnionPatternsBindDifferentNames", "")
let RequiredButNotSpecifiedE () = Message("RequiredButNotSpecified", "%s%s%s")
Expand Down Expand Up @@ -1547,6 +1549,14 @@ type Exception with
if sig1 <> sig2 then
os.AppendString(OverrideDoesntOverride3E().Format sig2)

// If implementation and required slot doesn't have same "instance-ness", then tell user that.
if impl.IsInstance <> minfoVirt.IsInstance then
// Requried slot is instance, meaning implementation is static, tell user that we expect instance.
if minfoVirt.IsInstance then
os.AppendString(OverrideShouldBeStatic().Format)
else
os.AppendString(OverrideShouldBeInstance().Format)

| UnionCaseWrongArguments (_, n1, n2, _) -> os.AppendString(UnionCaseWrongArgumentsE().Format n2 n1)

| UnionPatternsBindDifferentNames _ -> os.AppendString(UnionPatternsBindDifferentNamesE().Format)
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1729,3 +1729,5 @@ featureUnmanagedConstraintCsharpInterop,"Interop between C#'s and F#'s unmanaged
3582,tcInfoIfFunctionShadowsUnionCase,"This is a function definition that shadows a union case. If this is what you want, ignore or suppress this warning. If you want it to be a union case deconstruction, add parentheses."
3583,unnecessaryParentheses,"Parentheses can be removed."
3584,tcDotLambdaAtNotSupportedExpression,"Shorthand lambda syntax is only supported for atomic expressions, such as method, property, field or indexer on the implied '_' argument. For example: 'let f = _.Length'."
3855,tcNoStaticMemberFoundForOverride,"No static abstract member was found that corresponds to this override"
3859,tcNoStaticPropertyFoundForOverride,"No static abstract property was found that corresponds to this override"
6 changes: 6 additions & 0 deletions src/Compiler/FSStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,12 @@
<data name="OverrideDoesntOverride4" xml:space="preserve">
<value>The member '{0}' is specialized with 'unit' but 'unit' can't be used as return type of an abstract method parameterized on return type.</value>
</data>
<data name="OverrideShouldBeStatic" xml:space="preserve">
<value> Static member is expected.</value>
</data>
<data name="OverrideShouldBeInstance" xml:space="preserve">
<value> Non-static member is expected.</value>
</data>
<data name="UnionCaseWrongArguments" xml:space="preserve">
<value>This constructor is applied to {0} argument(s) but expects {1}</value>
</data>
Expand Down
Loading