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