From 25b5824f5a6f8cb60f25d7ac029689fd70e6c87c Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 3 Apr 2025 15:03:30 +0200 Subject: [PATCH 1/2] Fix IL mismatch - Some() was created for a ValueOption method --- src/Compiler/Checking/MethodCalls.fs | 12 ++++-- src/Compiler/Checking/PostInferenceChecks.fs | 24 ++++++++---- .../OptionalArguments/OptionalArguments.fs | 39 ++++++++++++++++++- tests/FSharp.Test.Utilities/Compiler.fs | 3 +- 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 41d731f007..19b91dcf0b 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -348,6 +348,12 @@ let inline mkOptionalNone (g: TcGlobals) ty calledArgTy mMethExpr = else mkNone g calledArgTy mMethExpr +let inline mkOptionalSome (g: TcGlobals) outerOptTy innerNonOptionalType expr mMethExpr = + if g.langVersion.SupportsFeature LanguageFeature.SupportValueOptionsAsOptionalParameters && isValueOptionTy g outerOptTy then + mkValueSome g innerNonOptionalType expr mMethExpr + else + mkSome g innerNonOptionalType expr mMethExpr + /// Adjust the called argument type to take into account whether the caller's argument is CSharpMethod(?arg=Some(3)) or CSharpMethod(arg=1) let AdjustCalledArgTypeForOptionals (infoReader: InfoReader) ad enforceNullableOptionalsKnownTypes (calledArg: CalledArg) calledArgTy (callerArg: CallerArg<_>) = @@ -1502,14 +1508,14 @@ let GetDefaultExpressionForCalleeSideOptionalArg g (calledArg: CalledArg) eCalle match calledArg.CallerInfo, eCallerMemberName with | CallerLineNumber, _ when typeEquiv g calledNonOptTy g.int_ty -> let lineExpr = Expr.Const(Const.Int32 mMethExpr.StartLine, mMethExpr, calledNonOptTy) - mkSome g calledNonOptTy lineExpr mMethExpr + mkOptionalSome g calledArgTy calledNonOptTy lineExpr mMethExpr | CallerFilePath, _ when typeEquiv g calledNonOptTy g.string_ty -> let fileName = mMethExpr.FileName |> FileSystem.GetFullPathShim |> PathMap.apply g.pathMap let filePathExpr = Expr.Const (Const.String(fileName), mMethExpr, calledNonOptTy) - mkSome g calledNonOptTy filePathExpr mMethExpr + mkOptionalSome g calledArgTy calledNonOptTy filePathExpr mMethExpr | CallerMemberName, Some(callerName) when typeEquiv g calledNonOptTy g.string_ty -> let memberNameExpr = Expr.Const (Const.String callerName, mMethExpr, calledNonOptTy) - mkSome g calledNonOptTy memberNameExpr mMethExpr + mkOptionalSome g calledArgTy calledNonOptTy memberNameExpr mMethExpr | _ -> mkOptionalNone g calledArgTy calledNonOptTy mMethExpr diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index 4df0185a2e..8faa14328d 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -2398,13 +2398,25 @@ let CheckEntityDefn cenv env (tycon: Entity) = errorR(Error(FSComp.SR.chkCurriedMethodsCantHaveOutParams(), m)) if numCurriedArgSets = 1 then + let inline tryDestOptionalTy g ty = + if isOptionTy g ty then + destOptionTy g ty |> ValueSome + elif g.langVersion.SupportsFeature LanguageFeature.SupportValueOptionsAsOptionalParameters && isValueOptionTy g ty then + destValueOptionTy g ty |> ValueSome + else + ValueNone + let errorIfNotStringTy m ty callerInfo = if not (typeEquiv g g.string_ty ty) then errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, "string", NicePrint.minimalStringOfType cenv.denv ty), m)) - let errorIfNotStringOptionTy m ty callerInfo = - if not ((isOptionTy g ty) && (typeEquiv g g.string_ty (destOptionTy g ty))) then - errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, "string", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m)) + let errorIfNotOptional tyToCompare desiredTyName m ty callerInfo = + + match tryDestOptionalTy g ty with + | ValueSome t when typeEquiv g tyToCompare t -> () + | ValueSome innerTy -> errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, desiredTyName, NicePrint.minimalStringOfType cenv.denv innerTy), m)) + | ValueNone -> errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, desiredTyName, NicePrint.minimalStringOfType cenv.denv ty), m)) + minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) |> List.iterSquared (fun (ParamData(_, isInArg, _, optArgInfo, callerInfo, nameOpt, _, ty)) -> @@ -2421,11 +2433,9 @@ let CheckEntityDefn cenv env (tycon: Entity) = | CallerSide _, CallerLineNumber -> if not (typeEquiv g g.int32_ty ty) then errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, "int", NicePrint.minimalStringOfType cenv.denv ty), m)) - | CalleeSide, CallerLineNumber -> - if not ((isOptionTy g ty) && (typeEquiv g g.int32_ty (destOptionTy g ty))) then - errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo |> string, "int", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m)) + | CalleeSide, CallerLineNumber -> errorIfNotOptional g.int32_ty "int" m ty callerInfo | CallerSide _, (CallerFilePath | CallerMemberName) -> errorIfNotStringTy m ty callerInfo - | CalleeSide, (CallerFilePath | CallerMemberName) -> errorIfNotStringOptionTy m ty callerInfo + | CalleeSide, (CallerFilePath | CallerMemberName) -> errorIfNotOptional g.string_ty "string" m ty callerInfo ) for pinfo in immediateProps do diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs index c0604630d5..4d0843014e 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs @@ -609,4 +609,41 @@ but here has type ''T option' but here has type ''a voption' " - ] \ No newline at end of file + ] + + [] + let ``Struct optional args can have caller member name`` () = + + let source = """module TestLib +open System.Runtime.CompilerServices + +let printItOut x = + printf "%s" $"{x};" + +type Ab() = + + static member aa ([]?b: string) = + printItOut b + + static member bb ([]?i: int) = + printItOut i + +[] +let main _args = + Ab.aa() + Ab.bb() + Ab.aa("hello") + Ab.bb(42) + 0 +""" + + source + |> FSharp + |> withLangVersionPreview + |> withNoWarn 25 + |> asExe + |> compile + |> ILVerifierModule.verifyPEFileWithSystemDlls + |> run + |> verifyOutputContains [|"main;18;hello;42;"|] + \ No newline at end of file diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index c6346cb30f..8108f8886a 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -1640,7 +1640,8 @@ Actual: | Some (ExecutionOutput {Outcome = Failure ex }) -> failwithf $"Eval or Execution has failed (expected to succeed): %A{ex}\n{diagnostics}" | _ -> - failwithf $"Operation failed (expected to succeed).\n{diagnostics}" + + failwithf $"Operation failed (expected to succeed).\n{diagnostics} \n OUTPUTs: %A{r.Output}" let shouldFail (result: CompilationResult) : CompilationResult = match result with From 311d76d919c66b1de23f49494a1aaab10e8aae51 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 9 Apr 2025 14:32:15 +0200 Subject: [PATCH 2/2] notes --- docs/release-notes/.FSharp.Compiler.Service/9.0.300.md | 1 + 1 file changed, 1 insertion(+) 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 7f0be7cb37..822a85e72a 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -24,6 +24,7 @@ * Reenable β-reduction and subsequent reoptimization of immediately-invoked F#-defined generic delegates. ([PR #18401](https://github.com/dotnet/fsharp/pull/18401)) * Fixed [#18433](https://github.com/dotnet/fsharp/issues/18433), a rare case of an internal error in xml comment processing. ([PR #18436](https://github.com/dotnet/fsharp/pull/18436)) * Fix missing `null` highlighting in tooltips ([PR #18457](https://github.com/dotnet/fsharp/pull/18457)) +* Make `[]` combination work([PR #18444](https://github.com/dotnet/fsharp/pull/18444/)) ### Added * Added missing type constraints in FCS. ([PR #18241](https://github.com/dotnet/fsharp/pull/18241))