about summary refs log tree commit diff
path: root/src/librustc_traits/chalk_context/unify.rs
blob: abb4812734123c5d9b35dff708bbcc14e270132a (plain)
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
use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate, NormalizationStrategy};
use rustc::infer::{InferCtxt, RegionVariableOrigin};
use rustc::traits::{DomainGoal, Goal, Environment, InEnvironment};
use rustc::ty::relate::{Relate, TypeRelation, RelateResult};
use rustc::ty;
use syntax_pos::DUMMY_SP;

crate struct UnificationResult<'tcx> {
    crate goals: Vec<InEnvironment<'tcx, Goal<'tcx>>>,
    crate constraints: Vec<super::RegionConstraint<'tcx>>,
}

crate fn unify<'me, 'gcx, 'tcx, T: Relate<'tcx>>(
    infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
    environment: Environment<'tcx>,
    variance: ty::Variance,
    a: &T,
    b: &T
) -> RelateResult<'tcx, UnificationResult<'tcx>> {
    debug!("unify(
        a = {:?},
        b = {:?},
        environment = {:?},
    )", a, b, environment);

    let mut delegate = ChalkTypeRelatingDelegate::new(
        infcx,
        environment
    );

    TypeRelating::new(
        infcx,
        &mut delegate,
        variance
    ).relate(a, b)?;

    debug!("unify: goals = {:?}, constraints = {:?}", delegate.goals, delegate.constraints);

    Ok(UnificationResult {
        goals: delegate.goals,
        constraints: delegate.constraints,
    })
}

struct ChalkTypeRelatingDelegate<'me, 'gcx: 'tcx, 'tcx: 'me> {
    infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
    environment: Environment<'tcx>,
    goals: Vec<InEnvironment<'tcx, Goal<'tcx>>>,
    constraints: Vec<super::RegionConstraint<'tcx>>,
}

impl ChalkTypeRelatingDelegate<'me, 'gcx, 'tcx> {
    fn new(
        infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
        environment: Environment<'tcx>,
    ) -> Self {
        Self {
            infcx,
            environment,
            goals: Vec::new(),
            constraints: Vec::new(),
        }
    }
}

impl TypeRelatingDelegate<'tcx> for &mut ChalkTypeRelatingDelegate<'_, '_, 'tcx> {
    fn create_next_universe(&mut self) -> ty::UniverseIndex {
        self.infcx.create_next_universe()
    }

    fn next_existential_region_var(&mut self) -> ty::Region<'tcx> {
        self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
    }

    fn next_placeholder_region(
        &mut self,
        placeholder: ty::PlaceholderRegion
    ) -> ty::Region<'tcx> {
        self.infcx.tcx.mk_region(ty::RePlaceholder(placeholder))
    }

    fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
        self.infcx.next_region_var_in_universe(
            RegionVariableOrigin::MiscVariable(DUMMY_SP),
            universe
        )
    }

    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
        self.constraints.push(ty::OutlivesPredicate(sup.into(), sub));
    }

    fn push_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>) {
        let goal = self.environment.with(
            self.infcx.tcx.mk_goal(domain_goal.into_goal())
        );
        self.goals.push(goal);
    }

    fn normalization() -> NormalizationStrategy {
        NormalizationStrategy::Lazy
    }

    fn forbid_inference_vars() -> bool {
        false
    }
}