]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/astconv.rs
auto merge of #8350 : dim-an/rust/fix-struct-match, r=pcwalton
[rust.git] / src / librustc / middle / typeck / astconv.rs
1 // Copyright 2012 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  * Conversion from AST representation of types to the ty.rs
13  * representation.  The main routine here is `ast_ty_to_ty()`: each use
14  * is parameterized by an instance of `AstConv` and a `region_scope`.
15  *
16  * The parameterization of `ast_ty_to_ty()` is because it behaves
17  * somewhat differently during the collect and check phases,
18  * particularly with respect to looking up the types of top-level
19  * items.  In the collect phase, the crate context is used as the
20  * `AstConv` instance; in this phase, the `get_item_ty()` function
21  * triggers a recursive call to `ty_of_item()`  (note that
22  * `ast_ty_to_ty()` will detect recursive types and report an error).
23  * In the check phase, when the @FnCtxt is used as the `AstConv`,
24  * `get_item_ty()` just looks up the item type in `tcx.tcache`.
25  *
26  * The `region_scope` trait controls how region references are
27  * handled.  It has two methods which are used to resolve anonymous
28  * region references (e.g., `&T`) and named region references (e.g.,
29  * `&a.T`).  There are numerous region scopes that can be used, but most
30  * commonly you want either `empty_rscope`, which permits only the static
31  * region, or `type_rscope`, which permits the self region if the type in
32  * question is parameterized by a region.
33  *
34  * Unlike the `AstConv` trait, the region scope can change as we descend
35  * the type.  This is to accommodate the fact that (a) fn types are binding
36  * scopes and (b) the default region may change.  To understand case (a),
37  * consider something like:
38  *
39  *   type foo = { x: &a.int, y: &fn(&a.int) }
40  *
41  * The type of `x` is an error because there is no region `a` in scope.
42  * In the type of `y`, however, region `a` is considered a bound region
43  * as it does not already appear in scope.
44  *
45  * Case (b) says that if you have a type:
46  *   type foo<'self> = ...;
47  *   type bar = fn(&foo, &a.foo)
48  * The fully expanded version of type bar is:
49  *   type bar = fn(&'foo &, &a.foo<'a>)
50  * Note that the self region for the `foo` defaulted to `&` in the first
51  * case but `&a` in the second.  Basically, defaults that appear inside
52  * an rptr (`&r.T`) use the region `r` that appears in the rptr.
53  */
54
55
56 use middle::const_eval;
57 use middle::ty::{substs};
58 use middle::ty::{ty_param_substs_and_ty};
59 use middle::ty;
60 use middle::typeck::rscope::in_binding_rscope;
61 use middle::typeck::rscope::{region_scope, RegionError};
62 use middle::typeck::rscope::RegionParamNames;
63 use middle::typeck::lookup_def_tcx;
64
65 use std::result;
66 use std::vec;
67 use syntax::abi::AbiSet;
68 use syntax::{ast, ast_util};
69 use syntax::codemap::span;
70 use syntax::opt_vec::OptVec;
71 use syntax::opt_vec;
72 use syntax::print::pprust::{lifetime_to_str, path_to_str};
73 use syntax::parse::token::special_idents;
74 use util::common::indenter;
75
76 pub trait AstConv {
77     fn tcx(&self) -> ty::ctxt;
78     fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty;
79     fn get_trait_def(&self, id: ast::def_id) -> @ty::TraitDef;
80
81     // what type should we use when a type is omitted?
82     fn ty_infer(&self, span: span) -> ty::t;
83 }
84
85 pub fn get_region_reporting_err(
86     tcx: ty::ctxt,
87     span: span,
88     a_r: &Option<ast::Lifetime>,
89     res: Result<ty::Region, RegionError>) -> ty::Region
90 {
91     match res {
92         result::Ok(r) => r,
93         result::Err(ref e) => {
94             let descr = match a_r {
95                 &None => ~"anonymous lifetime",
96                 &Some(ref a) => fmt!("lifetime %s",
97                                 lifetime_to_str(a, tcx.sess.intr()))
98             };
99             tcx.sess.span_err(
100                 span,
101                 fmt!("Illegal %s: %s",
102                      descr, e.msg));
103             e.replacement
104         }
105     }
106 }
107
108 pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Clone + 'static>(
109     this: &AC,
110     rscope: &RS,
111     default_span: span,
112     opt_lifetime: &Option<ast::Lifetime>) -> ty::Region
113 {
114     let (span, res) = match opt_lifetime {
115         &None => {
116             (default_span, rscope.anon_region(default_span))
117         }
118         &Some(ref lifetime) if lifetime.ident == special_idents::statik => {
119             (lifetime.span, Ok(ty::re_static))
120         }
121         &Some(ref lifetime) if lifetime.ident == special_idents::self_ => {
122             (lifetime.span, rscope.self_region(lifetime.span))
123         }
124         &Some(ref lifetime) => {
125             (lifetime.span, rscope.named_region(lifetime.span,
126                                                 lifetime.ident))
127         }
128     };
129
130     get_region_reporting_err(this.tcx(), span, opt_lifetime, res)
131 }
132
133 fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>(
134     this: &AC,
135     rscope: &RS,
136     def_id: ast::def_id,
137     decl_generics: &ty::Generics,
138     self_ty: Option<ty::t>,
139     path: &ast::Path) -> ty::substs
140 {
141     /*!
142      *
143      * Given a path `path` that refers to an item `I` with the
144      * declared generics `decl_generics`, returns an appropriate
145      * set of substitutions for this particular reference to `I`.
146      */
147
148     let tcx = this.tcx();
149
150     // If the type is parameterized by the this region, then replace this
151     // region with the current anon region binding (in other words,
152     // whatever & would get replaced with).
153     let regions = match (&decl_generics.region_param, &path.rp) {
154         (&None, &None) => {
155             opt_vec::Empty
156         }
157         (&None, &Some(_)) => {
158             tcx.sess.span_err(
159                 path.span,
160                 fmt!("no region bound is allowed on `%s`, \
161                       which is not declared as containing region pointers",
162                      ty::item_path_str(tcx, def_id)));
163             opt_vec::Empty
164         }
165         (&Some(_), &None) => {
166             let res = rscope.anon_region(path.span);
167             let r = get_region_reporting_err(this.tcx(), path.span, &None, res);
168             opt_vec::with(r)
169         }
170         (&Some(_), &Some(_)) => {
171             opt_vec::with(
172                 ast_region_to_region(this, rscope, path.span, &path.rp))
173         }
174     };
175
176     // Convert the type parameters supplied by the user.
177     if !vec::same_length(*decl_generics.type_param_defs, path.types) {
178         this.tcx().sess.span_fatal(
179             path.span,
180             fmt!("wrong number of type arguments: expected %u but found %u",
181                  decl_generics.type_param_defs.len(), path.types.len()));
182     }
183     let tps = path.types.map(|a_t| ast_ty_to_ty(this, rscope, a_t));
184
185     substs {regions:ty::NonerasedRegions(regions), self_ty:self_ty, tps:tps}
186 }
187
188 pub fn ast_path_to_substs_and_ty<AC:AstConv,
189                                  RS:region_scope + Clone + 'static>(
190                                  this: &AC,
191                                  rscope: &RS,
192                                  did: ast::def_id,
193                                  path: &ast::Path)
194                                  -> ty_param_substs_and_ty {
195     let tcx = this.tcx();
196     let ty::ty_param_bounds_and_ty {
197         generics: generics,
198         ty: decl_ty
199     } = this.get_item_ty(did);
200
201     let substs = ast_path_substs(this, rscope, did, &generics, None, path);
202     let ty = ty::subst(tcx, &substs, decl_ty);
203     ty_param_substs_and_ty { substs: substs, ty: ty }
204 }
205
206 pub fn ast_path_to_trait_ref<AC:AstConv,RS:region_scope + Clone + 'static>(
207     this: &AC,
208     rscope: &RS,
209     trait_def_id: ast::def_id,
210     self_ty: Option<ty::t>,
211     path: &ast::Path) -> @ty::TraitRef
212 {
213     let trait_def =
214         this.get_trait_def(trait_def_id);
215     let substs =
216         ast_path_substs(
217             this,
218             rscope,
219             trait_def.trait_ref.def_id,
220             &trait_def.generics,
221             self_ty,
222             path);
223     let trait_ref =
224         @ty::TraitRef {def_id: trait_def_id,
225                        substs: substs};
226     return trait_ref;
227 }
228
229 pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Clone + 'static>(
230         this: &AC,
231         rscope: &RS,
232         did: ast::def_id,
233         path: &ast::Path)
234      -> ty_param_substs_and_ty
235 {
236     // Look up the polytype of the item and then substitute the provided types
237     // for any type/region parameters.
238     let ty::ty_param_substs_and_ty {
239         substs: substs,
240         ty: ty
241     } = ast_path_to_substs_and_ty(this, rscope, did, path);
242     ty_param_substs_and_ty { substs: substs, ty: ty }
243 }
244
245 pub static NO_REGIONS: uint = 1;
246 pub static NO_TPS: uint = 2;
247
248 // Parses the programmer's textual representation of a type into our
249 // internal notion of a type. `getter` is a function that returns the type
250 // corresponding to a definition ID:
251 pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Clone + 'static>(
252     this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t {
253
254     fn ast_mt_to_mt<AC:AstConv, RS:region_scope + Clone + 'static>(
255         this: &AC, rscope: &RS, mt: &ast::mt) -> ty::mt {
256
257         ty::mt {ty: ast_ty_to_ty(this, rscope, mt.ty), mutbl: mt.mutbl}
258     }
259
260     // Handle @, ~, and & being able to mean estrs and evecs.
261     // If a_seq_ty is a str or a vec, make it an estr/evec.
262     // Also handle first-class trait types.
263     fn mk_pointer<AC:AstConv,RS:region_scope + Clone + 'static>(
264         this: &AC,
265         rscope: &RS,
266         a_seq_ty: &ast::mt,
267         vst: ty::vstore,
268         constr: &fn(ty::mt) -> ty::t) -> ty::t
269     {
270         let tcx = this.tcx();
271
272         match a_seq_ty.ty.node {
273             ast::ty_vec(ref mt) => {
274                 let mut mt = ast_mt_to_mt(this, rscope, mt);
275                 if a_seq_ty.mutbl == ast::m_mutbl ||
276                         a_seq_ty.mutbl == ast::m_const {
277                     mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl };
278                 }
279                 return ty::mk_evec(tcx, mt, vst);
280             }
281             ast::ty_path(ref path, ref bounds, id) => {
282                 // Note that the "bounds must be empty if path is not a trait"
283                 // restriction is enforced in the below case for ty_path, which
284                 // will run after this as long as the path isn't a trait.
285                 match tcx.def_map.find(&id) {
286                     Some(&ast::def_prim_ty(ast::ty_str)) if a_seq_ty.mutbl == ast::m_imm => {
287                         check_path_args(tcx, path, NO_TPS | NO_REGIONS);
288                         return ty::mk_estr(tcx, vst);
289                     }
290                     Some(&ast::def_trait(trait_def_id)) => {
291                         let result = ast_path_to_trait_ref(
292                             this, rscope, trait_def_id, None, path);
293                         let trait_store = match vst {
294                             ty::vstore_box => ty::BoxTraitStore,
295                             ty::vstore_uniq => ty::UniqTraitStore,
296                             ty::vstore_slice(r) => {
297                                 ty::RegionTraitStore(r)
298                             }
299                             ty::vstore_fixed(*) => {
300                                 tcx.sess.span_err(
301                                     path.span,
302                                     "@trait, ~trait or &trait are the only supported \
303                                      forms of casting-to-trait");
304                                 ty::BoxTraitStore
305                             }
306                         };
307                         let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
308                         return ty::mk_trait(tcx,
309                                             result.def_id,
310                                             result.substs.clone(),
311                                             trait_store,
312                                             a_seq_ty.mutbl,
313                                             bounds);
314                     }
315                     _ => {}
316                 }
317             }
318             _ => {}
319         }
320
321         let seq_ty = ast_mt_to_mt(this, rscope, a_seq_ty);
322         return constr(seq_ty);
323     }
324
325     fn check_path_args(tcx: ty::ctxt,
326                        path: &ast::Path,
327                        flags: uint) {
328         if (flags & NO_TPS) != 0u {
329             if path.types.len() > 0u {
330                 tcx.sess.span_err(
331                     path.span,
332                     "type parameters are not allowed on this type");
333             }
334         }
335
336         if (flags & NO_REGIONS) != 0u {
337             if path.rp.is_some() {
338                 tcx.sess.span_err(
339                     path.span,
340                     "region parameters are not allowed on this type");
341             }
342         }
343     }
344
345     let tcx = this.tcx();
346
347     match tcx.ast_ty_to_ty_cache.find(&ast_ty.id) {
348       Some(&ty::atttce_resolved(ty)) => return ty,
349       Some(&ty::atttce_unresolved) => {
350         tcx.sess.span_fatal(ast_ty.span, "illegal recursive type; \
351                                           insert an enum in the cycle, if this is desired");
352       }
353       None => { /* go on */ }
354     }
355
356     tcx.ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
357     let typ = match ast_ty.node {
358       ast::ty_nil => ty::mk_nil(),
359       ast::ty_bot => ty::mk_bot(),
360       ast::ty_box(ref mt) => {
361         mk_pointer(this, rscope, mt, ty::vstore_box,
362                    |tmt| ty::mk_box(tcx, tmt))
363       }
364       ast::ty_uniq(ref mt) => {
365         mk_pointer(this, rscope, mt, ty::vstore_uniq,
366                    |tmt| ty::mk_uniq(tcx, tmt))
367       }
368       ast::ty_vec(ref mt) => {
369         tcx.sess.span_err(ast_ty.span, "bare `[]` is not a type");
370         // return /something/ so they can at least get more errors
371         ty::mk_evec(tcx, ast_mt_to_mt(this, rscope, mt), ty::vstore_uniq)
372       }
373       ast::ty_ptr(ref mt) => {
374         ty::mk_ptr(tcx, ast_mt_to_mt(this, rscope, mt))
375       }
376       ast::ty_rptr(ref region, ref mt) => {
377         let r = ast_region_to_region(this, rscope, ast_ty.span, region);
378         mk_pointer(this, rscope, mt, ty::vstore_slice(r),
379                    |tmt| ty::mk_rptr(tcx, r, tmt))
380       }
381       ast::ty_tup(ref fields) => {
382         let flds = fields.map(|t| ast_ty_to_ty(this, rscope, t));
383         ty::mk_tup(tcx, flds)
384       }
385       ast::ty_bare_fn(ref bf) => {
386           ty::mk_bare_fn(tcx, ty_of_bare_fn(this, rscope, bf.purity,
387                                             bf.abis, &bf.lifetimes, &bf.decl))
388       }
389       ast::ty_closure(ref f) => {
390           let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil {
391               // Use corresponding trait store to figure out default bounds
392               // if none were specified.
393               ast::BorrowedSigil => ty::RegionTraitStore(ty::re_empty), // dummy region
394               ast::OwnedSigil    => ty::UniqTraitStore,
395               ast::ManagedSigil  => ty::BoxTraitStore,
396           });
397           let fn_decl = ty_of_closure(this,
398                                       rscope,
399                                       f.sigil,
400                                       f.purity,
401                                       f.onceness,
402                                       bounds,
403                                       &f.region,
404                                       &f.decl,
405                                       None,
406                                       &f.lifetimes,
407                                       ast_ty.span);
408           ty::mk_closure(tcx, fn_decl)
409       }
410       ast::ty_path(ref path, ref bounds, id) => {
411         let a_def = match tcx.def_map.find(&id) {
412           None => tcx.sess.span_fatal(
413               ast_ty.span, fmt!("unbound path %s",
414                                 path_to_str(path, tcx.sess.intr()))),
415           Some(&d) => d
416         };
417         // Kind bounds on path types are only supported for traits.
418         match a_def {
419             // But don't emit the error if the user meant to do a trait anyway.
420             ast::def_trait(*) => { },
421             _ if bounds.is_some() =>
422                 tcx.sess.span_err(ast_ty.span,
423                     "kind bounds can only be used on trait types"),
424             _ => { },
425         }
426         match a_def {
427           ast::def_trait(_) => {
428               let path_str = path_to_str(path, tcx.sess.intr());
429               tcx.sess.span_err(
430                   ast_ty.span,
431                   fmt!("reference to trait `%s` where a type is expected; \
432                         try `@%s`, `~%s`, or `&%s`",
433                        path_str, path_str, path_str, path_str));
434               ty::mk_err()
435           }
436           ast::def_ty(did) | ast::def_struct(did) => {
437             ast_path_to_ty(this, rscope, did, path).ty
438           }
439           ast::def_prim_ty(nty) => {
440             match nty {
441               ast::ty_bool => {
442                 check_path_args(tcx, path, NO_TPS | NO_REGIONS);
443                 ty::mk_bool()
444               }
445               ast::ty_int(it) => {
446                 check_path_args(tcx, path, NO_TPS | NO_REGIONS);
447                 ty::mk_mach_int(it)
448               }
449               ast::ty_uint(uit) => {
450                 check_path_args(tcx, path, NO_TPS | NO_REGIONS);
451                 ty::mk_mach_uint(uit)
452               }
453               ast::ty_float(ft) => {
454                 check_path_args(tcx, path, NO_TPS | NO_REGIONS);
455                 ty::mk_mach_float(ft)
456               }
457               ast::ty_str => {
458                 tcx.sess.span_err(ast_ty.span,
459                                   "bare `str` is not a type");
460                 // return /something/ so they can at least get more errors
461                 ty::mk_estr(tcx, ty::vstore_uniq)
462               }
463             }
464           }
465           ast::def_ty_param(id, n) => {
466             check_path_args(tcx, path, NO_TPS | NO_REGIONS);
467             ty::mk_param(tcx, n, id)
468           }
469           ast::def_self_ty(id) => {
470             // n.b.: resolve guarantees that the this type only appears in a
471             // trait, which we rely upon in various places when creating
472             // substs
473             check_path_args(tcx, path, NO_TPS | NO_REGIONS);
474             let did = ast_util::local_def(id);
475             ty::mk_self(tcx, did)
476           }
477           _ => {
478             tcx.sess.span_fatal(ast_ty.span,
479                                 fmt!("found value name used as a type: %?", a_def));
480           }
481         }
482       }
483       ast::ty_fixed_length_vec(ref a_mt, e) => {
484         match const_eval::eval_const_expr_partial(&tcx, e) {
485           Ok(ref r) => {
486             match *r {
487               const_eval::const_int(i) =>
488                 ty::mk_evec(tcx, ast_mt_to_mt(this, rscope, a_mt),
489                             ty::vstore_fixed(i as uint)),
490               const_eval::const_uint(i) =>
491                 ty::mk_evec(tcx, ast_mt_to_mt(this, rscope, a_mt),
492                             ty::vstore_fixed(i as uint)),
493               _ => {
494                 tcx.sess.span_fatal(
495                     ast_ty.span, "expected constant expr for vector length");
496               }
497             }
498           }
499           Err(ref r) => {
500             tcx.sess.span_fatal(
501                 ast_ty.span,
502                 fmt!("expected constant expr for vector length: %s",
503                      *r));
504           }
505         }
506       }
507       ast::ty_infer => {
508         // ty_infer should only appear as the type of arguments or return
509         // values in a fn_expr, or as the type of local variables.  Both of
510         // these cases are handled specially and should not descend into this
511         // routine.
512         this.tcx().sess.span_bug(
513             ast_ty.span,
514             "found `ty_infer` in unexpected place");
515       }
516       ast::ty_mac(_) => {
517         tcx.sess.span_bug(ast_ty.span,
518                           "found `ty_mac` in unexpected place");
519       }
520     };
521
522     tcx.ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_resolved(typ));
523     return typ;
524 }
525
526 pub fn ty_of_arg<AC:AstConv,
527                  RS:region_scope + Clone + 'static>(
528                  this: &AC,
529                  rscope: &RS,
530                  a: &ast::arg,
531                  expected_ty: Option<ty::t>)
532                  -> ty::t {
533     match a.ty.node {
534         ast::ty_infer if expected_ty.is_some() => expected_ty.unwrap(),
535         ast::ty_infer => this.ty_infer(a.ty.span),
536         _ => ast_ty_to_ty(this, rscope, &a.ty),
537     }
538 }
539
540 pub fn bound_lifetimes<AC:AstConv>(
541     this: &AC,
542     ast_lifetimes: &OptVec<ast::Lifetime>) -> OptVec<ast::ident>
543 {
544     /*!
545      *
546      * Converts a list of lifetimes into a list of bound identifier
547      * names.  Does not permit special names like 'static or 'this to
548      * be bound.  Note that this function is for use in closures,
549      * methods, and fn definitions.  It is legal to bind 'this in a
550      * type.  Eventually this distinction should go away and the same
551      * rules should apply everywhere ('this would not be a special name
552      * at that point).
553      */
554
555     let special_idents = [special_idents::statik, special_idents::self_];
556     let mut bound_lifetime_names = opt_vec::Empty;
557     ast_lifetimes.map_to_vec(|ast_lifetime| {
558         if special_idents.iter().any(|&i| i == ast_lifetime.ident) {
559             this.tcx().sess.span_err(
560                 ast_lifetime.span,
561                 fmt!("illegal lifetime parameter name: `%s`",
562                      lifetime_to_str(ast_lifetime, this.tcx().sess.intr())));
563         } else {
564             bound_lifetime_names.push(ast_lifetime.ident);
565         }
566     });
567     bound_lifetime_names
568 }
569
570 struct SelfInfo {
571     untransformed_self_ty: ty::t,
572     explicit_self: ast::explicit_self
573 }
574
575 pub fn ty_of_method<AC:AstConv,RS:region_scope + Clone + 'static>(
576     this: &AC,
577     rscope: &RS,
578     purity: ast::purity,
579     lifetimes: &OptVec<ast::Lifetime>,
580     untransformed_self_ty: ty::t,
581     explicit_self: ast::explicit_self,
582     decl: &ast::fn_decl) -> (Option<ty::t>, ty::BareFnTy)
583 {
584     let self_info = SelfInfo {
585         untransformed_self_ty: untransformed_self_ty,
586         explicit_self: explicit_self
587     };
588     let (a, b) = ty_of_method_or_bare_fn(
589         this, rscope, purity, AbiSet::Rust(), lifetimes, Some(&self_info), decl);
590     (a.unwrap(), b)
591 }
592
593 pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Clone + 'static>(
594     this: &AC,
595     rscope: &RS,
596     purity: ast::purity,
597     abi: AbiSet,
598     lifetimes: &OptVec<ast::Lifetime>,
599     decl: &ast::fn_decl) -> ty::BareFnTy
600 {
601     let (_, b) = ty_of_method_or_bare_fn(
602         this, rscope, purity, abi, lifetimes, None, decl);
603     b
604 }
605
606 fn ty_of_method_or_bare_fn<AC:AstConv,RS:region_scope + Clone + 'static>(
607     this: &AC,
608     rscope: &RS,
609     purity: ast::purity,
610     abi: AbiSet,
611     lifetimes: &OptVec<ast::Lifetime>,
612     opt_self_info: Option<&SelfInfo>,
613     decl: &ast::fn_decl) -> (Option<Option<ty::t>>, ty::BareFnTy)
614 {
615     debug!("ty_of_bare_fn");
616
617     // new region names that appear inside of the fn decl are bound to
618     // that function type
619     let bound_lifetime_names = bound_lifetimes(this, lifetimes);
620     let rb =
621         in_binding_rscope(rscope,
622                           RegionParamNames(bound_lifetime_names.clone()));
623
624     let opt_transformed_self_ty = do opt_self_info.map_move |self_info| {
625         transform_self_ty(this, &rb, self_info)
626     };
627
628     let input_tys = decl.inputs.map(|a| ty_of_arg(this, &rb, a, None));
629
630     let output_ty = match decl.output.node {
631         ast::ty_infer => this.ty_infer(decl.output.span),
632         _ => ast_ty_to_ty(this, &rb, &decl.output)
633     };
634
635     return (opt_transformed_self_ty,
636             ty::BareFnTy {
637                 purity: purity,
638                 abis: abi,
639                 sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names,
640                                 inputs: input_tys,
641                                 output: output_ty}
642             });
643
644     fn transform_self_ty<AC:AstConv,RS:region_scope + Clone + 'static>(
645         this: &AC,
646         rscope: &RS,
647         self_info: &SelfInfo) -> Option<ty::t>
648     {
649         match self_info.explicit_self.node {
650             ast::sty_static => None,
651             ast::sty_value => {
652                 Some(self_info.untransformed_self_ty)
653             }
654             ast::sty_region(ref lifetime, mutability) => {
655                 let region =
656                     ast_region_to_region(this, rscope,
657                                          self_info.explicit_self.span,
658                                          lifetime);
659                 Some(ty::mk_rptr(this.tcx(), region,
660                                  ty::mt {ty: self_info.untransformed_self_ty,
661                                          mutbl: mutability}))
662             }
663             ast::sty_box(mutability) => {
664                 Some(ty::mk_box(this.tcx(),
665                                 ty::mt {ty: self_info.untransformed_self_ty,
666                                         mutbl: mutability}))
667             }
668             ast::sty_uniq => {
669                 Some(ty::mk_uniq(this.tcx(),
670                                  ty::mt {ty: self_info.untransformed_self_ty,
671                                          mutbl: ast::m_imm}))
672             }
673         }
674     }
675 }
676
677 pub fn ty_of_closure<AC:AstConv,RS:region_scope + Clone + 'static>(
678     this: &AC,
679     rscope: &RS,
680     sigil: ast::Sigil,
681     purity: ast::purity,
682     onceness: ast::Onceness,
683     bounds: ty::BuiltinBounds,
684     opt_lifetime: &Option<ast::Lifetime>,
685     decl: &ast::fn_decl,
686     expected_sig: Option<ty::FnSig>,
687     lifetimes: &OptVec<ast::Lifetime>,
688     span: span)
689     -> ty::ClosureTy
690 {
691     // The caller should not both provide explicit bound lifetime
692     // names and expected types.  Either we infer the bound lifetime
693     // names or they are provided, but not both.
694     assert!(lifetimes.is_empty() || expected_sig.is_none());
695
696     debug!("ty_of_fn_decl");
697     let _i = indenter();
698
699     // resolve the function bound region in the original region
700     // scope `rscope`, not the scope of the function parameters
701     let bound_region = match opt_lifetime {
702         &Some(_) => {
703             ast_region_to_region(this, rscope, span, opt_lifetime)
704         }
705         &None => {
706             match sigil {
707                 ast::OwnedSigil | ast::ManagedSigil => {
708                     // @fn(), ~fn() default to static as the bound
709                     // on their upvars:
710                     ty::re_static
711                 }
712                 ast::BorrowedSigil => {
713                     // &fn() defaults as normal for an omitted lifetime:
714                     ast_region_to_region(this, rscope, span, opt_lifetime)
715                 }
716             }
717         }
718     };
719
720     // new region names that appear inside of the fn decl are bound to
721     // that function type
722     let bound_lifetime_names = bound_lifetimes(this, lifetimes);
723     let rb =
724         in_binding_rscope(rscope,
725                           RegionParamNames(bound_lifetime_names.clone()));
726
727     let input_tys = do decl.inputs.iter().enumerate().transform |(i, a)| {
728         let expected_arg_ty = do expected_sig.chain_ref |e| {
729             // no guarantee that the correct number of expected args
730             // were supplied
731             if i < e.inputs.len() {Some(e.inputs[i])} else {None}
732         };
733         ty_of_arg(this, &rb, a, expected_arg_ty)
734     }.collect();
735
736     let expected_ret_ty = expected_sig.map(|e| e.output);
737     let output_ty = match decl.output.node {
738         ast::ty_infer if expected_ret_ty.is_some() => expected_ret_ty.unwrap(),
739         ast::ty_infer => this.ty_infer(decl.output.span),
740         _ => ast_ty_to_ty(this, &rb, &decl.output)
741     };
742
743     ty::ClosureTy {
744         purity: purity,
745         sigil: sigil,
746         onceness: onceness,
747         region: bound_region,
748         bounds: bounds,
749         sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names,
750                         inputs: input_tys,
751                         output: output_ty}
752     }
753 }
754
755 fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBound>>,
756                        store: ty::TraitStore)
757                        -> ty::BuiltinBounds {
758     //! Converts a list of bounds from the AST into a `BuiltinBounds`
759     //! struct. Reports an error if any of the bounds that appear
760     //! in the AST refer to general traits and not the built-in traits
761     //! like `Send`. Used to translate the bounds that
762     //! appear in closure and trait types, where only builtin bounds are
763     //! legal.
764     //! If no bounds were specified, we choose a "default" bound based on
765     //! the allocation type of the fn/trait, as per issue #7264. The user can
766     //! override this with an empty bounds list, e.g. "~fn:()" or "~Trait:".
767
768     match (ast_bounds, store) {
769         (&Some(ref bound_vec), _) => {
770             let mut builtin_bounds = ty::EmptyBuiltinBounds();
771             for ast_bound in bound_vec.iter() {
772                 match *ast_bound {
773                     ast::TraitTyParamBound(ref b) => {
774                         match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
775                             ast::def_trait(trait_did) => {
776                                 if try_add_builtin_trait(tcx,
777                                                          trait_did,
778                                                          &mut builtin_bounds) {
779                                     loop; // success
780                                 }
781                             }
782                             _ => { }
783                         }
784                         tcx.sess.span_fatal(
785                             b.path.span,
786                             fmt!("only the builtin traits can be used \
787                                   as closure or object bounds"));
788                     }
789                     ast::RegionTyParamBound => {
790                         builtin_bounds.add(ty::BoundStatic);
791                     }
792                 }
793             }
794             builtin_bounds
795         },
796         // ~Trait is sugar for ~Trait:Send.
797         (&None, ty::UniqTraitStore) => {
798             let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundSend); set
799         }
800         // @Trait is sugar for @Trait:'static.
801         // &'static Trait is sugar for &'static Trait:'static.
802         (&None, ty::BoxTraitStore) |
803         (&None, ty::RegionTraitStore(ty::re_static)) => {
804             let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundStatic); set
805         }
806         // &'r Trait is sugar for &'r Trait:<no-bounds>.
807         (&None, ty::RegionTraitStore(*)) => ty::EmptyBuiltinBounds(),
808     }
809 }
810
811 pub fn try_add_builtin_trait(tcx: ty::ctxt,
812                              trait_def_id: ast::def_id,
813                              builtin_bounds: &mut ty::BuiltinBounds) -> bool {
814     //! Checks whether `trait_ref` refers to one of the builtin
815     //! traits, like `Send`, and adds the corresponding
816     //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
817     //! is a builtin trait.
818
819     let li = &tcx.lang_items;
820     if Some(trait_def_id) == li.send_trait() {
821         builtin_bounds.add(ty::BoundSend);
822         true
823     } else if Some(trait_def_id) == li.freeze_trait() {
824         builtin_bounds.add(ty::BoundFreeze);
825         true
826     } else if Some(trait_def_id) == li.sized_trait() {
827         builtin_bounds.add(ty::BoundSized);
828         true
829     } else {
830         false
831     }
832 }