diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index 12f4074a4a..73c5e1d47d 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -16,6 +16,7 @@ * Fix "type inference problem too complicated" for SRTP with T:null and T:struct dummy constraint([Issue #18288](https://github.com/dotnet/fsharp/issues/18288), [PR #18345](https://github.com/dotnet/fsharp/pull/18345)) * Fix for missing parse diagnostics in TransparentCompiler.ParseAndCheckProject ([PR #18366](https://github.com/dotnet/fsharp/pull/18366)) * Miscellanous parentheses analyzer fixes. ([PR #18350](https://github.com/dotnet/fsharp/pull/18350)) +* Fix MethodDefNotFound when compiling code invoking delegate with option parameter ([Issue #5171](https://github.com/dotnet/fsharp/issues/5171), [PR #18385](https://github.com/dotnet/fsharp/pull/18385)) ### Added * Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241)) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 8422bd4083..78acf62bb9 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -3697,7 +3697,20 @@ module EstablishTypeDefinitionCores = if curriedArgInfos.Length < 1 then error(Error(FSComp.SR.tcInvalidDelegateSpecification(), m)) if curriedArgInfos.Length > 1 then error(Error(FSComp.SR.tcDelegatesCannotBeCurried(), m)) let ttps = thisTyconRef.Typars m - let fparams = curriedArgInfos.Head |> List.map MakeSlotParam + let fparams = + curriedArgInfos.Head + |> List.map (fun (ty, argInfo: ArgReprInfo) -> + let ty = + if HasFSharpAttribute g g.attrib_OptionalArgumentAttribute argInfo.Attribs then + match TryFindFSharpAttribute g g.attrib_StructAttribute argInfo.Attribs with + | Some (Attrib(range=m)) -> + checkLanguageFeatureAndRecover g.langVersion LanguageFeature.SupportValueOptionsAsOptionalParameters m + mkValueOptionTy g ty + | _ -> + mkOptionTy g ty + else ty + + MakeSlotParam(ty, argInfo)) TFSharpDelegate (MakeSlotSig("Invoke", thisTy, ttps, [], [fparams], returnTy)) | _ -> error(InternalError("should have inferred tycon kind", m)) diff --git a/src/Compiler/Checking/CheckPatterns.fs b/src/Compiler/Checking/CheckPatterns.fs index cdffd9acb7..9587c3b5e9 100644 --- a/src/Compiler/Checking/CheckPatterns.fs +++ b/src/Compiler/Checking/CheckPatterns.fs @@ -58,14 +58,6 @@ let UnifyRefTupleType contextInfo (cenv: cenv) denv m ty ps = AddCxTypeEqualsType contextInfo denv cenv.css m ty (TType_tuple (tupInfoRef, ptys)) ptys -let inline mkOptionalParamTyBasedOnAttribute (g: TcGlobals) tyarg attribs = - if g.langVersion.SupportsFeature(LanguageFeature.SupportValueOptionsAsOptionalParameters) - && findSynAttribute "StructAttribute" attribs - then - mkValueOptionTy g tyarg - else - mkOptionTy g tyarg - let rec TryAdjustHiddenVarNameToCompGenName (cenv: cenv) env (id: Ident) altNameRefCellOpt = match altNameRefCellOpt with | Some ({contents = SynSimplePatAlternativeIdInfo.Undecided altId } as altNameRefCell) -> diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 9dba2586e0..f1e6960cc2 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -4307,8 +4307,8 @@ and TcValSpec (cenv: cenv) env declKind newOk containerInfo memFlagsOpt thisTyOp ((List.mapSquared fst curriedArgTys), valSynInfo.CurriedArgInfos) ||> List.map2 (fun argTys argInfos -> (argTys, argInfos) - ||> List.map2 (fun argTy argInfo -> - if SynInfo.IsOptionalArg argInfo then mkOptionTy g argTy + ||> List.map2 (fun argTy (SynArgInfo(attribs, _, _) as argInfo) -> + if SynInfo.IsOptionalArg argInfo then mkOptionalParamTyBasedOnAttribute g argTy attribs else argTy)) mkIteratedFunTy g (List.map (mkRefTupledTy g) curriedArgTys) returnTy else tyR diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index 4b9de82d75..7f5ff2f9f6 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -384,3 +384,12 @@ let compileSeqExprMatchClauses (cenv: TcFileState) env inputExprMark (pat: Patte bindPatTy genInnerTy tclauses + +let inline mkOptionalParamTyBasedOnAttribute (g: TcGlobals.TcGlobals) tyarg attribs = + if + g.langVersion.SupportsFeature(LanguageFeature.SupportValueOptionsAsOptionalParameters) + && findSynAttribute "StructAttribute" attribs + then + mkValueOptionTy g tyarg + else + mkOptionTy g tyarg diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/DelegateTypes/DelegateDefinition.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/DelegateTypes/DelegateDefinition.fs index b14bc83ce3..1f4462fa6d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/DelegateTypes/DelegateDefinition.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/DelegateTypes/DelegateDefinition.fs @@ -46,3 +46,25 @@ namespace FSharpTest """ |> compile |> shouldSucceed + + [] + let ``Delegate with optional parameter`` () = + FSharp """open System.Runtime.CompilerServices +type A = delegate of [] ?a: int -> unit +let f = fun (a: int option) -> defaultArg a 100 |> printf "line: %d" +let a = A f +a.Invoke()""" + |> compileExeAndRun + |> shouldSucceed + |> verifyOutput "line: 5" + + [] + let ``Delegate with struct optional parameter`` () = + FSharp """type A = delegate of [] ?a: int -> unit +let f = fun (a: int voption) -> defaultValueArg a 100 |> printf "line: %d" +let a = A f +a.Invoke(5)""" + |> withLangVersionPreview + |> compileExeAndRun + |> shouldSucceed + |> verifyOutput "line: 5"