diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index ed951e0a03b..668190e6aad 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -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, @@ -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( @@ -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) diff --git a/src/Compiler/AbstractIL/il.fsi b/src/Compiler/AbstractIL/il.fsi index 55c713968e2..f02b36392d8 100644 --- a/src/Compiler/AbstractIL/il.fsi +++ b/src/Compiler/AbstractIL/il.fsi @@ -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: diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 5b655c16adc..02bf009ba03 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -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) @@ -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 | _ -> () @@ -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 | _ -> ()] diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 94c64d17cc9..690510cec12 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -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 @@ -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 @@ -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. @@ -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 @@ -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) @@ -11218,8 +11216,8 @@ 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 @@ -11227,7 +11225,7 @@ and AnalyzeRecursiveInstanceMemberDecl // 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) diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 7d7097dc25a..6690918ba30 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -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, diff --git a/src/Compiler/Checking/InfoReader.fs b/src/Compiler/Checking/InfoReader.fs index a4d9f00076c..f55e1cfc4c9 100644 --- a/src/Compiler/Checking/InfoReader.fs +++ b/src/Compiler/Checking/InfoReader.fs @@ -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 @@ -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 @@ -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 diff --git a/src/Compiler/Checking/InfoReader.fsi b/src/Compiler/Checking/InfoReader.fsi index 5941702256a..b06b571296a 100644 --- a/src/Compiler/Checking/InfoReader.fsi +++ b/src/Compiler/Checking/InfoReader.fsi @@ -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 diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index f4338d311df..5de06521fca 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -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 diff --git a/src/Compiler/Checking/MethodOverrides.fs b/src/Compiler/Checking/MethodOverrides.fs index 9ebf6777bd4..5ae3b02e01b 100644 --- a/src/Compiler/Checking/MethodOverrides.fs +++ b/src/Compiler/Checking/MethodOverrides.fs @@ -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 @@ -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 diff --git a/src/Compiler/CodeGen/EraseClosures.fs b/src/Compiler/CodeGen/EraseClosures.fs index 6f6646177a5..ae92dcecf0b 100644 --- a/src/Compiler/CodeGen/EraseClosures.fs +++ b/src/Compiler/CodeGen/EraseClosures.fs @@ -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 *) , [], @@ -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, diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index a421d8d6eae..8ecfcff5510 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -1373,7 +1373,7 @@ let GetMethodSpecForMemberVal cenv (memberInfo: ValMemberInfo) (vref: ValRef) = // Find the 'this' argument type if any let thisTy, flatArgInfos = if isCtor then - (GetFSharpViewOfReturnType g returnTy), flatArgInfos + GetFSharpViewOfReturnType g returnTy, flatArgInfos else match flatArgInfos with | [] -> error (InternalError("This instance method '" + vref.LogicalName + "' has no arguments", m)) @@ -1392,8 +1392,7 @@ let GetMethodSpecForMemberVal cenv (memberInfo: ValMemberInfo) (vref: ValRef) = warning (InternalError(msg, m)) else - List.iter2 - (fun gtp ty2 -> + (ctps, thisArgTys) ||> List.iter2 (fun gtp ty2 -> if not (typeEquiv g (mkTyparTy gtp) ty2) then warning ( InternalError( @@ -1406,8 +1405,6 @@ let GetMethodSpecForMemberVal cenv (memberInfo: ValMemberInfo) (vref: ValRef) = m ) )) - ctps - thisArgTys let methodArgTys, paramInfos = List.unzip flatArgInfos @@ -5741,7 +5738,7 @@ and fixupMethodImplFlags (mdef: ILMethodDef) = and fixupStaticAbstractSlotFlags (mdef: ILMethodDef) = mdef.WithHideBySig(true) -and GenObjectMethod cenv eenvinner (cgbuf: CodeGenBuffer) useMethodImpl tmethod = +and GenObjectExprMethod cenv eenvinner (cgbuf: CodeGenBuffer) useMethodImpl tmethod = let g = cenv.g let (TObjExprMethod (slotsig, attribs, methTyparsOfOverridingMethod, methParams, methBodyExpr, m)) = @@ -5786,6 +5783,7 @@ and GenObjectMethod cenv eenvinner (cgbuf: CodeGenBuffer) useMethodImpl tmethod let mdef = mkILGenericVirtualMethod ( nameOfOverridingMethod, + ILCallingConv.Instance, ILMemberAccess.Public, GenGenericParams cenv eenvUnderTypars methTyparsOfOverridingMethod, ilParamsOfOverridingMethod, @@ -5969,7 +5967,7 @@ and GenStructStateMachine cenv cgbuf eenvouter (res: LoweredStateMachine) sequel (ilArgTys, argVals) ||> List.map2 (fun ty v -> mkILParamNamed (v.LogicalName, ty)) - mkILNonGenericVirtualMethod (imethName, ILMemberAccess.Public, ilParams, mkILReturn ilRetTy, MethodBody.IL(notlazy ilCode)) + mkILNonGenericVirtualInstanceMethod (imethName, ILMemberAccess.Public, ilParams, mkILReturn ilRetTy, MethodBody.IL(notlazy ilCode)) ] let mimpls = @@ -6176,7 +6174,7 @@ and GenObjectExpr cenv cgbuf eenvouter objExpr (baseType, baseValOpt, basecall, let genMethodAndOptionalMethodImpl tmethod useMethodImpl = [ for (useMethodImpl, methodImplGeneratorFunction, methTyparsOfOverridingMethod), mdef in - GenObjectMethod cenv eenvinner cgbuf useMethodImpl tmethod do + GenObjectExprMethod cenv eenvinner cgbuf useMethodImpl tmethod do let mimpl = (if useMethodImpl then Some(methodImplGeneratorFunction (ilTyForOverriding, methTyparsOfOverridingMethod)) @@ -6327,7 +6325,7 @@ and GenSequenceExpr GenSequel cenv eenv.cloc cgbuf Return), m) - mkILNonGenericVirtualMethod ( + mkILNonGenericVirtualInstanceMethod ( "GetFreshEnumerator", ILMemberAccess.Public, [], @@ -6340,13 +6338,13 @@ and GenSequenceExpr let ilCode = CodeGenMethodForExpr cenv cgbuf.mgbuf ([], "Close", eenvinner, 1, None, closeExpr, discardAndReturnVoid) - mkILNonGenericVirtualMethod ("Close", ILMemberAccess.Public, [], mkILReturn ILType.Void, MethodBody.IL(lazy ilCode)) + mkILNonGenericVirtualInstanceMethod ("Close", ILMemberAccess.Public, [], mkILReturn ILType.Void, MethodBody.IL(lazy ilCode)) let checkCloseMethod = let ilCode = CodeGenMethodForExpr cenv cgbuf.mgbuf ([], "get_CheckClose", eenvinner, 1, None, checkCloseExpr, Return) - mkILNonGenericVirtualMethod ("get_CheckClose", ILMemberAccess.Public, [], mkILReturn g.ilg.typ_Bool, MethodBody.IL(lazy ilCode)) + mkILNonGenericVirtualInstanceMethod ("get_CheckClose", ILMemberAccess.Public, [], mkILReturn g.ilg.typ_Bool, MethodBody.IL(lazy ilCode)) let generateNextMethod = // the 'next enumerator' byref arg is at arg position 1 @@ -6359,13 +6357,13 @@ and GenSequenceExpr let ilCode = MethodBody.IL(lazy (CodeGenMethodForExpr cenv cgbuf.mgbuf ([], "GenerateNext", eenvinner, 2, None, generateNextExpr, Return))) - mkILNonGenericVirtualMethod ("GenerateNext", ILMemberAccess.Public, ilParams, ilReturn, ilCode) + mkILNonGenericVirtualInstanceMethod ("GenerateNext", ILMemberAccess.Public, ilParams, ilReturn, ilCode) let lastGeneratedMethod = let ilCode = CodeGenMethodForExpr cenv cgbuf.mgbuf ([], "get_LastGenerated", eenvinner, 1, None, exprForValRef m currvref, Return) - mkILNonGenericVirtualMethod ("get_LastGenerated", ILMemberAccess.Public, [], mkILReturn ilCloSeqElemTy, MethodBody.IL(lazy ilCode)) + mkILNonGenericVirtualInstanceMethod ("get_LastGenerated", ILMemberAccess.Public, [], mkILReturn ilCloSeqElemTy, MethodBody.IL(lazy ilCode)) |> AddNonUserCompilerGeneratedAttribs g let ilCtorBody = @@ -6561,6 +6559,7 @@ and GenClosureAsLocalTypeFunction cenv (cgbuf: CodeGenBuffer) eenv thisVars expr [ mkILGenericVirtualMethod ( "DirectInvoke", + ILCallingConv.Instance, ILMemberAccess.Assembly, ilDirectGenericParams, ilDirectWitnessParams, @@ -9078,8 +9077,10 @@ and GenMethodForBinding let flagFixups = ComputeFlagFixupsForMemberBinding cenv v + let cconv = if memberInfo.MemberFlags.IsInstance then ILCallingConv.Instance else ILCallingConv.Static + let mdef = - mkILGenericVirtualMethod (mspec.Name, ILMemberAccess.Public, ilMethTypars, ilParams, ilReturn, ilMethodBody) + mkILGenericVirtualMethod (mspec.Name, cconv, ILMemberAccess.Public, ilMethTypars, ilParams, ilReturn, ilMethodBody) let mdef = List.fold (fun mdef f -> f mdef) mdef flagFixups @@ -10143,7 +10144,7 @@ and GenEqualsOverrideCallingIComparable cenv (tcref: TyconRef, ilThisTy, _ilThat let ilMethodBody = mkMethodBody (true, [], 2, nonBranchingInstrsToCode ilInstrs, None, None) - mkILNonGenericVirtualMethod ( + mkILNonGenericVirtualInstanceMethod ( "Equals", ILMemberAccess.Public, [ mkILParamNamed ("obj", g.ilg.typ_Object) ], @@ -10226,6 +10227,7 @@ and GenAbstractBinding cenv eenv tref (vref: ValRef) = let mdef = mkILGenericVirtualMethod ( vref.CompiledName g.CompilerGlobalState, + mspec.CallingConv, ILMemberAccess.Public, ilMethTypars, ilParams, @@ -10235,16 +10237,9 @@ and GenAbstractBinding cenv eenv tref (vref: ValRef) = let mdef = fixupVirtualSlotFlags mdef - let mdef = - if mdef.IsVirtual then - mdef - .WithFinal(memberInfo.MemberFlags.IsFinal) - .WithAbstract(memberInfo.MemberFlags.IsDispatchSlot) - else - mdef - let mdef = mdef + .WithFinal(memberInfo.MemberFlags.IsFinal) .WithPreserveSig(hasPreserveSigImplFlag) .WithSynchronized(hasSynchronizedImplFlag) .WithNoInlining(hasNoInliningFlag) @@ -10346,7 +10341,7 @@ and GenPrintingMethod cenv eenv methName ilThisTy m = mkMethodBody (true, [], 2, nonBranchingInstrsToCode ilInstrs, None, eenv.imports) let mdef = - mkILNonGenericVirtualMethod (methName, ILMemberAccess.Public, [], mkILReturn g.ilg.typ_String, ilMethodBody) + mkILNonGenericVirtualInstanceMethod (methName, ILMemberAccess.Public, [], mkILReturn g.ilg.typ_String, ilMethodBody) let mdef = mdef.With(customAttrs = mkILCustomAttrs [ g.CompilerGeneratedAttribute ]) yield mdef diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index ab609449d6a..5ffd7917e30 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -49,7 +49,7 @@ type LanguageFeature = | DelegateTypeNameResolutionFix | ReallyLongLists | ErrorOnDeprecatedRequireQualifiedAccess - | VirtualStaticsInInterfaces + | InterfacesWithAbstractStaticMembers /// LanguageVersion management type LanguageVersion(versionText) = @@ -112,7 +112,7 @@ type LanguageVersion(versionText) = LanguageFeature.BetterExceptionPrinting, previewVersion LanguageFeature.ReallyLongLists, previewVersion LanguageFeature.ErrorOnDeprecatedRequireQualifiedAccess, previewVersion - LanguageFeature.VirtualStaticsInInterfaces, previewVersion + LanguageFeature.InterfacesWithAbstractStaticMembers, previewVersion ] @@ -213,7 +213,7 @@ type LanguageVersion(versionText) = | LanguageFeature.DelegateTypeNameResolutionFix -> FSComp.SR.featureDelegateTypeNameResolutionFix () | LanguageFeature.ReallyLongLists -> FSComp.SR.featureReallyLongList () | LanguageFeature.ErrorOnDeprecatedRequireQualifiedAccess -> FSComp.SR.featureErrorOnDeprecatedRequireQualifiedAccess () - | LanguageFeature.VirtualStaticsInInterfaces -> FSComp.SR.featureVirtualStaticsInInterfaces () + | LanguageFeature.InterfacesWithAbstractStaticMembers -> FSComp.SR.featureVirtualStaticsInInterfaces () /// Get a version string associated with the given feature. member _.GetFeatureVersionString feature = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index fe91bae6ae3..ddc2623268c 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -39,7 +39,7 @@ type LanguageFeature = | DelegateTypeNameResolutionFix | ReallyLongLists | ErrorOnDeprecatedRequireQualifiedAccess - | VirtualStaticsInInterfaces + | InterfacesWithAbstractStaticMembers /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index ae00238bb90..f6eea0b4dd0 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -1401,7 +1401,8 @@ type SynMemberDefn = ident: Ident * typeOpt: SynType option * propKind: SynMemberKind * - memberFlags: (SynMemberKind -> SynMemberFlags) * + memberFlags: SynMemberFlags * + memberFlagsForSet: SynMemberFlags * xmlDoc: PreXmlDoc * accessibility: SynAccess option * equalsRange: range * diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index 31bf8d19ebc..a7c2b27bbd8 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -1593,7 +1593,8 @@ type SynMemberDefn = ident: Ident * typeOpt: SynType option * propKind: SynMemberKind * - memberFlags: (SynMemberKind -> SynMemberFlags) * + memberFlags: SynMemberFlags * + memberFlagsForSet: SynMemberFlags * xmlDoc: PreXmlDoc * accessibility: SynAccess option * equalsRange: range * diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs index 64e66218780..150f8198059 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs @@ -730,10 +730,10 @@ let OverrideMemberFlags trivia k : SynMemberFlags = Trivia = trivia } -let AbstractMemberFlags trivia k : SynMemberFlags = +let AbstractMemberFlags isInstance trivia k : SynMemberFlags = { MemberKind = k - IsInstance = true + IsInstance = isInstance IsDispatchSlot = true IsOverrideOrExplicitImpl = false IsFinal = false @@ -814,6 +814,24 @@ let AbstractMemberSynMemberFlagsTrivia (mAbstract: range) (mMember: range) : Syn DefaultRange = None } +let StaticAbstractSynMemberFlagsTrivia mStatic mAbstract = + { + MemberRange = None + OverrideRange = None + AbstractRange = Some mAbstract + StaticRange = Some mStatic + DefaultRange = None + } + +let StaticAbstractMemberSynMemberFlagsTrivia mStatic mAbstract mMember = + { + MemberRange = Some mMember + OverrideRange = None + AbstractRange = Some mAbstract + StaticRange = Some mStatic + DefaultRange = None + } + let inferredTyparDecls = SynValTyparDecls(None, true) let noInferredTypars = SynValTyparDecls(None, false) diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi index 50037218557..a9831932090 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi @@ -296,7 +296,7 @@ val ClassCtorMemberFlags: trivia: SynMemberFlagsTrivia -> SynMemberFlags val OverrideMemberFlags: trivia: SynMemberFlagsTrivia -> k: SynMemberKind -> SynMemberFlags -val AbstractMemberFlags: trivia: SynMemberFlagsTrivia -> k: SynMemberKind -> SynMemberFlags +val AbstractMemberFlags: isInstance: bool -> trivia: SynMemberFlagsTrivia -> k: SynMemberKind -> SynMemberFlags val StaticMemberFlags: trivia: SynMemberFlagsTrivia -> k: SynMemberKind -> SynMemberFlags @@ -314,6 +314,10 @@ val AbstractSynMemberFlagsTrivia: mAbstract: range -> SynMemberFlagsTrivia val AbstractMemberSynMemberFlagsTrivia: mAbstract: range -> mMember: range -> SynMemberFlagsTrivia +val StaticAbstractSynMemberFlagsTrivia: mStatic: range -> mAbstract: range -> SynMemberFlagsTrivia + +val StaticAbstractMemberSynMemberFlagsTrivia: mStatic: range -> mAbstract: range -> mMember: range -> SynMemberFlagsTrivia + val inferredTyparDecls: SynValTyparDecls val noInferredTypars: SynValTyparDecls diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index 92f1bc5719e..f05b4a83333 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -8840,12 +8840,11 @@ let CompileAsEvent g attrs = HasFSharpAttribute g g.attrib_CLIEventAttribute att let MemberIsCompiledAsInstance g parent isExtensionMember (membInfo: ValMemberInfo) attrs = // All extension members are compiled as static members - if isExtensionMember then false - // Members implementing a dispatch slot is compiled as an instance member - // Exception is static interface members: - elif not membInfo.MemberFlags.IsInstance && membInfo.MemberFlags.IsOverrideOrExplicitImpl then false - elif membInfo.MemberFlags.IsOverrideOrExplicitImpl then true - elif not (isNil membInfo.ImplementedSlotSigs) then true + if isExtensionMember then + false + // Abstract slots, overrides and interface impls are all true to IsInstance + elif membInfo.MemberFlags.IsDispatchSlot || membInfo.MemberFlags.IsOverrideOrExplicitImpl || not (isNil membInfo.ImplementedSlotSigs) then + membInfo.MemberFlags.IsInstance else // Otherwise check attributes to see if there is an explicit instance or explicit static flag let explicitInstance, explicitStatic = diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 72cc9ccd815..4c2d563926a 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -995,7 +995,9 @@ tyconSpfnRhs: | DELEGATE OF topType { let m = lhs parseState let ty, arity = $3 - let invoke = SynMemberSig.Member(SynValSig([], (SynIdent(mkSynId m "Invoke", None)), inferredTyparDecls, ty, arity, false, false, PreXmlDoc.Empty, None, None, m, SynValSigTrivia.Zero), AbstractMemberFlags SynMemberFlagsTrivia.Zero SynMemberKind.Member, m) + let flags = AbstractMemberFlags true SynMemberFlagsTrivia.Zero SynMemberKind.Member + let valSig = SynValSig([], (SynIdent(mkSynId m "Invoke", None)), inferredTyparDecls, ty, arity, false, false, PreXmlDoc.Empty, None, None, m, SynValSigTrivia.Zero) + let invoke = SynMemberSig.Member(valSig, flags, m) (fun nameRange nameInfo mEquals augmentation -> if not (isNil augmentation) then raiseParseErrorAt m (FSComp.SR.parsAugmentationsIllegalOnDelegateType()) let mWhole = unionRanges nameRange m @@ -1082,8 +1084,8 @@ classMemberSpfn: | None -> m | Some e -> unionRanges m e.Range let valSpfn = SynValSig($1, id, explicitValTyparDecls, ty, arity, isInline, false, doc, vis2, optLiteralValue, wholeRange, { ValKeyword = None; WithKeyword = mWith; EqualsRange = mEquals }) - let _, flags = $3 - SynMemberSig.Member(valSpfn, flags (getSetAdjuster arity), wholeRange) } + let flags = $3 (getSetAdjuster arity) + SynMemberSig.Member(valSpfn, flags, wholeRange) } | opt_attributes opt_declVisibility interfaceMember appType { if Option.isSome $2 then errorR(Error(FSComp.SR.parsVisibilityDeclarationsShouldComePriorToIdentifier(), rhs parseState 2)) @@ -1156,13 +1158,7 @@ classMemberSpfnGetSetElements: memberSpecFlags: | memberFlags { $1 } - | ABSTRACT - { let mAbstract = rhs parseState 1 - (false, AbstractMemberFlags(AbstractSynMemberFlagsTrivia mAbstract)) } - | ABSTRACT MEMBER - { let mAbstract = rhs parseState 1 - let mMember = rhs parseState 2 - (false, AbstractMemberFlags(AbstractMemberSynMemberFlagsTrivia mAbstract mMember)) } + | abstractMemberFlags { $1 } /* Part of an exception definition in a signature file */ @@ -1598,16 +1594,16 @@ memberFlags: | STATIC MEMBER { let mStatic = rhs parseState 1 let mMember = rhs parseState 2 - (true, StaticMemberFlags(StaticMemberSynMemberFlagsTrivia mStatic mMember)) } + StaticMemberFlags(StaticMemberSynMemberFlagsTrivia mStatic mMember) } | MEMBER { let mMember = rhs parseState 1 - (false, NonVirtualMemberFlags(MemberSynMemberFlagsTrivia mMember)) } + NonVirtualMemberFlags(MemberSynMemberFlagsTrivia mMember) } | OVERRIDE { let mOverride = rhs parseState 1 - (false, OverrideMemberFlags(OverrideSynMemberFlagsTrivia mOverride)) } + OverrideMemberFlags(OverrideSynMemberFlagsTrivia mOverride) } | DEFAULT { let mDefault = rhs parseState 1 - (false, OverrideMemberFlags(DefaultSynMemberFlagsTrivia mDefault)) } + OverrideMemberFlags(DefaultSynMemberFlagsTrivia mDefault) } /* The name of a type in a signature or implementation, possibly with type parameters and constraints */ typeNameInfo: @@ -1741,8 +1737,9 @@ tyconDefnRhs: { let m = lhs parseState let ty, arity = $3 (fun nameRange augmentation -> - let valSpfn = SynValSig([], (SynIdent(mkSynId m "Invoke", None)), inferredTyparDecls, ty, arity, false, false, PreXmlDoc.Empty, None, None, m, SynValSigTrivia.Zero) - let invoke = SynMemberDefn.AbstractSlot(valSpfn, AbstractMemberFlags SynMemberFlagsTrivia.Zero SynMemberKind.Member, m) + let valSig = SynValSig([], (SynIdent(mkSynId m "Invoke", None)), inferredTyparDecls, ty, arity, false, false, PreXmlDoc.Empty, None, None, m, SynValSigTrivia.Zero) + let flags = AbstractMemberFlags true SynMemberFlagsTrivia.Zero SynMemberKind.Member + let invoke = SynMemberDefn.AbstractSlot(valSig, flags, m) if not (isNil augmentation) then raiseParseErrorAt m (FSComp.SR.parsAugmentationsIllegalOnDelegateType()) SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Delegate (ty, arity), [invoke], m), []) } @@ -2065,16 +2062,23 @@ memberCore: | _ -> []) } - abstractMemberFlags: | ABSTRACT { let mAbstract = rhs parseState 1 - AbstractSynMemberFlagsTrivia mAbstract } - | ABSTRACT MEMBER + AbstractMemberFlags true (AbstractSynMemberFlagsTrivia mAbstract) } + | ABSTRACT MEMBER { let mAbstract = rhs parseState 1 let mMember = rhs parseState 2 - AbstractMemberSynMemberFlagsTrivia mAbstract mMember } - + AbstractMemberFlags true (AbstractMemberSynMemberFlagsTrivia mAbstract mMember) } + | STATIC ABSTRACT + { let mStatic = rhs parseState 1 + let mAbstract = rhs parseState 2 + AbstractMemberFlags false (StaticAbstractSynMemberFlagsTrivia mStatic mAbstract) } + | STATIC ABSTRACT MEMBER + { let mStatic = rhs parseState 1 + let mAbstract = rhs parseState 2 + let mMember = rhs parseState 3 + AbstractMemberFlags false (StaticAbstractMemberSynMemberFlagsTrivia mStatic mAbstract mMember) } /* A member definition */ classDefnMember: @@ -2090,7 +2094,7 @@ classDefnMember: { let rangeStart = rhs parseState 1 if Option.isSome $2 then errorR (Error (FSComp.SR.parsVisibilityDeclarationsShouldComePriorToIdentifier (), rhs parseState 2)) - let _, flags = $3 + let flags = $3 $4 $2 flags $1 rangeStart } | opt_attributes opt_declVisibility interfaceMember appType opt_interfaceImplDefn @@ -2115,7 +2119,7 @@ classDefnMember: |> unionRangeWithXmlDoc doc if Option.isSome $2 then errorR(Error(FSComp.SR.parsAccessibilityModsIllegalForAbstract(), wholeRange)) let valSpfn = SynValSig($1, id, explicitValTyparDecls, ty, arity, isInline, false, doc, None, None, wholeRange, { ValKeyword = None; WithKeyword = mWith; EqualsRange = None }) - [ SynMemberDefn.AbstractSlot(valSpfn, AbstractMemberFlags $3 (getSetAdjuster arity), wholeRange) ] } + [ SynMemberDefn.AbstractSlot(valSpfn, $3 (getSetAdjuster arity), wholeRange) ] } | opt_attributes opt_declVisibility inheritsDefn { if not (isNil $1) then errorR(Error(FSComp.SR.parsAttributesIllegalOnInherit(), rhs parseState 1)) @@ -2136,8 +2140,8 @@ classDefnMember: { let rangeStart = rhs parseState 1 if Option.isSome $2 then errorR(Error(FSComp.SR.parsVisibilityDeclarationsShouldComePriorToIdentifier(), rhs parseState 2)) - let isStatic, flags = $3 - $4 $1 isStatic flags rangeStart } + let flags = $3 + $4 $1 flags rangeStart } | opt_attributes opt_declVisibility NEW atomicPattern optAsSpec EQUALS typedSequentialExprBlock opt_ODECLEND { let mWholeBindLhs = rhs2 parseState 1 (if Option.isSome $5 then 5 else 4) @@ -2177,11 +2181,13 @@ autoPropsDefnDecl: let mEquals = rhs parseState 6 if $2 then errorR (Error (FSComp.SR.parsMutableOnAutoPropertyShouldBeGetSet (), rhs parseState 3)) - (fun attribs isStatic flags rangeStart -> + (fun attribs flags rangeStart -> let xmlDoc = grabXmlDocAtRangeStart(parseState, attribs, rangeStart) let memberRange = unionRanges rangeStart $7.Range |> unionRangeWithXmlDoc xmlDoc - [ SynMemberDefn.AutoProperty(attribs, isStatic, $4, $5, getSet, flags, xmlDoc, $3, mEquals, $7, mWith, mGetSetOpt, memberRange) ]) } - + let memberFlags = flags SynMemberKind.Member + let memberFlagsForSet = flags SynMemberKind.PropertySet + let isStatic = not memberFlags.IsInstance + [ SynMemberDefn.AutoProperty(attribs, isStatic, $4, $5, getSet, memberFlags, memberFlagsForSet, xmlDoc, $3, mEquals, $7, mWith, mGetSetOpt, memberRange) ]) } /* An optional type on an auto-property definition */ opt_typ: @@ -2346,7 +2352,7 @@ objectImplementationMember: | opt_attributes staticMemberOrMemberOrOverride autoPropsDefnDecl opt_ODECLEND { let rangeStart = rhs parseState 1 - $3 $1 false $2 rangeStart } + $3 $1 $2 rangeStart } | opt_attributes staticMemberOrMemberOrOverride error { [] } diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs index e0eab1b6ff1..39653161a07 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/StaticsInInterfaces.fs @@ -315,4 +315,56 @@ let main _ = |> withLangVersionPreview |> withReferences [csharpLib] |> compileAndRun - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + +#if !NETCOREAPP + [] +#else + [] +#endif + let ``F# can implement interfaces with static abstract methods`` () = + + let fsharpSource = + """ + +type IAdditionOperator<'T> = + static abstract op_Addition: 'T * 'T -> 'T + +type C() = + interface IAdditionOperator with + static member op_Addition(x: C, y: C) = C() + +[] +let main _ = 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> compileAndRun + |> shouldSucceed + +#if !NETCOREAPP + [] +#else + [] +#endif + let ``F# supports inference for types of arguments when implementing interfaces`` () = + + let fsharpSource = + """ + +type IAdditionOperator<'T> = + static abstract op_Addition: 'T * 'T -> 'T + +type C() = + interface IAdditionOperator with + static member op_Addition(x, y) = C() // no type annotation needed on 'x' and 'y' + +[] +let main _ = 0 +""" + FSharp fsharpSource + |> asExe + |> withLangVersionPreview + |> compileAndRun + |> shouldSucceed diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index 508221afb6f..5dab3f97ce5 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -3552,25 +3552,25 @@ type Foo = SynModuleOrNamespace.SynModuleOrNamespace(decls = [ SynModuleDecl.Types ([ SynTypeDefn.SynTypeDefn (typeRepr = SynTypeDefnRepr.ObjectModel (members=[ - SynMemberDefn.AutoProperty(memberFlags= mkFlags1) - SynMemberDefn.AutoProperty(memberFlags= mkFlags2) - SynMemberDefn.AutoProperty(memberFlags= mkFlags3) - SynMemberDefn.AutoProperty(memberFlags= mkFlags4) + SynMemberDefn.AutoProperty(memberFlags=flags1) + SynMemberDefn.AutoProperty(memberFlags=flags2) + SynMemberDefn.AutoProperty(memberFlags=flags3) + SynMemberDefn.AutoProperty(memberFlags=flags4) ])) ], _) ]) ])) -> - let ({ Trivia = flagsTrivia1 } : SynMemberFlags) = mkFlags1 SynMemberKind.Member + let ({ Trivia = flagsTrivia1 } : SynMemberFlags) = flags1 assertRange (3, 4) (3, 10) flagsTrivia1.StaticRange.Value assertRange (3, 11) (3, 17) flagsTrivia1.MemberRange.Value - let ({ Trivia = flagsTrivia2 } : SynMemberFlags) = mkFlags2 SynMemberKind.Member + let ({ Trivia = flagsTrivia2 } : SynMemberFlags) = flags2 assertRange (4, 4) (4, 10) flagsTrivia2.MemberRange.Value - let ({ Trivia = flagsTrivia3 } : SynMemberFlags) = mkFlags3 SynMemberKind.Member + let ({ Trivia = flagsTrivia3 } : SynMemberFlags) = flags3 assertRange (5, 4) (5, 12) flagsTrivia3.OverrideRange.Value - let ({ Trivia = flagsTrivia4 } : SynMemberFlags) = mkFlags4 SynMemberKind.Member + let ({ Trivia = flagsTrivia4 } : SynMemberFlags) = flags4 assertRange (6, 4) (6, 11) flagsTrivia4.DefaultRange.Value | _ -> Assert.Fail "Could not get valid AST"