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.
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.
11 //! Constraint construction and representation
13 //! The second pass over the AST determines the set of constraints.
14 //! We walk the set of items and, for each member, generate new constraints.
16 use dep_graph::DepTrackingMapConfig;
17 use hir::def_id::DefId;
18 use middle::resolve_lifetime as rl;
19 use rustc::ty::subst::Substs;
20 use rustc::ty::{self, Ty, TyCtxt};
21 use rustc::ty::maps::ItemVariances;
22 use rustc::hir::map as hir_map;
25 use rustc::hir::intravisit::Visitor;
28 use super::terms::VarianceTerm::*;
31 pub struct ConstraintContext<'a, 'tcx: 'a> {
32 pub terms_cx: TermsContext<'a, 'tcx>,
34 // These are pointers to common `ConstantTerm` instances
35 covariant: VarianceTermPtr<'a>,
36 contravariant: VarianceTermPtr<'a>,
37 invariant: VarianceTermPtr<'a>,
38 bivariant: VarianceTermPtr<'a>,
40 pub constraints: Vec<Constraint<'a>> ,
43 /// Declares that the variable `decl_id` appears in a location with
44 /// variance `variance`.
45 #[derive(Copy, Clone)]
46 pub struct Constraint<'a> {
47 pub inferred: InferredIndex,
48 pub variance: &'a VarianceTerm<'a>,
51 pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
52 -> ConstraintContext<'a, 'tcx>
54 let tcx = terms_cx.tcx;
55 let covariant = terms_cx.arena.alloc(ConstantTerm(ty::Covariant));
56 let contravariant = terms_cx.arena.alloc(ConstantTerm(ty::Contravariant));
57 let invariant = terms_cx.arena.alloc(ConstantTerm(ty::Invariant));
58 let bivariant = terms_cx.arena.alloc(ConstantTerm(ty::Bivariant));
59 let mut constraint_cx = ConstraintContext {
62 contravariant: contravariant,
65 constraints: Vec::new(),
68 // See README.md for a discussion on dep-graph management.
69 tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
75 impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
76 fn visit_item(&mut self, item: &hir::Item) {
77 let tcx = self.terms_cx.tcx;
78 let did = tcx.map.local_def_id(item.id);
80 debug!("visit_item item={}", tcx.map.node_to_string(item.id));
83 hir::ItemEnum(..) | hir::ItemStruct(..) => {
84 let scheme = tcx.lookup_item_type(did);
86 // Not entirely obvious: constraints on structs/enums do not
87 // affect the variance of their type parameters. See discussion
88 // in comment at top of module.
90 // self.add_constraints_from_generics(&scheme.generics);
92 for field in tcx.lookup_adt_def(did).all_fields() {
93 self.add_constraints_from_ty(&scheme.generics,
98 hir::ItemTrait(..) => {
99 let trait_def = tcx.lookup_trait_def(did);
100 self.add_constraints_from_trait_ref(&trait_def.generics,
105 hir::ItemExternCrate(_) |
107 hir::ItemStatic(..) |
111 hir::ItemForeignMod(..) |
114 hir::ItemDefaultImpl(..) => {
120 /// Is `param_id` a lifetime according to `map`?
121 fn is_lifetime(map: &hir_map::Map, param_id: ast::NodeId) -> bool {
122 match map.find(param_id) {
123 Some(hir_map::NodeLifetime(..)) => true, _ => false
127 impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
128 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
132 fn inferred_index(&self, param_id: ast::NodeId) -> InferredIndex {
133 match self.terms_cx.inferred_map.get(¶m_id) {
134 Some(&index) => index,
136 bug!("no inferred index entry for {}",
137 self.tcx().map.node_to_string(param_id));
142 fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId {
143 let tcx = self.terms_cx.tcx;
144 assert!(is_lifetime(&tcx.map, param_id));
145 match tcx.named_region_map.defs.get(¶m_id) {
146 Some(&rl::DefEarlyBoundRegion(_, lifetime_decl_id))
148 Some(_) => bug!("should not encounter non early-bound cases"),
150 // The lookup should only fail when `param_id` is
151 // itself a lifetime binding: use it as the decl_id.
157 /// Is `param_id` a type parameter for which we infer variance?
158 fn is_to_be_inferred(&self, param_id: ast::NodeId) -> bool {
159 let result = self.terms_cx.inferred_map.contains_key(¶m_id);
161 // To safe-guard against invalid inferred_map constructions,
162 // double-check if variance is inferred at some use of a type
163 // parameter (by inspecting parent of its binding declaration
164 // to see if it is introduced by a type or by a fn/impl).
166 let check_result = |this:&ConstraintContext| -> bool {
167 let tcx = this.terms_cx.tcx;
168 let decl_id = this.find_binding_for_lifetime(param_id);
169 // Currently only called on lifetimes; double-checking that.
170 assert!(is_lifetime(&tcx.map, param_id));
171 let parent_id = tcx.map.get_parent(decl_id);
172 let parent = tcx.map.find(parent_id).unwrap_or_else(
173 || bug!("tcx.map missing entry for id: {}", parent_id));
176 macro_rules! cannot_happen { () => { {
177 bug!("invalid parent: {} for {}",
178 tcx.map.node_to_string(parent_id),
179 tcx.map.node_to_string(param_id));
183 hir_map::NodeItem(p) => {
187 hir::ItemStruct(..) |
188 hir::ItemTrait(..) => is_inferred = true,
189 hir::ItemFn(..) => is_inferred = false,
190 _ => cannot_happen!(),
193 hir_map::NodeTraitItem(..) => is_inferred = false,
194 hir_map::NodeImplItem(..) => is_inferred = false,
195 _ => cannot_happen!(),
201 assert_eq!(result, check_result(self));
206 /// Returns a variance term representing the declared variance of the type/region parameter
207 /// with the given id.
208 fn declared_variance(&self,
212 -> VarianceTermPtr<'a> {
213 assert_eq!(param_def_id.krate, item_def_id.krate);
215 if let Some(param_node_id) = self.tcx().map.as_local_node_id(param_def_id) {
216 // Parameter on an item defined within current crate:
217 // variance not yet inferred, so return a symbolic
219 let InferredIndex(index) = self.inferred_index(param_node_id);
220 self.terms_cx.inferred_infos[index].term
222 // Parameter on an item defined within another crate:
223 // variance already inferred, just look it up.
224 let variances = self.tcx().item_variances(item_def_id);
225 self.constant_term(variances[index])
229 fn add_constraint(&mut self,
230 InferredIndex(index): InferredIndex,
231 variance: VarianceTermPtr<'a>) {
232 debug!("add_constraint(index={}, variance={:?})",
234 self.constraints.push(Constraint { inferred: InferredIndex(index),
235 variance: variance });
238 fn contravariant(&mut self,
239 variance: VarianceTermPtr<'a>)
240 -> VarianceTermPtr<'a> {
241 self.xform(variance, self.contravariant)
244 fn invariant(&mut self,
245 variance: VarianceTermPtr<'a>)
246 -> VarianceTermPtr<'a> {
247 self.xform(variance, self.invariant)
250 fn constant_term(&self, v: ty::Variance) -> VarianceTermPtr<'a> {
252 ty::Covariant => self.covariant,
253 ty::Invariant => self.invariant,
254 ty::Contravariant => self.contravariant,
255 ty::Bivariant => self.bivariant,
260 v1: VarianceTermPtr<'a>,
261 v2: VarianceTermPtr<'a>)
262 -> VarianceTermPtr<'a> {
264 (_, ConstantTerm(ty::Covariant)) => {
265 // Applying a "covariant" transform is always a no-op
269 (ConstantTerm(c1), ConstantTerm(c2)) => {
270 self.constant_term(c1.xform(c2))
274 &*self.terms_cx.arena.alloc(TransformTerm(v1, v2))
279 fn add_constraints_from_trait_ref(&mut self,
280 generics: &ty::Generics<'tcx>,
281 trait_ref: ty::TraitRef<'tcx>,
282 variance: VarianceTermPtr<'a>) {
283 debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
287 let trait_def = self.tcx().lookup_trait_def(trait_ref.def_id);
289 // This edge is actually implied by the call to
290 // `lookup_trait_def`, but I'm trying to be future-proof. See
291 // README.md for a discussion on dep-graph management.
292 self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
294 self.add_constraints_from_substs(
297 &trait_def.generics.types,
298 &trait_def.generics.regions,
303 /// Adds constraints appropriate for an instance of `ty` appearing
304 /// in a context with the generics defined in `generics` and
305 /// ambient variance `variance`
306 fn add_constraints_from_ty(&mut self,
307 generics: &ty::Generics<'tcx>,
309 variance: VarianceTermPtr<'a>) {
310 debug!("add_constraints_from_ty(ty={:?}, variance={:?})",
316 ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
317 ty::TyFloat(_) | ty::TyStr | ty::TyNever => {
318 /* leaf type -- noop */
321 ty::TyClosure(..) | ty::TyAnon(..) => {
322 bug!("Unexpected closure type in variance computation");
325 ty::TyRef(region, ref mt) => {
326 let contra = self.contravariant(variance);
327 self.add_constraints_from_region(generics, region, contra);
328 self.add_constraints_from_mt(generics, mt, variance);
331 ty::TyBox(typ) | ty::TyArray(typ, _) | ty::TySlice(typ) => {
332 self.add_constraints_from_ty(generics, typ, variance);
336 ty::TyRawPtr(ref mt) => {
337 self.add_constraints_from_mt(generics, mt, variance);
340 ty::TyTuple(subtys) => {
341 for &subty in subtys {
342 self.add_constraints_from_ty(generics, subty, variance);
346 ty::TyEnum(def, substs) |
347 ty::TyStruct(def, substs) => {
348 let item_type = self.tcx().lookup_item_type(def.did);
350 // This edge is actually implied by the call to
351 // `lookup_trait_def`, but I'm trying to be future-proof. See
352 // README.md for a discussion on dep-graph management.
353 self.tcx().dep_graph.read(ItemVariances::to_dep_node(&def.did));
355 self.add_constraints_from_substs(
358 &item_type.generics.types,
359 &item_type.generics.regions,
364 ty::TyProjection(ref data) => {
365 let trait_ref = &data.trait_ref;
366 let trait_def = self.tcx().lookup_trait_def(trait_ref.def_id);
368 // This edge is actually implied by the call to
369 // `lookup_trait_def`, but I'm trying to be future-proof. See
370 // README.md for a discussion on dep-graph management.
371 self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
373 self.add_constraints_from_substs(
376 &trait_def.generics.types,
377 &trait_def.generics.regions,
382 ty::TyTrait(ref data) => {
383 // The type `Foo<T+'a>` is contravariant w/r/t `'a`:
384 let contra = self.contravariant(variance);
385 self.add_constraints_from_region(generics, data.region_bound, contra);
388 data.principal.with_self_ty(self.tcx(), self.tcx().types.err);
389 self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance);
391 for projection in &data.projection_bounds {
392 self.add_constraints_from_ty(generics, projection.0.ty, self.invariant);
396 ty::TyParam(ref data) => {
397 assert_eq!(generics.parent, None);
398 let mut i = data.idx as usize;
399 if !generics.has_self || i > 0 {
400 i -= generics.regions.len();
402 let def_id = generics.types[i].def_id;
403 let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
404 match self.terms_cx.inferred_map.get(&node_id) {
406 self.add_constraint(index, variance);
409 // We do not infer variance for type parameters
410 // declared on methods. They will not be present
411 // in the inferred_map.
416 ty::TyFnDef(_, _, &ty::BareFnTy { ref sig, .. }) |
417 ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => {
418 self.add_constraints_from_sig(generics, sig, variance);
422 // we encounter this when walking the trait references for object
423 // types, where we use TyError as the Self type
427 bug!("unexpected type encountered in \
428 variance inference: {}", ty);
433 /// Adds constraints appropriate for a nominal type (enum, struct,
434 /// object, etc) appearing in a context with ambient variance `variance`
435 fn add_constraints_from_substs(&mut self,
436 generics: &ty::Generics<'tcx>,
438 type_param_defs: &[ty::TypeParameterDef<'tcx>],
439 region_param_defs: &[ty::RegionParameterDef],
440 substs: &Substs<'tcx>,
441 variance: VarianceTermPtr<'a>) {
442 debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})",
447 for p in type_param_defs {
449 self.declared_variance(p.def_id, def_id, p.index as usize);
450 let variance_i = self.xform(variance, variance_decl);
451 let substs_ty = substs.type_for_def(p);
452 debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
453 variance_decl, variance_i);
454 self.add_constraints_from_ty(generics, substs_ty, variance_i);
457 for p in region_param_defs {
459 self.declared_variance(p.def_id, def_id, p.index as usize);
460 let variance_i = self.xform(variance, variance_decl);
461 let substs_r = substs.region_for_def(p);
462 self.add_constraints_from_region(generics, substs_r, variance_i);
466 /// Adds constraints appropriate for a function with signature
467 /// `sig` appearing in a context with ambient variance `variance`
468 fn add_constraints_from_sig(&mut self,
469 generics: &ty::Generics<'tcx>,
470 sig: &ty::PolyFnSig<'tcx>,
471 variance: VarianceTermPtr<'a>) {
472 let contra = self.contravariant(variance);
473 for &input in &sig.0.inputs {
474 self.add_constraints_from_ty(generics, input, contra);
476 self.add_constraints_from_ty(generics, sig.0.output, variance);
479 /// Adds constraints appropriate for a region appearing in a
480 /// context with ambient variance `variance`
481 fn add_constraints_from_region(&mut self,
482 generics: &ty::Generics<'tcx>,
483 region: &'tcx ty::Region,
484 variance: VarianceTermPtr<'a>) {
486 ty::ReEarlyBound(ref data) => {
487 assert_eq!(generics.parent, None);
488 let i = data.index as usize - generics.has_self as usize;
489 let def_id = generics.regions[i].def_id;
490 let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
491 if self.is_to_be_inferred(node_id) {
492 let index = self.inferred_index(node_id);
493 self.add_constraint(index, variance);
499 ty::ReLateBound(..) => {
500 // We do not infer variance for region parameters on
501 // methods or in fn types.
504 ty::ReFree(..) | ty::ReScope(..) | ty::ReVar(..) |
505 ty::ReSkolemized(..) | ty::ReEmpty | ty::ReErased => {
506 // We don't expect to see anything but 'static or bound
507 // regions when visiting member types or method types.
508 bug!("unexpected region encountered in variance \
515 /// Adds constraints appropriate for a mutability-type pair
516 /// appearing in a context with ambient variance `variance`
517 fn add_constraints_from_mt(&mut self,
518 generics: &ty::Generics<'tcx>,
519 mt: &ty::TypeAndMut<'tcx>,
520 variance: VarianceTermPtr<'a>) {
523 let invar = self.invariant(variance);
524 self.add_constraints_from_ty(generics, mt.ty, invar);
527 hir::MutImmutable => {
528 self.add_constraints_from_ty(generics, mt.ty, variance);