Skip to content
This repository was archived by the owner on Dec 23, 2024. It is now read-only.

Commit 3eb4140

Browse files
dsymenosami
authored andcommitted
Fix 9449 (dotnet#9456)
* alternative fix for 9449 * add test case * fix 9449 properly by assert type equations simultaneously
1 parent 7bc8a68 commit 3eb4140

File tree

4 files changed

+93
-40
lines changed

4 files changed

+93
-40
lines changed

src/fsharp/ConstraintSolver.fs

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,6 @@ type ConstraintSolverState =
245245
/// The function used to freshen values we encounter during trait constraint solving
246246
TcVal: TcValF
247247

248-
/// Indicates if the constraint solver is being run after type checking is complete,
249-
/// e.g. during codegen to determine solutions and witnesses for trait constraints.
250-
/// Suppresses the generation of certain errors such as missing constraint warnings.
251-
codegen: bool
252-
253248
/// This table stores all unsolved, ungeneralized trait constraints, indexed by free type variable.
254249
/// That is, there will be one entry in this table for each free type variable in
255250
/// each outstanding, unsolved, ungeneralized trait constraint. Constraints are removed from the table and resolved
@@ -262,7 +257,6 @@ type ConstraintSolverState =
262257
amap = amap
263258
ExtraCxs = HashMultiMap(10, HashIdentity.Structural)
264259
InfoReader = infoReader
265-
codegen = false
266260
TcVal = tcVal }
267261

268262
type ConstraintSolverEnv =
@@ -867,34 +861,31 @@ let CheckWarnIfRigid (csenv: ConstraintSolverEnv) ty1 (r: Typar) ty =
867861

868862
/// Add the constraint "ty1 = ty" to the constraint problem, where ty1 is a type variable.
869863
/// Propagate all effects of adding this constraint, e.g. to solve other variables
870-
let rec SolveTyparEqualsType (csenv: ConstraintSolverEnv) ndeep m2 (trace: OptionalTrace) ty1 ty = trackErrors {
871-
let m = csenv.m
872-
do! DepthCheck ndeep m
873-
match ty1 with
874-
| TType_var r | TType_measure (Measure.Var r) ->
875-
// The types may still be equivalent due to abbreviations, which we are trying not to eliminate
876-
if typeEquiv csenv.g ty1 ty then () else
877-
// The famous 'occursCheck' check to catch "infinite types" like 'a = list<'a> - see also https://github.com/Microsoft/visualfsharp/issues/1170
878-
if occursCheck csenv.g r ty then return! ErrorD (ConstraintSolverInfiniteTypes(csenv.DisplayEnv, csenv.eContextInfo, ty1, ty, m, m2)) else
879-
// Note: warn _and_ continue!
880-
do! CheckWarnIfRigid csenv ty1 r ty
881-
// Record the solution before we solve the constraints, since
882-
// We may need to make use of the equation when solving the constraints.
883-
// Record a entry in the undo trace if one is provided
884-
trace.Exec (fun () -> r.typar_solution <- Some ty) (fun () -> r.typar_solution <- None)
885-
886-
// Only solve constraints if this is not an error var
887-
if r.IsFromError then () else
888-
889-
// Check to see if this type variable is relevant to any trait constraints.
890-
// If so, re-solve the relevant constraints.
891-
if csenv.SolverState.ExtraCxs.ContainsKey r.Stamp then
892-
do! RepeatWhileD ndeep (fun ndeep -> SolveRelevantMemberConstraintsForTypar csenv ndeep PermitWeakResolution.No trace r)
864+
let rec SolveTyparEqualsTypePart1 (csenv: ConstraintSolverEnv) m2 (trace: OptionalTrace) ty1 r ty = trackErrors {
865+
// The types may still be equivalent due to abbreviations, which we are trying not to eliminate
866+
if typeEquiv csenv.g ty1 ty then () else
867+
// The famous 'occursCheck' check to catch "infinite types" like 'a = list<'a> - see also https://github.com/Microsoft/visualfsharp/issues/1170
868+
if occursCheck csenv.g r ty then return! ErrorD (ConstraintSolverInfiniteTypes(csenv.DisplayEnv, csenv.eContextInfo, ty1, ty, csenv.m, m2)) else
869+
// Note: warn _and_ continue!
870+
do! CheckWarnIfRigid csenv ty1 r ty
871+
// Record the solution before we solve the constraints, since
872+
// We may need to make use of the equation when solving the constraints.
873+
// Record a entry in the undo trace if one is provided
874+
trace.Exec (fun () -> r.typar_solution <- Some ty) (fun () -> r.typar_solution <- None)
875+
}
876+
877+
and SolveTyparEqualsTypePart2 (csenv: ConstraintSolverEnv) ndeep m2 (trace: OptionalTrace) (r: Typar) ty = trackErrors {
878+
// Only solve constraints if this is not an error var
879+
if r.IsFromError then () else
880+
881+
// Check to see if this type variable is relevant to any trait constraints.
882+
// If so, re-solve the relevant constraints.
883+
if csenv.SolverState.ExtraCxs.ContainsKey r.Stamp then
884+
do! RepeatWhileD ndeep (fun ndeep -> SolveRelevantMemberConstraintsForTypar csenv ndeep PermitWeakResolution.No trace r)
885+
886+
// Re-solve the other constraints associated with this type variable
887+
return! solveTypMeetsTyparConstraints csenv ndeep m2 trace ty r
893888

894-
// Re-solve the other constraints associated with this type variable
895-
return! solveTypMeetsTyparConstraints csenv ndeep m2 trace ty r
896-
897-
| _ -> failwith "SolveTyparEqualsType"
898889
}
899890

900891
/// Apply the constraints on 'typar' to the type 'ty'
@@ -939,6 +930,28 @@ and solveTypMeetsTyparConstraints (csenv: ConstraintSolverEnv) ndeep m2 trace ty
939930
}
940931

941932

933+
and SolveTyparEqualsType (csenv: ConstraintSolverEnv) ndeep m2 (trace: OptionalTrace) ty1 ty = trackErrors {
934+
let m = csenv.m
935+
do! DepthCheck ndeep m
936+
match ty1 with
937+
| TType_var r | TType_measure (Measure.Var r) ->
938+
do! SolveTyparEqualsTypePart1 csenv m2 trace ty1 r ty
939+
do! SolveTyparEqualsTypePart2 csenv ndeep m2 trace r ty
940+
| _ -> failwith "SolveTyparEqualsType"
941+
}
942+
943+
// Like SolveTyparEqualsType but asserts all typar equalities simultaneously instead of one by one
944+
and SolveTyparsEqualTypes (csenv: ConstraintSolverEnv) ndeep m2 (trace: OptionalTrace) tptys tys = trackErrors {
945+
do! (tptys, tys) ||> Iterate2D (fun tpty ty ->
946+
match tpty with
947+
| TType_var r | TType_measure (Measure.Var r) -> SolveTyparEqualsTypePart1 csenv m2 trace tpty r ty
948+
| _ -> failwith "SolveTyparsEqualTypes")
949+
do! (tptys, tys) ||> Iterate2D (fun tpty ty ->
950+
match tpty with
951+
| TType_var r | TType_measure (Measure.Var r) -> SolveTyparEqualsTypePart2 csenv ndeep m2 trace r ty
952+
| _ -> failwith "SolveTyparsEqualTypes")
953+
}
954+
942955
and SolveAnonInfoEqualsAnonInfo (csenv: ConstraintSolverEnv) m2 (anonInfo1: AnonRecdTypeInfo) (anonInfo2: AnonRecdTypeInfo) =
943956
if evalTupInfoIsStruct anonInfo1.TupInfo <> evalTupInfoIsStruct anonInfo2.TupInfo then ErrorD (ConstraintSolverError(FSComp.SR.tcTupleStructMismatch(), csenv.m,m2)) else
944957
(match anonInfo1.Assembly, anonInfo2.Assembly with
@@ -1945,14 +1958,14 @@ and AddConstraint (csenv: ConstraintSolverEnv) ndeep m2 trace tp newConstraint
19451958
| (TyparRigidity.Rigid | TyparRigidity.WillBeRigid), TyparConstraint.DefaultsTo _ -> true
19461959
| _ -> false) then
19471960
()
1948-
elif tp.Rigidity = TyparRigidity.Rigid && not csenv.SolverState.codegen then
1961+
elif tp.Rigidity = TyparRigidity.Rigid then
19491962
return! ErrorD (ConstraintSolverMissingConstraint(denv, tp, newConstraint, m, m2))
19501963
else
19511964
// It is important that we give a warning if a constraint is missing from a
19521965
// will-be-made-rigid type variable. This is because the existence of these warnings
19531966
// is relevant to the overload resolution rules (see 'candidateWarnCount' in the overload resolution
19541967
// implementation).
1955-
if tp.Rigidity.WarnIfMissingConstraint && not csenv.SolverState.codegen then
1968+
if tp.Rigidity.WarnIfMissingConstraint then
19561969
do! WarnD (ConstraintSolverMissingConstraint(denv, tp, newConstraint, m, m2))
19571970

19581971
let newConstraints =
@@ -3065,8 +3078,7 @@ let CreateCodegenState tcVal g amap =
30653078
amap = amap
30663079
TcVal = tcVal
30673080
ExtraCxs = HashMultiMap(10, HashIdentity.Structural)
3068-
InfoReader = new InfoReader(g, amap)
3069-
codegen = true }
3081+
InfoReader = new InfoReader(g, amap) }
30703082

30713083
/// Generate a witness expression if none is otherwise available, e.g. in legacy non-witness-passing code
30723084
let CodegenWitnessForTraitConstraint tcVal g amap m (traitInfo:TraitConstraintInfo) argExprs = trackErrors {
@@ -3083,7 +3095,7 @@ let CodegenWitnessesForTyparInst tcVal g amap m typars tyargs = trackErrors {
30833095
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m (DisplayEnv.Empty g)
30843096
let ftps, _renaming, tinst = FreshenTypeInst m typars
30853097
let traitInfos = GetTraitConstraintInfosOfTypars g ftps
3086-
do! SolveTypeEqualsTypeEqns csenv 0 m NoTrace None tinst tyargs
3098+
do! SolveTyparsEqualTypes csenv 0 m NoTrace tinst tyargs
30873099
return MethodCalls.GenWitnessArgs amap g m traitInfos
30883100
}
30893101

@@ -3140,7 +3152,6 @@ let IsApplicableMethApprox g amap m (minfo: MethInfo) availObjTy =
31403152
amap = amap
31413153
TcVal = (fun _ -> failwith "should not be called")
31423154
ExtraCxs = HashMultiMap(10, HashIdentity.Structural)
3143-
codegen = false
31443155
InfoReader = new InfoReader(g, amap) }
31453156
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m (DisplayEnv.Empty g)
31463157
let minst = FreshenMethInfo m minfo

tests/fsharp/tests.fs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#load "../FSharp.Test.Utilities/TestFramework.fs"
66
#load "single-test.fs"
77
#else
8-
module ``FSharp-Tests-Core``
8+
module FSharp.Tests.Core
99
#endif
1010

1111
open System
@@ -2204,6 +2204,15 @@ module TypecheckTests =
22042204
fsc cfg "%s --target:library -o:pos35.dll --warnaserror" cfg.fsc_flags ["pos35.fs"]
22052205
peverify cfg "pos35.dll"
22062206

2207+
[<Test>]
2208+
let ``sigs pos36-srtp`` () =
2209+
let cfg = testConfig' "typecheck/sigs"
2210+
fsc cfg "%s --target:library -o:pos36-srtp-lib.dll --warnaserror" cfg.fsc_flags ["pos36-srtp-lib.fs"]
2211+
fsc cfg "%s --target:exe -r:pos36-srtp-lib.dll -o:pos36-srtp-app.exe --warnaserror" cfg.fsc_flags ["pos36-srtp-app.fs"]
2212+
peverify cfg "pos36-srtp-lib.dll"
2213+
peverify cfg "pos36-srtp-app.exe"
2214+
exec cfg ("." ++ "pos36-srtp-app.exe") ""
2215+
22072216
[<Test>]
22082217
let ``sigs pos23`` () =
22092218
let cfg = testConfig' "typecheck/sigs"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Pos36
2+
3+
open Lib
4+
5+
let check msg x y = if x = y then printfn "passed %s" msg else failwithf "failed '%s'" msg
6+
7+
let tbind () =
8+
check "vwknvewoiwvren1" (StaticMethods.M(C(3))) "M(C), x = 3"
9+
check "vwknvewoiwvren2" (StaticMethods.M(3L)) "M(int64), x = 3"
10+
11+
tbind()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
3+
module Lib
4+
5+
let inline RequireM< ^Witnesses, ^T when (^Witnesses or ^T): (static member M : ^T -> string) > (x: ^T) : string =
6+
((^Witnesses or ^T): (static member M : ^T -> string) x)
7+
8+
type C(p:int) =
9+
member x.P = p
10+
11+
type Witnesses() =
12+
13+
static member M (x: C) : string = sprintf "M(C), x = %d" x.P
14+
15+
static member M (x: int64) : string = sprintf "M(int64), x = %d" x
16+
17+
type StaticMethods =
18+
19+
static member inline M< ^T when (Witnesses or ^T): (static member M: ^T -> string)> (x: ^T) : string =
20+
21+
RequireM< Witnesses, ^T> (x)
22+

0 commit comments

Comments
 (0)