diff options
| author | barras | 2012-10-17 02:35:08 +0000 |
|---|---|---|
| committer | barras | 2012-10-17 02:35:08 +0000 |
| commit | 9834fe8ac933230607eb33c9cbbaa68a7b13f4fe (patch) | |
| tree | eba7cac3370d517aa0bf48a76e383a902426e894 /kernel | |
| parent | 927b92eb8e1abf7ff1978f812b602b276d69dd27 (diff) | |
univ inconsistency error message gives evidence of a cycle
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@15898 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/univ.ml | 92 | ||||
| -rw-r--r-- | kernel/univ.mli | 17 |
2 files changed, 74 insertions, 35 deletions
diff --git a/kernel/univ.ml b/kernel/univ.ml index f1fc8bda50..39cb6bc102 100644 --- a/kernel/univ.ml +++ b/kernel/univ.ml @@ -137,7 +137,9 @@ let sup u v = (* Comparison on this type is pointer equality *) type canonical_arc = - { univ: UniverseLevel.t; lt: UniverseLevel.t list; le: UniverseLevel.t list } + { univ: UniverseLevel.t; + lt: UniverseLevel.t list; + le: UniverseLevel.t list } let terminal u = {univ=u; lt=[]; le=[]} @@ -267,8 +269,17 @@ let between g arcu arcv = Otherwise, between g u v = [] *) +type constraint_type = Lt | Le | Eq +type explanation = (constraint_type * universe) list + +(* Assuming the current universe has been reached by [p] and [l] + correspond to the universes in (direct) relation [rel] with it, + make a list of canonical universe, updating the relation with + the starting point (path stored in reverse order). *) +let canp g (p:explanation) rel l : (canonical_arc * explanation) list = + List.map (fun u -> (repr g u, (rel,Atom u)::p)) l -type order = EQ | LT | LE | NLE +type order = EQ | LT of explanation | LE of explanation | NLE (** [compare_neq] : is [arcv] in the transitive upward closure of [arcu] ? @@ -291,43 +302,54 @@ type order = EQ | LT | LE | NLE *) let compare_neq strict g arcu arcv = + (* [c] characterizes whether (and how) arcv has already been related + to arcu among the lt_done,le_done universe *) let rec cmp c lt_done le_done = function | [],[] -> c - | arc::lt_todo, le_todo -> + | (arc,p)::lt_todo, le_todo -> if List.memq arc lt_done then cmp c lt_done le_done (lt_todo,le_todo) else - let lt_new = can g (arc.lt@arc.le) in - if List.memq arcv lt_new then - if strict then LT else LE - else cmp c (arc::lt_done) le_done (lt_new@lt_todo,le_todo) - | [], arc::le_todo -> + let lt_new = canp g p Lt arc.lt@ canp g p Le arc.le in + (try + let p = List.assq arcv lt_new in + if strict then LT p else LE p + with Not_found -> + cmp c (arc::lt_done) le_done (lt_new@lt_todo,le_todo)) + | [], (arc,p)::le_todo -> if arc == arcv then (* No need to continue inspecting universes above arc: if arcv is strictly above arc, then we would have a cycle. But we cannot answer LE yet, a stronger constraint may come later from [le_todo]. *) - if strict then cmp LE lt_done le_done ([],le_todo) else LE + if strict then cmp (LE p) lt_done le_done ([],le_todo) else LE p else if (List.memq arc lt_done) || (List.memq arc le_done) then cmp c lt_done le_done ([],le_todo) else - let lt_new = can g arc.lt in - if List.memq arcv lt_new then - if strict then LT else LE - else - let le_new = can g arc.le in - cmp c lt_done (arc::le_done) (lt_new, le_new@le_todo) + let lt_new = canp g p Lt arc.lt in + (try + let p = List.assq arcv lt_new in + if strict then LT p else LE p + with Not_found -> + let le_new = canp g p Le arc.le in + cmp c lt_done (arc::le_done) (lt_new, le_new@le_todo)) in - cmp NLE [] [] ([],[arcu]) + cmp NLE [] [] ([],[arcu,[]]) let compare g arcu arcv = if arcu == arcv then EQ else compare_neq true g arcu arcv let is_leq g arcu arcv = - arcu == arcv || (compare_neq false g arcu arcv = LE) + arcu == arcv || + (match compare_neq false g arcu arcv with + NLE -> false + | (EQ|LE _|LT _) -> true) -let is_lt g arcu arcv = (compare g arcu arcv = LT) +let is_lt g arcu arcv = + match compare g arcu arcv with + LT _ -> true + | (EQ|LE _|NLE) -> false (* Invariants : compare(u,v) = EQ <=> compare(v,u) = EQ compare(u,v) = LT or LE => compare(v,u) = NLE @@ -385,7 +407,7 @@ let check_leq g u v = (** Enforcing new constraints : [setlt], [setleq], [merge], [merge_disc] *) -(* setlt : UniverseLevel.t -> UniverseLevel.t -> unit *) +(* setlt : UniverseLevel.t -> UniverseLevel.t -> reason -> unit *) (* forces u > v *) (* this is normally an update of u in g rather than a creation. *) let setlt g arcu arcv = @@ -443,11 +465,11 @@ let merge_disc g arcu arcv = (* Universe inconsistency: error raised when trying to enforce a relation that would create a cycle in the graph of universes. *) -type constraint_type = Lt | Le | Eq - -exception UniverseInconsistency of constraint_type * universe * universe +exception UniverseInconsistency of + constraint_type * universe * universe * explanation -let error_inconsistency o u v = raise (UniverseInconsistency (o,Atom u,Atom v)) +let error_inconsistency o u v (p:explanation) = + raise (UniverseInconsistency (o,Atom u,Atom v,p)) (* enforce_univ_leq : UniverseLevel.t -> UniverseLevel.t -> unit *) (* enforce_univ_leq u v will force u<=v if possible, will fail otherwise *) @@ -456,8 +478,8 @@ let enforce_univ_leq u v g = let g,arcv = safe_repr g v in if is_leq g arcu arcv then g else match compare g arcv arcu with - | LT -> error_inconsistency Le u v - | LE -> merge g arcv arcu + | LT p -> error_inconsistency Le u v (List.rev p) + | LE _ -> merge g arcv arcu | NLE -> fst (setleq g arcu arcv) | EQ -> anomaly "Univ.compare" @@ -468,12 +490,12 @@ let enforce_univ_eq u v g = let g,arcv = safe_repr g v in match compare g arcu arcv with | EQ -> g - | LT -> error_inconsistency Eq u v - | LE -> merge g arcu arcv + | LT p -> error_inconsistency Eq u v (List.rev p) + | LE _ -> merge g arcu arcv | NLE -> (match compare g arcv arcu with - | LT -> error_inconsistency Eq u v - | LE -> merge g arcv arcu + | LT p -> error_inconsistency Eq u v (List.rev p) + | LE _ -> merge g arcv arcu | NLE -> merge_disc g arcu arcv | EQ -> anomaly "Univ.compare") @@ -482,12 +504,14 @@ let enforce_univ_lt u v g = let g,arcu = safe_repr g u in let g,arcv = safe_repr g v in match compare g arcu arcv with - | LT -> g - | LE -> fst (setlt g arcu arcv) - | EQ -> error_inconsistency Lt u v + | LT _ -> g + | LE _ -> fst (setlt g arcu arcv) + | EQ -> error_inconsistency Lt u v [(Eq,Atom v)] | NLE -> - if is_leq g arcv arcu then error_inconsistency Lt u v - else fst (setlt g arcu arcv) + (match compare_neq false g arcv arcu with + NLE -> fst (setlt g arcu arcv) + | EQ -> anomaly "Univ.compare" + | (LE p|LT p) -> error_inconsistency Lt u v (List.rev p)) (* Constraints and sets of consrtaints. *) diff --git a/kernel/univ.mli b/kernel/univ.mli index a1c1bb2065..c53a3c54d5 100644 --- a/kernel/univ.mli +++ b/kernel/univ.mli @@ -71,7 +71,22 @@ val enforce_eq : constraint_function type constraint_type = Lt | Le | Eq -exception UniverseInconsistency of constraint_type * universe * universe +(** Type explanation is used to decorate error messages to provide + useful explanation why a given constraint is rejected. It is composed + of a path of universes and relation kinds [(r1,u1);..;(rn,un)] means + .. <(r1) u1 <(r2) ... <(rn) un (where <(ri) is the relation symbol + denoted by ri, currently only < and <=). The lowest end of the chain + is supposed known (see UniverseInconsistency exn). The upper end may + differ from the second univ of UniverseInconsistency because all + universes in the path are canonical. Note that each step does not + necessarily correspond to an actual constraint, but reflect how the + system stores the graph and may result from combination of several + constraints... +*) +type explanation = (constraint_type * universe) list + +exception UniverseInconsistency of + constraint_type * universe * universe * explanation val merge_constraints : constraints -> universes -> universes val normalize_universes : universes -> universes |
