Skip to content

Commit 5e1f92c

Browse files
committed
Reworked auto trait functionality in rustdoc.
1 parent 136abb9 commit 5e1f92c

File tree

3 files changed

+62
-734
lines changed

3 files changed

+62
-734
lines changed

src/librustc/traits/auto_trait.rs

Lines changed: 27 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ use std::collections::hash_map::Entry;
1515

1616
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1717

18-
use hir::WherePredicate;
19-
2018
use infer::{InferCtxt, RegionObligation};
2119
use infer::region_constraints::{Constraint, RegionConstraintData};
2220

@@ -36,32 +34,42 @@ pub struct RegionDeps<'tcx> {
3634
smaller: FxHashSet<RegionTarget<'tcx>>
3735
}
3836

39-
pub enum AutoTraitResult {
37+
pub enum AutoTraitResult<A> {
4038
ExplicitImpl,
41-
PositiveImpl, /*(ty::Generics), TODO(twk)*/
39+
PositiveImpl(A),
4240
NegativeImpl,
4341
}
4442

45-
impl AutoTraitResult {
43+
impl<A> AutoTraitResult<A> {
4644
fn is_auto(&self) -> bool {
4745
match *self {
48-
AutoTraitResult::PositiveImpl | AutoTraitResult::NegativeImpl => true,
46+
AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true,
4947
_ => false,
5048
}
5149
}
5250
}
5351

52+
pub struct AutoTraitInfo<'cx> {
53+
pub full_user_env: ty::ParamEnv<'cx>,
54+
pub region_data: RegionConstraintData<'cx>,
55+
pub names_map: FxHashMap<String, String>,
56+
pub vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'cx>>,
57+
}
58+
5459
pub struct AutoTraitFinder<'a, 'tcx: 'a> {
5560
pub tcx: &'a TyCtxt<'a, 'tcx, 'tcx>,
5661
}
5762

5863
impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
59-
pub fn find_auto_trait_generics(
64+
pub fn find_auto_trait_generics<A, F>(
6065
&self,
6166
did: DefId,
6267
trait_did: DefId,
6368
generics: &ty::Generics,
64-
) -> AutoTraitResult {
69+
auto_trait_callback: F)
70+
-> AutoTraitResult<A>
71+
where F: for<'b, 'cx, 'cx2> Fn(&InferCtxt<'b, 'cx, 'cx2>, AutoTraitInfo<'cx2>) -> A
72+
{
6573
let tcx = self.tcx;
6674
let ty = self.tcx.type_of(did);
6775

@@ -72,7 +80,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
7280
substs: tcx.mk_substs_trait(ty, &[]),
7381
};
7482

75-
let trait_pred = ty::Binder(trait_ref);
83+
let trait_pred = ty::Binder::bind(trait_ref);
7684

7785
let bail_out = tcx.infer_ctxt().enter(|infcx| {
7886
let mut selcx = SelectionContext::with_negative(&infcx, true);
@@ -149,7 +157,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
149157
None => return AutoTraitResult::NegativeImpl,
150158
};
151159

152-
let (full_env, _full_user_env) = self.evaluate_predicates(
160+
let (full_env, full_user_env) = self.evaluate_predicates(
153161
&mut infcx,
154162
did,
155163
trait_did,
@@ -193,8 +201,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
193201
let names_map: FxHashMap<String, String> = generics
194202
.regions
195203
.iter()
196-
.map(|l| (l.name.as_str().to_string(), l.name.to_string()))
197-
// TODO(twk): Lifetime branding
204+
.map(|l| (l.name.to_string(), l.name.to_string()))
205+
// TODO(twk): Lifetime branding and why is this map a set?!
206+
// l.clean(self.cx) was present in the original code
198207
.collect();
199208

200209
let body_ids: FxHashSet<_> = infcx
@@ -213,33 +222,16 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
213222
.region_constraint_data()
214223
.clone();
215224

216-
let lifetime_predicates = self.handle_lifetimes(&region_data, &names_map);
217225
let vid_to_region = self.map_vid_to_region(&region_data);
218226

219-
debug!(
220-
"find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): computed \
221-
lifetime information '{:?}' '{:?}'",
222-
did, trait_did, generics, lifetime_predicates, vid_to_region
223-
);
227+
let info = AutoTraitInfo { full_user_env, region_data, names_map, vid_to_region };
224228

225-
/* let new_generics = self.param_env_to_generics(
226-
infcx.tcx,
227-
did,
228-
full_user_env,
229-
generics.clone(),
230-
lifetime_predicates,
231-
vid_to_region,
232-
); */
233-
234-
debug!(
235-
"find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): finished with \
236-
<generics placeholder here>",
237-
did, trait_did, generics /* , new_generics */
238-
);
239-
return AutoTraitResult::PositiveImpl;
229+
return AutoTraitResult::PositiveImpl(auto_trait_callback(&infcx, info));
240230
});
241231
}
232+
}
242233

234+
impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
243235
// The core logic responsible for computing the bounds for our synthesized impl.
244236
//
245237
// To calculate the bounds, we call SelectionContext.select in a loop. Like FulfillmentContext,
@@ -294,7 +286,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
294286

295287
let mut already_visited = FxHashSet();
296288
let mut predicates = VecDeque::new();
297-
predicates.push_back(ty::Binder(ty::TraitPredicate {
289+
predicates.push_back(ty::Binder::bind(ty::TraitPredicate {
298290
trait_ref: ty::TraitRef {
299291
def_id: trait_did,
300292
substs: infcx.tcx.mk_substs_trait(ty, &[]),
@@ -359,14 +351,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
359351
new_env = ty::ParamEnv::new(
360352
tcx.mk_predicates(normalized_preds),
361353
param_env.reveal,
362-
ty::UniverseIndex::ROOT,
363354
);
364355
}
365356

366357
let final_user_env = ty::ParamEnv::new(
367358
tcx.mk_predicates(user_computed_preds.into_iter()),
368359
user_env.reveal,
369-
ty::UniverseIndex::ROOT,
370360
);
371361
debug!(
372362
"evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \
@@ -377,165 +367,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
377367
return Some((new_env, final_user_env));
378368
}
379369

380-
// This method calculates two things: Lifetime constraints of the form 'a: 'b,
381-
// and region constraints of the form ReVar: 'a
382-
//
383-
// This is essentially a simplified version of lexical_region_resolve. However,
384-
// handle_lifetimes determines what *needs be* true in order for an impl to hold.
385-
// lexical_region_resolve, along with much of the rest of the compiler, is concerned
386-
// with determining if a given set up constraints/predicates *are* met, given some
387-
// starting conditions (e.g. user-provided code). For this reason, it's easier
388-
// to perform the calculations we need on our own, rather than trying to make
389-
// existing inference/solver code do what we want.
390-
pub fn handle_lifetimes<'cx>(
391-
&self,
392-
regions: &RegionConstraintData<'cx>,
393-
names_map: &FxHashMap<String, String>, // TODO(twk): lifetime branding
394-
) -> Vec<WherePredicate> {
395-
// Our goal is to 'flatten' the list of constraints by eliminating
396-
// all intermediate RegionVids. At the end, all constraints should
397-
// be between Regions (aka region variables). This gives us the information
398-
// we need to create the Generics.
399-
let mut finished = FxHashMap();
400-
401-
let mut vid_map: FxHashMap<RegionTarget, RegionDeps> = FxHashMap();
402-
403-
// Flattening is done in two parts. First, we insert all of the constraints
404-
// into a map. Each RegionTarget (either a RegionVid or a Region) maps
405-
// to its smaller and larger regions. Note that 'larger' regions correspond
406-
// to sub-regions in Rust code (e.g. in 'a: 'b, 'a is the larger region).
407-
for constraint in regions.constraints.keys() {
408-
match constraint {
409-
&Constraint::VarSubVar(r1, r2) => {
410-
{
411-
let deps1 = vid_map
412-
.entry(RegionTarget::RegionVid(r1))
413-
.or_insert_with(|| Default::default());
414-
deps1.larger.insert(RegionTarget::RegionVid(r2));
415-
}
416-
417-
let deps2 = vid_map
418-
.entry(RegionTarget::RegionVid(r2))
419-
.or_insert_with(|| Default::default());
420-
deps2.smaller.insert(RegionTarget::RegionVid(r1));
421-
}
422-
&Constraint::RegSubVar(region, vid) => {
423-
let deps = vid_map
424-
.entry(RegionTarget::RegionVid(vid))
425-
.or_insert_with(|| Default::default());
426-
deps.smaller.insert(RegionTarget::Region(region));
427-
}
428-
&Constraint::VarSubReg(vid, region) => {
429-
let deps = vid_map
430-
.entry(RegionTarget::RegionVid(vid))
431-
.or_insert_with(|| Default::default());
432-
deps.larger.insert(RegionTarget::Region(region));
433-
}
434-
&Constraint::RegSubReg(r1, r2) => {
435-
// The constraint is already in the form that we want, so we're done with it
436-
// Desired order is 'larger, smaller', so flip then
437-
if self.region_name(r1) != self.region_name(r2) {
438-
finished
439-
.entry(self.region_name(r2).unwrap())
440-
.or_insert_with(|| Vec::new())
441-
.push(r1);
442-
}
443-
}
444-
}
445-
}
446-
447-
// Here, we 'flatten' the map one element at a time.
448-
// All of the element's sub and super regions are connected
449-
// to each other. For example, if we have a graph that looks like this:
450-
//
451-
// (A, B) - C - (D, E)
452-
// Where (A, B) are subregions, and (D,E) are super-regions
453-
//
454-
// then after deleting 'C', the graph will look like this:
455-
// ... - A - (D, E ...)
456-
// ... - B - (D, E, ...)
457-
// (A, B, ...) - D - ...
458-
// (A, B, ...) - E - ...
459-
//
460-
// where '...' signifies the existing sub and super regions of an entry
461-
// When two adjacent ty::Regions are encountered, we've computed a final
462-
// constraint, and add it to our list. Since we make sure to never re-add
463-
// deleted items, this process will always finish.
464-
while !vid_map.is_empty() {
465-
let target = vid_map.keys().next().expect("Keys somehow empty").clone();
466-
let deps = vid_map.remove(&target).expect("Entry somehow missing");
467-
468-
for smaller in deps.smaller.iter() {
469-
for larger in deps.larger.iter() {
470-
match (smaller, larger) {
471-
(&RegionTarget::Region(r1), &RegionTarget::Region(r2)) => {
472-
if self.region_name(r1) != self.region_name(r2) {
473-
finished
474-
.entry(self.region_name(r2).unwrap())
475-
.or_insert_with(|| Vec::new())
476-
.push(r1) // Larger, smaller
477-
}
478-
}
479-
(&RegionTarget::RegionVid(_), &RegionTarget::Region(_)) => {
480-
if let Entry::Occupied(v) = vid_map.entry(*smaller) {
481-
let smaller_deps = v.into_mut();
482-
smaller_deps.larger.insert(*larger);
483-
smaller_deps.larger.remove(&target);
484-
}
485-
}
486-
(&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => {
487-
if let Entry::Occupied(v) = vid_map.entry(*larger) {
488-
let deps = v.into_mut();
489-
deps.smaller.insert(*smaller);
490-
deps.smaller.remove(&target);
491-
}
492-
}
493-
(&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
494-
if let Entry::Occupied(v) = vid_map.entry(*smaller) {
495-
let smaller_deps = v.into_mut();
496-
smaller_deps.larger.insert(*larger);
497-
smaller_deps.larger.remove(&target);
498-
}
499-
500-
if let Entry::Occupied(v) = vid_map.entry(*larger) {
501-
let larger_deps = v.into_mut();
502-
larger_deps.smaller.insert(*smaller);
503-
larger_deps.smaller.remove(&target);
504-
}
505-
}
506-
}
507-
}
508-
}
509-
}
510-
511-
let lifetime_predicates = names_map
512-
.iter()
513-
.flat_map(|(name, _lifetime)| {
514-
let empty = Vec::new();
515-
let bounds: FxHashSet<String> = finished // TODO(twk): lifetime branding
516-
.get(name)
517-
.unwrap_or(&empty)
518-
.iter()
519-
.map(|region| self.get_lifetime(region, names_map))
520-
.collect();
521-
522-
if bounds.is_empty() {
523-
return None;
524-
}
525-
/* Some(WherePredicate::RegionPredicate {
526-
lifetime: lifetime.clone(),
527-
bounds: bounds.into_iter().collect(),
528-
}) */
529-
None // TODO(twk): use the correct WherePredicate and rebuild the code above
530-
})
531-
.collect();
532-
533-
lifetime_predicates
534-
}
535-
536370
pub fn region_name(&self, region: Region) -> Option<String> {
537371
match region {
538-
&ty::ReEarlyBound(r) => Some(r.name.as_str().to_string()),
372+
&ty::ReEarlyBound(r) => Some(r.name.to_string()),
539373
_ => None,
540374
}
541375
}

0 commit comments

Comments
 (0)