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 //! This file infers the variance of type and lifetime parameters. The
12 //! algorithm is taken from Section 4 of the paper "Taming the Wildcards:
13 //! Combining Definition- and Use-Site Variance" published in PLDI'11 and
14 //! written by Altidor et al., and hereafter referred to as The Paper.
16 //! This inference is explicitly designed *not* to consider the uses of
17 //! types within code. To determine the variance of type parameters
18 //! defined on type `X`, we only consider the definition of the type `X`
19 //! and the definitions of any types it references.
21 //! We only infer variance for type parameters found on *types*: structs,
22 //! enums, and traits. We do not infer variance for type parameters found
23 //! on fns or impls. This is because those things are not type definitions
24 //! and variance doesn't really make sense in that context.
26 //! It is worth covering what variance means in each case. For structs and
27 //! enums, I think it is fairly straightforward. The variance of the type
28 //! or lifetime parameters defines whether `T<A>` is a subtype of `T<B>`
29 //! (resp. `T<'a>` and `T<'b>`) based on the relationship of `A` and `B`
30 //! (resp. `'a` and `'b`). (FIXME #3598 -- we do not currently make use of
31 //! the variances we compute for type parameters.)
33 //! ### Variance on traits
35 //! The meaning of variance for trait parameters is more subtle and worth
36 //! expanding upon. There are in fact two uses of the variance values we
39 //! #### Trait variance and object types
41 //! The first is for object types. Just as with structs and enums, we can
42 //! decide the subtyping relationship between two object types `&Trait<A>`
43 //! and `&Trait<B>` based on the relationship of `A` and `B`. Note that
44 //! for object types we ignore the `Self` type parameter -- it is unknown,
45 //! and the nature of dynamic dispatch ensures that we will always call a
46 //! function that is expected the appropriate `Self` type. However, we
47 //! must be careful with the other type parameters, or else we could end
48 //! up calling a function that is expecting one type but provided another.
50 //! To see what I mean, consider a trait like so:
52 //! trait ConvertTo<A> {
53 //! fn convertTo(&self) -> A;
56 //! Intuitively, If we had one object `O=&ConvertTo<Object>` and another
57 //! `S=&ConvertTo<String>`, then `S <: O` because `String <: Object`
58 //! (presuming Java-like "string" and "object" types, my go to examples
59 //! for subtyping). The actual algorithm would be to compare the
60 //! (explicit) type parameters pairwise respecting their variance: here,
61 //! the type parameter A is covariant (it appears only in a return
62 //! position), and hence we require that `String <: Object`.
64 //! You'll note though that we did not consider the binding for the
65 //! (implicit) `Self` type parameter: in fact, it is unknown, so that's
66 //! good. The reason we can ignore that parameter is precisely because we
67 //! don't need to know its value until a call occurs, and at that time (as
68 //! you said) the dynamic nature of virtual dispatch means the code we run
69 //! will be correct for whatever value `Self` happens to be bound to for
70 //! the particular object whose method we called. `Self` is thus different
71 //! from `A`, because the caller requires that `A` be known in order to
72 //! know the return type of the method `convertTo()`. (As an aside, we
73 //! have rules preventing methods where `Self` appears outside of the
74 //! receiver position from being called via an object.)
76 //! #### Trait variance and vtable resolution
78 //! But traits aren't only used with objects. They're also used when
79 //! deciding whether a given impl satisfies a given trait bound. To set the
80 //! scene here, imagine I had a function:
82 //! fn convertAll<A,T:ConvertTo<A>>(v: &[T]) {
86 //! Now imagine that I have an implementation of `ConvertTo` for `Object`:
88 //! impl ConvertTo<int> for Object { ... }
90 //! And I want to call `convertAll` on an array of strings. Suppose
91 //! further that for whatever reason I specifically supply the value of
92 //! `String` for the type parameter `T`:
94 //! let mut vector = ~["string", ...];
95 //! convertAll::<int, String>(v);
97 //! Is this legal? To put another way, can we apply the `impl` for
98 //! `Object` to the type `String`? The answer is yes, but to see why
99 //! we have to expand out what will happen:
101 //! - `convertAll` will create a pointer to one of the entries in the
102 //! vector, which will have type `&String`
103 //! - It will then call the impl of `convertTo()` that is intended
104 //! for use with objects. This has the type:
106 //! fn(self: &Object) -> int
108 //! It is ok to provide a value for `self` of type `&String` because
109 //! `&String <: &Object`.
111 //! OK, so intuitively we want this to be legal, so let's bring this back
112 //! to variance and see whether we are computing the correct result. We
113 //! must first figure out how to phrase the question "is an impl for
114 //! `Object,int` usable where an impl for `String,int` is expected?"
116 //! Maybe it's helpful to think of a dictionary-passing implementation of
117 //! type classes. In that case, `convertAll()` takes an implicit parameter
118 //! representing the impl. In short, we *have* an impl of type:
120 //! V_O = ConvertTo<int> for Object
122 //! and the function prototype expects an impl of type:
124 //! V_S = ConvertTo<int> for String
126 //! As with any argument, this is legal if the type of the value given
127 //! (`V_O`) is a subtype of the type expected (`V_S`). So is `V_O <: V_S`?
128 //! The answer will depend on the variance of the various parameters. In
129 //! this case, because the `Self` parameter is contravariant and `A` is
130 //! covariant, it means that:
136 //! These conditions are satisfied and so we are happy.
138 //! ### The algorithm
140 //! The basic idea is quite straightforward. We iterate over the types
141 //! defined and, for each use of a type parameter X, accumulate a
142 //! constraint indicating that the variance of X must be valid for the
143 //! variance of that use site. We then iteratively refine the variance of
144 //! X until all constraints are met. There is *always* a sol'n, because at
145 //! the limit we can declare all type parameters to be invariant and all
146 //! constraints will be satisfied.
148 //! As a simple example, consider:
150 //! enum Option<A> { Some(A), None }
151 //! enum OptionalFn<B> { Some(|B|), None }
152 //! enum OptionalMap<C> { Some(|C| -> C), None }
154 //! Here, we will generate the constraints:
161 //! These indicate that (1) the variance of A must be at most covariant;
162 //! (2) the variance of B must be at most contravariant; and (3, 4) the
163 //! variance of C must be at most covariant *and* contravariant. All of these
164 //! results are based on a variance lattice defined as follows:
166 //! * Top (bivariant)
168 //! o Bottom (invariant)
170 //! Based on this lattice, the solution V(A)=+, V(B)=-, V(C)=o is the
171 //! optimal solution. Note that there is always a naive solution which
172 //! just declares all variables to be invariant.
174 //! You may be wondering why fixed-point iteration is required. The reason
175 //! is that the variance of a use site may itself be a function of the
176 //! variance of other type parameters. In full generality, our constraints
180 //! Term := + | - | * | o | V(X) | Term x Term
182 //! Here the notation V(X) indicates the variance of a type/region
183 //! parameter `X` with respect to its defining class. `Term x Term`
184 //! represents the "variance transform" as defined in the paper:
186 //! If the variance of a type variable `X` in type expression `E` is `V2`
187 //! and the definition-site variance of the [corresponding] type parameter
188 //! of a class `C` is `V1`, then the variance of `X` in the type expression
189 //! `C<E>` is `V3 = V1.xform(V2)`.
191 use self::VarianceTerm::*;
192 use self::ParamKind::*;
196 use middle::resolve_lifetime as rl;
198 use middle::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace};
199 use middle::ty::{self, Ty};
202 use std::iter::repeat;
205 use syntax::ast_util;
207 use syntax::visit::Visitor;
208 use util::nodemap::NodeMap;
209 use util::ppaux::Repr;
211 pub fn infer_variance(tcx: &ty::ctxt) {
212 let krate = tcx.map.krate();
213 let mut arena = arena::Arena::new();
214 let terms_cx = determine_parameters_to_be_inferred(tcx, &mut arena, krate);
215 let constraints_cx = add_constraints_from_crate(terms_cx, krate);
216 solve_constraints(constraints_cx);
217 tcx.variance_computed.set(true);
220 // Representing terms
222 // Terms are structured as a straightforward tree. Rather than rely on
223 // GC, we allocate terms out of a bounded arena (the lifetime of this
224 // arena is the lifetime 'a that is threaded around).
226 // We assign a unique index to each type/region parameter whose variance
227 // is to be inferred. We refer to such variables as "inferreds". An
228 // `InferredIndex` is a newtype'd int representing the index of such
231 type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
233 #[derive(Copy, Show)]
234 struct InferredIndex(uint);
237 enum VarianceTerm<'a> {
238 ConstantTerm(ty::Variance),
239 TransformTerm(VarianceTermPtr<'a>, VarianceTermPtr<'a>),
240 InferredTerm(InferredIndex),
243 impl<'a> fmt::Show for VarianceTerm<'a> {
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246 ConstantTerm(c1) => write!(f, "{:?}", c1),
247 TransformTerm(v1, v2) => write!(f, "({:?} \u{00D7} {:?})", v1, v2),
248 InferredTerm(id) => write!(f, "[{}]", { let InferredIndex(i) = id; i })
253 // The first pass over the crate simply builds up the set of inferreds.
255 struct TermsContext<'a, 'tcx: 'a> {
256 tcx: &'a ty::ctxt<'tcx>,
259 empty_variances: Rc<ty::ItemVariances>,
261 // Maps from the node id of a type/generic parameter to the
262 // corresponding inferred index.
263 inferred_map: NodeMap<InferredIndex>,
265 // Maps from an InferredIndex to the info for that variable.
266 inferred_infos: Vec<InferredInfo<'a>> ,
269 #[derive(Copy, Show, PartialEq)]
275 struct InferredInfo<'a> {
276 item_id: ast::NodeId,
280 param_id: ast::NodeId,
281 term: VarianceTermPtr<'a>,
284 fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
285 arena: &'a mut Arena,
287 -> TermsContext<'a, 'tcx> {
288 let mut terms_cx = TermsContext {
291 inferred_map: NodeMap(),
292 inferred_infos: Vec::new(),
294 // cache and share the variance struct used for items with
295 // no type/region parameters
296 empty_variances: Rc::new(ty::ItemVariances {
297 types: VecPerParamSpace::empty(),
298 regions: VecPerParamSpace::empty()
302 visit::walk_crate(&mut terms_cx, krate);
307 impl<'a, 'tcx> TermsContext<'a, 'tcx> {
308 fn add_inferred(&mut self,
309 item_id: ast::NodeId,
313 param_id: ast::NodeId) {
314 let inf_index = InferredIndex(self.inferred_infos.len());
315 let term = self.arena.alloc(|| InferredTerm(inf_index));
316 self.inferred_infos.push(InferredInfo { item_id: item_id,
322 let newly_added = self.inferred_map.insert(param_id, inf_index).is_none();
323 assert!(newly_added);
325 debug!("add_inferred(item_id={}, \
330 item_id, kind, index, param_id, inf_index);
333 fn num_inferred(&self) -> uint {
334 self.inferred_infos.len()
338 impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
339 fn visit_item(&mut self, item: &ast::Item) {
340 debug!("add_inferreds for item {}", item.repr(self.tcx));
342 let inferreds_on_entry = self.num_inferred();
344 // NB: In the code below for writing the results back into the
345 // tcx, we rely on the fact that all inferreds for a particular
346 // item are assigned continuous indices.
348 ast::ItemTrait(..) => {
349 self.add_inferred(item.id, TypeParam, SelfSpace, 0, item.id);
355 ast::ItemEnum(_, ref generics) |
356 ast::ItemStruct(_, ref generics) |
357 ast::ItemTrait(_, ref generics, _, _) => {
358 for (i, p) in generics.lifetimes.iter().enumerate() {
359 let id = p.lifetime.id;
360 self.add_inferred(item.id, RegionParam, TypeSpace, i, id);
362 for (i, p) in generics.ty_params.iter().enumerate() {
363 self.add_inferred(item.id, TypeParam, TypeSpace, i, p.id);
366 // If this item has no type or lifetime parameters,
367 // then there are no variances to infer, so just
368 // insert an empty entry into the variance map.
369 // Arguably we could just leave the map empty in this
370 // case but it seems cleaner to be able to distinguish
371 // "invalid item id" from "item id with no
373 if self.num_inferred() == inferreds_on_entry {
374 let newly_added = self.tcx.item_variance_map.borrow_mut().insert(
375 ast_util::local_def(item.id),
376 self.empty_variances.clone()).is_none();
377 assert!(newly_added);
380 visit::walk_item(self, item);
383 ast::ItemExternCrate(_) |
386 ast::ItemStatic(..) |
390 ast::ItemForeignMod(..) |
392 ast::ItemMac(..) => {
393 visit::walk_item(self, item);
399 // Constraint construction and representation
401 // The second pass over the AST determines the set of constraints.
402 // We walk the set of items and, for each member, generate new constraints.
404 struct ConstraintContext<'a, 'tcx: 'a> {
405 terms_cx: TermsContext<'a, 'tcx>,
407 // These are the def-id of the std::marker::InvariantType,
408 // std::marker::InvariantLifetime, and so on. The arrays
409 // are indexed by the `ParamKind` (type, lifetime, self). Note
410 // that there are no marker types for self, so the entries for
411 // self are always None.
412 invariant_lang_items: [Option<ast::DefId>; 2],
413 covariant_lang_items: [Option<ast::DefId>; 2],
414 contravariant_lang_items: [Option<ast::DefId>; 2],
415 unsafe_lang_item: Option<ast::DefId>,
417 // These are pointers to common `ConstantTerm` instances
418 covariant: VarianceTermPtr<'a>,
419 contravariant: VarianceTermPtr<'a>,
420 invariant: VarianceTermPtr<'a>,
421 bivariant: VarianceTermPtr<'a>,
423 constraints: Vec<Constraint<'a>> ,
426 /// Declares that the variable `decl_id` appears in a location with
427 /// variance `variance`.
429 struct Constraint<'a> {
430 inferred: InferredIndex,
431 variance: &'a VarianceTerm<'a>,
434 fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>,
436 -> ConstraintContext<'a, 'tcx> {
437 let mut invariant_lang_items = [None; 2];
438 let mut covariant_lang_items = [None; 2];
439 let mut contravariant_lang_items = [None; 2];
441 covariant_lang_items[TypeParam as uint] =
442 terms_cx.tcx.lang_items.covariant_type();
443 covariant_lang_items[RegionParam as uint] =
444 terms_cx.tcx.lang_items.covariant_lifetime();
446 contravariant_lang_items[TypeParam as uint] =
447 terms_cx.tcx.lang_items.contravariant_type();
448 contravariant_lang_items[RegionParam as uint] =
449 terms_cx.tcx.lang_items.contravariant_lifetime();
451 invariant_lang_items[TypeParam as uint] =
452 terms_cx.tcx.lang_items.invariant_type();
453 invariant_lang_items[RegionParam as uint] =
454 terms_cx.tcx.lang_items.invariant_lifetime();
456 let unsafe_lang_item = terms_cx.tcx.lang_items.unsafe_type();
458 let covariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Covariant));
459 let contravariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Contravariant));
460 let invariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Invariant));
461 let bivariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Bivariant));
462 let mut constraint_cx = ConstraintContext {
465 invariant_lang_items: invariant_lang_items,
466 covariant_lang_items: covariant_lang_items,
467 contravariant_lang_items: contravariant_lang_items,
468 unsafe_lang_item: unsafe_lang_item,
470 covariant: covariant,
471 contravariant: contravariant,
472 invariant: invariant,
473 bivariant: bivariant,
474 constraints: Vec::new(),
476 visit::walk_crate(&mut constraint_cx, krate);
480 impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
481 fn visit_item(&mut self, item: &ast::Item) {
482 let did = ast_util::local_def(item.id);
483 let tcx = self.terms_cx.tcx;
485 debug!("visit_item item={}",
489 ast::ItemEnum(ref enum_definition, _) => {
490 let generics = &ty::lookup_item_type(tcx, did).generics;
492 // Hack: If we directly call `ty::enum_variants`, it
493 // annoyingly takes it upon itself to run off and
494 // evaluate the discriminants eagerly (*grumpy* that's
495 // not the typical pattern). This results in double
496 // error messages because typeck goes off and does
497 // this at a later time. All we really care about is
498 // the types of the variant arguments, so we just call
499 // `ty::VariantInfo::from_ast_variant()` ourselves
500 // here, mainly so as to mask the differences between
501 // struct-like enums and so forth.
502 for ast_variant in enum_definition.variants.iter() {
504 ty::VariantInfo::from_ast_variant(tcx,
507 for arg_ty in variant.args.iter() {
508 self.add_constraints_from_ty(generics, *arg_ty, self.covariant);
513 ast::ItemStruct(..) => {
514 let generics = &ty::lookup_item_type(tcx, did).generics;
515 let struct_fields = ty::lookup_struct_fields(tcx, did);
516 for field_info in struct_fields.iter() {
517 assert_eq!(field_info.id.krate, ast::LOCAL_CRATE);
518 let field_ty = ty::node_id_to_type(tcx, field_info.id.node);
519 self.add_constraints_from_ty(generics, field_ty, self.covariant);
523 ast::ItemTrait(..) => {
524 let trait_items = ty::trait_items(tcx, did);
525 for trait_item in trait_items.iter() {
527 ty::MethodTraitItem(ref method) => {
528 self.add_constraints_from_sig(&method.generics,
532 ty::TypeTraitItem(_) => {}
537 ast::ItemExternCrate(_) |
539 ast::ItemStatic(..) |
543 ast::ItemForeignMod(..) |
546 ast::ItemMac(..) => {
547 visit::walk_item(self, item);
553 /// Is `param_id` a lifetime according to `map`?
554 fn is_lifetime(map: &ast_map::Map, param_id: ast::NodeId) -> bool {
555 match map.find(param_id) {
556 Some(ast_map::NodeLifetime(..)) => true, _ => false
560 impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
561 fn tcx(&self) -> &'a ty::ctxt<'tcx> {
565 fn inferred_index(&self, param_id: ast::NodeId) -> InferredIndex {
566 match self.terms_cx.inferred_map.get(¶m_id) {
567 Some(&index) => index,
569 self.tcx().sess.bug(&format!(
570 "no inferred index entry for {}",
571 self.tcx().map.node_to_string(param_id))[]);
576 fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId {
577 let tcx = self.terms_cx.tcx;
578 assert!(is_lifetime(&tcx.map, param_id));
579 match tcx.named_region_map.get(¶m_id) {
580 Some(&rl::DefEarlyBoundRegion(_, _, lifetime_decl_id))
582 Some(_) => panic!("should not encounter non early-bound cases"),
584 // The lookup should only fail when `param_id` is
585 // itself a lifetime binding: use it as the decl_id.
591 /// Is `param_id` a type parameter for which we infer variance?
592 fn is_to_be_inferred(&self, param_id: ast::NodeId) -> bool {
593 let result = self.terms_cx.inferred_map.contains_key(¶m_id);
595 // To safe-guard against invalid inferred_map constructions,
596 // double-check if variance is inferred at some use of a type
597 // parameter (by inspecting parent of its binding declaration
598 // to see if it is introduced by a type or by a fn/impl).
600 let check_result = |&: this:&ConstraintContext| -> bool {
601 let tcx = this.terms_cx.tcx;
602 let decl_id = this.find_binding_for_lifetime(param_id);
603 // Currently only called on lifetimes; double-checking that.
604 assert!(is_lifetime(&tcx.map, param_id));
605 let parent_id = tcx.map.get_parent(decl_id);
606 let parent = tcx.map.find(parent_id).unwrap_or_else(
607 || panic!("tcx.map missing entry for id: {}", parent_id));
610 macro_rules! cannot_happen { () => { {
611 panic!("invalid parent: {} for {}",
612 tcx.map.node_to_string(parent_id),
613 tcx.map.node_to_string(param_id));
617 ast_map::NodeItem(p) => {
621 ast::ItemStruct(..) |
622 ast::ItemTrait(..) => is_inferred = true,
623 ast::ItemFn(..) => is_inferred = false,
624 _ => cannot_happen!(),
627 ast_map::NodeTraitItem(..) => is_inferred = false,
628 ast_map::NodeImplItem(..) => is_inferred = false,
629 _ => cannot_happen!(),
635 assert_eq!(result, check_result(self));
640 /// Returns a variance term representing the declared variance of the type/region parameter
641 /// with the given id.
642 fn declared_variance(&self,
643 param_def_id: ast::DefId,
644 item_def_id: ast::DefId,
648 -> VarianceTermPtr<'a> {
649 assert_eq!(param_def_id.krate, item_def_id.krate);
651 if self.invariant_lang_items[kind as uint] == Some(item_def_id) {
653 } else if self.covariant_lang_items[kind as uint] == Some(item_def_id) {
655 } else if self.contravariant_lang_items[kind as uint] == Some(item_def_id) {
657 } else if kind == TypeParam && Some(item_def_id) == self.unsafe_lang_item {
659 } else if param_def_id.krate == ast::LOCAL_CRATE {
660 // Parameter on an item defined within current crate:
661 // variance not yet inferred, so return a symbolic
663 let InferredIndex(index) = self.inferred_index(param_def_id.node);
664 self.terms_cx.inferred_infos[index].term
666 // Parameter on an item defined within another crate:
667 // variance already inferred, just look it up.
668 let variances = ty::item_variances(self.tcx(), item_def_id);
669 let variance = match kind {
670 TypeParam => *variances.types.get(space, index),
671 RegionParam => *variances.regions.get(space, index),
673 self.constant_term(variance)
677 fn add_constraint(&mut self,
678 InferredIndex(index): InferredIndex,
679 variance: VarianceTermPtr<'a>) {
680 debug!("add_constraint(index={}, variance={:?})",
682 self.constraints.push(Constraint { inferred: InferredIndex(index),
683 variance: variance });
686 fn contravariant(&mut self,
687 variance: VarianceTermPtr<'a>)
688 -> VarianceTermPtr<'a> {
689 self.xform(variance, self.contravariant)
692 fn invariant(&mut self,
693 variance: VarianceTermPtr<'a>)
694 -> VarianceTermPtr<'a> {
695 self.xform(variance, self.invariant)
698 fn constant_term(&self, v: ty::Variance) -> VarianceTermPtr<'a> {
700 ty::Covariant => self.covariant,
701 ty::Invariant => self.invariant,
702 ty::Contravariant => self.contravariant,
703 ty::Bivariant => self.bivariant,
708 v1: VarianceTermPtr<'a>,
709 v2: VarianceTermPtr<'a>)
710 -> VarianceTermPtr<'a> {
712 (_, ConstantTerm(ty::Covariant)) => {
713 // Applying a "covariant" transform is always a no-op
717 (ConstantTerm(c1), ConstantTerm(c2)) => {
718 self.constant_term(c1.xform(c2))
722 &*self.terms_cx.arena.alloc(|| TransformTerm(v1, v2))
727 /// Adds constraints appropriate for an instance of `ty` appearing
728 /// in a context with the generics defined in `generics` and
729 /// ambient variance `variance`
730 fn add_constraints_from_ty(&mut self,
731 generics: &ty::Generics<'tcx>,
733 variance: VarianceTermPtr<'a>) {
734 debug!("add_constraints_from_ty(ty={})", ty.repr(self.tcx()));
738 ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) |
739 ty::ty_float(_) | ty::ty_str => {
740 /* leaf type -- noop */
743 ty::ty_unboxed_closure(..) => {
744 self.tcx().sess.bug("Unexpected unboxed closure type in variance computation");
747 ty::ty_rptr(region, ref mt) => {
748 let contra = self.contravariant(variance);
749 self.add_constraints_from_region(generics, *region, contra);
750 self.add_constraints_from_mt(generics, mt, variance);
753 ty::ty_uniq(typ) | ty::ty_vec(typ, _) | ty::ty_open(typ) => {
754 self.add_constraints_from_ty(generics, typ, variance);
757 ty::ty_ptr(ref mt) => {
758 self.add_constraints_from_mt(generics, mt, variance);
761 ty::ty_tup(ref subtys) => {
762 for &subty in subtys.iter() {
763 self.add_constraints_from_ty(generics, subty, variance);
767 ty::ty_enum(def_id, substs) |
768 ty::ty_struct(def_id, substs) => {
769 let item_type = ty::lookup_item_type(self.tcx(), def_id);
771 // All type parameters on enums and structs should be
773 assert!(item_type.generics.types.is_empty_in(subst::SelfSpace));
774 assert!(item_type.generics.types.is_empty_in(subst::FnSpace));
775 assert!(item_type.generics.regions.is_empty_in(subst::SelfSpace));
776 assert!(item_type.generics.regions.is_empty_in(subst::FnSpace));
778 self.add_constraints_from_substs(
781 item_type.generics.types.get_slice(subst::TypeSpace),
782 item_type.generics.regions.get_slice(subst::TypeSpace),
787 ty::ty_projection(ref data) => {
788 let trait_ref = &data.trait_ref;
789 let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id);
790 self.add_constraints_from_substs(
793 trait_def.generics.types.as_slice(),
794 trait_def.generics.regions.as_slice(),
799 ty::ty_trait(ref data) => {
800 let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(),
801 self.tcx().types.err);
802 let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id());
804 // Traits never declare region parameters in the self
805 // space nor anything in the fn space.
806 assert!(trait_def.generics.regions.is_empty_in(subst::SelfSpace));
807 assert!(trait_def.generics.types.is_empty_in(subst::FnSpace));
808 assert!(trait_def.generics.regions.is_empty_in(subst::FnSpace));
810 // The type `Foo<T+'a>` is contravariant w/r/t `'a`:
811 let contra = self.contravariant(variance);
812 self.add_constraints_from_region(generics, data.bounds.region_bound, contra);
814 self.add_constraints_from_substs(
817 trait_def.generics.types.get_slice(subst::TypeSpace),
818 trait_def.generics.regions.get_slice(subst::TypeSpace),
823 ty::ty_param(ref data) => {
824 let def_id = generics.types.get(data.space, data.idx as uint).def_id;
825 assert_eq!(def_id.krate, ast::LOCAL_CRATE);
826 match self.terms_cx.inferred_map.get(&def_id.node) {
828 self.add_constraint(index, variance);
831 // We do not infer variance for type parameters
832 // declared on methods. They will not be present
833 // in the inferred_map.
838 ty::ty_bare_fn(_, &ty::BareFnTy { ref sig, .. }) => {
839 self.add_constraints_from_sig(generics, sig, variance);
842 ty::ty_infer(..) | ty::ty_err => {
844 &format!("unexpected type encountered in \
845 variance inference: {}",
846 ty.repr(self.tcx()))[]);
852 /// Adds constraints appropriate for a nominal type (enum, struct,
853 /// object, etc) appearing in a context with ambient variance `variance`
854 fn add_constraints_from_substs(&mut self,
855 generics: &ty::Generics<'tcx>,
857 type_param_defs: &[ty::TypeParameterDef<'tcx>],
858 region_param_defs: &[ty::RegionParameterDef],
859 substs: &subst::Substs<'tcx>,
860 variance: VarianceTermPtr<'a>) {
861 debug!("add_constraints_from_substs(def_id={:?})", def_id);
863 for p in type_param_defs.iter() {
865 self.declared_variance(p.def_id, def_id, TypeParam,
866 p.space, p.index as uint);
867 let variance_i = self.xform(variance, variance_decl);
868 let substs_ty = *substs.types.get(p.space, p.index as uint);
869 self.add_constraints_from_ty(generics, substs_ty, variance_i);
872 for p in region_param_defs.iter() {
874 self.declared_variance(p.def_id, def_id,
875 RegionParam, p.space, p.index as uint);
876 let variance_i = self.xform(variance, variance_decl);
877 let substs_r = *substs.regions().get(p.space, p.index as uint);
878 self.add_constraints_from_region(generics, substs_r, variance_i);
882 /// Adds constraints appropriate for a function with signature
883 /// `sig` appearing in a context with ambient variance `variance`
884 fn add_constraints_from_sig(&mut self,
885 generics: &ty::Generics<'tcx>,
886 sig: &ty::PolyFnSig<'tcx>,
887 variance: VarianceTermPtr<'a>) {
888 let contra = self.contravariant(variance);
889 for &input in sig.0.inputs.iter() {
890 self.add_constraints_from_ty(generics, input, contra);
892 if let ty::FnConverging(result_type) = sig.0.output {
893 self.add_constraints_from_ty(generics, result_type, variance);
897 /// Adds constraints appropriate for a region appearing in a
898 /// context with ambient variance `variance`
899 fn add_constraints_from_region(&mut self,
900 _generics: &ty::Generics<'tcx>,
902 variance: VarianceTermPtr<'a>) {
904 ty::ReEarlyBound(param_id, _, _, _) => {
905 if self.is_to_be_inferred(param_id) {
906 let index = self.inferred_index(param_id);
907 self.add_constraint(index, variance);
913 ty::ReLateBound(..) => {
914 // We do not infer variance for region parameters on
915 // methods or in fn types.
918 ty::ReFree(..) | ty::ReScope(..) | ty::ReInfer(..) |
920 // We don't expect to see anything but 'static or bound
921 // regions when visiting member types or method types.
924 .bug(&format!("unexpected region encountered in variance \
926 region.repr(self.tcx()))[]);
931 /// Adds constraints appropriate for a mutability-type pair
932 /// appearing in a context with ambient variance `variance`
933 fn add_constraints_from_mt(&mut self,
934 generics: &ty::Generics<'tcx>,
936 variance: VarianceTermPtr<'a>) {
939 let invar = self.invariant(variance);
940 self.add_constraints_from_ty(generics, mt.ty, invar);
943 ast::MutImmutable => {
944 self.add_constraints_from_ty(generics, mt.ty, variance);
950 // Constraint solving
952 // The final phase iterates over the constraints, refining the variance
953 // for each inferred until a fixed point is reached. This will be the
954 // optimal solution to the constraints. The final variance for each
955 // inferred is then written into the `variance_map` in the tcx.
957 struct SolveContext<'a, 'tcx: 'a> {
958 terms_cx: TermsContext<'a, 'tcx>,
959 constraints: Vec<Constraint<'a>> ,
961 // Maps from an InferredIndex to the inferred value for that variable.
962 solutions: Vec<ty::Variance> }
964 fn solve_constraints(constraints_cx: ConstraintContext) {
965 let ConstraintContext { terms_cx, constraints, .. } = constraints_cx;
966 let solutions: Vec<_> = repeat(ty::Bivariant).take(terms_cx.num_inferred()).collect();
967 let mut solutions_cx = SolveContext {
969 constraints: constraints,
972 solutions_cx.solve();
973 solutions_cx.write();
976 impl<'a, 'tcx> SolveContext<'a, 'tcx> {
977 fn solve(&mut self) {
978 // Propagate constraints until a fixed point is reached. Note
979 // that the maximum number of iterations is 2C where C is the
980 // number of constraints (each variable can change values at most
981 // twice). Since number of constraints is linear in size of the
982 // input, so is the inference process.
983 let mut changed = true;
987 for constraint in self.constraints.iter() {
988 let Constraint { inferred, variance: term } = *constraint;
989 let InferredIndex(inferred) = inferred;
990 let variance = self.evaluate(term);
991 let old_value = self.solutions[inferred];
992 let new_value = glb(variance, old_value);
993 if old_value != new_value {
994 debug!("Updating inferred {} (node {}) \
995 from {:?} to {:?} due to {:?}",
998 .inferred_infos[inferred]
1004 self.solutions[inferred] = new_value;
1012 // Collect all the variances for a particular item and stick
1013 // them into the variance map. We rely on the fact that we
1014 // generate all the inferreds for a particular item
1015 // consecutively (that is, we collect solutions for an item
1016 // until we see a new item id, and we assume (1) the solutions
1017 // are in the same order as the type parameters were declared
1018 // and (2) all solutions or a given item appear before a new
1021 let tcx = self.terms_cx.tcx;
1022 let solutions = &self.solutions;
1023 let inferred_infos = &self.terms_cx.inferred_infos;
1025 let num_inferred = self.terms_cx.num_inferred();
1026 while index < num_inferred {
1027 let item_id = inferred_infos[index].item_id;
1028 let mut types = VecPerParamSpace::empty();
1029 let mut regions = VecPerParamSpace::empty();
1031 while index < num_inferred &&
1032 inferred_infos[index].item_id == item_id {
1033 let info = &inferred_infos[index];
1034 let variance = solutions[index];
1035 debug!("Index {} Info {} / {:?} / {:?} Variance {:?}",
1036 index, info.index, info.kind, info.space, variance);
1039 types.push(info.space, variance);
1042 regions.push(info.space, variance);
1048 let item_variances = ty::ItemVariances {
1052 debug!("item_id={} item_variances={}",
1054 item_variances.repr(tcx));
1056 let item_def_id = ast_util::local_def(item_id);
1058 // For unit testing: check for a special "rustc_variance"
1059 // attribute and report an error with various results if found.
1060 if ty::has_attr(tcx, item_def_id, "rustc_variance") {
1061 let found = item_variances.repr(tcx);
1062 tcx.sess.span_err(tcx.map.span(item_id), &found[]);
1065 let newly_added = tcx.item_variance_map.borrow_mut()
1066 .insert(item_def_id, Rc::new(item_variances)).is_none();
1067 assert!(newly_added);
1071 fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
1073 ConstantTerm(v) => {
1077 TransformTerm(t1, t2) => {
1078 let v1 = self.evaluate(t1);
1079 let v2 = self.evaluate(t2);
1083 InferredTerm(InferredIndex(index)) => {
1084 self.solutions[index]
1090 // Miscellany transformations on variance
1093 fn xform(self, v: Self) -> Self;
1096 impl Xform for ty::Variance {
1097 fn xform(self, v: ty::Variance) -> ty::Variance {
1098 // "Variance transformation", Figure 1 of The Paper
1100 // Figure 1, column 1.
1101 (ty::Covariant, ty::Covariant) => ty::Covariant,
1102 (ty::Covariant, ty::Contravariant) => ty::Contravariant,
1103 (ty::Covariant, ty::Invariant) => ty::Invariant,
1104 (ty::Covariant, ty::Bivariant) => ty::Bivariant,
1106 // Figure 1, column 2.
1107 (ty::Contravariant, ty::Covariant) => ty::Contravariant,
1108 (ty::Contravariant, ty::Contravariant) => ty::Covariant,
1109 (ty::Contravariant, ty::Invariant) => ty::Invariant,
1110 (ty::Contravariant, ty::Bivariant) => ty::Bivariant,
1112 // Figure 1, column 3.
1113 (ty::Invariant, _) => ty::Invariant,
1115 // Figure 1, column 4.
1116 (ty::Bivariant, _) => ty::Bivariant,
1121 fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance {
1122 // Greatest lower bound of the variance lattice as
1123 // defined in The Paper:
1129 (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant,
1131 (ty::Covariant, ty::Contravariant) => ty::Invariant,
1132 (ty::Contravariant, ty::Covariant) => ty::Invariant,
1134 (ty::Covariant, ty::Covariant) => ty::Covariant,
1136 (ty::Contravariant, ty::Contravariant) => ty::Contravariant,
1138 (x, ty::Bivariant) | (ty::Bivariant, x) => x,