]>
Commit | Line | Data |
---|---|---|
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 | |
56 | use middle::const_eval; | |
970d7e83 | 57 | use middle::ty::{substs}; |
223e47cc LB |
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; | |
970d7e83 | 63 | use middle::typeck::lookup_def_tcx; |
223e47cc | 64 | |
970d7e83 LB |
65 | use std::result; |
66 | use std::vec; | |
223e47cc LB |
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; | |
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 | ||
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(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 |
108 | pub 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 |
133 | fn 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 |
187 | pub 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 |
204 | pub 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 | ||
227 | pub 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 | ||
243 | pub static NO_REGIONS: uint = 1; | |
244 | pub 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 |
249 | pub 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 |
524 | pub 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 | ||
538 | pub 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 |
568 | struct SelfInfo { |
569 | untransformed_self_ty: ty::t, | |
570 | explicit_self: ast::explicit_self | |
571 | } | |
572 | ||
573 | pub 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 | ||
591 | pub 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 | ||
604 | fn 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 |
673 | pub 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 | |
749 | fn 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 | ||
805 | pub 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 | } |