1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//! The fact API — the one typed query surface of charter #5/#8 (P4-1a).
//!
//! Every analysis a consumer reads is a **fact group**: a table keyed by
//! [`FactGroup::Key`], computed by a registered producer, never a field on a
//! god struct. Consumers **declare** the groups they read as const data
//! ([`FactConsumer::DEMAND`]); a run computes exactly the transitive closure of
//! the declared union, in stratum order, each group at most once per artifact
//! ([`FactManager`]).
//!
//! # Identity
//!
//! A group's identity is a pass-manager [`AnalysisId`], so a pass's
//! [`Preserved`](crate::pass::Preserved) mask names fact groups directly: one
//! identity space, capped by [`MAX_ANALYSES`](crate::pass::MAX_ANALYSES) and
//! its existing const assertion. A [`Demand`] is the same 64-bit shape.
//!
//! # Stratification — demand cycles are unrepresentable
//!
//! A group names a [`FactGroup::STRATUM`] and may depend only on groups in
//! **strictly lower** strata. [`FactRegistry::new`] checks that in a `const
//! fn`, so a registry that breaks it is a compile error; with every edge
//! pointing strictly downwards no cycle can be written down at all (the Swift
//! request-evaluator anti-lesson: cycle detection at run time is a design
//! that already failed).
//!
//! # The undeclared-access detector (TS-35)
//!
//! Under `debug_assertions` a [`FactView`] carries its consumer's declared
//! demand; reading a group outside it returns the exact
//! [`FactError::Undeclared`] and bumps a process-global counter
//! ([`undeclared_accesses`]) even when another consumer's demand happened to
//! compute the table. In release builds the declared demand is a zero-sized
//! type (const-asserted) and the check compiles away.
//!
//! # Example
//!
//! ```
//! use vize_l0::fact::{
//! Demand, FactConsumer, FactGroup, FactManager, FactProducer, FactRegistry, FactTable,
//! FactView, ProducerEntry,
//! };
//! use vize_l0::pass::AnalysisId;
//!
//! /// Stratum 0: the length of every word.
//! struct Lengths;
//! impl FactGroup for Lengths {
//! const ID: AnalysisId = AnalysisId::new(32);
//! const NAME: &'static str = "lengths";
//! const STRATUM: u8 = 0;
//! const DEPENDS: Demand = Demand::NONE;
//! type Key = u32;
//! type Value = usize;
//! }
//! impl FactProducer<[&str]> for Lengths {
//! fn produce(words: &[&str], _: &FactView<'_>) -> FactTable<Self> {
//! (0u32..).zip(words.iter().map(|word| word.len())).collect()
//! }
//! }
//!
//! /// Stratum 1: the longest word, read off `Lengths`.
//! struct Longest;
//! impl FactGroup for Longest {
//! const ID: AnalysisId = AnalysisId::new(33);
//! const NAME: &'static str = "longest";
//! const STRATUM: u8 = 1;
//! const DEPENDS: Demand = Demand::NONE.with(Lengths::ID);
//! type Key = ();
//! type Value = u32;
//! }
//! impl FactProducer<[&str]> for Longest {
//! fn produce(_: &[&str], inputs: &FactView<'_>) -> FactTable<Self> {
//! let lengths = inputs.get::<Lengths>().expect("declared");
//! let longest = lengths.iter().max_by_key(|(_, len)| **len).map(|(at, _)| *at);
//! longest.map(|at| ((), at)).into_iter().collect()
//! }
//! }
//!
//! const REGISTRY: FactRegistry<[&str]> =
//! FactRegistry::new(&[ProducerEntry::of::<Lengths>(), ProducerEntry::of::<Longest>()]);
//!
//! struct LongestWordRule;
//! impl FactConsumer for LongestWordRule {
//! const NAME: &'static str = "longest-word";
//! const DEMAND: Demand = Demand::NONE.with(Longest::ID);
//! }
//!
//! let words: &[&str] = &["fact", "demand", "view"];
//! let mut manager = FactManager::new(®ISTRY);
//! let view = manager.prepare::<LongestWordRule>(words).unwrap();
//! assert_eq!(view.get::<Longest>().unwrap().get(&()), Some(&1));
//! ```
//!
//! # Module layout
//!
//! - [`demand`] — [`Demand`], the const-built group set
//! - [`registry`] — [`GroupDesc`], [`FactRegistry`] and the stratification
//! check
//! - [`table`] — [`FactTable`], the borrowed table a query returns
//! - [`manager`] — [`FactManager`]
//! - [`view`] — [`FactView`], [`FactError`] and the process-global counters
//! - [`preserve`] — facts across passes: [`FactManager::after_pass`], the
//! named preservation groups and the verify mode (P4-1b)
//! - [`ids`] — the production fact-group identity table
//! - [`alpha`] — the α (exported, versioned) form of a group (P4-2)
pub use ;
pub use Demand;
pub use ;
pub use FactManager;
pub use ;
pub use ;
pub use ;
pub use ;
use crateAnalysisId;
/// One fact group: its identity, its stratum, what it reads, and the shape of
/// its table.
///
/// Implemented by a unit type per group. Everything is `const` so the
/// registry can check stratification at compile time and a consumer can
/// build its demand in a `const` item.
/// A consumer of facts: a lint rule, a lowering, a projection, an LSP
/// feature. Its demand is const data, declared once, read by the detector.
/// How a registered producer computes its group over an artifact `A`.
///
/// The producer reads its inputs through a [`FactView`] whose declared
/// demand is its own [`FactGroup::DEPENDS`], so a producer reading a group it
/// did not declare trips the same detector a consumer does.