]>
Commit | Line | Data |
---|---|---|
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 | ||
16 | use dep_graph::DepTrackingMapConfig; | |
54a0048b | 17 | use hir::def_id::DefId; |
7453a54e | 18 | use middle::resolve_lifetime as rl; |
54a0048b SL |
19 | use rustc::ty::subst; |
20 | use rustc::ty::subst::ParamSpace; | |
21 | use rustc::ty::{self, Ty, TyCtxt}; | |
22 | use rustc::ty::maps::ItemVariances; | |
23 | use rustc::hir::map as hir_map; | |
7453a54e | 24 | use syntax::ast; |
54a0048b SL |
25 | use rustc::hir; |
26 | use rustc::hir::intravisit::Visitor; | |
7453a54e SL |
27 | |
28 | use super::terms::*; | |
29 | use super::terms::VarianceTerm::*; | |
30 | use super::terms::ParamKind::*; | |
31 | use super::xform::*; | |
32 | ||
33 | pub 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)] | |
48 | pub struct Constraint<'a> { | |
49 | pub inferred: InferredIndex, | |
50 | pub variance: &'a VarianceTerm<'a>, | |
51 | } | |
52 | ||
53 | pub 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 | ||
77 | impl<'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`? | |
123 | fn 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 | ||
129 | impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { | |
a7813a04 | 130 | fn tcx(&self) -> TyCtxt<'a, 'tcx, '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(¶m_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)); | |
3157f602 | 147 | match tcx.named_region_map.defs.get(¶m_id) { |
7453a54e SL |
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(¶m_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(_) | | |
5bcae85e | 325 | ty::TyFloat(_) | ty::TyStr | ty::TyNever => { |
7453a54e SL |
326 | /* leaf type -- noop */ |
327 | } | |
328 | ||
5bcae85e | 329 | ty::TyClosure(..) | ty::TyAnon(..) => { |
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 | ||
a7813a04 | 348 | ty::TyTuple(subtys) => { |
7453a54e SL |
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 | } | |
5bcae85e | 493 | self.add_constraints_from_ty(generics, sig.0.output, variance); |
7453a54e SL |
494 | } |
495 | ||
496 | /// Adds constraints appropriate for a region appearing in a | |
497 | /// context with ambient variance `variance` | |
498 | fn add_constraints_from_region(&mut self, | |
499 | generics: &ty::Generics<'tcx>, | |
500 | region: ty::Region, | |
501 | variance: VarianceTermPtr<'a>) { | |
502 | match region { | |
503 | ty::ReEarlyBound(ref data) => { | |
504 | let def_id = | |
505 | generics.regions.get(data.space, data.index as usize).def_id; | |
506 | let node_id = self.tcx().map.as_local_node_id(def_id).unwrap(); | |
507 | if self.is_to_be_inferred(node_id) { | |
508 | let index = self.inferred_index(node_id); | |
509 | self.add_constraint(index, variance); | |
510 | } | |
511 | } | |
512 | ||
513 | ty::ReStatic => { } | |
514 | ||
515 | ty::ReLateBound(..) => { | |
516 | // We do not infer variance for region parameters on | |
517 | // methods or in fn types. | |
518 | } | |
519 | ||
520 | ty::ReFree(..) | ty::ReScope(..) | ty::ReVar(..) | | |
3157f602 | 521 | ty::ReSkolemized(..) | ty::ReEmpty | ty::ReErased => { |
7453a54e SL |
522 | // We don't expect to see anything but 'static or bound |
523 | // regions when visiting member types or method types. | |
54a0048b SL |
524 | bug!("unexpected region encountered in variance \ |
525 | inference: {:?}", | |
526 | region); | |
7453a54e SL |
527 | } |
528 | } | |
529 | } | |
530 | ||
531 | /// Adds constraints appropriate for a mutability-type pair | |
532 | /// appearing in a context with ambient variance `variance` | |
533 | fn add_constraints_from_mt(&mut self, | |
534 | generics: &ty::Generics<'tcx>, | |
535 | mt: &ty::TypeAndMut<'tcx>, | |
536 | variance: VarianceTermPtr<'a>) { | |
537 | match mt.mutbl { | |
538 | hir::MutMutable => { | |
539 | let invar = self.invariant(variance); | |
540 | self.add_constraints_from_ty(generics, mt.ty, invar); | |
541 | } | |
542 | ||
543 | hir::MutImmutable => { | |
544 | self.add_constraints_from_ty(generics, mt.ty, variance); | |
545 | } | |
546 | } | |
547 | } | |
548 | } |