]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 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 | use astconv::AstConv; | |
d9579d0f | 12 | use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; |
9346a6ac | 13 | use constrained_type_params::{identify_constrained_type_params, Parameter}; |
1a4d82fc JJ |
14 | use CrateCtxt; |
15 | use middle::region; | |
85aaf69f | 16 | use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; |
1a4d82fc JJ |
17 | use middle::traits; |
18 | use middle::ty::{self, Ty}; | |
19 | use middle::ty::liberate_late_bound_regions; | |
20 | use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty}; | |
1a4d82fc JJ |
21 | |
22 | use std::collections::HashSet; | |
23 | use syntax::ast; | |
c34b1796 | 24 | use syntax::ast_util::local_def; |
62682a34 | 25 | use syntax::codemap::{DUMMY_SP, Span}; |
85aaf69f | 26 | use syntax::parse::token::{self, special_idents}; |
1a4d82fc JJ |
27 | use syntax::visit; |
28 | use syntax::visit::Visitor; | |
29 | ||
30 | pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> { | |
31 | ccx: &'ccx CrateCtxt<'ccx, 'tcx>, | |
32 | cache: HashSet<Ty<'tcx>> | |
33 | } | |
34 | ||
35 | impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { | |
36 | pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>) -> CheckTypeWellFormedVisitor<'ccx, 'tcx> { | |
37 | CheckTypeWellFormedVisitor { ccx: ccx, cache: HashSet::new() } | |
38 | } | |
39 | ||
85aaf69f SL |
40 | fn tcx(&self) -> &ty::ctxt<'tcx> { |
41 | self.ccx.tcx | |
42 | } | |
43 | ||
1a4d82fc JJ |
44 | /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are |
45 | /// well-formed, meaning that they do not require any constraints not declared in the struct | |
46 | /// definition itself. For example, this definition would be illegal: | |
47 | /// | |
48 | /// struct Ref<'a, T> { x: &'a T } | |
49 | /// | |
50 | /// because the type did not declare that `T:'a`. | |
51 | /// | |
52 | /// We do this check as a pre-pass before checking fn bodies because if these constraints are | |
53 | /// not included it frequently leads to confusing errors in fn bodies. So it's better to check | |
54 | /// the types first. | |
55 | fn check_item_well_formed(&mut self, item: &ast::Item) { | |
56 | let ccx = self.ccx; | |
57 | debug!("check_item_well_formed(it.id={}, it.ident={})", | |
58 | item.id, | |
59 | ty::item_path_str(ccx.tcx, local_def(item.id))); | |
60 | ||
61 | match item.node { | |
85aaf69f SL |
62 | /// Right now we check that every default trait implementation |
63 | /// has an implementation of itself. Basically, a case like: | |
64 | /// | |
65 | /// `impl Trait for T {}` | |
66 | /// | |
67 | /// has a requirement of `T: Trait` which was required for default | |
68 | /// method implementations. Although this could be improved now that | |
69 | /// there's a better infrastructure in place for this, it's being left | |
70 | /// for a follow-up work. | |
71 | /// | |
72 | /// Since there's such a requirement, we need to check *just* positive | |
73 | /// implementations, otherwise things like: | |
74 | /// | |
75 | /// impl !Send for T {} | |
76 | /// | |
77 | /// won't be allowed unless there's an *explicit* implementation of `Send` | |
78 | /// for `T` | |
79 | ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => { | |
1a4d82fc JJ |
80 | self.check_impl(item); |
81 | } | |
c34b1796 | 82 | ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(_), _, _) => { |
62682a34 SL |
83 | let trait_ref = ty::impl_trait_ref(ccx.tcx, |
84 | local_def(item.id)).unwrap(); | |
c34b1796 | 85 | ty::populate_implementations_for_trait_if_necessary(ccx.tcx, trait_ref.def_id); |
85aaf69f SL |
86 | match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { |
87 | Some(ty::BoundSend) | Some(ty::BoundSync) => {} | |
88 | Some(_) | None => { | |
c34b1796 AL |
89 | if !ty::trait_has_default_impl(ccx.tcx, trait_ref.def_id) { |
90 | span_err!(ccx.tcx.sess, item.span, E0192, | |
91 | "negative impls are only allowed for traits with \ | |
92 | default impls (e.g., `Send` and `Sync`)") | |
93 | } | |
85aaf69f SL |
94 | } |
95 | } | |
96 | } | |
1a4d82fc JJ |
97 | ast::ItemFn(..) => { |
98 | self.check_item_type(item); | |
99 | } | |
100 | ast::ItemStatic(..) => { | |
101 | self.check_item_type(item); | |
102 | } | |
103 | ast::ItemConst(..) => { | |
104 | self.check_item_type(item); | |
105 | } | |
85aaf69f | 106 | ast::ItemStruct(ref struct_def, ref ast_generics) => { |
1a4d82fc JJ |
107 | self.check_type_defn(item, |fcx| { |
108 | vec![struct_variant(fcx, &**struct_def)] | |
109 | }); | |
85aaf69f SL |
110 | |
111 | self.check_variances_for_type_defn(item, ast_generics); | |
1a4d82fc | 112 | } |
85aaf69f | 113 | ast::ItemEnum(ref enum_def, ref ast_generics) => { |
1a4d82fc JJ |
114 | self.check_type_defn(item, |fcx| { |
115 | enum_variants(fcx, enum_def) | |
116 | }); | |
85aaf69f SL |
117 | |
118 | self.check_variances_for_type_defn(item, ast_generics); | |
1a4d82fc | 119 | } |
9346a6ac | 120 | ast::ItemTrait(_, _, _, ref items) => { |
85aaf69f SL |
121 | let trait_predicates = |
122 | ty::lookup_predicates(ccx.tcx, local_def(item.id)); | |
9346a6ac | 123 | reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates); |
c34b1796 AL |
124 | if ty::trait_has_default_impl(ccx.tcx, local_def(item.id)) { |
125 | if !items.is_empty() { | |
62682a34 SL |
126 | span_err!(ccx.tcx.sess, item.span, E0380, |
127 | "traits with default impls (`e.g. unsafe impl \ | |
128 | Trait for ..`) must have no methods or associated items") | |
c34b1796 AL |
129 | } |
130 | } | |
1a4d82fc JJ |
131 | } |
132 | _ => {} | |
133 | } | |
134 | } | |
135 | ||
136 | fn with_fcx<F>(&mut self, item: &ast::Item, mut f: F) where | |
137 | F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>), | |
138 | { | |
139 | let ccx = self.ccx; | |
140 | let item_def_id = local_def(item.id); | |
141 | let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id); | |
85aaf69f SL |
142 | let type_predicates = ty::lookup_predicates(ccx.tcx, item_def_id); |
143 | reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates); | |
1a4d82fc JJ |
144 | let param_env = |
145 | ty::construct_parameter_environment(ccx.tcx, | |
85aaf69f | 146 | item.span, |
1a4d82fc | 147 | &type_scheme.generics, |
85aaf69f | 148 | &type_predicates, |
1a4d82fc JJ |
149 | item.id); |
150 | let inh = Inherited::new(ccx.tcx, param_env); | |
151 | let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); | |
152 | f(self, &fcx); | |
d9579d0f | 153 | fcx.select_all_obligations_or_error(); |
1a4d82fc JJ |
154 | regionck::regionck_item(&fcx, item); |
155 | } | |
156 | ||
157 | /// In a type definition, we check that to ensure that the types of the fields are well-formed. | |
158 | fn check_type_defn<F>(&mut self, item: &ast::Item, mut lookup_fields: F) where | |
159 | F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec<AdtVariant<'tcx>>, | |
160 | { | |
161 | self.with_fcx(item, |this, fcx| { | |
162 | let variants = lookup_fields(fcx); | |
163 | let mut bounds_checker = BoundsChecker::new(fcx, | |
85aaf69f | 164 | item.id, |
1a4d82fc | 165 | Some(&mut this.cache)); |
85aaf69f SL |
166 | debug!("check_type_defn at bounds_checker.scope: {:?}", bounds_checker.scope); |
167 | ||
62682a34 | 168 | for variant in &variants { |
85aaf69f | 169 | for field in &variant.fields { |
1a4d82fc | 170 | // Regions are checked below. |
62682a34 | 171 | bounds_checker.check_traits_in_ty(field.ty, field.span); |
1a4d82fc JJ |
172 | } |
173 | ||
174 | // For DST, all intermediate types must be sized. | |
9346a6ac | 175 | if !variant.fields.is_empty() { |
85aaf69f | 176 | for field in variant.fields.init() { |
1a4d82fc JJ |
177 | fcx.register_builtin_bound( |
178 | field.ty, | |
179 | ty::BoundSized, | |
180 | traits::ObligationCause::new(field.span, | |
181 | fcx.body_id, | |
182 | traits::FieldSized)); | |
183 | } | |
184 | } | |
185 | } | |
186 | ||
187 | let field_tys: Vec<Ty> = | |
188 | variants.iter().flat_map(|v| v.fields.iter().map(|f| f.ty)).collect(); | |
189 | ||
190 | regionck::regionck_ensure_component_tys_wf( | |
85aaf69f | 191 | fcx, item.span, &field_tys); |
1a4d82fc JJ |
192 | }); |
193 | } | |
194 | ||
195 | fn check_item_type(&mut self, | |
196 | item: &ast::Item) | |
197 | { | |
198 | self.with_fcx(item, |this, fcx| { | |
199 | let mut bounds_checker = BoundsChecker::new(fcx, | |
85aaf69f | 200 | item.id, |
1a4d82fc | 201 | Some(&mut this.cache)); |
85aaf69f | 202 | debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope); |
1a4d82fc JJ |
203 | |
204 | let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); | |
205 | let item_ty = fcx.instantiate_type_scheme(item.span, | |
206 | &fcx.inh.param_env.free_substs, | |
207 | &type_scheme.ty); | |
208 | ||
62682a34 | 209 | bounds_checker.check_traits_in_ty(item_ty, item.span); |
1a4d82fc JJ |
210 | }); |
211 | } | |
212 | ||
213 | fn check_impl(&mut self, | |
214 | item: &ast::Item) | |
215 | { | |
216 | self.with_fcx(item, |this, fcx| { | |
1a4d82fc | 217 | let mut bounds_checker = BoundsChecker::new(fcx, |
85aaf69f | 218 | item.id, |
1a4d82fc | 219 | Some(&mut this.cache)); |
85aaf69f | 220 | debug!("check_impl at bounds_checker.scope: {:?}", bounds_checker.scope); |
1a4d82fc JJ |
221 | |
222 | // Find the impl self type as seen from the "inside" -- | |
223 | // that is, with all type parameters converted from bound | |
224 | // to free. | |
225 | let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); | |
226 | let self_ty = fcx.instantiate_type_scheme(item.span, | |
227 | &fcx.inh.param_env.free_substs, | |
228 | &self_ty); | |
229 | ||
62682a34 | 230 | bounds_checker.check_traits_in_ty(self_ty, item.span); |
1a4d82fc JJ |
231 | |
232 | // Similarly, obtain an "inside" reference to the trait | |
233 | // that the impl implements. | |
234 | let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) { | |
235 | None => { return; } | |
236 | Some(t) => { t } | |
237 | }; | |
238 | ||
239 | let trait_ref = fcx.instantiate_type_scheme(item.span, | |
240 | &fcx.inh.param_env.free_substs, | |
241 | &trait_ref); | |
242 | ||
1a4d82fc JJ |
243 | // We are stricter on the trait-ref in an impl than the |
244 | // self-type. In particular, we enforce region | |
245 | // relationships. The reason for this is that (at least | |
246 | // presently) "applying" an impl does not require that the | |
247 | // application site check the well-formedness constraints on the | |
248 | // trait reference. Instead, this is done at the impl site. | |
249 | // Arguably this is wrong and we should treat the trait-reference | |
250 | // the same way as we treat the self-type. | |
62682a34 | 251 | bounds_checker.check_trait_ref(&trait_ref, item.span); |
1a4d82fc JJ |
252 | |
253 | let cause = | |
254 | traits::ObligationCause::new( | |
255 | item.span, | |
256 | fcx.body_id, | |
257 | traits::ItemObligation(trait_ref.def_id)); | |
258 | ||
259 | // Find the supertrait bounds. This will add `int:Bar`. | |
260 | let poly_trait_ref = ty::Binder(trait_ref); | |
c34b1796 AL |
261 | let predicates = ty::lookup_super_predicates(fcx.tcx(), poly_trait_ref.def_id()); |
262 | let predicates = predicates.instantiate_supertrait(fcx.tcx(), &poly_trait_ref); | |
1a4d82fc JJ |
263 | let predicates = { |
264 | let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx); | |
265 | traits::normalize(selcx, cause.clone(), &predicates) | |
266 | }; | |
c34b1796 | 267 | for predicate in predicates.value.predicates { |
1a4d82fc JJ |
268 | fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate)); |
269 | } | |
85aaf69f | 270 | for obligation in predicates.obligations { |
1a4d82fc JJ |
271 | fcx.register_predicate(obligation); |
272 | } | |
273 | }); | |
274 | } | |
85aaf69f SL |
275 | |
276 | fn check_variances_for_type_defn(&self, | |
277 | item: &ast::Item, | |
278 | ast_generics: &ast::Generics) | |
279 | { | |
280 | let item_def_id = local_def(item.id); | |
9346a6ac | 281 | let ty_predicates = ty::lookup_predicates(self.tcx(), item_def_id); |
85aaf69f SL |
282 | let variances = ty::item_variances(self.tcx(), item_def_id); |
283 | ||
284 | let mut constrained_parameters: HashSet<_> = | |
285 | variances.types | |
9346a6ac AL |
286 | .iter_enumerated() |
287 | .filter(|&(_, _, &variance)| variance != ty::Bivariant) | |
288 | .map(|(space, index, _)| self.param_ty(ast_generics, space, index)) | |
289 | .map(|p| Parameter::Type(p)) | |
290 | .collect(); | |
85aaf69f SL |
291 | |
292 | identify_constrained_type_params(self.tcx(), | |
293 | ty_predicates.predicates.as_slice(), | |
294 | None, | |
295 | &mut constrained_parameters); | |
296 | ||
297 | for (space, index, _) in variances.types.iter_enumerated() { | |
298 | let param_ty = self.param_ty(ast_generics, space, index); | |
9346a6ac | 299 | if constrained_parameters.contains(&Parameter::Type(param_ty)) { |
85aaf69f SL |
300 | continue; |
301 | } | |
302 | let span = self.ty_param_span(ast_generics, item, space, index); | |
9346a6ac | 303 | self.report_bivariance(span, param_ty.name); |
85aaf69f SL |
304 | } |
305 | ||
306 | for (space, index, &variance) in variances.regions.iter_enumerated() { | |
307 | if variance != ty::Bivariant { | |
308 | continue; | |
309 | } | |
310 | ||
311 | assert_eq!(space, TypeSpace); | |
312 | let span = ast_generics.lifetimes[index].lifetime.span; | |
313 | let name = ast_generics.lifetimes[index].lifetime.name; | |
9346a6ac | 314 | self.report_bivariance(span, name); |
85aaf69f SL |
315 | } |
316 | } | |
317 | ||
318 | fn param_ty(&self, | |
319 | ast_generics: &ast::Generics, | |
320 | space: ParamSpace, | |
321 | index: usize) | |
322 | -> ty::ParamTy | |
323 | { | |
324 | let name = match space { | |
325 | TypeSpace => ast_generics.ty_params[index].ident.name, | |
326 | SelfSpace => special_idents::type_self.name, | |
327 | FnSpace => self.tcx().sess.bug("Fn space occupied?"), | |
328 | }; | |
329 | ||
330 | ty::ParamTy { space: space, idx: index as u32, name: name } | |
331 | } | |
332 | ||
333 | fn ty_param_span(&self, | |
334 | ast_generics: &ast::Generics, | |
335 | item: &ast::Item, | |
336 | space: ParamSpace, | |
337 | index: usize) | |
338 | -> Span | |
339 | { | |
340 | match space { | |
341 | TypeSpace => ast_generics.ty_params[index].span, | |
342 | SelfSpace => item.span, | |
343 | FnSpace => self.tcx().sess.span_bug(item.span, "Fn space occupied?"), | |
344 | } | |
345 | } | |
346 | ||
347 | fn report_bivariance(&self, | |
348 | span: Span, | |
9346a6ac | 349 | param_name: ast::Name) |
85aaf69f | 350 | { |
62682a34 SL |
351 | span_err!(self.tcx().sess, span, E0392, |
352 | "parameter `{}` is never used", param_name); | |
85aaf69f | 353 | |
9346a6ac | 354 | let suggested_marker_id = self.tcx().lang_items.phantom_data(); |
85aaf69f SL |
355 | match suggested_marker_id { |
356 | Some(def_id) => { | |
c34b1796 | 357 | self.tcx().sess.fileline_help( |
85aaf69f | 358 | span, |
c34b1796 | 359 | &format!("consider removing `{}` or using a marker such as `{}`", |
62682a34 | 360 | param_name, |
c34b1796 | 361 | ty::item_path_str(self.tcx(), def_id))); |
85aaf69f SL |
362 | } |
363 | None => { | |
364 | // no lang items, no help! | |
365 | } | |
366 | } | |
367 | } | |
1a4d82fc JJ |
368 | } |
369 | ||
370 | // Reject any predicates that do not involve a type parameter. | |
371 | fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, | |
372 | span: Span, | |
85aaf69f | 373 | predicates: &ty::GenericPredicates<'tcx>) { |
62682a34 | 374 | for predicate in &predicates.predicates { |
1a4d82fc JJ |
375 | match predicate { |
376 | &ty::Predicate::Trait(ty::Binder(ref tr)) => { | |
377 | let found_param = tr.input_types().iter() | |
378 | .flat_map(|ty| ty.walk()) | |
379 | .any(is_ty_param); | |
380 | if !found_param { report_bound_error(tcx, span, tr.self_ty() )} | |
381 | } | |
382 | &ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(ty, _))) => { | |
383 | let found_param = ty.walk().any(|t| is_ty_param(t)); | |
384 | if !found_param { report_bound_error(tcx, span, ty) } | |
385 | } | |
386 | _ => {} | |
387 | }; | |
388 | } | |
389 | ||
390 | fn report_bound_error<'t>(tcx: &ty::ctxt<'t>, | |
391 | span: Span, | |
392 | bounded_ty: ty::Ty<'t>) { | |
85aaf69f SL |
393 | span_err!(tcx.sess, span, E0193, |
394 | "cannot bound type `{}`, where clause \ | |
1a4d82fc JJ |
395 | bounds may only be attached to types involving \ |
396 | type parameters", | |
62682a34 | 397 | bounded_ty) |
1a4d82fc JJ |
398 | } |
399 | ||
400 | fn is_ty_param(ty: ty::Ty) -> bool { | |
401 | match &ty.sty { | |
62682a34 | 402 | &ty::TyParam(_) => true, |
1a4d82fc JJ |
403 | _ => false |
404 | } | |
405 | } | |
406 | } | |
407 | ||
408 | fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>, | |
409 | span: Span, | |
410 | generics: &ty::Generics<'tcx>) { | |
411 | let impl_params = generics.types.get_slice(subst::TypeSpace).iter() | |
412 | .map(|tp| tp.name).collect::<HashSet<_>>(); | |
413 | ||
85aaf69f | 414 | for method_param in generics.types.get_slice(subst::FnSpace) { |
1a4d82fc | 415 | if impl_params.contains(&method_param.name) { |
85aaf69f SL |
416 | span_err!(tcx.sess, span, E0194, |
417 | "type parameter `{}` shadows another type parameter of the same name", | |
418 | token::get_name(method_param.name)); | |
1a4d82fc JJ |
419 | } |
420 | } | |
421 | } | |
422 | ||
423 | impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { | |
424 | fn visit_item(&mut self, i: &ast::Item) { | |
425 | self.check_item_well_formed(i); | |
426 | visit::walk_item(self, i); | |
427 | } | |
428 | ||
429 | fn visit_fn(&mut self, | |
430 | fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, | |
431 | b: &'v ast::Block, span: Span, id: ast::NodeId) { | |
432 | match fk { | |
433 | visit::FkFnBlock | visit::FkItemFn(..) => {} | |
434 | visit::FkMethod(..) => { | |
85aaf69f | 435 | match ty::impl_or_trait_item(self.tcx(), local_def(id)) { |
1a4d82fc | 436 | ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { |
85aaf69f | 437 | reject_shadowing_type_parameters(self.tcx(), span, &ty_method.generics) |
1a4d82fc JJ |
438 | } |
439 | _ => {} | |
440 | } | |
441 | } | |
442 | } | |
443 | visit::walk_fn(self, fk, fd, b, span) | |
444 | } | |
445 | ||
c34b1796 AL |
446 | fn visit_trait_item(&mut self, trait_item: &'v ast::TraitItem) { |
447 | if let ast::MethodTraitItem(_, None) = trait_item.node { | |
448 | match ty::impl_or_trait_item(self.tcx(), local_def(trait_item.id)) { | |
449 | ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { | |
450 | reject_non_type_param_bounds( | |
451 | self.tcx(), | |
452 | trait_item.span, | |
453 | &ty_method.predicates); | |
454 | reject_shadowing_type_parameters( | |
455 | self.tcx(), | |
456 | trait_item.span, | |
457 | &ty_method.generics); | |
1a4d82fc | 458 | } |
c34b1796 | 459 | _ => {} |
1a4d82fc JJ |
460 | } |
461 | } | |
462 | ||
c34b1796 | 463 | visit::walk_trait_item(self, trait_item) |
1a4d82fc JJ |
464 | } |
465 | } | |
466 | ||
467 | pub struct BoundsChecker<'cx,'tcx:'cx> { | |
468 | fcx: &'cx FnCtxt<'cx,'tcx>, | |
469 | span: Span, | |
85aaf69f SL |
470 | |
471 | // This field is often attached to item impls; it is not clear | |
472 | // that `CodeExtent` is well-defined for such nodes, so pnkfelix | |
473 | // has left it as a NodeId rather than porting to CodeExtent. | |
474 | scope: ast::NodeId, | |
475 | ||
c34b1796 | 476 | binding_count: usize, |
1a4d82fc JJ |
477 | cache: Option<&'cx mut HashSet<Ty<'tcx>>>, |
478 | } | |
479 | ||
480 | impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { | |
481 | pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>, | |
85aaf69f | 482 | scope: ast::NodeId, |
1a4d82fc JJ |
483 | cache: Option<&'cx mut HashSet<Ty<'tcx>>>) |
484 | -> BoundsChecker<'cx,'tcx> { | |
62682a34 | 485 | BoundsChecker { fcx: fcx, span: DUMMY_SP, scope: scope, |
1a4d82fc JJ |
486 | cache: cache, binding_count: 0 } |
487 | } | |
488 | ||
489 | /// Given a trait ref like `A : Trait<B>`, where `Trait` is defined as (say): | |
490 | /// | |
491 | /// trait Trait<B:OtherTrait> : Copy { ... } | |
492 | /// | |
493 | /// This routine will check that `B : OtherTrait` and `A : Trait<B>`. It will also recursively | |
494 | /// check that the types `A` and `B` are well-formed. | |
495 | /// | |
496 | /// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated | |
497 | /// to the point where impl `A : Trait<B>` is implemented). | |
62682a34 | 498 | pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, span: Span) { |
85aaf69f | 499 | let trait_predicates = ty::lookup_predicates(self.fcx.tcx(), trait_ref.def_id); |
1a4d82fc | 500 | |
62682a34 | 501 | let bounds = self.fcx.instantiate_bounds(span, |
85aaf69f SL |
502 | trait_ref.substs, |
503 | &trait_predicates); | |
1a4d82fc JJ |
504 | |
505 | self.fcx.add_obligations_for_parameters( | |
506 | traits::ObligationCause::new( | |
62682a34 | 507 | span, |
1a4d82fc JJ |
508 | self.fcx.body_id, |
509 | traits::ItemObligation(trait_ref.def_id)), | |
510 | &bounds); | |
511 | ||
62682a34 SL |
512 | for &ty in &trait_ref.substs.types { |
513 | self.check_traits_in_ty(ty, span); | |
1a4d82fc JJ |
514 | } |
515 | } | |
516 | ||
62682a34 SL |
517 | pub fn check_ty(&mut self, ty: Ty<'tcx>, span: Span) { |
518 | self.span = span; | |
1a4d82fc JJ |
519 | ty.fold_with(self); |
520 | } | |
521 | ||
62682a34 SL |
522 | fn check_traits_in_ty(&mut self, ty: Ty<'tcx>, span: Span) { |
523 | self.span = span; | |
1a4d82fc JJ |
524 | // When checking types outside of a type def'n, we ignore |
525 | // region obligations. See discussion below in fold_ty(). | |
526 | self.binding_count += 1; | |
527 | ty.fold_with(self); | |
528 | self.binding_count -= 1; | |
529 | } | |
530 | } | |
531 | ||
532 | impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { | |
533 | fn tcx(&self) -> &ty::ctxt<'tcx> { | |
534 | self.fcx.tcx() | |
535 | } | |
536 | ||
537 | fn fold_binder<T>(&mut self, binder: &ty::Binder<T>) -> ty::Binder<T> | |
62682a34 | 538 | where T : TypeFoldable<'tcx> |
1a4d82fc JJ |
539 | { |
540 | self.binding_count += 1; | |
85aaf69f SL |
541 | let value = liberate_late_bound_regions( |
542 | self.fcx.tcx(), | |
543 | region::DestructionScopeData::new(self.scope), | |
544 | binder); | |
62682a34 SL |
545 | debug!("BoundsChecker::fold_binder: late-bound regions replaced: {:?} at scope: {:?}", |
546 | value, self.scope); | |
1a4d82fc JJ |
547 | let value = value.fold_with(self); |
548 | self.binding_count -= 1; | |
549 | ty::Binder(value) | |
550 | } | |
551 | ||
552 | fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { | |
62682a34 SL |
553 | debug!("BoundsChecker t={:?}", |
554 | t); | |
1a4d82fc JJ |
555 | |
556 | match self.cache { | |
557 | Some(ref mut cache) => { | |
558 | if !cache.insert(t) { | |
559 | // Already checked this type! Don't check again. | |
560 | debug!("cached"); | |
561 | return t; | |
562 | } | |
563 | } | |
564 | None => { } | |
565 | } | |
566 | ||
567 | match t.sty{ | |
62682a34 SL |
568 | ty::TyStruct(type_id, substs) | |
569 | ty::TyEnum(type_id, substs) => { | |
85aaf69f SL |
570 | let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id); |
571 | let bounds = self.fcx.instantiate_bounds(self.span, substs, | |
572 | &type_predicates); | |
1a4d82fc JJ |
573 | |
574 | if self.binding_count == 0 { | |
575 | self.fcx.add_obligations_for_parameters( | |
576 | traits::ObligationCause::new(self.span, | |
577 | self.fcx.body_id, | |
578 | traits::ItemObligation(type_id)), | |
579 | &bounds); | |
580 | } else { | |
581 | // There are two circumstances in which we ignore | |
582 | // region obligations. | |
583 | // | |
584 | // The first is when we are inside of a closure | |
585 | // type. This is because in that case the region | |
586 | // obligations for the parameter types are things | |
587 | // that the closure body gets to assume and the | |
588 | // caller must prove at the time of call. In other | |
589 | // words, if there is a type like `<'a, 'b> | &'a | |
590 | // &'b int |`, it is well-formed, and caller will | |
591 | // have to show that `'b : 'a` at the time of | |
592 | // call. | |
593 | // | |
594 | // The second is when we are checking for | |
595 | // well-formedness outside of a type def'n or fn | |
596 | // body. This is for a similar reason: in general, | |
597 | // we only do WF checking for regions in the | |
598 | // result of expressions and type definitions, so | |
599 | // to as allow for implicit where clauses. | |
600 | // | |
601 | // (I believe we should do the same for traits, but | |
602 | // that will require an RFC. -nmatsakis) | |
603 | let bounds = filter_to_trait_obligations(bounds); | |
604 | self.fcx.add_obligations_for_parameters( | |
605 | traits::ObligationCause::new(self.span, | |
606 | self.fcx.body_id, | |
607 | traits::ItemObligation(type_id)), | |
608 | &bounds); | |
609 | } | |
610 | ||
611 | self.fold_substs(substs); | |
612 | } | |
613 | _ => { | |
614 | super_fold_ty(self, t); | |
615 | } | |
616 | } | |
617 | ||
618 | t // we're not folding to produce a new type, so just return `t` here | |
619 | } | |
620 | } | |
621 | ||
622 | /////////////////////////////////////////////////////////////////////////// | |
623 | // ADT | |
624 | ||
625 | struct AdtVariant<'tcx> { | |
626 | fields: Vec<AdtField<'tcx>>, | |
627 | } | |
628 | ||
629 | struct AdtField<'tcx> { | |
630 | ty: Ty<'tcx>, | |
631 | span: Span, | |
632 | } | |
633 | ||
634 | fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, | |
635 | struct_def: &ast::StructDef) | |
636 | -> AdtVariant<'tcx> { | |
637 | let fields = | |
638 | struct_def.fields | |
639 | .iter() | |
640 | .map(|field| { | |
641 | let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id); | |
642 | let field_ty = fcx.instantiate_type_scheme(field.span, | |
643 | &fcx.inh.param_env.free_substs, | |
644 | &field_ty); | |
645 | AdtField { ty: field_ty, span: field.span } | |
646 | }) | |
647 | .collect(); | |
648 | AdtVariant { fields: fields } | |
649 | } | |
650 | ||
651 | fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, | |
652 | enum_def: &ast::EnumDef) | |
653 | -> Vec<AdtVariant<'tcx>> { | |
654 | enum_def.variants.iter() | |
655 | .map(|variant| { | |
656 | match variant.node.kind { | |
9346a6ac | 657 | ast::TupleVariantKind(ref args) if !args.is_empty() => { |
1a4d82fc JJ |
658 | let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id); |
659 | ||
660 | // the regions in the argument types come from the | |
661 | // enum def'n, and hence will all be early bound | |
662 | let arg_tys = | |
85aaf69f SL |
663 | ty::no_late_bound_regions( |
664 | fcx.tcx(), &ty::ty_fn_args(ctor_ty)).unwrap(); | |
1a4d82fc JJ |
665 | AdtVariant { |
666 | fields: args.iter().enumerate().map(|(index, arg)| { | |
667 | let arg_ty = arg_tys[index]; | |
668 | let arg_ty = | |
669 | fcx.instantiate_type_scheme(variant.span, | |
670 | &fcx.inh.param_env.free_substs, | |
671 | &arg_ty); | |
672 | AdtField { | |
673 | ty: arg_ty, | |
674 | span: arg.ty.span | |
675 | } | |
676 | }).collect() | |
677 | } | |
678 | } | |
679 | ast::TupleVariantKind(_) => { | |
680 | AdtVariant { | |
681 | fields: Vec::new() | |
682 | } | |
683 | } | |
684 | ast::StructVariantKind(ref struct_def) => { | |
685 | struct_variant(fcx, &**struct_def) | |
686 | } | |
687 | } | |
688 | }) | |
689 | .collect() | |
690 | } | |
691 | ||
85aaf69f SL |
692 | fn filter_to_trait_obligations<'tcx>(bounds: ty::InstantiatedPredicates<'tcx>) |
693 | -> ty::InstantiatedPredicates<'tcx> | |
1a4d82fc | 694 | { |
85aaf69f | 695 | let mut result = ty::InstantiatedPredicates::empty(); |
1a4d82fc JJ |
696 | for (space, _, predicate) in bounds.predicates.iter_enumerated() { |
697 | match *predicate { | |
698 | ty::Predicate::Trait(..) | | |
699 | ty::Predicate::Projection(..) => { | |
700 | result.predicates.push(space, predicate.clone()) | |
701 | } | |
702 | ty::Predicate::Equate(..) | | |
703 | ty::Predicate::TypeOutlives(..) | | |
704 | ty::Predicate::RegionOutlives(..) => { | |
705 | } | |
706 | } | |
707 | } | |
708 | result | |
709 | } |