1 //! Constraint construction and representation
3 //! The second pass over the AST determines the set of constraints.
4 //! We walk the set of items and, for each member, generate new constraints.
6 use hir::def_id::DefId;
7 use rustc::ty::subst::{GenericArgKind, SubstsRef};
8 use rustc::ty::{self, Ty, TyCtxt};
10 use rustc_hir::itemlikevisit::ItemLikeVisitor;
12 use super::terms::VarianceTerm::*;
15 pub struct ConstraintContext<'a, 'tcx> {
16 pub terms_cx: TermsContext<'a, 'tcx>,
18 // These are pointers to common `ConstantTerm` instances
19 covariant: VarianceTermPtr<'a>,
20 contravariant: VarianceTermPtr<'a>,
21 invariant: VarianceTermPtr<'a>,
22 bivariant: VarianceTermPtr<'a>,
24 pub constraints: Vec<Constraint<'a>>,
27 /// Declares that the variable `decl_id` appears in a location with
28 /// variance `variance`.
29 #[derive(Copy, Clone)]
30 pub struct Constraint<'a> {
31 pub inferred: InferredIndex,
32 pub variance: &'a VarianceTerm<'a>,
35 /// To build constraints, we visit one item (type, trait) at a time
36 /// and look at its contents. So e.g., if we have
42 /// then while we are visiting `Bar<T>`, the `CurrentItem` would have
43 /// the `DefId` and the start of `Foo`'s inferreds.
44 pub struct CurrentItem {
45 inferred_start: InferredIndex,
48 pub fn add_constraints_from_crate<'a, 'tcx>(
49 terms_cx: TermsContext<'a, 'tcx>,
50 ) -> ConstraintContext<'a, 'tcx> {
51 let tcx = terms_cx.tcx;
52 let covariant = terms_cx.arena.alloc(ConstantTerm(ty::Covariant));
53 let contravariant = terms_cx.arena.alloc(ConstantTerm(ty::Contravariant));
54 let invariant = terms_cx.arena.alloc(ConstantTerm(ty::Invariant));
55 let bivariant = terms_cx.arena.alloc(ConstantTerm(ty::Bivariant));
56 let mut constraint_cx = ConstraintContext {
62 constraints: Vec::new(),
65 tcx.hir().krate().visit_all_item_likes(&mut constraint_cx);
70 impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
71 fn visit_item(&mut self, item: &hir::Item<'_>) {
73 hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
74 self.visit_node_helper(item.hir_id);
76 if let hir::VariantData::Tuple(..) = *struct_def {
77 self.visit_node_helper(struct_def.ctor_hir_id().unwrap());
81 hir::ItemKind::Enum(ref enum_def, _) => {
82 self.visit_node_helper(item.hir_id);
84 for variant in enum_def.variants {
85 if let hir::VariantData::Tuple(..) = variant.data {
86 self.visit_node_helper(variant.data.ctor_hir_id().unwrap());
91 hir::ItemKind::Fn(..) => {
92 self.visit_node_helper(item.hir_id);
95 hir::ItemKind::ForeignMod(ref foreign_mod) => {
96 for foreign_item in foreign_mod.items {
97 if let hir::ForeignItemKind::Fn(..) = foreign_item.kind {
98 self.visit_node_helper(foreign_item.hir_id);
107 fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
108 if let hir::TraitItemKind::Method(..) = trait_item.kind {
109 self.visit_node_helper(trait_item.hir_id);
113 fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
114 if let hir::ImplItemKind::Method(..) = impl_item.kind {
115 self.visit_node_helper(impl_item.hir_id);
120 impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
121 fn visit_node_helper(&mut self, id: hir::HirId) {
122 let tcx = self.terms_cx.tcx;
123 let def_id = tcx.hir().local_def_id(id);
124 self.build_constraints_for_item(def_id);
127 fn tcx(&self) -> TyCtxt<'tcx> {
131 fn build_constraints_for_item(&mut self, def_id: DefId) {
132 let tcx = self.tcx();
133 debug!("build_constraints_for_item({})", tcx.def_path_str(def_id));
135 // Skip items with no generics - there's nothing to infer in them.
136 if tcx.generics_of(def_id).count() == 0 {
140 let id = tcx.hir().as_local_hir_id(def_id).unwrap();
141 let inferred_start = self.terms_cx.inferred_starts[&id];
142 let current_item = &CurrentItem { inferred_start };
143 match tcx.type_of(def_id).kind {
145 // Not entirely obvious: constraints on structs/enums do not
146 // affect the variance of their type parameters. See discussion
147 // in comment at top of module.
149 // self.add_constraints_from_generics(generics);
151 for field in def.all_fields() {
152 self.add_constraints_from_ty(
154 tcx.type_of(field.did),
161 self.add_constraints_from_sig(current_item, tcx.fn_sig(def_id), self.covariant);
166 tcx.def_span(def_id),
167 "`build_constraints_for_item` unsupported for this item"
173 fn add_constraint(&mut self, current: &CurrentItem, index: u32, variance: VarianceTermPtr<'a>) {
174 debug!("add_constraint(index={}, variance={:?})", index, variance);
175 self.constraints.push(Constraint {
176 inferred: InferredIndex(current.inferred_start.0 + index as usize),
181 fn contravariant(&mut self, variance: VarianceTermPtr<'a>) -> VarianceTermPtr<'a> {
182 self.xform(variance, self.contravariant)
185 fn invariant(&mut self, variance: VarianceTermPtr<'a>) -> VarianceTermPtr<'a> {
186 self.xform(variance, self.invariant)
189 fn constant_term(&self, v: ty::Variance) -> VarianceTermPtr<'a> {
191 ty::Covariant => self.covariant,
192 ty::Invariant => self.invariant,
193 ty::Contravariant => self.contravariant,
194 ty::Bivariant => self.bivariant,
198 fn xform(&mut self, v1: VarianceTermPtr<'a>, v2: VarianceTermPtr<'a>) -> VarianceTermPtr<'a> {
200 (_, ConstantTerm(ty::Covariant)) => {
201 // Applying a "covariant" transform is always a no-op
205 (ConstantTerm(c1), ConstantTerm(c2)) => self.constant_term(c1.xform(c2)),
207 _ => &*self.terms_cx.arena.alloc(TransformTerm(v1, v2)),
211 fn add_constraints_from_trait_ref(
213 current: &CurrentItem,
214 trait_ref: ty::TraitRef<'tcx>,
215 variance: VarianceTermPtr<'a>,
217 debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}", trait_ref, variance);
218 self.add_constraints_from_invariant_substs(current, trait_ref.substs, variance);
221 fn add_constraints_from_invariant_substs(
223 current: &CurrentItem,
224 substs: SubstsRef<'tcx>,
225 variance: VarianceTermPtr<'a>,
228 "add_constraints_from_invariant_substs: substs={:?} variance={:?}",
232 // Trait are always invariant so we can take advantage of that.
233 let variance_i = self.invariant(variance);
237 GenericArgKind::Lifetime(lt) => {
238 self.add_constraints_from_region(current, lt, variance_i)
240 GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
241 GenericArgKind::Const(_) => {
242 // Consts impose no constraints.
248 /// Adds constraints appropriate for an instance of `ty` appearing
249 /// in a context with the generics defined in `generics` and
250 /// ambient variance `variance`
251 fn add_constraints_from_ty(
253 current: &CurrentItem,
255 variance: VarianceTermPtr<'a>,
257 debug!("add_constraints_from_ty(ty={:?}, variance={:?})", ty, variance);
267 | ty::Foreign(..) => {
271 ty::FnDef(..) | ty::Generator(..) | ty::Closure(..) => {
272 bug!("Unexpected closure type in variance computation");
275 ty::Ref(region, ty, mutbl) => {
276 let contra = self.contravariant(variance);
277 self.add_constraints_from_region(current, region, contra);
278 self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
281 ty::Array(typ, _) => {
282 self.add_constraints_from_ty(current, typ, variance);
286 self.add_constraints_from_ty(current, typ, variance);
289 ty::RawPtr(ref mt) => {
290 self.add_constraints_from_mt(current, mt, variance);
293 ty::Tuple(subtys) => {
294 for &subty in subtys {
295 self.add_constraints_from_ty(current, subty.expect_ty(), variance);
299 ty::Adt(def, substs) => {
300 self.add_constraints_from_substs(current, def.did, substs, variance);
303 ty::Projection(ref data) => {
304 let tcx = self.tcx();
305 self.add_constraints_from_trait_ref(current, data.trait_ref(tcx), variance);
308 ty::Opaque(_, substs) => {
309 self.add_constraints_from_invariant_substs(current, substs, variance);
312 ty::Dynamic(ref data, r) => {
313 // The type `Foo<T+'a>` is contravariant w/r/t `'a`:
314 let contra = self.contravariant(variance);
315 self.add_constraints_from_region(current, r, contra);
317 if let Some(poly_trait_ref) = data.principal() {
319 poly_trait_ref.with_self_ty(self.tcx(), self.tcx().types.err);
320 self.add_constraints_from_trait_ref(
322 *poly_trait_ref.skip_binder(),
327 for projection in data.projection_bounds() {
328 self.add_constraints_from_ty(
330 projection.skip_binder().ty,
336 ty::Param(ref data) => {
337 self.add_constraint(current, data.index, variance);
341 self.add_constraints_from_sig(current, sig, variance);
345 // we encounter this when walking the trait references for object
346 // types, where we use Error as the Self type
350 | ty::UnnormalizedProjection(..)
351 | ty::GeneratorWitness(..)
355 "unexpected type encountered in \
356 variance inference: {}",
363 /// Adds constraints appropriate for a nominal type (enum, struct,
364 /// object, etc) appearing in a context with ambient variance `variance`
365 fn add_constraints_from_substs(
367 current: &CurrentItem,
369 substs: SubstsRef<'tcx>,
370 variance: VarianceTermPtr<'a>,
373 "add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})",
374 def_id, substs, variance
377 // We don't record `inferred_starts` entries for empty generics.
378 if substs.is_empty() {
382 let (local, remote) = if let Some(id) = self.tcx().hir().as_local_hir_id(def_id) {
383 (Some(self.terms_cx.inferred_starts[&id]), None)
385 (None, Some(self.tcx().variances_of(def_id)))
388 for (i, k) in substs.iter().enumerate() {
389 let variance_decl = if let Some(InferredIndex(start)) = local {
390 // Parameter on an item defined within current crate:
391 // variance not yet inferred, so return a symbolic
393 self.terms_cx.inferred_terms[start + i]
395 // Parameter on an item defined within another crate:
396 // variance already inferred, just look it up.
397 self.constant_term(remote.as_ref().unwrap()[i])
399 let variance_i = self.xform(variance, variance_decl);
401 "add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
402 variance_decl, variance_i
405 GenericArgKind::Lifetime(lt) => {
406 self.add_constraints_from_region(current, lt, variance_i)
408 GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
409 GenericArgKind::Const(_) => {
410 // Consts impose no constraints.
416 /// Adds constraints appropriate for a function with signature
417 /// `sig` appearing in a context with ambient variance `variance`
418 fn add_constraints_from_sig(
420 current: &CurrentItem,
421 sig: ty::PolyFnSig<'tcx>,
422 variance: VarianceTermPtr<'a>,
424 let contra = self.contravariant(variance);
425 for &input in sig.skip_binder().inputs() {
426 self.add_constraints_from_ty(current, input, contra);
428 self.add_constraints_from_ty(current, sig.skip_binder().output(), variance);
431 /// Adds constraints appropriate for a region appearing in a
432 /// context with ambient variance `variance`
433 fn add_constraints_from_region(
435 current: &CurrentItem,
436 region: ty::Region<'tcx>,
437 variance: VarianceTermPtr<'a>,
440 ty::ReEarlyBound(ref data) => {
441 self.add_constraint(current, data.index, variance);
446 ty::ReLateBound(..) => {
447 // Late-bound regions do not get substituted the same
448 // way early-bound regions do, so we skip them here.
452 | ty::ReClosureBound(..)
455 | ty::RePlaceholder(..)
458 // We don't expect to see anything but 'static or bound
459 // regions when visiting member types or method types.
461 "unexpected region encountered in variance \
469 /// Adds constraints appropriate for a mutability-type pair
470 /// appearing in a context with ambient variance `variance`
471 fn add_constraints_from_mt(
473 current: &CurrentItem,
474 mt: &ty::TypeAndMut<'tcx>,
475 variance: VarianceTermPtr<'a>,
478 hir::Mutability::Mut => {
479 let invar = self.invariant(variance);
480 self.add_constraints_from_ty(current, mt.ty, invar);
483 hir::Mutability::Not => {
484 self.add_constraints_from_ty(current, mt.ty, variance);