Skip to content
Open
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
2 changes: 2 additions & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

### Added

* Type checker: recover function type unification in method checking ([#19036](https://github.com/dotnet/fsharp/pull/19036#pullrequestreview-3392846258))

### Changed

* Parallel compilation stabilised and enabled by default ([PR #18998](https://github.com/dotnet/fsharp/pull/18998))
Expand Down
18 changes: 16 additions & 2 deletions src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,20 @@ let UnifyFunctionType extraInfo (cenv: cenv) denv mFunExpr ty =
| Some argm -> error (NotAFunction(denv, ty, mFunExpr, argm))
| None -> error (FunctionExpected(denv, ty, mFunExpr))

let UnifyFunctionTypeAndRecover extraInfo (cenv: cenv) denv mFunExpr ty =
match UnifyFunctionTypeUndoIfFailed cenv denv mFunExpr ty with
| ValueSome res -> res
| ValueNone ->
match extraInfo with
| Some argm -> errorR (NotAFunction(denv, ty, mFunExpr, argm))
| None -> errorR (FunctionExpected(denv, ty, mFunExpr))

let g = cenv.g
let domainTy = NewInferenceType g
let resultTy = NewInferenceType g
domainTy, resultTy


let ReportImplicitlyIgnoredBoolExpression denv m ty expr =
let checkExpr m expr =
match stripDebugPoints expr with
Expand Down Expand Up @@ -9988,7 +10002,7 @@ and TcMethodApplication_UniqueOverloadInference
// type we assume the number of arguments is just "1".
| None, _ ->

let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy.Commit
let domainTy, returnTy = UnifyFunctionTypeAndRecover None cenv denv mMethExpr exprTy.Commit
let argTys = if isUnitTy g domainTy then [] else tryDestRefTupleTy g domainTy
// Only apply this rule if a candidate method exists with this number of arguments
let argTys =
Expand Down Expand Up @@ -10068,7 +10082,7 @@ and TcMethodApplication_CheckArguments
let curriedArgTys, returnTy = UnifyMatchingSimpleArgumentTypes cenv env exprTy.Commit calledMeth mMethExpr mItem
curriedArgTys, paramNamesIfFeatureEnabled g calledMeth, MustEqual returnTy
| _ ->
let domainTy, returnTy = UnifyFunctionType None cenv denv mMethExpr exprTy.Commit
let domainTy, returnTy = UnifyFunctionTypeAndRecover None cenv denv mMethExpr exprTy.Commit
let argTys = if isUnitTy g domainTy then [] else tryDestRefTupleTy g domainTy
// Only apply this rule if a candidate method exists with this number of arguments
let argTys, argNames =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
module FSharp.Compiler.Service.Tests.TypeChecker.TypeCheckerRecoveryTests

open FSharp.Compiler.Service.Tests
open FSharp.Compiler.Text
open FSharp.Test.Assert
open Xunit

let assertHasSymbolUsageAtCaret name source =
let context, checkResults = Checker.getCheckedResolveContext source

getSymbolUses checkResults
|> Seq.exists (fun symbolUse ->
Range.rangeContainsPos symbolUse.Range context.Pos &&
symbolUse.Symbol.DisplayNameCore = name
)
|> shouldEqual true

[<Fact>]
let ``Let 01`` () =
let _, checkResults = getParseAndCheckResults """
Expand Down Expand Up @@ -49,4 +60,42 @@ Math.Max(a,b,)
"(4,0--4,14)", 503
]

assertHasSymbolUsages ["Max"] checkResults
assertHasSymbolUsages ["Max"] checkResults

module Expressions =
[<Fact>]
let ``Method type 01`` () =
assertHasSymbolUsageAtCaret "ToString" """
if true then
"".ToString{caret}
"""


[<Fact>]
let ``Method type 02`` () =
assertHasSymbolUsageAtCaret "M" """
type T =
static member M() = ""

if true then
T.M{caret}
"""

[<Fact>]
let ``Method type 03`` () =
assertHasSymbolUsageAtCaret "M" """
type T =
static member M(i: int) = ""
static member M(s: string) = ""

if true then
T.M{caret}
"""

[<Fact>]
let ``Method type 04`` () =
assertHasSymbolUsageAtCaret "GetHashCode" """
let o: obj = null
if true then
o.GetHashCode{caret}
"""
Loading