]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/variance/constraints.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_typeck / variance / constraints.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 construction and representation
12//!
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.
15
16use dep_graph::DepTrackingMapConfig;
54a0048b 17use hir::def_id::DefId;
7453a54e 18use middle::resolve_lifetime as rl;
54a0048b
SL
19use rustc::ty::subst;
20use rustc::ty::subst::ParamSpace;
21use rustc::ty::{self, Ty, TyCtxt};
22use rustc::ty::maps::ItemVariances;
23use rustc::hir::map as hir_map;
7453a54e 24use syntax::ast;
54a0048b
SL
25use rustc::hir;
26use rustc::hir::intravisit::Visitor;
7453a54e
SL
27
28use super::terms::*;
29use super::terms::VarianceTerm::*;
30use super::terms::ParamKind::*;
31use super::xform::*;
32
33pub struct ConstraintContext<'a, 'tcx: 'a> {
34 pub terms_cx: TermsContext<'a, 'tcx>,
35
36 // These are pointers to common `ConstantTerm` instances
37 covariant: VarianceTermPtr<'a>,
38 contravariant: VarianceTermPtr<'a>,
39 invariant: VarianceTermPtr<'a>,
40 bivariant: VarianceTermPtr<'a>,
41
42 pub constraints: Vec<Constraint<'a>> ,
43}
44
45/// Declares that the variable `decl_id` appears in a location with
46/// variance `variance`.
47#[derive(Copy, Clone)]
48pub struct Constraint<'a> {
49 pub inferred: InferredIndex,
50 pub variance: &'a VarianceTerm<'a>,
51}
52
53pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
54 -> ConstraintContext<'a, 'tcx>
55{
56 let tcx = terms_cx.tcx;
57 let covariant = terms_cx.arena.alloc(ConstantTerm(ty::Covariant));
58 let contravariant = terms_cx.arena.alloc(ConstantTerm(ty::Contravariant));
59 let invariant = terms_cx.arena.alloc(ConstantTerm(ty::Invariant));
60 let bivariant = terms_cx.arena.alloc(ConstantTerm(ty::Bivariant));
61 let mut constraint_cx = ConstraintContext {
62 terms_cx: terms_cx,
63 covariant: covariant,
64 contravariant: contravariant,
65 invariant: invariant,
66 bivariant: bivariant,
67 constraints: Vec::new(),
68 };
69
70 // See README.md for a discussion on dep-graph management.
71 tcx.visit_all_items_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
72 &mut constraint_cx);
73
74 constraint_cx
75}
76
77impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
78 fn visit_item(&mut self, item: &hir::Item) {
79 let tcx = self.terms_cx.tcx;
80 let did = tcx.map.local_def_id(item.id);
81
82 debug!("visit_item item={}", tcx.map.node_to_string(item.id));
83
84 match item.node {
85 hir::ItemEnum(..) | hir::ItemStruct(..) => {
86 let scheme = tcx.lookup_item_type(did);
87
88 // Not entirely obvious: constraints on structs/enums do not
89 // affect the variance of their type parameters. See discussion
90 // in comment at top of module.
91 //
92 // self.add_constraints_from_generics(&scheme.generics);
93
94 for field in tcx.lookup_adt_def(did).all_fields() {
95 self.add_constraints_from_ty(&scheme.generics,
96 field.unsubst_ty(),
97 self.covariant);
98 }
99 }
100 hir::ItemTrait(..) => {
101 let trait_def = tcx.lookup_trait_def(did);
102 self.add_constraints_from_trait_ref(&trait_def.generics,
103 trait_def.trait_ref,
104 self.invariant);
105 }
106
107 hir::ItemExternCrate(_) |
108 hir::ItemUse(_) |
109 hir::ItemStatic(..) |
110 hir::ItemConst(..) |
111 hir::ItemFn(..) |
112 hir::ItemMod(..) |
113 hir::ItemForeignMod(..) |
114 hir::ItemTy(..) |
115 hir::ItemImpl(..) |
116 hir::ItemDefaultImpl(..) => {
117 }
118 }
119 }
120}
121
122/// Is `param_id` a lifetime according to `map`?
123fn is_lifetime(map: &hir_map::Map, param_id: ast::NodeId) -> bool {
124 match map.find(param_id) {
125 Some(hir_map::NodeLifetime(..)) => true, _ => false
126 }
127}
128
129impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
54a0048b 130 fn tcx(&self) -> &'a TyCtxt<'tcx> {
7453a54e
SL
131 self.terms_cx.tcx
132 }
133
134 fn inferred_index(&self, param_id: ast::NodeId) -> InferredIndex {
135 match self.terms_cx.inferred_map.get(&param_id) {
136 Some(&index) => index,
137 None => {
54a0048b
SL
138 bug!("no inferred index entry for {}",
139 self.tcx().map.node_to_string(param_id));
7453a54e
SL
140 }
141 }
142 }
143
144 fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId {
145 let tcx = self.terms_cx.tcx;
146 assert!(is_lifetime(&tcx.map, param_id));
147 match tcx.named_region_map.get(&param_id) {
148 Some(&rl::DefEarlyBoundRegion(_, _, lifetime_decl_id))
149 => lifetime_decl_id,
54a0048b 150 Some(_) => bug!("should not encounter non early-bound cases"),
7453a54e
SL
151
152 // The lookup should only fail when `param_id` is
153 // itself a lifetime binding: use it as the decl_id.
154 None => param_id,
155 }
156
157 }
158
159 /// Is `param_id` a type parameter for which we infer variance?
160 fn is_to_be_inferred(&self, param_id: ast::NodeId) -> bool {
161 let result = self.terms_cx.inferred_map.contains_key(&param_id);
162
163 // To safe-guard against invalid inferred_map constructions,
164 // double-check if variance is inferred at some use of a type
165 // parameter (by inspecting parent of its binding declaration
166 // to see if it is introduced by a type or by a fn/impl).
167
168 let check_result = |this:&ConstraintContext| -> bool {
169 let tcx = this.terms_cx.tcx;
170 let decl_id = this.find_binding_for_lifetime(param_id);
171 // Currently only called on lifetimes; double-checking that.
172 assert!(is_lifetime(&tcx.map, param_id));
173 let parent_id = tcx.map.get_parent(decl_id);
174 let parent = tcx.map.find(parent_id).unwrap_or_else(
54a0048b 175 || bug!("tcx.map missing entry for id: {}", parent_id));
7453a54e
SL
176
177 let is_inferred;
178 macro_rules! cannot_happen { () => { {
54a0048b
SL
179 bug!("invalid parent: {} for {}",
180 tcx.map.node_to_string(parent_id),
181 tcx.map.node_to_string(param_id));
7453a54e
SL
182 } } }
183
184 match parent {
185 hir_map::NodeItem(p) => {
186 match p.node {
187 hir::ItemTy(..) |
188 hir::ItemEnum(..) |
189 hir::ItemStruct(..) |
190 hir::ItemTrait(..) => is_inferred = true,
191 hir::ItemFn(..) => is_inferred = false,
192 _ => cannot_happen!(),
193 }
194 }
195 hir_map::NodeTraitItem(..) => is_inferred = false,
196 hir_map::NodeImplItem(..) => is_inferred = false,
197 _ => cannot_happen!(),
198 }
199
200 return is_inferred;
201 };
202
203 assert_eq!(result, check_result(self));
204
205 return result;
206 }
207
208 /// Returns a variance term representing the declared variance of the type/region parameter
209 /// with the given id.
210 fn declared_variance(&self,
211 param_def_id: DefId,
212 item_def_id: DefId,
213 kind: ParamKind,
214 space: ParamSpace,
215 index: usize)
216 -> VarianceTermPtr<'a> {
217 assert_eq!(param_def_id.krate, item_def_id.krate);
218
219 if let Some(param_node_id) = self.tcx().map.as_local_node_id(param_def_id) {
220 // Parameter on an item defined within current crate:
221 // variance not yet inferred, so return a symbolic
222 // variance.
223 let InferredIndex(index) = self.inferred_index(param_node_id);
224 self.terms_cx.inferred_infos[index].term
225 } else {
226 // Parameter on an item defined within another crate:
227 // variance already inferred, just look it up.
228 let variances = self.tcx().item_variances(item_def_id);
229 let variance = match kind {
230 TypeParam => *variances.types.get(space, index),
231 RegionParam => *variances.regions.get(space, index),
232 };
233 self.constant_term(variance)
234 }
235 }
236
237 fn add_constraint(&mut self,
238 InferredIndex(index): InferredIndex,
239 variance: VarianceTermPtr<'a>) {
240 debug!("add_constraint(index={}, variance={:?})",
241 index, variance);
242 self.constraints.push(Constraint { inferred: InferredIndex(index),
243 variance: variance });
244 }
245
246 fn contravariant(&mut self,
247 variance: VarianceTermPtr<'a>)
248 -> VarianceTermPtr<'a> {
249 self.xform(variance, self.contravariant)
250 }
251
252 fn invariant(&mut self,
253 variance: VarianceTermPtr<'a>)
254 -> VarianceTermPtr<'a> {
255 self.xform(variance, self.invariant)
256 }
257
258 fn constant_term(&self, v: ty::Variance) -> VarianceTermPtr<'a> {
259 match v {
260 ty::Covariant => self.covariant,
261 ty::Invariant => self.invariant,
262 ty::Contravariant => self.contravariant,
263 ty::Bivariant => self.bivariant,
264 }
265 }
266
267 fn xform(&mut self,
268 v1: VarianceTermPtr<'a>,
269 v2: VarianceTermPtr<'a>)
270 -> VarianceTermPtr<'a> {
271 match (*v1, *v2) {
272 (_, ConstantTerm(ty::Covariant)) => {
273 // Applying a "covariant" transform is always a no-op
274 v1
275 }
276
277 (ConstantTerm(c1), ConstantTerm(c2)) => {
278 self.constant_term(c1.xform(c2))
279 }
280
281 _ => {
282 &*self.terms_cx.arena.alloc(TransformTerm(v1, v2))
283 }
284 }
285 }
286
287 fn add_constraints_from_trait_ref(&mut self,
288 generics: &ty::Generics<'tcx>,
289 trait_ref: ty::TraitRef<'tcx>,
290 variance: VarianceTermPtr<'a>) {
291 debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
292 trait_ref,
293 variance);
294
295 let trait_def = self.tcx().lookup_trait_def(trait_ref.def_id);
296
297 // This edge is actually implied by the call to
298 // `lookup_trait_def`, but I'm trying to be future-proof. See
299 // README.md for a discussion on dep-graph management.
300 self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
301
302 self.add_constraints_from_substs(
303 generics,
304 trait_ref.def_id,
305 trait_def.generics.types.as_slice(),
306 trait_def.generics.regions.as_slice(),
307 trait_ref.substs,
308 variance);
309 }
310
311 /// Adds constraints appropriate for an instance of `ty` appearing
312 /// in a context with the generics defined in `generics` and
313 /// ambient variance `variance`
314 fn add_constraints_from_ty(&mut self,
315 generics: &ty::Generics<'tcx>,
316 ty: Ty<'tcx>,
317 variance: VarianceTermPtr<'a>) {
318 debug!("add_constraints_from_ty(ty={:?}, variance={:?})",
319 ty,
320 variance);
321
322 match ty.sty {
323 ty::TyBool |
324 ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
325 ty::TyFloat(_) | ty::TyStr => {
326 /* leaf type -- noop */
327 }
328
329 ty::TyClosure(..) => {
54a0048b 330 bug!("Unexpected closure type in variance computation");
7453a54e
SL
331 }
332
333 ty::TyRef(region, ref mt) => {
334 let contra = self.contravariant(variance);
335 self.add_constraints_from_region(generics, *region, contra);
336 self.add_constraints_from_mt(generics, mt, variance);
337 }
338
339 ty::TyBox(typ) | ty::TyArray(typ, _) | ty::TySlice(typ) => {
340 self.add_constraints_from_ty(generics, typ, variance);
341 }
342
343
344 ty::TyRawPtr(ref mt) => {
345 self.add_constraints_from_mt(generics, mt, variance);
346 }
347
348 ty::TyTuple(ref subtys) => {
349 for &subty in subtys {
350 self.add_constraints_from_ty(generics, subty, variance);
351 }
352 }
353
354 ty::TyEnum(def, substs) |
355 ty::TyStruct(def, substs) => {
356 let item_type = self.tcx().lookup_item_type(def.did);
357
358 // This edge is actually implied by the call to
359 // `lookup_trait_def`, but I'm trying to be future-proof. See
360 // README.md for a discussion on dep-graph management.
361 self.tcx().dep_graph.read(ItemVariances::to_dep_node(&def.did));
362
363 // All type parameters on enums and structs should be
364 // in the TypeSpace.
365 assert!(item_type.generics.types.is_empty_in(subst::SelfSpace));
366 assert!(item_type.generics.types.is_empty_in(subst::FnSpace));
367 assert!(item_type.generics.regions.is_empty_in(subst::SelfSpace));
368 assert!(item_type.generics.regions.is_empty_in(subst::FnSpace));
369
370 self.add_constraints_from_substs(
371 generics,
372 def.did,
373 item_type.generics.types.get_slice(subst::TypeSpace),
374 item_type.generics.regions.get_slice(subst::TypeSpace),
375 substs,
376 variance);
377 }
378
379 ty::TyProjection(ref data) => {
380 let trait_ref = &data.trait_ref;
381 let trait_def = self.tcx().lookup_trait_def(trait_ref.def_id);
382
383 // This edge is actually implied by the call to
384 // `lookup_trait_def`, but I'm trying to be future-proof. See
385 // README.md for a discussion on dep-graph management.
386 self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
387
388 self.add_constraints_from_substs(
389 generics,
390 trait_ref.def_id,
391 trait_def.generics.types.as_slice(),
392 trait_def.generics.regions.as_slice(),
393 trait_ref.substs,
394 variance);
395 }
396
397 ty::TyTrait(ref data) => {
398 let poly_trait_ref =
399 data.principal_trait_ref_with_self_ty(self.tcx(),
400 self.tcx().types.err);
401
402 // The type `Foo<T+'a>` is contravariant w/r/t `'a`:
403 let contra = self.contravariant(variance);
404 self.add_constraints_from_region(generics, data.bounds.region_bound, contra);
405
406 // Ignore the SelfSpace, it is erased.
407 self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance);
408
409 let projections = data.projection_bounds_with_self_ty(self.tcx(),
410 self.tcx().types.err);
411 for projection in &projections {
412 self.add_constraints_from_ty(generics, projection.0.ty, self.invariant);
413 }
414 }
415
416 ty::TyParam(ref data) => {
417 let def_id = generics.types.get(data.space, data.idx as usize).def_id;
418 let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
419 match self.terms_cx.inferred_map.get(&node_id) {
420 Some(&index) => {
421 self.add_constraint(index, variance);
422 }
423 None => {
424 // We do not infer variance for type parameters
425 // declared on methods. They will not be present
426 // in the inferred_map.
427 }
428 }
429 }
430
54a0048b
SL
431 ty::TyFnDef(_, _, &ty::BareFnTy { ref sig, .. }) |
432 ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => {
7453a54e
SL
433 self.add_constraints_from_sig(generics, sig, variance);
434 }
435
436 ty::TyError => {
437 // we encounter this when walking the trait references for object
438 // types, where we use TyError as the Self type
439 }
440
441 ty::TyInfer(..) => {
54a0048b
SL
442 bug!("unexpected type encountered in \
443 variance inference: {}", ty);
7453a54e
SL
444 }
445 }
446 }
447
448 /// Adds constraints appropriate for a nominal type (enum, struct,
449 /// object, etc) appearing in a context with ambient variance `variance`
450 fn add_constraints_from_substs(&mut self,
451 generics: &ty::Generics<'tcx>,
452 def_id: DefId,
453 type_param_defs: &[ty::TypeParameterDef<'tcx>],
454 region_param_defs: &[ty::RegionParameterDef],
455 substs: &subst::Substs<'tcx>,
456 variance: VarianceTermPtr<'a>) {
457 debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})",
458 def_id,
459 substs,
460 variance);
461
462 for p in type_param_defs {
463 let variance_decl =
464 self.declared_variance(p.def_id, def_id, TypeParam,
465 p.space, p.index as usize);
466 let variance_i = self.xform(variance, variance_decl);
467 let substs_ty = *substs.types.get(p.space, p.index as usize);
468 debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
469 variance_decl, variance_i);
470 self.add_constraints_from_ty(generics, substs_ty, variance_i);
471 }
472
473 for p in region_param_defs {
474 let variance_decl =
475 self.declared_variance(p.def_id, def_id,
476 RegionParam, p.space, p.index as usize);
477 let variance_i = self.xform(variance, variance_decl);
54a0048b 478 let substs_r = *substs.regions.get(p.space, p.index as usize);
7453a54e
SL
479 self.add_constraints_from_region(generics, substs_r, variance_i);
480 }
481 }
482
483 /// Adds constraints appropriate for a function with signature
484 /// `sig` appearing in a context with ambient variance `variance`
485 fn add_constraints_from_sig(&mut self,
486 generics: &ty::Generics<'tcx>,
487 sig: &ty::PolyFnSig<'tcx>,
488 variance: VarianceTermPtr<'a>) {
489 let contra = self.contravariant(variance);
490 for &input in &sig.0.inputs {
491 self.add_constraints_from_ty(generics, input, contra);
492 }
493 if let ty::FnConverging(result_type) = sig.0.output {
494 self.add_constraints_from_ty(generics, result_type, variance);
495 }
496 }
497
498 /// Adds constraints appropriate for a region appearing in a
499 /// context with ambient variance `variance`
500 fn add_constraints_from_region(&mut self,
501 generics: &ty::Generics<'tcx>,
502 region: ty::Region,
503 variance: VarianceTermPtr<'a>) {
504 match region {
505 ty::ReEarlyBound(ref data) => {
506 let def_id =
507 generics.regions.get(data.space, data.index as usize).def_id;
508 let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
509 if self.is_to_be_inferred(node_id) {
510 let index = self.inferred_index(node_id);
511 self.add_constraint(index, variance);
512 }
513 }
514
515 ty::ReStatic => { }
516
517 ty::ReLateBound(..) => {
518 // We do not infer variance for region parameters on
519 // methods or in fn types.
520 }
521
522 ty::ReFree(..) | ty::ReScope(..) | ty::ReVar(..) |
523 ty::ReSkolemized(..) | ty::ReEmpty => {
524 // We don't expect to see anything but 'static or bound
525 // regions when visiting member types or method types.
54a0048b
SL
526 bug!("unexpected region encountered in variance \
527 inference: {:?}",
528 region);
7453a54e
SL
529 }
530 }
531 }
532
533 /// Adds constraints appropriate for a mutability-type pair
534 /// appearing in a context with ambient variance `variance`
535 fn add_constraints_from_mt(&mut self,
536 generics: &ty::Generics<'tcx>,
537 mt: &ty::TypeAndMut<'tcx>,
538 variance: VarianceTermPtr<'a>) {
539 match mt.mutbl {
540 hir::MutMutable => {
541 let invar = self.invariant(variance);
542 self.add_constraints_from_ty(generics, mt.ty, invar);
543 }
544
545 hir::MutImmutable => {
546 self.add_constraints_from_ty(generics, mt.ty, variance);
547 }
548 }
549 }
550}