]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/kind.rs
Simplify PatIdent to contain an Ident rather than a Path
[rust.git] / src / librustc / middle / kind.rs
1 // Copyright 2012-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
12 use middle::freevars::freevar_entry;
13 use middle::freevars;
14 use middle::subst;
15 use middle::ty;
16 use middle::typeck;
17 use util::ppaux::{Repr, ty_to_str};
18 use util::ppaux::UserString;
19
20 use syntax::ast::*;
21 use syntax::attr;
22 use syntax::codemap::Span;
23 use syntax::print::pprust::{expr_to_str, ident_to_str};
24 use syntax::{visit};
25 use syntax::visit::Visitor;
26
27 // Kind analysis pass.
28 //
29 // There are several kinds defined by various operations. The most restrictive
30 // kind is noncopyable. The noncopyable kind can be extended with any number
31 // of the following attributes.
32 //
33 //  Send: Things that can be sent on channels or included in spawned closures. It
34 //  includes scalar types as well as classes and unique types containing only
35 //  sendable types.
36 //  'static: Things that do not contain references.
37 //
38 // This pass ensures that type parameters are only instantiated with types
39 // whose kinds are equal or less general than the way the type parameter was
40 // annotated (with the `Send` bound).
41 //
42 // It also verifies that noncopyable kinds are not copied. Sendability is not
43 // applied, since none of our language primitives send. Instead, the sending
44 // primitives in the stdlib are explicitly annotated to only take sendable
45 // types.
46
47 #[deriving(Clone)]
48 pub struct Context<'a> {
49     tcx: &'a ty::ctxt,
50 }
51
52 impl<'a> Visitor<()> for Context<'a> {
53
54     fn visit_expr(&mut self, ex: &Expr, _: ()) {
55         check_expr(self, ex);
56     }
57
58     fn visit_fn(&mut self, fk: &visit::FnKind, fd: &FnDecl,
59                 b: &Block, s: Span, n: NodeId, _: ()) {
60         check_fn(self, fk, fd, b, s, n);
61     }
62
63     fn visit_ty(&mut self, t: &Ty, _: ()) {
64         check_ty(self, t);
65     }
66
67     fn visit_item(&mut self, i: &Item, _: ()) {
68         check_item(self, i);
69     }
70
71     fn visit_pat(&mut self, p: &Pat, _: ()) {
72         check_pat(self, p);
73     }
74 }
75
76 pub fn check_crate(tcx: &ty::ctxt,
77                    krate: &Crate) {
78     let mut ctx = Context {
79         tcx: tcx,
80     };
81     visit::walk_crate(&mut ctx, krate, ());
82     tcx.sess.abort_if_errors();
83 }
84
85 fn check_struct_safe_for_destructor(cx: &mut Context,
86                                     span: Span,
87                                     struct_did: DefId) {
88     let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
89     if !struct_tpt.generics.has_type_params(subst::TypeSpace) {
90         let struct_ty = ty::mk_struct(cx.tcx, struct_did,
91                                       subst::Substs::empty());
92         if !ty::type_is_sendable(cx.tcx, struct_ty) {
93             cx.tcx.sess.span_err(span,
94                                  "cannot implement a destructor on a \
95                                   structure that does not satisfy Send");
96             cx.tcx.sess.span_note(span,
97                                   "use \"#[unsafe_destructor]\" on the \
98                                    implementation to force the compiler to \
99                                    allow this");
100         }
101     } else {
102         cx.tcx.sess.span_err(span,
103                              "cannot implement a destructor on a structure \
104                               with type parameters");
105         cx.tcx.sess.span_note(span,
106                               "use \"#[unsafe_destructor]\" on the \
107                                implementation to force the compiler to \
108                                allow this");
109     }
110 }
111
112 fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_type: &Ty) {
113     let ast_trait_def = *cx.tcx.def_map.borrow()
114                               .find(&trait_ref.ref_id)
115                               .expect("trait ref not in def map!");
116     let trait_def_id = ast_trait_def.def_id();
117     let trait_def = cx.tcx.trait_defs.borrow()
118                           .find_copy(&trait_def_id)
119                           .expect("trait def not in trait-defs map!");
120
121     // If this trait has builtin-kind supertraits, meet them.
122     let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
123     debug!("checking impl with self type {:?}", ty::get(self_ty).sty);
124     check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
125         cx.tcx.sess.span_err(self_type.span,
126             format!("the type `{}', which does not fulfill `{}`, cannot implement this \
127                     trait",
128                     ty_to_str(cx.tcx, self_ty),
129                     missing.user_string(cx.tcx)).as_slice());
130         cx.tcx.sess.span_note(self_type.span,
131             format!("types implementing this trait must fulfill `{}`",
132                     trait_def.bounds.user_string(cx.tcx)).as_slice());
133     });
134
135     // If this is a destructor, check kinds.
136     if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
137         match self_type.node {
138             TyPath(_, ref bounds, path_node_id) => {
139                 assert!(bounds.is_none());
140                 let struct_def = cx.tcx.def_map.borrow().get_copy(&path_node_id);
141                 let struct_did = struct_def.def_id();
142                 check_struct_safe_for_destructor(cx, self_type.span, struct_did);
143             }
144             _ => {
145                 cx.tcx.sess.span_bug(self_type.span,
146                     "the self type for the Drop trait impl is not a path");
147             }
148         }
149     }
150 }
151
152 fn check_item(cx: &mut Context, item: &Item) {
153     if !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") {
154         match item.node {
155             ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
156                 check_impl_of_trait(cx, item, trait_ref, &**self_type);
157             }
158             _ => {}
159         }
160     }
161
162     visit::walk_item(cx, item, ());
163 }
164
165 // Yields the appropriate function to check the kind of closed over
166 // variables. `id` is the NodeId for some expression that creates the
167 // closure.
168 fn with_appropriate_checker(cx: &Context,
169                             id: NodeId,
170                             b: |checker: |&Context, &freevar_entry||) {
171     fn check_for_uniq(cx: &Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) {
172         // all captured data must be owned, regardless of whether it is
173         // moved in or copied in.
174         let id = fv.def.def_id().node;
175         let var_t = ty::node_id_to_type(cx.tcx, id);
176
177         check_freevar_bounds(cx, fv.span, var_t, bounds, None);
178     }
179
180     fn check_for_block(cx: &Context, fv: &freevar_entry,
181                        bounds: ty::BuiltinBounds, region: ty::Region) {
182         let id = fv.def.def_id().node;
183         let var_t = ty::node_id_to_type(cx.tcx, id);
184         // FIXME(#3569): Figure out whether the implicit borrow is actually
185         // mutable. Currently we assume all upvars are referenced mutably.
186         let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t);
187         check_freevar_bounds(cx, fv.span, implicit_borrowed_type,
188                              bounds, Some(var_t));
189     }
190
191     fn check_for_bare(cx: &Context, fv: &freevar_entry) {
192         cx.tcx.sess.span_err(
193             fv.span,
194             "can't capture dynamic environment in a fn item; \
195             use the || { ... } closure form instead");
196     } // same check is done in resolve.rs, but shouldn't be done
197
198     let fty = ty::node_id_to_type(cx.tcx, id);
199     match ty::get(fty).sty {
200         ty::ty_closure(box ty::ClosureTy {
201             store: ty::UniqTraitStore,
202             bounds: mut bounds, ..
203         }) => {
204             // Procs can't close over non-static references!
205             bounds.add(ty::BoundStatic);
206
207             b(|cx, fv| check_for_uniq(cx, fv, bounds))
208         }
209
210         ty::ty_closure(box ty::ClosureTy {
211             store: ty::RegionTraitStore(region, _), bounds, ..
212         }) => b(|cx, fv| check_for_block(cx, fv, bounds, region)),
213
214         ty::ty_bare_fn(_) => {
215             b(check_for_bare)
216         }
217         ref s => {
218             cx.tcx.sess.bug(format!("expect fn type in kind checker, not \
219                                      {:?}",
220                                     s).as_slice());
221         }
222     }
223 }
224
225 // Check that the free variables used in a shared/sendable closure conform
226 // to the copy/move kind bounds. Then recursively check the function body.
227 fn check_fn(
228     cx: &mut Context,
229     fk: &visit::FnKind,
230     decl: &FnDecl,
231     body: &Block,
232     sp: Span,
233     fn_id: NodeId) {
234
235     // Check kinds on free variables:
236     with_appropriate_checker(cx, fn_id, |chk| {
237         freevars::with_freevars(cx.tcx, fn_id, |freevars| {
238             for fv in freevars.iter() {
239                 chk(cx, fv);
240             }
241         });
242     });
243
244     visit::walk_fn(cx, fk, decl, body, sp, ());
245 }
246
247 pub fn check_expr(cx: &mut Context, e: &Expr) {
248     debug!("kind::check_expr({})", expr_to_str(e));
249
250     // Handle any kind bounds on type parameters
251     check_bounds_on_type_parameters(cx, e);
252
253     match e.node {
254         ExprBox(ref loc, ref interior) => {
255             let def = ty::resolve_expr(cx.tcx, &**loc);
256             if Some(def.def_id()) == cx.tcx.lang_items.managed_heap() {
257                 let interior_type = ty::expr_ty(cx.tcx, &**interior);
258                 let _ = check_static(cx.tcx, interior_type, interior.span);
259             }
260         }
261         ExprCast(ref source, _) => {
262             let source_ty = ty::expr_ty(cx.tcx, &**source);
263             let target_ty = ty::expr_ty(cx.tcx, e);
264             check_trait_cast(cx, source_ty, target_ty, source.span);
265         }
266         ExprRepeat(ref element, ref count_expr) => {
267             let count = ty::eval_repeat_count(cx.tcx, &**count_expr);
268             if count > 1 {
269                 let element_ty = ty::expr_ty(cx.tcx, &**element);
270                 check_copy(cx, element_ty, element.span,
271                            "repeated element will be copied");
272             }
273         }
274         _ => {}
275     }
276
277     // Search for auto-adjustments to find trait coercions.
278     match cx.tcx.adjustments.borrow().find(&e.id) {
279         Some(adjustment) => {
280             match *adjustment {
281                 ty::AutoObject(..) => {
282                     let source_ty = ty::expr_ty(cx.tcx, e);
283                     let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
284                     check_trait_cast(cx, source_ty, target_ty, e.span);
285                 }
286                 ty::AutoAddEnv(..) |
287                 ty::AutoDerefRef(..) => {}
288             }
289         }
290         None => {}
291     }
292
293     visit::walk_expr(cx, e, ());
294 }
295
296 fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
297     let method_map = cx.tcx.method_map.borrow();
298     let method = method_map.find(&typeck::MethodCall::expr(e.id));
299
300     // Find the values that were provided (if any)
301     let item_substs = cx.tcx.item_substs.borrow();
302     let (types, is_object_call) = match method {
303         Some(method) => {
304             let is_object_call = match method.origin {
305                 typeck::MethodObject(..) => true,
306                 typeck::MethodStatic(..) | typeck::MethodParam(..) => false
307             };
308             (&method.substs.types, is_object_call)
309         }
310         None => {
311             match item_substs.find(&e.id) {
312                 None => { return; }
313                 Some(s) => { (&s.substs.types, false) }
314             }
315         }
316     };
317
318     // Find the relevant type parameter definitions
319     let def_map = cx.tcx.def_map.borrow();
320     let type_param_defs = match e.node {
321         ExprPath(_) => {
322             let did = def_map.get_copy(&e.id).def_id();
323             ty::lookup_item_type(cx.tcx, did).generics.types.clone()
324         }
325         _ => {
326             // Type substitutions should only occur on paths and
327             // method calls, so this needs to be a method call.
328
329             // Even though the callee_id may have been the id with
330             // node_type_substs, e.id is correct here.
331             match method {
332                 Some(method) => {
333                     ty::method_call_type_param_defs(cx.tcx, method.origin)
334                 }
335                 None => {
336                     cx.tcx.sess.span_bug(e.span,
337                                          "non path/method call expr has type substs??");
338                 }
339             }
340         }
341     };
342
343     // Check that the value provided for each definition meets the
344     // kind requirements
345     for type_param_def in type_param_defs.iter() {
346         let ty = *types.get(type_param_def.space, type_param_def.index);
347
348         // If this is a call to an object method (`foo.bar()` where
349         // `foo` has a type like `Trait`), then the self type is
350         // unknown (after all, this is a virtual call). In that case,
351         // we will have put a ty_err in the substitutions, and we can
352         // just skip over validating the bounds (because the bounds
353         // would have been enforced when the object instance was
354         // created).
355         if is_object_call && type_param_def.space == subst::SelfSpace {
356             assert_eq!(type_param_def.index, 0);
357             assert!(ty::type_is_error(ty));
358             continue;
359         }
360
361         debug!("type_param_def space={} index={} ty={}",
362                type_param_def.space, type_param_def.index, ty.repr(cx.tcx));
363         check_typaram_bounds(cx, e.span, ty, type_param_def)
364     }
365 }
366
367 fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
368     check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
369     match ty::get(target_ty).sty {
370         ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => match ty::get(ty).sty {
371             ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
372                 check_trait_cast_bounds(cx, span, source_ty, bounds);
373             }
374             _ => {}
375         },
376         _ => {}
377     }
378 }
379
380 fn check_ty(cx: &mut Context, aty: &Ty) {
381     match aty.node {
382         TyPath(_, _, id) => {
383             match cx.tcx.item_substs.borrow().find(&id) {
384                 None => { }
385                 Some(ref item_substs) => {
386                     let def_map = cx.tcx.def_map.borrow();
387                     let did = def_map.get_copy(&id).def_id();
388                     let generics = ty::lookup_item_type(cx.tcx, did).generics;
389                     for def in generics.types.iter() {
390                         let ty = *item_substs.substs.types.get(def.space,
391                                                                def.index);
392                         check_typaram_bounds(cx, aty.span, ty, def)
393                     }
394                 }
395             }
396         }
397         _ => {}
398     }
399     visit::walk_ty(cx, aty, ());
400 }
401
402 // Calls "any_missing" if any bounds were missing.
403 pub fn check_builtin_bounds(cx: &Context,
404                             ty: ty::t,
405                             bounds: ty::BuiltinBounds,
406                             any_missing: |ty::BuiltinBounds|) {
407     let kind = ty::type_contents(cx.tcx, ty);
408     let mut missing = ty::empty_builtin_bounds();
409     for bound in bounds.iter() {
410         if !kind.meets_bound(cx.tcx, bound) {
411             missing.add(bound);
412         }
413     }
414     if !missing.is_empty() {
415         any_missing(missing);
416     }
417 }
418
419 pub fn check_typaram_bounds(cx: &Context,
420                             sp: Span,
421                             ty: ty::t,
422                             type_param_def: &ty::TypeParameterDef) {
423     check_builtin_bounds(cx,
424                          ty,
425                          type_param_def.bounds.builtin_bounds,
426                          |missing| {
427         cx.tcx.sess.span_err(
428             sp,
429             format!("instantiating a type parameter with an incompatible type \
430                      `{}`, which does not fulfill `{}`",
431                     ty_to_str(cx.tcx, ty),
432                     missing.user_string(cx.tcx)).as_slice());
433     });
434 }
435
436 pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
437                             bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
438 {
439     check_builtin_bounds(cx, ty, bounds, |missing| {
440         // Will be Some if the freevar is implicitly borrowed (stack closure).
441         // Emit a less mysterious error message in this case.
442         match referenced_ty {
443             Some(rty) => {
444                 cx.tcx.sess.span_err(sp,
445                 format!("cannot implicitly borrow variable of type `{}` in a \
446                          bounded stack closure (implicit reference does not \
447                          fulfill `{}`)",
448                         ty_to_str(cx.tcx, rty),
449                         missing.user_string(cx.tcx)).as_slice())
450             }
451             None => {
452                 cx.tcx.sess.span_err(sp,
453                 format!("cannot capture variable of type `{}`, which does \
454                          not fulfill `{}`, in a bounded closure",
455                         ty_to_str(cx.tcx, ty),
456                         missing.user_string(cx.tcx)).as_slice())
457             }
458         }
459         cx.tcx.sess.span_note(
460             sp,
461             format!("this closure's environment must satisfy `{}`",
462                     bounds.user_string(cx.tcx)).as_slice());
463     });
464 }
465
466 pub fn check_trait_cast_bounds(cx: &Context, sp: Span, ty: ty::t,
467                                bounds: ty::BuiltinBounds) {
468     check_builtin_bounds(cx, ty, bounds, |missing| {
469         cx.tcx.sess.span_err(sp,
470             format!("cannot pack type `{}`, which does not fulfill \
471                      `{}`, as a trait bounded by {}",
472                     ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx),
473                     bounds.user_string(cx.tcx)).as_slice());
474     });
475 }
476
477 fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) {
478     debug!("type_contents({})={}",
479            ty_to_str(cx.tcx, ty),
480            ty::type_contents(cx.tcx, ty).to_str());
481     if ty::type_moves_by_default(cx.tcx, ty) {
482         cx.tcx.sess.span_err(
483             sp,
484             format!("copying a value of non-copyable type `{}`",
485                     ty_to_str(cx.tcx, ty)).as_slice());
486         cx.tcx.sess.span_note(sp, format!("{}", reason).as_slice());
487     }
488 }
489
490 pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool {
491     if !ty::type_is_static(tcx, ty) {
492         match ty::get(ty).sty {
493           ty::ty_param(..) => {
494             tcx.sess.span_err(sp,
495                 format!("value may contain references; \
496                          add `'static` bound to `{}`",
497                         ty_to_str(tcx, ty)).as_slice());
498           }
499           _ => {
500             tcx.sess.span_err(sp, "value may contain references");
501           }
502         }
503         false
504     } else {
505         true
506     }
507 }
508
509 /// This is rather subtle.  When we are casting a value to an instantiated
510 /// trait like `a as trait<'r>`, regionck already ensures that any references
511 /// that appear in the type of `a` are bounded by `'r` (ed.: rem
512 /// FIXME(#5723)).  However, it is possible that there are *type parameters*
513 /// in the type of `a`, and those *type parameters* may have references
514 /// within them.  We have to guarantee that the regions which appear in those
515 /// type parameters are not obscured.
516 ///
517 /// Therefore, we ensure that one of three conditions holds:
518 ///
519 /// (1) The trait instance cannot escape the current fn.  This is
520 /// guaranteed if the region bound `&r` is some scope within the fn
521 /// itself.  This case is safe because whatever references are
522 /// found within the type parameter, they must enclose the fn body
523 /// itself.
524 ///
525 /// (2) The type parameter appears in the type of the trait.  For
526 /// example, if the type parameter is `T` and the trait type is
527 /// `deque<T>`, then whatever references may appear in `T` also
528 /// appear in `deque<T>`.
529 ///
530 /// (3) The type parameter is sendable (and therefore does not contain
531 /// references).
532 ///
533 /// FIXME(#5723)---This code should probably move into regionck.
534 pub fn check_cast_for_escaping_regions(
535     cx: &Context,
536     source_ty: ty::t,
537     target_ty: ty::t,
538     source_span: Span)
539 {
540     // Determine what type we are casting to; if it is not a trait, then no
541     // worries.
542     if !ty::type_is_trait(target_ty) {
543         return;
544     }
545
546     // Collect up the regions that appear in the target type.  We want to
547     // ensure that these lifetimes are shorter than all lifetimes that are in
548     // the source type.  See test `src/test/compile-fail/regions-trait-2.rs`
549     let mut target_regions = Vec::new();
550     ty::walk_regions_and_ty(
551         cx.tcx,
552         target_ty,
553         |r| {
554             if !r.is_bound() {
555                 target_regions.push(r);
556             }
557         },
558         |_| ());
559
560     // Check, based on the region associated with the trait, whether it can
561     // possibly escape the enclosing fn item (note that all type parameters
562     // must have been declared on the enclosing fn item).
563     if target_regions.iter().any(|r| is_ReScope(*r)) {
564         return; /* case (1) */
565     }
566
567     // Assuming the trait instance can escape, then ensure that each parameter
568     // either appears in the trait type or is sendable.
569     let target_params = ty::param_tys_in_type(target_ty);
570     ty::walk_regions_and_ty(
571         cx.tcx,
572         source_ty,
573
574         |_r| {
575             // FIXME(#5723) --- turn this check on once &Objects are usable
576             //
577             // if !target_regions.iter().any(|t_r| is_subregion_of(cx, *t_r, r)) {
578             //     cx.tcx.sess.span_err(
579             //         source_span,
580             //         format!("source contains reference with lifetime \
581             //               not found in the target type `{}`",
582             //              ty_to_str(cx.tcx, target_ty)));
583             //     note_and_explain_region(
584             //         cx.tcx, "source data is only valid for ", r, "");
585             // }
586         },
587
588         |ty| {
589             match ty::get(ty).sty {
590                 ty::ty_param(source_param) => {
591                     if source_param.space == subst::SelfSpace {
592                         // FIXME (#5723) -- there is no reason that
593                         // Self should be exempt from this check,
594                         // except for historical accident. Bottom
595                         // line, we need proper region bounding.
596                     } else if target_params.iter().any(|x| x == &source_param) {
597                         /* case (2) */
598                     } else {
599                         check_static(cx.tcx, ty, source_span); /* case (3) */
600                     }
601                 }
602                 _ => {}
603             }
604         });
605
606     #[allow(non_snake_case_functions)]
607     fn is_ReScope(r: ty::Region) -> bool {
608         match r {
609             ty::ReScope(..) => true,
610             _ => false
611         }
612     }
613 }
614
615 // Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
616 fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
617     if !ty::type_is_sized(tcx, ty) {
618         tcx.sess.span_err(sp,
619                           format!("variable `{}` has dynamically sized type \
620                                    `{}`",
621                                   name,
622                                   ty_to_str(tcx, ty)).as_slice());
623     }
624 }
625
626 // Check that any variables in a pattern have types with statically known size.
627 fn check_pat(cx: &mut Context, pat: &Pat) {
628     let var_name = match pat.node {
629         PatWild => Some("_".to_string()),
630         PatIdent(_, ref path1, _) => Some(ident_to_str(&path1.node).to_string()),
631         _ => None
632     };
633
634     match var_name {
635         Some(name) => {
636             let types = cx.tcx.node_types.borrow();
637             let ty = types.find(&(pat.id as uint));
638             match ty {
639                 Some(ty) => {
640                     debug!("kind: checking sized-ness of variable {}: {}",
641                            name, ty_to_str(cx.tcx, *ty));
642                     check_sized(cx.tcx, *ty, name, pat.span);
643                 }
644                 None => {} // extern fn args
645             }
646         }
647         None => {}
648     }
649
650     visit::walk_pat(cx, pat, ());
651 }