]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/variance/solve.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_typeck / variance / solve.rs
CommitLineData
7453a54e
SL
1// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Constraint solving
12//!
13//! The final phase iterates over the constraints, refining the variance
14//! for each inferred until a fixed point is reached. This will be the
15//! optimal solution to the constraints. The final variance for each
16//! inferred is then written into the `variance_map` in the tcx.
17
54a0048b
SL
18use rustc::ty::subst::VecPerParamSpace;
19use rustc::ty;
7453a54e
SL
20use std::rc::Rc;
21
22use super::constraints::*;
23use super::terms::*;
24use super::terms::VarianceTerm::*;
25use super::terms::ParamKind::*;
26use super::xform::*;
27
28struct SolveContext<'a, 'tcx: 'a> {
29 terms_cx: TermsContext<'a, 'tcx>,
30 constraints: Vec<Constraint<'a>> ,
31
32 // Maps from an InferredIndex to the inferred value for that variable.
33 solutions: Vec<ty::Variance>
34}
35
36pub fn solve_constraints(constraints_cx: ConstraintContext) {
37 let ConstraintContext { terms_cx, constraints, .. } = constraints_cx;
38
39 let solutions =
40 terms_cx.inferred_infos.iter()
41 .map(|ii| ii.initial_variance)
42 .collect();
43
44 let mut solutions_cx = SolveContext {
45 terms_cx: terms_cx,
46 constraints: constraints,
47 solutions: solutions
48 };
49 solutions_cx.solve();
50 solutions_cx.write();
51}
52
53impl<'a, 'tcx> SolveContext<'a, 'tcx> {
54 fn solve(&mut self) {
55 // Propagate constraints until a fixed point is reached. Note
56 // that the maximum number of iterations is 2C where C is the
57 // number of constraints (each variable can change values at most
58 // twice). Since number of constraints is linear in size of the
59 // input, so is the inference process.
60 let mut changed = true;
61 while changed {
62 changed = false;
63
64 for constraint in &self.constraints {
65 let Constraint { inferred, variance: term } = *constraint;
66 let InferredIndex(inferred) = inferred;
67 let variance = self.evaluate(term);
68 let old_value = self.solutions[inferred];
69 let new_value = glb(variance, old_value);
70 if old_value != new_value {
71 debug!("Updating inferred {} (node {}) \
72 from {:?} to {:?} due to {:?}",
73 inferred,
74 self.terms_cx
75 .inferred_infos[inferred]
76 .param_id,
77 old_value,
78 new_value,
79 term);
80
81 self.solutions[inferred] = new_value;
82 changed = true;
83 }
84 }
85 }
86 }
87
88 fn write(&self) {
89 // Collect all the variances for a particular item and stick
90 // them into the variance map. We rely on the fact that we
91 // generate all the inferreds for a particular item
92 // consecutively (that is, we collect solutions for an item
93 // until we see a new item id, and we assume (1) the solutions
94 // are in the same order as the type parameters were declared
95 // and (2) all solutions or a given item appear before a new
96 // item id).
97
98 let tcx = self.terms_cx.tcx;
99
100 // Ignore the writes here because the relevant edges were
101 // already accounted for in `constraints.rs`. See the section
102 // on dependency graph management in README.md for more
103 // information.
104 let _ignore = tcx.dep_graph.in_ignore();
105
106 let solutions = &self.solutions;
107 let inferred_infos = &self.terms_cx.inferred_infos;
108 let mut index = 0;
109 let num_inferred = self.terms_cx.num_inferred();
110 while index < num_inferred {
111 let item_id = inferred_infos[index].item_id;
112 let mut types = VecPerParamSpace::empty();
113 let mut regions = VecPerParamSpace::empty();
114
115 while index < num_inferred && inferred_infos[index].item_id == item_id {
116 let info = &inferred_infos[index];
117 let variance = solutions[index];
118 debug!("Index {} Info {} / {:?} / {:?} Variance {:?}",
119 index, info.index, info.kind, info.space, variance);
120 match info.kind {
121 TypeParam => { types.push(info.space, variance); }
122 RegionParam => { regions.push(info.space, variance); }
123 }
124
125 index += 1;
126 }
127
128 let item_variances = ty::ItemVariances {
129 types: types,
130 regions: regions
131 };
132 debug!("item_id={} item_variances={:?}",
133 item_id,
134 item_variances);
135
136 let item_def_id = tcx.map.local_def_id(item_id);
137
138 // For unit testing: check for a special "rustc_variance"
139 // attribute and report an error with various results if found.
140 if tcx.has_attr(item_def_id, "rustc_variance") {
141 span_err!(tcx.sess, tcx.map.span(item_id), E0208, "{:?}", item_variances);
142 }
143
144 let newly_added = tcx.item_variance_map.borrow_mut()
145 .insert(item_def_id, Rc::new(item_variances)).is_none();
146 assert!(newly_added);
147 }
148 }
149
150 fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
151 match *term {
152 ConstantTerm(v) => {
153 v
154 }
155
156 TransformTerm(t1, t2) => {
157 let v1 = self.evaluate(t1);
158 let v2 = self.evaluate(t2);
159 v1.xform(v2)
160 }
161
162 InferredTerm(InferredIndex(index)) => {
163 self.solutions[index]
164 }
165 }
166 }
167}