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