Skip to content

Commit

Permalink
Merge pull request #2 from dsyme/statics-in-interfaces-2
Browse files Browse the repository at this point in the history
  • Loading branch information
vzarytovskii authored Jun 23, 2022
2 parents 82a079e + be1909c commit 7546888
Show file tree
Hide file tree
Showing 21 changed files with 197 additions and 132 deletions.
27 changes: 16 additions & 11 deletions src/Compiler/AbstractIL/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3814,18 +3814,20 @@ let mkILClassCtor impl =
let mk_ospec (ty: ILType, callconv, nm, genparams, formal_args, formal_ret) =
OverridesSpec(mkILMethRef (ty.TypeRef, callconv, nm, genparams, formal_args, formal_ret), ty)

let mkILGenericVirtualMethod (nm, access, genparams, actual_args, actual_ret, impl) =
let mkILGenericVirtualMethod (nm, callconv: ILCallingConv, access, genparams, actual_args, actual_ret, impl) =
let attributes =
convertMemberAccess access
||| MethodAttributes.CheckAccessOnOverride
||| (match impl with
| MethodBody.Abstract -> MethodAttributes.Abstract ||| MethodAttributes.Virtual
| _ -> MethodAttributes.Virtual)
||| (if callconv.IsInstance then enum 0 else MethodAttributes.Static)
ILMethodDef(
name = nm,
attributes =
(convertMemberAccess access
||| MethodAttributes.CheckAccessOnOverride
||| (match impl with
| MethodBody.Abstract -> MethodAttributes.Abstract ||| MethodAttributes.Virtual
| _ -> MethodAttributes.Virtual)),
attributes = attributes,
implAttributes = MethodImplAttributes.Managed,
genericParams = genparams,
callingConv = ILCallingConv.Instance,
callingConv = callconv,
parameters = actual_args,
ret = actual_ret,
isEntryPoint = false,
Expand All @@ -3834,8 +3836,11 @@ let mkILGenericVirtualMethod (nm, access, genparams, actual_args, actual_ret, im
body = notlazy impl
)

let mkILNonGenericVirtualMethod (nm, access, args, ret, impl) =
mkILGenericVirtualMethod (nm, access, mkILEmptyGenericParams, args, ret, impl)
let mkILNonGenericVirtualMethod (nm, callconv, access, args, ret, impl) =
mkILGenericVirtualMethod (nm, callconv, access, mkILEmptyGenericParams, args, ret, impl)

let mkILNonGenericVirtualInstanceMethod (nm, access, args, ret, impl) =
mkILNonGenericVirtualMethod (nm, ILCallingConv.Instance, access, args, ret, impl)

let mkILGenericNonVirtualMethod (nm, access, genparams, actual_args, actual_ret, impl) =
ILMethodDef(
Expand Down Expand Up @@ -4258,7 +4263,7 @@ let mkILDelegateMethods access (ilg: ILGlobals) (iltyp_AsyncCallback, iltyp_IAsy

let one nm args ret =
let mdef =
mkILNonGenericVirtualMethod (nm, access, args, mkILReturn ret, MethodBody.Abstract)
mkILNonGenericVirtualInstanceMethod (nm, access, args, mkILReturn ret, MethodBody.Abstract)

mdef.WithAbstract(false).WithHideBySig(true).WithRuntime(true)

Expand Down
5 changes: 4 additions & 1 deletion src/Compiler/AbstractIL/il.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -2030,12 +2030,15 @@ val internal mkILNonGenericStaticMethod:
string * ILMemberAccess * ILParameter list * ILReturn * MethodBody -> ILMethodDef

val internal mkILGenericVirtualMethod:
string * ILMemberAccess * ILGenericParameterDefs * ILParameter list * ILReturn * MethodBody -> ILMethodDef
string * ILCallingConv * ILMemberAccess * ILGenericParameterDefs * ILParameter list * ILReturn * MethodBody -> ILMethodDef

val internal mkILGenericNonVirtualMethod:
string * ILMemberAccess * ILGenericParameterDefs * ILParameter list * ILReturn * MethodBody -> ILMethodDef

val internal mkILNonGenericVirtualMethod:
string * ILCallingConv * ILMemberAccess * ILParameter list * ILReturn * MethodBody -> ILMethodDef

val internal mkILNonGenericVirtualInstanceMethod:
string * ILMemberAccess * ILParameter list * ILReturn * MethodBody -> ILMethodDef

val internal mkILNonGenericInstanceMethod:
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 @@ -4875,7 +4875,7 @@ module TcDeclarations =
// Convert auto properties to member bindings in the post-list
let rec postAutoProps memb =
match memb with
| SynMemberDefn.AutoProperty(attributes=Attributes attribs; isStatic=isStatic; ident=id; typeOpt=tyOpt; propKind=propKind; memberFlags=memberFlags; xmlDoc=xmlDoc; accessibility=access; getSetRange=mGetSetOpt) ->
| SynMemberDefn.AutoProperty(attributes=Attributes attribs; isStatic=isStatic; ident=id; typeOpt=tyOpt; propKind=propKind; memberFlags=memberFlags; memberFlagsForSet=memberFlagsForSet; xmlDoc=xmlDoc; accessibility=access; getSetRange=mGetSetOpt) ->
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 @@ -4896,7 +4896,7 @@ module TcDeclarations =
let rhsExpr = SynExpr.Ident fldId
let retInfo = match tyOpt with None -> None | Some ty -> Some (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 SynMemberKind.Member), SynBindingTrivia.Zero)
let binding = mkSynBinding (xmlDoc, headPat) (access, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, retInfo, rhsExpr, rhsExpr.Range, [], attribs, Some memberFlags, SynBindingTrivia.Zero)
SynMemberDefn.Member (binding, mMemberPortion)
yield getter
| _ -> ()
Expand All @@ -4909,7 +4909,7 @@ module TcDeclarations =
let headPat = SynPat.LongIdent (SynLongIdent(headPatIds, [], List.replicate headPatIds.Length None), None, None, Some noInferredTypars, SynArgPats.Pats [mkSynPatVar None vId], None, mMemberPortion)
let rhsExpr = mkSynAssign (SynExpr.Ident fldId) (SynExpr.Ident vId)
//let retInfo = match tyOpt with None -> None | Some ty -> Some (SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range))
let binding = mkSynBinding (xmlDoc, headPat) (access, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, None, rhsExpr, rhsExpr.Range, [], [], Some (memberFlags SynMemberKind.PropertySet), SynBindingTrivia.Zero)
let binding = mkSynBinding (xmlDoc, headPat) (access, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, None, rhsExpr, rhsExpr.Range, [], [], Some memberFlagsForSet, SynBindingTrivia.Zero)
SynMemberDefn.Member (binding, mMemberPortion)
yield setter
| _ -> ()]
Expand Down
20 changes: 9 additions & 11 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10890,7 +10890,7 @@ and ComputeIsComplete enclosingDeclaredTypars declaredTypars ty =
/// Determine if a uniquely-identified-abstract-slot exists for an override member (or interface member implementation) based on the information available
/// at the syntactic definition of the member (i.e. prior to type inference). If so, we know the expected signature of the override, and the full slotsig
/// it implements. Apply the inferred slotsig.
and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (bindingTy, m, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, _objTy, intfSlotTyOpt, valSynData, memberFlags: SynMemberFlags, attribs) =
and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (argsAndRetTy, m, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, _objTy, intfSlotTyOpt, valSynData, memberFlags: SynMemberFlags, attribs) =

let g = cenv.g
let ad = envinner.eAccessRights
Expand Down Expand Up @@ -10953,7 +10953,7 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (bindingTy, m, syn

let absSlotTy = mkMethodTy g argTysFromAbsSlot retTyFromAbsSlot

UnifyTypes cenv envinner m bindingTy absSlotTy
UnifyTypes cenv envinner m argsAndRetTy absSlotTy
declaredTypars
| _ -> declaredTypars

Expand Down Expand Up @@ -11020,7 +11020,7 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (bindingTy, m, syn
error(Error(FSComp.SR.tcInvalidSignatureForSet(), memberId.idRange))
mkFunTy g retTyFromAbsSlot g.unit_ty

UnifyTypes cenv envinner m bindingTy absSlotTy)
UnifyTypes cenv envinner m argsAndRetTy absSlotTy)

// What's the type containing the abstract slot we're implementing? Used later on in MakeMemberDataAndMangledNameForMemberVal.
// This type must be in terms of the enclosing type's formal type parameters, hence the application of revRenaming.
Expand Down Expand Up @@ -11087,8 +11087,8 @@ and AnalyzeRecursiveStaticMemberOrValDecl
match tcrefContainerInfo, memberFlagsOpt with
| Some(MemberOrValContainerInfo(tcref, intfSlotTyOpt, _, _, declaredTyconTypars)), Some memberFlags
when memberFlags.MemberKind = SynMemberKind.Member &&
memberFlags.IsInstance = false &&
memberFlags.IsOverrideOrExplicitImpl = true ->
not memberFlags.IsInstance &&
memberFlags.IsOverrideOrExplicitImpl ->

CheckMemberFlags intfSlotTyOpt newslotsOK overridesOK memberFlags id.idRange
CheckForNonAbstractInterface declKind tcref memberFlags id.idRange
Expand All @@ -11100,10 +11100,8 @@ and AnalyzeRecursiveStaticMemberOrValDecl

let (ExplicitTyparInfo(_, declaredTypars, infer)) = explicitTyparInfo

let domainTy = NewInferenceType g

let optInferredImplSlotTys, declaredTypars =
ApplyAbstractSlotInference cenv envinner (domainTy, mBinding, synTyparDecls, declaredTypars, id, tcrefObjTy, renaming, objTy, intfSlotTyOpt, valSynInfo, memberFlags, bindingAttribs)
ApplyAbstractSlotInference cenv envinner (ty, mBinding, synTyparDecls, declaredTypars, id, tcrefObjTy, renaming, objTy, intfSlotTyOpt, valSynInfo, memberFlags, bindingAttribs)

let explicitTyparInfo = ExplicitTyparInfo(declaredTypars, declaredTypars, infer)

Expand Down Expand Up @@ -11218,16 +11216,16 @@ and AnalyzeRecursiveInstanceMemberDecl
let baseValOpt = if tcref.IsFSharpObjectModelTycon then baseValOpt else None

// Apply the known type of 'this'
let bindingTy = NewInferenceType g
UnifyTypes cenv envinner mBinding ty (mkFunTy g thisTy bindingTy)
let argsAndRetTy = NewInferenceType g
UnifyTypes cenv envinner mBinding ty (mkFunTy g thisTy argsAndRetTy)

CheckForNonAbstractInterface declKind tcref memberFlags memberId.idRange

// Determine if a uniquely-identified-override exists based on the information
// at the member signature. If so, we know the type of this member, and the full slotsig
// it implements. Apply the inferred slotsig.
let optInferredImplSlotTys, declaredTypars =
ApplyAbstractSlotInference cenv envinner (bindingTy, mBinding, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, objTy, intfSlotTyOpt, valSynInfo, memberFlags, bindingAttribs)
ApplyAbstractSlotInference cenv envinner (argsAndRetTy, mBinding, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, objTy, intfSlotTyOpt, valSynInfo, memberFlags, bindingAttribs)

// Update the ExplicitTyparInfo to reflect the declaredTypars inferred from the abstract slot
let explicitTyparInfo = ExplicitTyparInfo(declaredTypars, declaredTypars, infer)
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/ConstraintSolver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2957,7 +2957,7 @@ and ResolveOverloading

// Static IL interfaces methods are not supported in lower F# versions.
if calledMeth.Method.IsILMethod && not calledMeth.Method.IsInstance && isInterfaceTy g calledMeth.Method.ApparentEnclosingType then
checkLanguageFeatureRuntimeErrorRecover csenv.InfoReader LanguageFeature.DefaultInterfaceMemberConsumption m
checkLanguageFeatureRuntimeAndRecover csenv.InfoReader LanguageFeature.DefaultInterfaceMemberConsumption m
checkLanguageFeatureAndRecover g.langVersion LanguageFeature.DefaultInterfaceMemberConsumption m

calledMethOpt,
Expand Down
20 changes: 4 additions & 16 deletions src/Compiler/Checking/InfoReader.fs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this =
lazy isRuntimeFeatureSupported this "DefaultImplementationsOfInterfaces"

let isRuntimeFeatureVirtualStaticsInInterfacesSupported =
lazy isRuntimeFeatureSupported this "VirtualStaticsInInterfaces"
lazy isRuntimeFeatureSupported this "InterfacesWithAbstractStaticMembers"

member _.g = g
member _.amap = amap
Expand Down Expand Up @@ -762,7 +762,7 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this =
match langFeature with
// Both default and static interface method consumption features are tied to the runtime support of DIMs.
| LanguageFeature.DefaultInterfaceMemberConsumption -> isRuntimeFeatureDefaultImplementationsOfInterfacesSupported.Value
| LanguageFeature.VirtualStaticsInInterfaces -> isRuntimeFeatureVirtualStaticsInInterfacesSupported.Value
| LanguageFeature.InterfacesWithAbstractStaticMembers -> isRuntimeFeatureVirtualStaticsInInterfacesSupported.Value
| _ -> true

/// Get the declared constructors of any F# type
Expand Down Expand Up @@ -847,22 +847,10 @@ type InfoReader(g: TcGlobals, amap: Import.ImportMap) as this =
member _.FindImplicitConversions m ad ty =
implicitConversionCache.Apply((ad, m, ty))

let private tryLanguageFeatureRuntimeErrorAux (infoReader: InfoReader) langFeature m error =
let checkLanguageFeatureRuntimeAndRecover (infoReader: InfoReader) langFeature m =
if not (infoReader.IsLanguageFeatureRuntimeSupported langFeature) then
let featureStr = infoReader.g.langVersion.GetFeatureString langFeature
error (Error(FSComp.SR.chkFeatureNotRuntimeSupported featureStr, m))
false
else
true

let checkLanguageFeatureRuntimeError infoReader langFeature m =
tryLanguageFeatureRuntimeErrorAux infoReader langFeature m error |> ignore

let checkLanguageFeatureRuntimeErrorRecover infoReader langFeature m =
tryLanguageFeatureRuntimeErrorAux infoReader langFeature m errorR |> ignore

let tryLanguageFeatureRuntimeErrorRecover infoReader langFeature m =
tryLanguageFeatureRuntimeErrorAux infoReader langFeature m errorR
errorR (Error(FSComp.SR.chkFeatureNotRuntimeSupported featureStr, m))

let GetIntrinsicConstructorInfosOfType (infoReader: InfoReader) m ty =
infoReader.GetIntrinsicConstructorInfosOfTypeAux m ty ty
Expand Down
8 changes: 1 addition & 7 deletions src/Compiler/Checking/InfoReader.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,9 @@ type InfoReader =
/// Find the op_Implicit for a type
member FindImplicitConversions: m: range -> ad: AccessorDomain -> ty: TType -> MethInfo list

val checkLanguageFeatureRuntimeError:
val checkLanguageFeatureRuntimeAndRecover:
infoReader: InfoReader -> langFeature: Features.LanguageFeature -> m: range -> unit

val checkLanguageFeatureRuntimeErrorRecover:
infoReader: InfoReader -> langFeature: Features.LanguageFeature -> m: range -> unit

val tryLanguageFeatureRuntimeErrorRecover:
infoReader: InfoReader -> langFeature: Features.LanguageFeature -> m: range -> bool

/// Get the declared constructors of any F# type
val GetIntrinsicConstructorInfosOfType: infoReader: InfoReader -> m: range -> ty: TType -> MethInfo list

Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/MethodCalls.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,7 @@ let ILFieldStaticChecks g amap infoReader ad m (finfo : ILFieldInfo) =

// Static IL interfaces fields are not supported in lower F# versions.
if isInterfaceTy g finfo.ApparentEnclosingType then
checkLanguageFeatureRuntimeErrorRecover infoReader LanguageFeature.DefaultInterfaceMemberConsumption m
checkLanguageFeatureRuntimeAndRecover infoReader LanguageFeature.DefaultInterfaceMemberConsumption m
checkLanguageFeatureAndRecover g.langVersion LanguageFeature.DefaultInterfaceMemberConsumption m

CheckILFieldAttributes g finfo m
Expand Down
6 changes: 3 additions & 3 deletions src/Compiler/Checking/MethodOverrides.fs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ module DispatchSlotChecking =

// Always try to raise a target runtime error if we have a DIM.
if reqdSlot.HasDefaultInterfaceImplementation then
checkLanguageFeatureRuntimeErrorRecover infoReader LanguageFeature.DefaultInterfaceMemberConsumption m
checkLanguageFeatureRuntimeAndRecover infoReader LanguageFeature.DefaultInterfaceMemberConsumption m

let maybeResolvedSlot =
NameMultiMap.find dispatchSlot.LogicalName overridesKeyed
Expand Down Expand Up @@ -924,8 +924,8 @@ let FinalTypeDefinitionChecksAtEndOfInferenceScope (infoReader: InfoReader, nenv
let GetAbstractMethInfosForSynMethodDecl(infoReader: InfoReader, ad, memberName: Ident, bindm, typToSearchForAbstractMembers, valSynData, memberFlags: SynMemberFlags) =

if not memberFlags.IsInstance && memberFlags.IsOverrideOrExplicitImpl then
checkLanguageFeatureRuntimeErrorRecover infoReader LanguageFeature.VirtualStaticsInInterfaces bindm
checkLanguageFeatureAndRecover infoReader.g.langVersion LanguageFeature.VirtualStaticsInInterfaces bindm
checkLanguageFeatureRuntimeAndRecover infoReader LanguageFeature.InterfacesWithAbstractStaticMembers bindm
checkLanguageFeatureAndRecover infoReader.g.langVersion LanguageFeature.InterfacesWithAbstractStaticMembers bindm

let minfos =
match typToSearchForAbstractMembers with
Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/CodeGen/EraseClosures.fs
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo =
let nowApplyMethDef =
mkILGenericVirtualMethod (
"Specialize",
ILCallingConv.Instance,
ILMemberAccess.Public,
addedGenParams (* method is generic over added ILGenericParameterDefs *) ,
[],
Expand Down Expand Up @@ -703,7 +704,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo =
let convil = convILMethodBody (Some nowCloSpec, None) (Lazy.force clo.cloCode)

let nowApplyMethDef =
mkILNonGenericVirtualMethod (
mkILNonGenericVirtualInstanceMethod (
"Invoke",
ILMemberAccess.Public,
nowParams,
Expand Down
Loading

0 comments on commit 7546888

Please sign in to comment.