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