Skip to content

Commit 7b29b0f

Browse files
dsymebaronfel
authored andcommitted
Fix 9449 (#9456)
* alternative fix for 9449 * add test case * fix 9449 properly by assert type equations simultaneously
1 parent 204fd35 commit 7b29b0f

File tree

1 file changed

+50
-39
lines changed

1 file changed

+50
-39
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

0 commit comments

Comments
 (0)