Skip to content

Commit 77447de

Browse files
varkoryodaldevoid
andcommitted
Add const_variable.rs
Co-Authored-By: Gabriel Smith <[email protected]>
1 parent 2254727 commit 77447de

File tree

1 file changed

+242
-0
lines changed

1 file changed

+242
-0
lines changed

src/librustc/infer/const_variable.rs

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
use crate::mir::interpret::ConstValue;
2+
use syntax::symbol::InternedString;
3+
use syntax_pos::Span;
4+
use crate::ty::{self, InferConst};
5+
6+
use std::cmp;
7+
use std::marker::PhantomData;
8+
use rustc_data_structures::snapshot_vec as sv;
9+
use rustc_data_structures::unify as ut;
10+
11+
pub struct ConstVariableTable<'tcx> {
12+
values: sv::SnapshotVec<Delegate<'tcx>>,
13+
14+
relations: ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>,
15+
}
16+
17+
/// Reasons to create a const inference variable
18+
#[derive(Copy, Clone, Debug)]
19+
pub enum ConstVariableOrigin {
20+
MiscVariable(Span),
21+
ConstInference(Span),
22+
ConstParameterDefinition(Span, InternedString),
23+
SubstitutionPlaceholder(Span),
24+
}
25+
26+
struct ConstVariableData {
27+
origin: ConstVariableOrigin,
28+
}
29+
30+
#[derive(Copy, Clone, Debug)]
31+
pub enum ConstVariableValue<'tcx> {
32+
Known { value: &'tcx ty::LazyConst<'tcx> },
33+
Unknown { universe: ty::UniverseIndex },
34+
}
35+
36+
impl<'tcx> ConstVariableValue<'tcx> {
37+
/// If this value is known, returns the const it is known to be.
38+
/// Otherwise, `None`.
39+
pub fn known(&self) -> Option<&'tcx ty::LazyConst<'tcx>> {
40+
match *self {
41+
ConstVariableValue::Unknown { .. } => None,
42+
ConstVariableValue::Known { value } => Some(value),
43+
}
44+
}
45+
46+
pub fn is_unknown(&self) -> bool {
47+
match *self {
48+
ConstVariableValue::Unknown { .. } => true,
49+
ConstVariableValue::Known { .. } => false,
50+
}
51+
}
52+
}
53+
54+
pub struct Snapshot<'tcx> {
55+
snapshot: sv::Snapshot,
56+
relation_snapshot: ut::Snapshot<ut::InPlace<ty::ConstVid<'tcx>>>,
57+
}
58+
59+
struct Instantiate<'tcx> {
60+
_vid: ty::ConstVid<'tcx>,
61+
}
62+
63+
struct Delegate<'tcx> {
64+
pub phantom: PhantomData<&'tcx ()>,
65+
}
66+
67+
impl<'tcx> ConstVariableTable<'tcx> {
68+
pub fn new() -> ConstVariableTable<'tcx> {
69+
ConstVariableTable {
70+
values: sv::SnapshotVec::new(),
71+
relations: ut::UnificationTable::new(),
72+
}
73+
}
74+
75+
/// Returns the origin that was given when `vid` was created.
76+
///
77+
/// Note that this function does not return care whether
78+
/// `vid` has been unified with something else or not.
79+
pub fn var_origin(&self, vid: ty::ConstVid<'tcx>) -> &ConstVariableOrigin {
80+
&self.values[vid.index as usize].origin
81+
}
82+
83+
pub fn unify_var_var(
84+
&mut self,
85+
a_id: ty::ConstVid<'tcx>,
86+
b_id: ty::ConstVid<'tcx>,
87+
) -> Result<(), (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>)> {
88+
self.relations.unify_var_var(a_id, b_id)
89+
}
90+
91+
pub fn unify_var_value(
92+
&mut self,
93+
a_id: ty::ConstVid<'tcx>,
94+
b: ConstVariableValue<'tcx>,
95+
) -> Result<(), (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>)> {
96+
self.relations.unify_var_value(a_id, b)
97+
}
98+
99+
/// Creates a new const variable.
100+
///
101+
/// - `origin`: indicates *why* the const variable was created.
102+
/// The code in this module doesn't care, but it can be useful
103+
/// for improving error messages.
104+
pub fn new_var(
105+
&mut self,
106+
universe: ty::UniverseIndex,
107+
origin: ConstVariableOrigin,
108+
) -> ty::ConstVid<'tcx> {
109+
let vid = self.relations.new_key(ConstVariableValue::Unknown{ universe });
110+
111+
let index = self.values.push(ConstVariableData {
112+
origin,
113+
});
114+
assert_eq!(vid.index, index as u32);
115+
116+
debug!("new_var(index={:?}, origin={:?}", vid, origin);
117+
118+
vid
119+
}
120+
121+
/// Retrieves the type to which `vid` has been instantiated, if
122+
/// any.
123+
pub fn probe(
124+
&mut self,
125+
vid: ty::ConstVid<'tcx>
126+
) -> ConstVariableValue<'tcx> {
127+
self.relations.probe_value(vid)
128+
}
129+
130+
/// If `t` is a type-inference variable, and it has been
131+
/// instantiated, then return the with which it was
132+
/// instantiated. Otherwise, returns `t`.
133+
pub fn replace_if_possible(
134+
&mut self,
135+
c: &'tcx ty::LazyConst<'tcx>
136+
) -> &'tcx ty::LazyConst<'tcx> {
137+
if let ty::LazyConst::Evaluated(ty::Const {
138+
val: ConstValue::Infer(InferConst::Var(vid)),
139+
..
140+
}) = c {
141+
match self.probe(*vid).known() {
142+
Some(c) => c,
143+
None => c,
144+
}
145+
} else {
146+
c
147+
}
148+
}
149+
150+
/// Creates a snapshot of the type variable state. This snapshot
151+
/// must later be committed (`commit()`) or rolled back
152+
/// (`rollback_to()`). Nested snapshots are permitted, but must
153+
/// be processed in a stack-like fashion.
154+
pub fn snapshot(&mut self) -> Snapshot<'tcx> {
155+
Snapshot {
156+
snapshot: self.values.start_snapshot(),
157+
relation_snapshot: self.relations.snapshot(),
158+
}
159+
}
160+
161+
/// Undoes all changes since the snapshot was created. Any
162+
/// snapshots created since that point must already have been
163+
/// committed or rolled back.
164+
pub fn rollback_to(&mut self, s: Snapshot<'tcx>) {
165+
debug!("rollback_to{:?}", {
166+
for action in self.values.actions_since_snapshot(&s.snapshot) {
167+
if let sv::UndoLog::NewElem(index) = *action {
168+
debug!("inference variable _#{}t popped", index)
169+
}
170+
}
171+
});
172+
173+
let Snapshot { snapshot, relation_snapshot } = s;
174+
self.values.rollback_to(snapshot);
175+
self.relations.rollback_to(relation_snapshot);
176+
}
177+
178+
/// Commits all changes since the snapshot was created, making
179+
/// them permanent (unless this snapshot was created within
180+
/// another snapshot). Any snapshots created since that point
181+
/// must already have been committed or rolled back.
182+
pub fn commit(&mut self, s: Snapshot<'tcx>) {
183+
let Snapshot { snapshot, relation_snapshot } = s;
184+
self.values.commit(snapshot);
185+
self.relations.commit(relation_snapshot);
186+
}
187+
}
188+
189+
impl<'tcx> ut::UnifyKey for ty::ConstVid<'tcx> {
190+
type Value = ConstVariableValue<'tcx>;
191+
fn index(&self) -> u32 { self.index }
192+
fn from_index(i: u32) -> Self { ty::ConstVid { index: i, phantom: PhantomData } }
193+
fn tag() -> &'static str { "ConstVid" }
194+
}
195+
196+
impl<'tcx> ut::UnifyValue for ConstVariableValue<'tcx> {
197+
type Error = (&'tcx ty::LazyConst<'tcx>, &'tcx ty::LazyConst<'tcx>);
198+
199+
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
200+
match (value1, value2) {
201+
(
202+
&ConstVariableValue::Known { value: value1 },
203+
&ConstVariableValue::Known { value: value2 }
204+
) => {
205+
match <&'tcx ty::LazyConst<'tcx>>::unify_values(&value1, &value2) {
206+
Ok(value) => Ok(ConstVariableValue::Known { value }),
207+
Err(err) => Err(err),
208+
}
209+
}
210+
211+
// If one side is known, prefer that one.
212+
(&ConstVariableValue::Known { .. }, &ConstVariableValue::Unknown { .. }) => Ok(*value1),
213+
(&ConstVariableValue::Unknown { .. }, &ConstVariableValue::Known { .. }) => Ok(*value2),
214+
215+
// If both sides are *unknown*, it hardly matters, does it?
216+
(&ConstVariableValue::Unknown { universe: universe1 },
217+
&ConstVariableValue::Unknown { universe: universe2 }) => {
218+
// If we unify two unbound variables, ?T and ?U, then whatever
219+
// value they wind up taking (which must be the same value) must
220+
// be nameable by both universes. Therefore, the resulting
221+
// universe is the minimum of the two universes, because that is
222+
// the one which contains the fewest names in scope.
223+
let universe = cmp::min(universe1, universe2);
224+
Ok(ConstVariableValue::Unknown { universe })
225+
}
226+
}
227+
}
228+
}
229+
230+
impl<'tcx> ut::EqUnifyValue for &'tcx ty::LazyConst<'tcx> {}
231+
232+
impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
233+
type Value = ConstVariableData;
234+
type Undo = Instantiate<'tcx>;
235+
236+
fn reverse(_values: &mut Vec<ConstVariableData>, _action: Instantiate<'tcx>) {
237+
// We don't actually have to *do* anything to reverse an
238+
// instantiation; the value for a variable is stored in the
239+
// `relations` and hence its rollback code will handle
240+
// it.
241+
}
242+
}

0 commit comments

Comments
 (0)