Skip to content

Commit 0a4bb51

Browse files
committed
Type checker: recover on adding constraints
1 parent 12efe3b commit 0a4bb51

File tree

5 files changed

+113
-22
lines changed

5 files changed

+113
-22
lines changed

src/Compiler/Checking/ConstraintSolver.fs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3939,7 +3939,7 @@ let AddCxTypeEqualsType contextInfo denv css m expected actual =
39393939
PostponeOnFailedMemberConstraintResolution csenv NoTrace
39403940
(fun csenv -> SolveTypeEqualsTypeWithReport csenv 0 m NoTrace None expected actual)
39413941
ErrorD
3942-
|> RaiseOperationResult
3942+
|> ReportOperationResultAndRecover
39433943

39443944
let UndoIfFailed f =
39453945
let trace = Trace.New()
@@ -4005,7 +4005,7 @@ let AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed denv css m extraRigidTypars
40054005
let AddCxTypeMustSubsumeType contextInfo denv css m trace ty1 ty2 =
40064006
let csenv = MakeConstraintSolverEnv contextInfo css m denv
40074007
SolveTypeSubsumesTypeWithReport csenv 0 m trace None None ty1 ty2
4008-
|> RaiseOperationResult
4008+
|> ReportOperationResultAndRecover
40094009

40104010
let AddCxMethodConstraint denv css m trace traitInfo =
40114011
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
@@ -4017,25 +4017,25 @@ let AddCxMethodConstraint denv css m trace traitInfo =
40174017
|> OperationResult.ignore
40184018
})
40194019
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4020-
|> RaiseOperationResult
4020+
|> ReportOperationResultAndRecover
40214021

40224022
let AddCxTypeDefnNotSupportsNull denv css m trace ty =
40234023
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
40244024
PostponeOnFailedMemberConstraintResolution csenv trace
40254025
(fun csenv -> SolveTypeUseNotSupportsNull csenv 0 m trace ty)
40264026
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4027-
|> RaiseOperationResult
4027+
|> ReportOperationResultAndRecover
40284028

40294029
let AddCxTypeUseSupportsNull denv css m trace ty =
40304030
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
40314031
PostponeOnFailedMemberConstraintResolution csenv trace
40324032
(fun csenv -> SolveTypeUseSupportsNull csenv 0 m trace ty)
40334033
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4034-
|> RaiseOperationResult
4034+
|> ReportOperationResultAndRecover
40354035

40364036
let AddCxTypeCanCarryNullnessInfo denv css m ty nullness =
40374037
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
4038-
let canCarryNullnessCheck() = SolveTypeCanCarryNullness csenv ty nullness |> RaiseOperationResult
4038+
let canCarryNullnessCheck() = SolveTypeCanCarryNullness csenv ty nullness |> ReportOperationResultAndRecover
40394039
csenv.SolverState.PushPostInferenceCheck (preDefaults=false, check = canCarryNullnessCheck)
40404040

40414041

@@ -4044,63 +4044,63 @@ let AddCxTypeMustSupportComparison denv css m trace ty =
40444044
PostponeOnFailedMemberConstraintResolution csenv trace
40454045
(fun csenv -> SolveTypeSupportsComparison csenv 0 m trace ty)
40464046
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4047-
|> RaiseOperationResult
4047+
|> ReportOperationResultAndRecover
40484048

40494049
let AddCxTypeMustSupportEquality denv css m trace ty =
40504050
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
40514051
PostponeOnFailedMemberConstraintResolution csenv trace
40524052
(fun csenv -> SolveTypeSupportsEquality csenv 0 m trace ty)
40534053
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4054-
|> RaiseOperationResult
4054+
|> ReportOperationResultAndRecover
40554055

40564056
let AddCxTypeMustSupportDefaultCtor denv css m trace ty =
40574057
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
40584058
PostponeOnFailedMemberConstraintResolution csenv trace
40594059
(fun csenv -> SolveTypeRequiresDefaultConstructor csenv 0 m trace ty)
40604060
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4061-
|> RaiseOperationResult
4061+
|> ReportOperationResultAndRecover
40624062

40634063
let AddCxTypeIsReferenceType denv css m trace ty =
40644064
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
40654065
PostponeOnFailedMemberConstraintResolution csenv trace
40664066
(fun csenv -> SolveTypeIsReferenceType csenv 0 m trace ty)
40674067
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4068-
|> RaiseOperationResult
4068+
|> ReportOperationResultAndRecover
40694069

40704070
let AddCxTypeIsValueType denv css m trace ty =
40714071
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
40724072
PostponeOnFailedMemberConstraintResolution csenv trace
40734073
(fun csenv -> SolveTypeIsNonNullableValueType csenv 0 m trace ty)
40744074
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4075-
|> RaiseOperationResult
4075+
|> ReportOperationResultAndRecover
40764076

40774077
let AddCxTypeIsUnmanaged denv css m trace ty =
40784078
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
40794079
PostponeOnFailedMemberConstraintResolution csenv trace
40804080
(fun csenv -> SolveTypeIsUnmanaged csenv 0 m trace ty)
40814081
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4082-
|> RaiseOperationResult
4082+
|> ReportOperationResultAndRecover
40834083

40844084
let AddCxTypeIsEnum denv css m trace ty underlying =
40854085
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
40864086
PostponeOnFailedMemberConstraintResolution csenv trace
40874087
(fun csenv -> SolveTypeIsEnum csenv 0 m trace ty underlying)
40884088
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4089-
|> RaiseOperationResult
4089+
|> ReportOperationResultAndRecover
40904090

40914091
let AddCxTypeIsDelegate denv css m trace ty aty bty =
40924092
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
40934093
PostponeOnFailedMemberConstraintResolution csenv trace
40944094
(fun csenv -> SolveTypeIsDelegate csenv 0 m trace ty aty bty)
40954095
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4096-
|> RaiseOperationResult
4096+
|> ReportOperationResultAndRecover
40974097

40984098
let AddCxTyparDefaultsTo denv css m ctxtInfo tp ridx ty =
40994099
let csenv = MakeConstraintSolverEnv ctxtInfo css m denv
41004100
PostponeOnFailedMemberConstraintResolution csenv NoTrace
41014101
(fun csenv -> AddConstraint csenv 0 m NoTrace tp (TyparConstraint.DefaultsTo(ridx, ty, m)))
41024102
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4103-
|> RaiseOperationResult
4103+
|> ReportOperationResultAndRecover
41044104

41054105
let SolveTypeAsError denv css m ty =
41064106
let ty2 = NewErrorType ()
@@ -4204,14 +4204,14 @@ let CheckDeclaredTypars denv css m typars1 typars2 =
42044204
ErrorD (ErrorFromAddingConstraint(denv, res, m)))
42054205
|> RaiseOperationResult
42064206

4207-
let CanonicalizePartialInferenceProblem css denv m tps =
4207+
let CanonicalizePartialInferenceProblem (css: ConstraintSolverState) (denv: DisplayEnv) (m: range) (tps: Typar list) : unit =
42084208
// Canonicalize constraints prior to generalization
42094209
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
42104210
let csenv = { csenv with ErrorOnFailedMemberConstraintResolution = true }
42114211
IgnoreFailedMemberConstraintResolution
42124212
(fun () -> CanonicalizeRelevantMemberConstraints csenv 0 NoTrace tps)
42134213
(fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m)))
4214-
|> RaiseOperationResult
4214+
|> ReportOperationResultAndRecover
42154215

42164216
/// An approximation used during name resolution for intellisense to eliminate extension members which will not
42174217
/// apply to a particular object argument. This is given as the isApplicableMeth argument to the partial name resolution

src/Compiler/Facilities/DiagnosticsLogger.fs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,14 @@ let CommitOperationResult res =
665665

666666
let RaiseOperationResult res : unit = CommitOperationResult res
667667

668+
let ReportOperationResultAndRecover (res: OperationResult<unit>) : unit =
669+
match res with
670+
| OkResult(warns, _) ->
671+
ReportWarnings warns
672+
| ErrorResult(warns, err) ->
673+
ReportWarnings warns
674+
errorR err
675+
668676
let inline ErrorD err = ErrorResult([], err)
669677

670678
let inline WarnD err = OkResult([ err ], ())

src/Compiler/Facilities/DiagnosticsLogger.fsi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,8 @@ type ImperativeOperationResult = OperationResult<unit>
351351

352352
val ReportWarnings: warns: #exn list -> unit
353353

354+
val ReportOperationResultAndRecover: res: OperationResult<unit> -> unit
355+
354356
val CommitOperationResult: res: OperationResult<'T> -> 'T
355357

356358
val RaiseOperationResult: res: OperationResult<unit> -> unit

tests/FSharp.Compiler.Service.Tests/Common.fs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -442,14 +442,16 @@ let assertContainsSymbolsWithNames (names: string list) source =
442442
|> Seq.contains name
443443
|> shouldEqual true
444444

445-
let assertHasSymbolUsages (names: string list) (results: FSharpCheckFileResults) =
445+
let assertHasSymbolUsages (expectedNames: string list) (results: FSharpCheckFileResults) =
446+
let symbols =
447+
getSymbolUses results |> getSymbols |> List.ofSeq
448+
446449
let symbolNames =
447-
getSymbolUses results
448-
|> getSymbols
450+
symbols
449451
|> Seq.choose getSymbolName
450452
|> set
451453

452-
for name in names do
454+
for name in expectedNames do
453455
Assert.True(Set.contains name symbolNames, name)
454456

455457
let findSymbolUseByName (name: string) (results: FSharpCheckFileResults) =

tests/FSharp.Compiler.Service.Tests/TypeChecker/TypeCheckerRecoveryTests.fs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,83 @@ Math.Max(a,b,)
4949
"(4,0--4,14)", 503
5050
]
5151

52-
assertHasSymbolUsages ["Max"] checkResults
52+
assertHasSymbolUsages ["Max"] checkResults
53+
54+
module Constraints =
55+
[<Fact>]
56+
let ``Type 01`` () =
57+
let _, checkResults = getParseAndCheckResults """
58+
let f (x: unit) =
59+
x + 1
60+
61+
f ()
62+
"""
63+
assertHasSymbolUsages ["f"; "x"] checkResults
64+
65+
[<Fact>]
66+
let ``Reference 01`` () =
67+
let _, checkResults = getParseAndCheckResults """
68+
let f<'T when 'T : not struct> (x: 'T) =
69+
x
70+
71+
let (i: int) = f<int> 1
72+
"""
73+
assertHasSymbolUsages ["f"; "x"; "i"] checkResults
74+
75+
[<Fact>]
76+
let ``Struct 01`` () =
77+
let _, checkResults = getParseAndCheckResults """
78+
let f<'T when 'T : struct> (x: 'T) =
79+
x
80+
81+
let i = f<obj> 1
82+
"""
83+
assertHasSymbolUsages ["f"; "x"; "i"] checkResults
84+
85+
[<Fact>]
86+
let ``Struct 02`` () =
87+
let _, checkResults = getParseAndCheckResults """
88+
let f<'T when 'T : struct> (x: 'T) =
89+
x
90+
91+
let i = f<obj> Unchecked.defaultof<obj>
92+
"""
93+
assertHasSymbolUsages ["f"; "x"; "defaultof"; "i"] checkResults
94+
95+
[<Fact>]
96+
let ``Struct 03`` () =
97+
let _, checkResults = getParseAndCheckResults """
98+
let f<'T when 'T : struct> (x: 'T) =
99+
x
100+
101+
let i = f Unchecked.defaultof<obj>
102+
"""
103+
assertHasSymbolUsages ["f"; "x"; "defaultof"; "i"] checkResults
104+
105+
[<Fact>]
106+
let ``Equality 01`` () =
107+
let _, checkResults = getParseAndCheckResults """
108+
let f<'T when 'T : equality> (x: 'T) =
109+
x
110+
111+
[<NoEquality>]
112+
type T() =
113+
class end
114+
115+
let i = f<T> Unchecked.defaultof<T>
116+
"""
117+
assertHasSymbolUsages ["f"; "x"; "defaultof"; "i"] checkResults
118+
119+
[<Fact>]
120+
let ``Equality 02`` () =
121+
let _, checkResults = getParseAndCheckResults """
122+
let f<'T when 'T : equality> (x: 'T) =
123+
x
124+
125+
[<NoEquality>]
126+
type T() =
127+
class end
128+
129+
let i = f Unchecked.defaultof<T>
130+
"""
131+
assertHasSymbolUsages ["f"; "x"; "defaultof"; "i"] checkResults

0 commit comments

Comments
 (0)