]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Conversion from AST representation of types to the ty.rs | |
12 | //! representation. The main routine here is `ast_ty_to_ty()`: each use | |
13 | //! is parameterized by an instance of `AstConv` and a `RegionScope`. | |
14 | //! | |
15 | //! The parameterization of `ast_ty_to_ty()` is because it behaves | |
16 | //! somewhat differently during the collect and check phases, | |
17 | //! particularly with respect to looking up the types of top-level | |
18 | //! items. In the collect phase, the crate context is used as the | |
19 | //! `AstConv` instance; in this phase, the `get_item_type_scheme()` function | |
20 | //! triggers a recursive call to `ty_of_item()` (note that | |
21 | //! `ast_ty_to_ty()` will detect recursive types and report an error). | |
22 | //! In the check phase, when the FnCtxt is used as the `AstConv`, | |
23 | //! `get_item_type_scheme()` just looks up the item type in `tcx.tcache`. | |
24 | //! | |
25 | //! The `RegionScope` trait controls what happens when the user does | |
26 | //! not specify a region in some location where a region is required | |
27 | //! (e.g., if the user writes `&Foo` as a type rather than `&'a Foo`). | |
28 | //! See the `rscope` module for more details. | |
29 | //! | |
30 | //! Unlike the `AstConv` trait, the region scope can change as we descend | |
31 | //! the type. This is to accommodate the fact that (a) fn types are binding | |
32 | //! scopes and (b) the default region may change. To understand case (a), | |
33 | //! consider something like: | |
34 | //! | |
35 | //! type foo = { x: &a.int, y: |&a.int| } | |
36 | //! | |
37 | //! The type of `x` is an error because there is no region `a` in scope. | |
38 | //! In the type of `y`, however, region `a` is considered a bound region | |
39 | //! as it does not already appear in scope. | |
40 | //! | |
41 | //! Case (b) says that if you have a type: | |
42 | //! type foo<'a> = ...; | |
43 | //! type bar = fn(&foo, &a.foo) | |
44 | //! The fully expanded version of type bar is: | |
45 | //! type bar = fn(&'foo &, &a.foo<'a>) | |
46 | //! Note that the self region for the `foo` defaulted to `&` in the first | |
47 | //! case but `&a` in the second. Basically, defaults that appear inside | |
48 | //! an rptr (`&r.T`) use the region `r` that appears in the rptr. | |
49 | ||
50 | use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGIONS}; | |
51 | use middle::const_eval; | |
52 | use middle::def; | |
53 | use middle::resolve_lifetime as rl; | |
54 | use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; | |
55 | use middle::traits; | |
56 | use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; | |
57 | use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope, | |
58 | ShiftedRscope, BindingRscope}; | |
59 | use TypeAndSubsts; | |
60 | use util::common::ErrorReported; | |
61 | use util::nodemap::DefIdMap; | |
62 | use util::ppaux::{self, Repr, UserString}; | |
63 | ||
64 | use std::rc::Rc; | |
65 | use std::iter::{repeat, AdditiveIterator}; | |
66 | use syntax::{abi, ast, ast_util}; | |
67 | use syntax::codemap::Span; | |
68 | use syntax::parse::token; | |
69 | use syntax::print::pprust; | |
70 | ||
71 | pub trait AstConv<'tcx> { | |
72 | fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; | |
73 | ||
74 | fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx>; | |
75 | ||
76 | fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>; | |
77 | ||
78 | /// Return an (optional) substitution to convert bound type parameters that | |
79 | /// are in scope into free ones. This function should only return Some | |
80 | /// within a fn body. | |
81 | /// See ParameterEnvironment::free_substs for more information. | |
82 | fn get_free_substs(&self) -> Option<&Substs<'tcx>> { | |
83 | None | |
84 | } | |
85 | ||
86 | /// What type should we use when a type is omitted? | |
87 | fn ty_infer(&self, span: Span) -> Ty<'tcx>; | |
88 | ||
89 | /// Projecting an associated type from a (potentially) | |
90 | /// higher-ranked trait reference is more complicated, because of | |
91 | /// the possibility of late-bound regions appearing in the | |
92 | /// associated type binding. This is not legal in function | |
93 | /// signatures for that reason. In a function body, we can always | |
94 | /// handle it because we can use inference variables to remove the | |
95 | /// late-bound regions. | |
96 | fn projected_ty_from_poly_trait_ref(&self, | |
97 | span: Span, | |
98 | poly_trait_ref: ty::PolyTraitRef<'tcx>, | |
99 | item_name: ast::Name) | |
100 | -> Ty<'tcx> | |
101 | { | |
102 | if ty::binds_late_bound_regions(self.tcx(), &poly_trait_ref) { | |
103 | self.tcx().sess.span_err( | |
104 | span, | |
105 | "cannot extract an associated type from a higher-ranked trait bound \ | |
106 | in this context"); | |
107 | self.tcx().types.err | |
108 | } else { | |
109 | // no late-bound regions, we can just ignore the binder | |
110 | self.projected_ty(span, poly_trait_ref.0.clone(), item_name) | |
111 | } | |
112 | } | |
113 | ||
114 | /// Project an associated type from a non-higher-ranked trait reference. | |
115 | /// This is fairly straightforward and can be accommodated in any context. | |
116 | fn projected_ty(&self, | |
117 | span: Span, | |
118 | _trait_ref: Rc<ty::TraitRef<'tcx>>, | |
119 | _item_name: ast::Name) | |
120 | -> Ty<'tcx> | |
121 | { | |
122 | self.tcx().sess.span_err( | |
123 | span, | |
124 | "associated types are not accepted in this context"); | |
125 | ||
126 | self.tcx().types.err | |
127 | } | |
128 | } | |
129 | ||
130 | pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) | |
131 | -> ty::Region { | |
132 | let r = match tcx.named_region_map.get(&lifetime.id) { | |
133 | None => { | |
134 | // should have been recorded by the `resolve_lifetime` pass | |
135 | tcx.sess.span_bug(lifetime.span, "unresolved lifetime"); | |
136 | } | |
137 | ||
138 | Some(&rl::DefStaticRegion) => { | |
139 | ty::ReStatic | |
140 | } | |
141 | ||
142 | Some(&rl::DefLateBoundRegion(debruijn, id)) => { | |
143 | ty::ReLateBound(debruijn, ty::BrNamed(ast_util::local_def(id), lifetime.name)) | |
144 | } | |
145 | ||
146 | Some(&rl::DefEarlyBoundRegion(space, index, id)) => { | |
147 | ty::ReEarlyBound(id, space, index, lifetime.name) | |
148 | } | |
149 | ||
150 | Some(&rl::DefFreeRegion(scope, id)) => { | |
151 | ty::ReFree(ty::FreeRegion { | |
152 | scope: scope, | |
153 | bound_region: ty::BrNamed(ast_util::local_def(id), | |
154 | lifetime.name) | |
155 | }) | |
156 | } | |
157 | }; | |
158 | ||
159 | debug!("ast_region_to_region(lifetime={} id={}) yields {}", | |
160 | lifetime.repr(tcx), | |
161 | lifetime.id, | |
162 | r.repr(tcx)); | |
163 | ||
164 | r | |
165 | } | |
166 | ||
167 | pub fn opt_ast_region_to_region<'tcx>( | |
168 | this: &AstConv<'tcx>, | |
169 | rscope: &RegionScope, | |
170 | default_span: Span, | |
171 | opt_lifetime: &Option<ast::Lifetime>) -> ty::Region | |
172 | { | |
173 | let r = match *opt_lifetime { | |
174 | Some(ref lifetime) => { | |
175 | ast_region_to_region(this.tcx(), lifetime) | |
176 | } | |
177 | ||
178 | None => { | |
179 | match rscope.anon_regions(default_span, 1) { | |
180 | Err(v) => { | |
181 | debug!("optional region in illegal location"); | |
182 | span_err!(this.tcx().sess, default_span, E0106, | |
183 | "missing lifetime specifier"); | |
184 | match v { | |
185 | Some(v) => { | |
186 | let mut m = String::new(); | |
187 | let len = v.len(); | |
188 | for (i, (name, n)) in v.into_iter().enumerate() { | |
189 | let help_name = if name.is_empty() { | |
190 | format!("argument {}", i + 1) | |
191 | } else { | |
192 | format!("`{}`", name) | |
193 | }; | |
194 | ||
195 | m.push_str(&(if n == 1 { | |
196 | help_name | |
197 | } else { | |
198 | format!("one of {}'s {} elided lifetimes", help_name, n) | |
199 | })[]); | |
200 | ||
201 | if len == 2 && i == 0 { | |
202 | m.push_str(" or "); | |
203 | } else if i == len - 2 { | |
204 | m.push_str(", or "); | |
205 | } else if i != len - 1 { | |
206 | m.push_str(", "); | |
207 | } | |
208 | } | |
209 | if len == 1 { | |
210 | span_help!(this.tcx().sess, default_span, | |
211 | "this function's return type contains a borrowed value, but \ | |
212 | the signature does not say which {} it is borrowed from", | |
213 | m); | |
214 | } else if len == 0 { | |
215 | span_help!(this.tcx().sess, default_span, | |
216 | "this function's return type contains a borrowed value, but \ | |
217 | there is no value for it to be borrowed from"); | |
218 | span_help!(this.tcx().sess, default_span, | |
219 | "consider giving it a 'static lifetime"); | |
220 | } else { | |
221 | span_help!(this.tcx().sess, default_span, | |
222 | "this function's return type contains a borrowed value, but \ | |
223 | the signature does not say whether it is borrowed from {}", | |
224 | m); | |
225 | } | |
226 | } | |
227 | None => {}, | |
228 | } | |
229 | ty::ReStatic | |
230 | } | |
231 | ||
232 | Ok(rs) => rs[0], | |
233 | } | |
234 | } | |
235 | }; | |
236 | ||
237 | debug!("opt_ast_region_to_region(opt_lifetime={}) yields {}", | |
238 | opt_lifetime.repr(this.tcx()), | |
239 | r.repr(this.tcx())); | |
240 | ||
241 | r | |
242 | } | |
243 | ||
244 | /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, | |
245 | /// returns an appropriate set of substitutions for this particular reference to `I`. | |
246 | pub fn ast_path_substs_for_ty<'tcx>( | |
247 | this: &AstConv<'tcx>, | |
248 | rscope: &RegionScope, | |
249 | decl_generics: &ty::Generics<'tcx>, | |
250 | path: &ast::Path) | |
251 | -> Substs<'tcx> | |
252 | { | |
253 | let tcx = this.tcx(); | |
254 | ||
255 | // ast_path_substs() is only called to convert paths that are | |
256 | // known to refer to traits, types, or structs. In these cases, | |
257 | // all type parameters defined for the item being referenced will | |
258 | // be in the TypeSpace or SelfSpace. | |
259 | // | |
260 | // Note: in the case of traits, the self parameter is also | |
261 | // defined, but we don't currently create a `type_param_def` for | |
262 | // `Self` because it is implicit. | |
263 | assert!(decl_generics.regions.all(|d| d.space == TypeSpace)); | |
264 | assert!(decl_generics.types.all(|d| d.space != FnSpace)); | |
265 | ||
266 | let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters { | |
267 | ast::AngleBracketedParameters(ref data) => { | |
268 | convert_angle_bracketed_parameters(this, rscope, data) | |
269 | } | |
270 | ast::ParenthesizedParameters(ref data) => { | |
271 | tcx.sess.span_err( | |
272 | path.span, | |
273 | "parenthesized parameters may only be used with a trait"); | |
274 | (Vec::new(), convert_parenthesized_parameters(this, data), Vec::new()) | |
275 | } | |
276 | }; | |
277 | ||
278 | prohibit_projections(this.tcx(), assoc_bindings.as_slice()); | |
279 | ||
280 | create_substs_for_ast_path(this, | |
281 | rscope, | |
282 | path.span, | |
283 | decl_generics, | |
284 | None, | |
285 | types, | |
286 | regions) | |
287 | } | |
288 | ||
289 | fn create_substs_for_ast_path<'tcx>( | |
290 | this: &AstConv<'tcx>, | |
291 | rscope: &RegionScope, | |
292 | span: Span, | |
293 | decl_generics: &ty::Generics<'tcx>, | |
294 | self_ty: Option<Ty<'tcx>>, | |
295 | types: Vec<Ty<'tcx>>, | |
296 | regions: Vec<ty::Region>) | |
297 | -> Substs<'tcx> | |
298 | { | |
299 | let tcx = this.tcx(); | |
300 | ||
301 | // If the type is parameterized by the this region, then replace this | |
302 | // region with the current anon region binding (in other words, | |
303 | // whatever & would get replaced with). | |
304 | let expected_num_region_params = decl_generics.regions.len(TypeSpace); | |
305 | let supplied_num_region_params = regions.len(); | |
306 | let regions = if expected_num_region_params == supplied_num_region_params { | |
307 | regions | |
308 | } else { | |
309 | let anon_regions = | |
310 | rscope.anon_regions(span, expected_num_region_params); | |
311 | ||
312 | if supplied_num_region_params != 0 || anon_regions.is_err() { | |
313 | span_err!(tcx.sess, span, E0107, | |
314 | "wrong number of lifetime parameters: expected {}, found {}", | |
315 | expected_num_region_params, supplied_num_region_params); | |
316 | } | |
317 | ||
318 | match anon_regions { | |
319 | Ok(v) => v.into_iter().collect(), | |
320 | Err(_) => range(0, expected_num_region_params) | |
321 | .map(|_| ty::ReStatic).collect() // hokey | |
322 | } | |
323 | }; | |
324 | ||
325 | // Convert the type parameters supplied by the user. | |
326 | let ty_param_defs = decl_generics.types.get_slice(TypeSpace); | |
327 | let supplied_ty_param_count = types.len(); | |
328 | let formal_ty_param_count = | |
329 | ty_param_defs.iter() | |
330 | .take_while(|x| !ty::is_associated_type(tcx, x.def_id)) | |
331 | .count(); | |
332 | let required_ty_param_count = | |
333 | ty_param_defs.iter() | |
334 | .take_while(|x| { | |
335 | x.default.is_none() && | |
336 | !ty::is_associated_type(tcx, x.def_id) | |
337 | }) | |
338 | .count(); | |
339 | if supplied_ty_param_count < required_ty_param_count { | |
340 | let expected = if required_ty_param_count < formal_ty_param_count { | |
341 | "expected at least" | |
342 | } else { | |
343 | "expected" | |
344 | }; | |
345 | this.tcx().sess.span_fatal(span, | |
346 | &format!("wrong number of type arguments: {} {}, found {}", | |
347 | expected, | |
348 | required_ty_param_count, | |
349 | supplied_ty_param_count)[]); | |
350 | } else if supplied_ty_param_count > formal_ty_param_count { | |
351 | let expected = if required_ty_param_count < formal_ty_param_count { | |
352 | "expected at most" | |
353 | } else { | |
354 | "expected" | |
355 | }; | |
356 | this.tcx().sess.span_fatal(span, | |
357 | &format!("wrong number of type arguments: {} {}, found {}", | |
358 | expected, | |
359 | formal_ty_param_count, | |
360 | supplied_ty_param_count)[]); | |
361 | } | |
362 | ||
363 | let mut substs = Substs::new_type(types, regions); | |
364 | ||
365 | match self_ty { | |
366 | None => { | |
367 | // If no self-type is provided, it's still possible that | |
368 | // one was declared, because this could be an object type. | |
369 | } | |
370 | Some(ty) => { | |
371 | // If a self-type is provided, one should have been | |
372 | // "declared" (in other words, this should be a | |
373 | // trait-ref). | |
374 | assert!(decl_generics.types.get_self().is_some()); | |
375 | substs.types.push(SelfSpace, ty); | |
376 | } | |
377 | } | |
378 | ||
379 | for param in ty_param_defs[supplied_ty_param_count..].iter() { | |
380 | match param.default { | |
381 | Some(default) => { | |
382 | // This is a default type parameter. | |
383 | let default = default.subst_spanned(tcx, | |
384 | &substs, | |
385 | Some(span)); | |
386 | substs.types.push(TypeSpace, default); | |
387 | } | |
388 | None => { | |
389 | tcx.sess.span_bug(span, "extra parameter without default"); | |
390 | } | |
391 | } | |
392 | } | |
393 | ||
394 | return substs; | |
395 | } | |
396 | ||
397 | struct ConvertedBinding<'tcx> { | |
398 | item_name: ast::Name, | |
399 | ty: Ty<'tcx>, | |
400 | span: Span, | |
401 | } | |
402 | ||
403 | fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>, | |
404 | rscope: &RegionScope, | |
405 | data: &ast::AngleBracketedParameterData) | |
406 | -> (Vec<ty::Region>, | |
407 | Vec<Ty<'tcx>>, | |
408 | Vec<ConvertedBinding<'tcx>>) | |
409 | { | |
410 | let regions: Vec<_> = | |
411 | data.lifetimes.iter() | |
412 | .map(|l| ast_region_to_region(this.tcx(), l)) | |
413 | .collect(); | |
414 | ||
415 | let types: Vec<_> = | |
416 | data.types.iter() | |
417 | .map(|t| ast_ty_to_ty(this, rscope, &**t)) | |
418 | .collect(); | |
419 | ||
420 | let assoc_bindings: Vec<_> = | |
421 | data.bindings.iter() | |
422 | .map(|b| ConvertedBinding { item_name: b.ident.name, | |
423 | ty: ast_ty_to_ty(this, rscope, &*b.ty), | |
424 | span: b.span }) | |
425 | .collect(); | |
426 | ||
427 | (regions, types, assoc_bindings) | |
428 | } | |
429 | ||
430 | /// Returns the appropriate lifetime to use for any output lifetimes | |
431 | /// (if one exists) and a vector of the (pattern, number of lifetimes) | |
432 | /// corresponding to each input type/pattern. | |
433 | fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec<String>) | |
434 | -> (Option<ty::Region>, Vec<(String, uint)>) | |
435 | { | |
436 | let mut lifetimes_for_params: Vec<(String, uint)> = Vec::new(); | |
437 | let mut possible_implied_output_region = None; | |
438 | ||
439 | for (input_type, input_pat) in input_tys.iter().zip(input_pats.into_iter()) { | |
440 | let mut accumulator = Vec::new(); | |
441 | ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type); | |
442 | ||
443 | if accumulator.len() == 1 { | |
444 | // there's a chance that the unique lifetime of this | |
445 | // iteration will be the appropriate lifetime for output | |
446 | // parameters, so lets store it. | |
447 | possible_implied_output_region = Some(accumulator[0]) | |
448 | } | |
449 | ||
450 | lifetimes_for_params.push((input_pat, accumulator.len())); | |
451 | } | |
452 | ||
453 | let implied_output_region = if lifetimes_for_params.iter().map(|&(_, n)| n).sum() == 1 { | |
454 | assert!(possible_implied_output_region.is_some()); | |
455 | possible_implied_output_region | |
456 | } else { | |
457 | None | |
458 | }; | |
459 | (implied_output_region, lifetimes_for_params) | |
460 | } | |
461 | ||
462 | fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>, | |
463 | implied_output_region: Option<ty::Region>, | |
464 | param_lifetimes: Vec<(String, uint)>, | |
465 | ty: &ast::Ty) | |
466 | -> Ty<'tcx> | |
467 | { | |
468 | match implied_output_region { | |
469 | Some(implied_output_region) => { | |
470 | let rb = SpecificRscope::new(implied_output_region); | |
471 | ast_ty_to_ty(this, &rb, ty) | |
472 | } | |
473 | None => { | |
474 | // All regions must be explicitly specified in the output | |
475 | // if the lifetime elision rules do not apply. This saves | |
476 | // the user from potentially-confusing errors. | |
477 | let rb = UnelidableRscope::new(param_lifetimes); | |
478 | ast_ty_to_ty(this, &rb, ty) | |
479 | } | |
480 | } | |
481 | } | |
482 | ||
483 | fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, | |
484 | data: &ast::ParenthesizedParameterData) | |
485 | -> Vec<Ty<'tcx>> | |
486 | { | |
487 | let binding_rscope = BindingRscope::new(); | |
488 | let inputs = data.inputs.iter() | |
489 | .map(|a_t| ast_ty_to_ty(this, &binding_rscope, &**a_t)) | |
490 | .collect::<Vec<Ty<'tcx>>>(); | |
491 | ||
492 | let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect(); | |
493 | let (implied_output_region, | |
494 | params_lifetimes) = find_implied_output_region(&*inputs, input_params); | |
495 | ||
496 | let input_ty = ty::mk_tup(this.tcx(), inputs); | |
497 | ||
498 | let output = match data.output { | |
499 | Some(ref output_ty) => convert_ty_with_lifetime_elision(this, | |
500 | implied_output_region, | |
501 | params_lifetimes, | |
502 | &**output_ty), | |
503 | None => ty::mk_nil(this.tcx()), | |
504 | }; | |
505 | ||
506 | vec![input_ty, output] | |
507 | } | |
508 | ||
509 | pub fn instantiate_poly_trait_ref<'tcx>( | |
510 | this: &AstConv<'tcx>, | |
511 | rscope: &RegionScope, | |
512 | ast_trait_ref: &ast::PolyTraitRef, | |
513 | self_ty: Option<Ty<'tcx>>, | |
514 | poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>) | |
515 | -> ty::PolyTraitRef<'tcx> | |
516 | { | |
517 | let mut projections = Vec::new(); | |
518 | ||
519 | let trait_ref = | |
520 | instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, | |
521 | self_ty, Some(&mut projections)); | |
522 | ||
523 | for projection in projections.into_iter() { | |
524 | poly_projections.push(ty::Binder(projection)); | |
525 | } | |
526 | ||
527 | ty::Binder(trait_ref) | |
528 | } | |
529 | ||
530 | /// Instantiates the path for the given trait reference, assuming that it's | |
531 | /// bound to a valid trait type. Returns the def_id for the defining trait. | |
532 | /// Fails if the type is a type other than a trait type. | |
533 | /// | |
534 | /// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>` | |
535 | /// are disallowed. Otherwise, they are pushed onto the vector given. | |
536 | pub fn instantiate_trait_ref<'tcx>( | |
537 | this: &AstConv<'tcx>, | |
538 | rscope: &RegionScope, | |
539 | ast_trait_ref: &ast::TraitRef, | |
540 | self_ty: Option<Ty<'tcx>>, | |
541 | projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>) | |
542 | -> Rc<ty::TraitRef<'tcx>> | |
543 | { | |
544 | match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) { | |
545 | def::DefTrait(trait_def_id) => { | |
546 | let trait_ref = ast_path_to_trait_ref(this, | |
547 | rscope, | |
548 | trait_def_id, | |
549 | self_ty, | |
550 | &ast_trait_ref.path, | |
551 | projections); | |
552 | this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, trait_ref.clone()); | |
553 | trait_ref | |
554 | } | |
555 | _ => { | |
556 | this.tcx().sess.span_fatal( | |
557 | ast_trait_ref.path.span, | |
558 | &format!("`{}` is not a trait", | |
559 | ast_trait_ref.path.user_string(this.tcx()))[]); | |
560 | } | |
561 | } | |
562 | } | |
563 | ||
564 | fn ast_path_to_trait_ref<'a,'tcx>( | |
565 | this: &AstConv<'tcx>, | |
566 | rscope: &RegionScope, | |
567 | trait_def_id: ast::DefId, | |
568 | self_ty: Option<Ty<'tcx>>, | |
569 | path: &ast::Path, | |
570 | mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>) | |
571 | -> Rc<ty::TraitRef<'tcx>> | |
572 | { | |
573 | debug!("ast_path_to_trait_ref {:?}", path); | |
574 | let trait_def = this.get_trait_def(trait_def_id); | |
575 | ||
576 | // the trait reference introduces a binding level here, so | |
577 | // we need to shift the `rscope`. It'd be nice if we could | |
578 | // do away with this rscope stuff and work this knowledge | |
579 | // into resolve_lifetimes, as we do with non-omitted | |
580 | // lifetimes. Oh well, not there yet. | |
581 | let shifted_rscope = ShiftedRscope::new(rscope); | |
582 | ||
583 | let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters { | |
584 | ast::AngleBracketedParameters(ref data) => { | |
585 | convert_angle_bracketed_parameters(this, &shifted_rscope, data) | |
586 | } | |
587 | ast::ParenthesizedParameters(ref data) => { | |
588 | // For now, require that parenthetical notation be used | |
589 | // only with `Fn()` etc. | |
590 | if !this.tcx().sess.features.borrow().unboxed_closures && | |
591 | this.tcx().lang_items.fn_trait_kind(trait_def_id).is_none() | |
592 | { | |
593 | this.tcx().sess.span_err(path.span, | |
594 | "parenthetical notation is only stable when \ | |
595 | used with the `Fn` family of traits"); | |
596 | span_help!(this.tcx().sess, path.span, | |
597 | "add `#![feature(unboxed_closures)]` to \ | |
598 | the crate attributes to enable"); | |
599 | } | |
600 | ||
601 | (Vec::new(), convert_parenthesized_parameters(this, data), Vec::new()) | |
602 | } | |
603 | }; | |
604 | ||
605 | let substs = create_substs_for_ast_path(this, | |
606 | &shifted_rscope, | |
607 | path.span, | |
608 | &trait_def.generics, | |
609 | self_ty, | |
610 | types, | |
611 | regions); | |
612 | let substs = this.tcx().mk_substs(substs); | |
613 | ||
614 | let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); | |
615 | ||
616 | match projections { | |
617 | None => { | |
618 | prohibit_projections(this.tcx(), assoc_bindings.as_slice()); | |
619 | } | |
620 | Some(ref mut v) => { | |
621 | for binding in assoc_bindings.iter() { | |
622 | match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), | |
623 | self_ty, binding) { | |
624 | Ok(pp) => { v.push(pp); } | |
625 | Err(ErrorReported) => { } | |
626 | } | |
627 | } | |
628 | } | |
629 | } | |
630 | ||
631 | trait_ref | |
632 | } | |
633 | ||
634 | fn ast_type_binding_to_projection_predicate<'tcx>( | |
635 | this: &AstConv<'tcx>, | |
636 | mut trait_ref: Rc<ty::TraitRef<'tcx>>, | |
637 | self_ty: Option<Ty<'tcx>>, | |
638 | binding: &ConvertedBinding<'tcx>) | |
639 | -> Result<ty::ProjectionPredicate<'tcx>, ErrorReported> | |
640 | { | |
641 | let tcx = this.tcx(); | |
642 | ||
643 | // Given something like `U : SomeTrait<T=X>`, we want to produce a | |
644 | // predicate like `<U as SomeTrait>::T = X`. This is somewhat | |
645 | // subtle in the event that `T` is defined in a supertrait of | |
646 | // `SomeTrait`, because in that case we need to upcast. | |
647 | // | |
648 | // That is, consider this case: | |
649 | // | |
650 | // ``` | |
651 | // trait SubTrait : SuperTrait<int> { } | |
652 | // trait SuperTrait<A> { type T; } | |
653 | // | |
654 | // ... B : SubTrait<T=foo> ... | |
655 | // ``` | |
656 | // | |
657 | // We want to produce `<B as SuperTrait<int>>::T == foo`. | |
658 | ||
659 | // Simple case: X is defined in the current trait. | |
660 | if trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) { | |
661 | return Ok(ty::ProjectionPredicate { | |
662 | projection_ty: ty::ProjectionTy { | |
663 | trait_ref: trait_ref, | |
664 | item_name: binding.item_name, | |
665 | }, | |
666 | ty: binding.ty, | |
667 | }); | |
668 | } | |
669 | ||
670 | // Otherwise, we have to walk through the supertraits to find | |
671 | // those that do. This is complicated by the fact that, for an | |
672 | // object type, the `Self` type is not present in the | |
673 | // substitutions (after all, it's being constructed right now), | |
674 | // but the `supertraits` iterator really wants one. To handle | |
675 | // this, we currently insert a dummy type and then remove it | |
676 | // later. Yuck. | |
677 | ||
678 | let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0)); | |
679 | if self_ty.is_none() { // if converting for an object type | |
680 | let mut dummy_substs = trait_ref.substs.clone(); | |
681 | assert!(dummy_substs.self_ty().is_none()); | |
682 | dummy_substs.types.push(SelfSpace, dummy_self_ty); | |
683 | trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id, | |
684 | tcx.mk_substs(dummy_substs))); | |
685 | } | |
686 | ||
687 | let mut candidates: Vec<ty::PolyTraitRef> = | |
688 | traits::supertraits(tcx, trait_ref.to_poly_trait_ref()) | |
689 | .filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name)) | |
690 | .collect(); | |
691 | ||
692 | // If converting for an object type, then remove the dummy-ty from `Self` now. | |
693 | // Yuckety yuck. | |
694 | if self_ty.is_none() { | |
695 | for candidate in candidates.iter_mut() { | |
696 | let mut dummy_substs = candidate.0.substs.clone(); | |
697 | assert!(dummy_substs.self_ty() == Some(dummy_self_ty)); | |
698 | dummy_substs.types.pop(SelfSpace); | |
699 | *candidate = ty::Binder(Rc::new(ty::TraitRef::new(candidate.def_id(), | |
700 | tcx.mk_substs(dummy_substs)))); | |
701 | } | |
702 | } | |
703 | ||
704 | if candidates.len() > 1 { | |
705 | tcx.sess.span_err( | |
706 | binding.span, | |
707 | format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`", | |
708 | token::get_name(binding.item_name), | |
709 | candidates.user_string(tcx)).as_slice()); | |
710 | return Err(ErrorReported); | |
711 | } | |
712 | ||
713 | let candidate = match candidates.pop() { | |
714 | Some(c) => c, | |
715 | None => { | |
716 | tcx.sess.span_err( | |
717 | binding.span, | |
718 | format!("no associated type `{}` defined in `{}`", | |
719 | token::get_name(binding.item_name), | |
720 | trait_ref.user_string(tcx)).as_slice()); | |
721 | return Err(ErrorReported); | |
722 | } | |
723 | }; | |
724 | ||
725 | if ty::binds_late_bound_regions(tcx, &candidate) { | |
726 | tcx.sess.span_err( | |
727 | binding.span, | |
728 | format!("associated type `{}` defined in higher-ranked supertrait `{}`", | |
729 | token::get_name(binding.item_name), | |
730 | candidate.user_string(tcx)).as_slice()); | |
731 | return Err(ErrorReported); | |
732 | } | |
733 | ||
734 | Ok(ty::ProjectionPredicate { | |
735 | projection_ty: ty::ProjectionTy { | |
736 | trait_ref: candidate.0, | |
737 | item_name: binding.item_name, | |
738 | }, | |
739 | ty: binding.ty, | |
740 | }) | |
741 | } | |
742 | ||
743 | pub fn ast_path_to_ty<'tcx>( | |
744 | this: &AstConv<'tcx>, | |
745 | rscope: &RegionScope, | |
746 | did: ast::DefId, | |
747 | path: &ast::Path) | |
748 | -> TypeAndSubsts<'tcx> | |
749 | { | |
750 | let tcx = this.tcx(); | |
751 | let ty::TypeScheme { | |
752 | generics, | |
753 | ty: decl_ty | |
754 | } = this.get_item_type_scheme(did); | |
755 | ||
756 | let substs = ast_path_substs_for_ty(this, | |
757 | rscope, | |
758 | &generics, | |
759 | path); | |
760 | let ty = decl_ty.subst(tcx, &substs); | |
761 | TypeAndSubsts { substs: substs, ty: ty } | |
762 | } | |
763 | ||
764 | /// Converts the given AST type to a built-in type. A "built-in type" is, at | |
765 | /// present, either a core numeric type, a string, or `Box`. | |
766 | pub fn ast_ty_to_builtin_ty<'tcx>( | |
767 | this: &AstConv<'tcx>, | |
768 | rscope: &RegionScope, | |
769 | ast_ty: &ast::Ty) | |
770 | -> Option<Ty<'tcx>> { | |
771 | match ast_ty_to_prim_ty(this.tcx(), ast_ty) { | |
772 | Some(typ) => return Some(typ), | |
773 | None => {} | |
774 | } | |
775 | ||
776 | match ast_ty.node { | |
777 | ast::TyPath(ref path, id) => { | |
778 | let a_def = match this.tcx().def_map.borrow().get(&id) { | |
779 | None => { | |
780 | this.tcx() | |
781 | .sess | |
782 | .span_bug(ast_ty.span, | |
783 | &format!("unbound path {}", | |
784 | path.repr(this.tcx()))[]) | |
785 | } | |
786 | Some(&d) => d | |
787 | }; | |
788 | ||
789 | // FIXME(#12938): This is a hack until we have full support for | |
790 | // DST. | |
791 | match a_def { | |
792 | def::DefTy(did, _) | | |
793 | def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => { | |
794 | let ty = ast_path_to_ty(this, rscope, did, path).ty; | |
795 | match ty.sty { | |
796 | ty::ty_struct(struct_def_id, ref substs) => { | |
797 | assert_eq!(struct_def_id, did); | |
798 | assert_eq!(substs.types.len(TypeSpace), 1); | |
799 | let referent_ty = *substs.types.get(TypeSpace, 0); | |
800 | Some(ty::mk_uniq(this.tcx(), referent_ty)) | |
801 | } | |
802 | _ => { | |
803 | this.tcx().sess.span_bug( | |
804 | path.span, | |
805 | &format!("converting `Box` to `{}`", | |
806 | ty.repr(this.tcx()))[]); | |
807 | } | |
808 | } | |
809 | } | |
810 | _ => None | |
811 | } | |
812 | } | |
813 | _ => None | |
814 | } | |
815 | } | |
816 | ||
817 | type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>); | |
818 | ||
819 | fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, | |
820 | rscope: &RegionScope, | |
821 | ty: &ast::Ty, | |
822 | bounds: &[ast::TyParamBound]) | |
823 | -> Result<TraitAndProjections<'tcx>, ErrorReported> | |
824 | { | |
825 | /*! | |
826 | * In a type like `Foo + Send`, we want to wait to collect the | |
827 | * full set of bounds before we make the object type, because we | |
828 | * need them to infer a region bound. (For example, if we tried | |
829 | * made a type from just `Foo`, then it wouldn't be enough to | |
830 | * infer a 'static bound, and hence the user would get an error.) | |
831 | * So this function is used when we're dealing with a sum type to | |
832 | * convert the LHS. It only accepts a type that refers to a trait | |
833 | * name, and reports an error otherwise. | |
834 | */ | |
835 | ||
836 | match ty.node { | |
837 | ast::TyPath(ref path, id) => { | |
838 | match this.tcx().def_map.borrow().get(&id) { | |
839 | Some(&def::DefTrait(trait_def_id)) => { | |
840 | let mut projection_bounds = Vec::new(); | |
841 | let trait_ref = ty::Binder(ast_path_to_trait_ref(this, | |
842 | rscope, | |
843 | trait_def_id, | |
844 | None, | |
845 | path, | |
846 | Some(&mut projection_bounds))); | |
847 | let projection_bounds = projection_bounds.into_iter() | |
848 | .map(ty::Binder) | |
849 | .collect(); | |
850 | Ok((trait_ref, projection_bounds)) | |
851 | } | |
852 | _ => { | |
853 | span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait"); | |
854 | Err(ErrorReported) | |
855 | } | |
856 | } | |
857 | } | |
858 | _ => { | |
859 | span_err!(this.tcx().sess, ty.span, E0178, | |
860 | "expected a path on the left-hand side of `+`, not `{}`", | |
861 | pprust::ty_to_string(ty)); | |
862 | match ty.node { | |
863 | ast::TyRptr(None, ref mut_ty) => { | |
864 | span_note!(this.tcx().sess, ty.span, | |
865 | "perhaps you meant `&{}({} +{})`? (per RFC 438)", | |
866 | ppaux::mutability_to_string(mut_ty.mutbl), | |
867 | pprust::ty_to_string(&*mut_ty.ty), | |
868 | pprust::bounds_to_string(bounds)); | |
869 | } | |
870 | ast::TyRptr(Some(ref lt), ref mut_ty) => { | |
871 | span_note!(this.tcx().sess, ty.span, | |
872 | "perhaps you meant `&{} {}({} +{})`? (per RFC 438)", | |
873 | pprust::lifetime_to_string(lt), | |
874 | ppaux::mutability_to_string(mut_ty.mutbl), | |
875 | pprust::ty_to_string(&*mut_ty.ty), | |
876 | pprust::bounds_to_string(bounds)); | |
877 | } | |
878 | ||
879 | _ => { | |
880 | span_note!(this.tcx().sess, ty.span, | |
881 | "perhaps you forgot parentheses? (per RFC 438)"); | |
882 | } | |
883 | } | |
884 | Err(ErrorReported) | |
885 | } | |
886 | } | |
887 | } | |
888 | ||
889 | fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, | |
890 | rscope: &RegionScope, | |
891 | span: Span, | |
892 | trait_ref: ty::PolyTraitRef<'tcx>, | |
893 | projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, | |
894 | bounds: &[ast::TyParamBound]) | |
895 | -> Ty<'tcx> | |
896 | { | |
897 | let existential_bounds = conv_existential_bounds(this, | |
898 | rscope, | |
899 | span, | |
900 | Some(trait_ref.clone()), | |
901 | projection_bounds, | |
902 | bounds); | |
903 | ||
904 | let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds); | |
905 | debug!("trait_ref_to_object_type: result={}", | |
906 | result.repr(this.tcx())); | |
907 | ||
908 | result | |
909 | } | |
910 | ||
911 | fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, | |
912 | ast_ty: &ast::Ty, | |
913 | provenance: def::TyParamProvenance, | |
914 | assoc_name: ast::Name) | |
915 | -> Ty<'tcx> | |
916 | { | |
917 | let tcx = this.tcx(); | |
918 | let ty_param_def_id = provenance.def_id(); | |
919 | ||
920 | let mut suitable_bounds: Vec<_>; | |
921 | let ty_param_name: ast::Name; | |
922 | { // contain scope of refcell: | |
923 | let ty_param_defs = tcx.ty_param_defs.borrow(); | |
924 | let ty_param_def = &ty_param_defs[ty_param_def_id.node]; | |
925 | ty_param_name = ty_param_def.name; | |
926 | ||
927 | // FIXME(#20300) -- search where clauses, not bounds | |
928 | suitable_bounds = | |
929 | traits::transitive_bounds(tcx, ty_param_def.bounds.trait_bounds.as_slice()) | |
930 | .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name)) | |
931 | .collect(); | |
932 | } | |
933 | ||
934 | if suitable_bounds.len() == 0 { | |
935 | tcx.sess.span_err(ast_ty.span, | |
936 | format!("associated type `{}` not found for type parameter `{}`", | |
937 | token::get_name(assoc_name), | |
938 | token::get_name(ty_param_name)).as_slice()); | |
939 | return this.tcx().types.err; | |
940 | } | |
941 | ||
942 | if suitable_bounds.len() > 1 { | |
943 | tcx.sess.span_err(ast_ty.span, | |
944 | format!("ambiguous associated type `{}` in bounds of `{}`", | |
945 | token::get_name(assoc_name), | |
946 | token::get_name(ty_param_name)).as_slice()); | |
947 | ||
948 | for suitable_bound in suitable_bounds.iter() { | |
949 | span_note!(this.tcx().sess, ast_ty.span, | |
950 | "associated type `{}` could derive from `{}`", | |
951 | token::get_name(ty_param_name), | |
952 | suitable_bound.user_string(this.tcx())); | |
953 | } | |
954 | } | |
955 | ||
956 | let suitable_bound = suitable_bounds.pop().unwrap().clone(); | |
957 | return this.projected_ty_from_poly_trait_ref(ast_ty.span, suitable_bound, assoc_name); | |
958 | } | |
959 | ||
960 | fn trait_defines_associated_type_named(this: &AstConv, | |
961 | trait_def_id: ast::DefId, | |
962 | assoc_name: ast::Name) | |
963 | -> bool | |
964 | { | |
965 | let tcx = this.tcx(); | |
966 | let trait_def = ty::lookup_trait_def(tcx, trait_def_id); | |
967 | trait_def.associated_type_names.contains(&assoc_name) | |
968 | } | |
969 | ||
970 | fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, | |
971 | rscope: &RegionScope, | |
972 | ast_ty: &ast::Ty, // the TyQPath | |
973 | qpath: &ast::QPath) | |
974 | -> Ty<'tcx> | |
975 | { | |
976 | debug!("qpath_to_ty(ast_ty={})", | |
977 | ast_ty.repr(this.tcx())); | |
978 | ||
979 | let self_type = ast_ty_to_ty(this, rscope, &*qpath.self_type); | |
980 | ||
981 | debug!("qpath_to_ty: self_type={}", self_type.repr(this.tcx())); | |
982 | ||
983 | let trait_ref = instantiate_trait_ref(this, | |
984 | rscope, | |
985 | &*qpath.trait_ref, | |
986 | Some(self_type), | |
987 | None); | |
988 | ||
989 | debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx())); | |
990 | ||
991 | return this.projected_ty(ast_ty.span, | |
992 | trait_ref, | |
993 | qpath.item_name.name); | |
994 | } | |
995 | ||
996 | // Parses the programmer's textual representation of a type into our | |
997 | // internal notion of a type. | |
998 | pub fn ast_ty_to_ty<'tcx>( | |
999 | this: &AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx> | |
1000 | { | |
1001 | debug!("ast_ty_to_ty(ast_ty={})", | |
1002 | ast_ty.repr(this.tcx())); | |
1003 | ||
1004 | let tcx = this.tcx(); | |
1005 | ||
1006 | let mut ast_ty_to_ty_cache = tcx.ast_ty_to_ty_cache.borrow_mut(); | |
1007 | match ast_ty_to_ty_cache.get(&ast_ty.id) { | |
1008 | Some(&ty::atttce_resolved(ty)) => return ty, | |
1009 | Some(&ty::atttce_unresolved) => { | |
1010 | tcx.sess.span_fatal(ast_ty.span, | |
1011 | "illegal recursive type; insert an enum \ | |
1012 | or struct in the cycle, if this is \ | |
1013 | desired"); | |
1014 | } | |
1015 | None => { /* go on */ } | |
1016 | } | |
1017 | ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved); | |
1018 | drop(ast_ty_to_ty_cache); | |
1019 | ||
1020 | let typ = ast_ty_to_builtin_ty(this, rscope, ast_ty).unwrap_or_else(|| { | |
1021 | match ast_ty.node { | |
1022 | ast::TyVec(ref ty) => { | |
1023 | ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None) | |
1024 | } | |
1025 | ast::TyObjectSum(ref ty, ref bounds) => { | |
1026 | match ast_ty_to_trait_ref(this, rscope, &**ty, &bounds[]) { | |
1027 | Ok((trait_ref, projection_bounds)) => { | |
1028 | trait_ref_to_object_type(this, | |
1029 | rscope, | |
1030 | ast_ty.span, | |
1031 | trait_ref, | |
1032 | projection_bounds, | |
1033 | &bounds[]) | |
1034 | } | |
1035 | Err(ErrorReported) => { | |
1036 | this.tcx().types.err | |
1037 | } | |
1038 | } | |
1039 | } | |
1040 | ast::TyPtr(ref mt) => { | |
1041 | ty::mk_ptr(tcx, ty::mt { | |
1042 | ty: ast_ty_to_ty(this, rscope, &*mt.ty), | |
1043 | mutbl: mt.mutbl | |
1044 | }) | |
1045 | } | |
1046 | ast::TyRptr(ref region, ref mt) => { | |
1047 | let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region); | |
1048 | debug!("ty_rptr r={}", r.repr(this.tcx())); | |
1049 | let t = ast_ty_to_ty(this, rscope, &*mt.ty); | |
1050 | ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl}) | |
1051 | } | |
1052 | ast::TyTup(ref fields) => { | |
1053 | let flds = fields.iter() | |
1054 | .map(|t| ast_ty_to_ty(this, rscope, &**t)) | |
1055 | .collect(); | |
1056 | ty::mk_tup(tcx, flds) | |
1057 | } | |
1058 | ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ), | |
1059 | ast::TyBareFn(ref bf) => { | |
1060 | if bf.decl.variadic && bf.abi != abi::C { | |
1061 | tcx.sess.span_err(ast_ty.span, | |
1062 | "variadic function must have C calling convention"); | |
1063 | } | |
1064 | let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl); | |
1065 | ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn)) | |
1066 | } | |
1067 | ast::TyPolyTraitRef(ref bounds) => { | |
1068 | conv_ty_poly_trait_ref(this, rscope, ast_ty.span, &bounds[]) | |
1069 | } | |
1070 | ast::TyPath(ref path, id) => { | |
1071 | let a_def = match tcx.def_map.borrow().get(&id) { | |
1072 | None => { | |
1073 | tcx.sess | |
1074 | .span_bug(ast_ty.span, | |
1075 | &format!("unbound path {}", | |
1076 | path.repr(tcx))[]) | |
1077 | } | |
1078 | Some(&d) => d | |
1079 | }; | |
1080 | match a_def { | |
1081 | def::DefTrait(trait_def_id) => { | |
1082 | // N.B. this case overlaps somewhat with | |
1083 | // TyObjectSum, see that fn for details | |
1084 | let mut projection_bounds = Vec::new(); | |
1085 | let trait_ref = ast_path_to_trait_ref(this, | |
1086 | rscope, | |
1087 | trait_def_id, | |
1088 | None, | |
1089 | path, | |
1090 | Some(&mut projection_bounds)); | |
1091 | let trait_ref = ty::Binder(trait_ref); | |
1092 | let projection_bounds = projection_bounds.into_iter() | |
1093 | .map(ty::Binder) | |
1094 | .collect(); | |
1095 | trait_ref_to_object_type(this, rscope, path.span, | |
1096 | trait_ref, projection_bounds, &[]) | |
1097 | } | |
1098 | def::DefTy(did, _) | def::DefStruct(did) => { | |
1099 | ast_path_to_ty(this, rscope, did, path).ty | |
1100 | } | |
1101 | def::DefTyParam(space, index, _, name) => { | |
1102 | check_path_args(tcx, path, NO_TPS | NO_REGIONS); | |
1103 | ty::mk_param(tcx, space, index, name) | |
1104 | } | |
1105 | def::DefSelfTy(_) => { | |
1106 | // n.b.: resolve guarantees that the this type only appears in a | |
1107 | // trait, which we rely upon in various places when creating | |
1108 | // substs | |
1109 | check_path_args(tcx, path, NO_TPS | NO_REGIONS); | |
1110 | ty::mk_self_type(tcx) | |
1111 | } | |
1112 | def::DefMod(id) => { | |
1113 | tcx.sess.span_fatal(ast_ty.span, | |
1114 | &format!("found module name used as a type: {}", | |
1115 | tcx.map.node_to_string(id.node))[]); | |
1116 | } | |
1117 | def::DefPrimTy(_) => { | |
1118 | panic!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call"); | |
1119 | } | |
1120 | def::DefAssociatedTy(trait_type_id) => { | |
1121 | let path_str = tcx.map.path_to_string( | |
1122 | tcx.map.get_parent(trait_type_id.node)); | |
1123 | tcx.sess.span_err(ast_ty.span, | |
1124 | &format!("ambiguous associated \ | |
1125 | type; specify the type \ | |
1126 | using the syntax `<Type \ | |
1127 | as {}>::{}`", | |
1128 | path_str, | |
1129 | token::get_ident( | |
1130 | path.segments | |
1131 | .last() | |
1132 | .unwrap() | |
1133 | .identifier) | |
1134 | .get())[]); | |
1135 | this.tcx().types.err | |
1136 | } | |
1137 | def::DefAssociatedPath(provenance, assoc_ident) => { | |
1138 | associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name) | |
1139 | } | |
1140 | _ => { | |
1141 | tcx.sess.span_fatal(ast_ty.span, | |
1142 | &format!("found value name used \ | |
1143 | as a type: {:?}", | |
1144 | a_def)[]); | |
1145 | } | |
1146 | } | |
1147 | } | |
1148 | ast::TyQPath(ref qpath) => { | |
1149 | qpath_to_ty(this, rscope, ast_ty, &**qpath) | |
1150 | } | |
1151 | ast::TyFixedLengthVec(ref ty, ref e) => { | |
1152 | match const_eval::eval_const_expr_partial(tcx, &**e) { | |
1153 | Ok(ref r) => { | |
1154 | match *r { | |
1155 | const_eval::const_int(i) => | |
1156 | ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), | |
1157 | Some(i as uint)), | |
1158 | const_eval::const_uint(i) => | |
1159 | ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), | |
1160 | Some(i as uint)), | |
1161 | _ => { | |
1162 | tcx.sess.span_fatal( | |
1163 | ast_ty.span, "expected constant expr for array length"); | |
1164 | } | |
1165 | } | |
1166 | } | |
1167 | Err(ref r) => { | |
1168 | tcx.sess.span_fatal( | |
1169 | ast_ty.span, | |
1170 | &format!("expected constant expr for array \ | |
1171 | length: {}", | |
1172 | *r)[]); | |
1173 | } | |
1174 | } | |
1175 | } | |
1176 | ast::TyTypeof(ref _e) => { | |
1177 | tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented"); | |
1178 | } | |
1179 | ast::TyInfer => { | |
1180 | // TyInfer also appears as the type of arguments or return | |
1181 | // values in a ExprClosure, or as | |
1182 | // the type of local variables. Both of these cases are | |
1183 | // handled specially and will not descend into this routine. | |
1184 | this.ty_infer(ast_ty.span) | |
1185 | } | |
1186 | } | |
1187 | }); | |
1188 | ||
1189 | tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ)); | |
1190 | return typ; | |
1191 | } | |
1192 | ||
1193 | pub fn ty_of_arg<'tcx>(this: &AstConv<'tcx>, | |
1194 | rscope: &RegionScope, | |
1195 | a: &ast::Arg, | |
1196 | expected_ty: Option<Ty<'tcx>>) | |
1197 | -> Ty<'tcx> | |
1198 | { | |
1199 | match a.ty.node { | |
1200 | ast::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), | |
1201 | ast::TyInfer => this.ty_infer(a.ty.span), | |
1202 | _ => ast_ty_to_ty(this, rscope, &*a.ty), | |
1203 | } | |
1204 | } | |
1205 | ||
1206 | struct SelfInfo<'a, 'tcx> { | |
1207 | untransformed_self_ty: Ty<'tcx>, | |
1208 | explicit_self: &'a ast::ExplicitSelf, | |
1209 | } | |
1210 | ||
1211 | pub fn ty_of_method<'tcx>(this: &AstConv<'tcx>, | |
1212 | unsafety: ast::Unsafety, | |
1213 | untransformed_self_ty: Ty<'tcx>, | |
1214 | explicit_self: &ast::ExplicitSelf, | |
1215 | decl: &ast::FnDecl, | |
1216 | abi: abi::Abi) | |
1217 | -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { | |
1218 | let self_info = Some(SelfInfo { | |
1219 | untransformed_self_ty: untransformed_self_ty, | |
1220 | explicit_self: explicit_self, | |
1221 | }); | |
1222 | let (bare_fn_ty, optional_explicit_self_category) = | |
1223 | ty_of_method_or_bare_fn(this, | |
1224 | unsafety, | |
1225 | abi, | |
1226 | self_info, | |
1227 | decl); | |
1228 | (bare_fn_ty, optional_explicit_self_category.unwrap()) | |
1229 | } | |
1230 | ||
1231 | pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi, | |
1232 | decl: &ast::FnDecl) -> ty::BareFnTy<'tcx> { | |
1233 | let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, unsafety, abi, None, decl); | |
1234 | bare_fn_ty | |
1235 | } | |
1236 | ||
1237 | fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, | |
1238 | unsafety: ast::Unsafety, | |
1239 | abi: abi::Abi, | |
1240 | opt_self_info: Option<SelfInfo<'a, 'tcx>>, | |
1241 | decl: &ast::FnDecl) | |
1242 | -> (ty::BareFnTy<'tcx>, Option<ty::ExplicitSelfCategory>) | |
1243 | { | |
1244 | debug!("ty_of_method_or_bare_fn"); | |
1245 | ||
1246 | // New region names that appear inside of the arguments of the function | |
1247 | // declaration are bound to that function type. | |
1248 | let rb = rscope::BindingRscope::new(); | |
1249 | ||
1250 | // `implied_output_region` is the region that will be assumed for any | |
1251 | // region parameters in the return type. In accordance with the rules for | |
1252 | // lifetime elision, we can determine it in two ways. First (determined | |
1253 | // here), if self is by-reference, then the implied output region is the | |
1254 | // region of the self parameter. | |
1255 | let mut explicit_self_category_result = None; | |
1256 | let (self_ty, mut implied_output_region) = match opt_self_info { | |
1257 | None => (None, None), | |
1258 | Some(self_info) => { | |
1259 | // This type comes from an impl or trait; no late-bound | |
1260 | // regions should be present. | |
1261 | assert!(!self_info.untransformed_self_ty.has_escaping_regions()); | |
1262 | ||
1263 | // Figure out and record the explicit self category. | |
1264 | let explicit_self_category = | |
1265 | determine_explicit_self_category(this, &rb, &self_info); | |
1266 | explicit_self_category_result = Some(explicit_self_category); | |
1267 | match explicit_self_category { | |
1268 | ty::StaticExplicitSelfCategory => { | |
1269 | (None, None) | |
1270 | } | |
1271 | ty::ByValueExplicitSelfCategory => { | |
1272 | (Some(self_info.untransformed_self_ty), None) | |
1273 | } | |
1274 | ty::ByReferenceExplicitSelfCategory(region, mutability) => { | |
1275 | (Some(ty::mk_rptr(this.tcx(), | |
1276 | this.tcx().mk_region(region), | |
1277 | ty::mt { | |
1278 | ty: self_info.untransformed_self_ty, | |
1279 | mutbl: mutability | |
1280 | })), | |
1281 | Some(region)) | |
1282 | } | |
1283 | ty::ByBoxExplicitSelfCategory => { | |
1284 | (Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty)), None) | |
1285 | } | |
1286 | } | |
1287 | } | |
1288 | }; | |
1289 | ||
1290 | // HACK(eddyb) replace the fake self type in the AST with the actual type. | |
1291 | let input_params = if self_ty.is_some() { | |
1292 | decl.inputs.slice_from(1) | |
1293 | } else { | |
1294 | &decl.inputs[] | |
1295 | }; | |
1296 | let input_tys = input_params.iter().map(|a| ty_of_arg(this, &rb, a, None)); | |
1297 | let input_pats: Vec<String> = input_params.iter() | |
1298 | .map(|a| pprust::pat_to_string(&*a.pat)) | |
1299 | .collect(); | |
1300 | let self_and_input_tys: Vec<Ty> = | |
1301 | self_ty.into_iter().chain(input_tys).collect(); | |
1302 | ||
1303 | ||
1304 | // Second, if there was exactly one lifetime (either a substitution or a | |
1305 | // reference) in the arguments, then any anonymous regions in the output | |
1306 | // have that lifetime. | |
1307 | let lifetimes_for_params = if implied_output_region.is_none() { | |
1308 | let input_tys = if self_ty.is_some() { | |
1309 | // Skip the first argument if `self` is present. | |
1310 | self_and_input_tys.slice_from(1) | |
1311 | } else { | |
1312 | self_and_input_tys.slice_from(0) | |
1313 | }; | |
1314 | ||
1315 | let (ior, lfp) = find_implied_output_region(input_tys, input_pats); | |
1316 | implied_output_region = ior; | |
1317 | lfp | |
1318 | } else { | |
1319 | vec![] | |
1320 | }; | |
1321 | ||
1322 | let output_ty = match decl.output { | |
1323 | ast::Return(ref output) if output.node == ast::TyInfer => | |
1324 | ty::FnConverging(this.ty_infer(output.span)), | |
1325 | ast::Return(ref output) => | |
1326 | ty::FnConverging(convert_ty_with_lifetime_elision(this, | |
1327 | implied_output_region, | |
1328 | lifetimes_for_params, | |
1329 | &**output)), | |
1330 | ast::NoReturn(_) => ty::FnDiverging | |
1331 | }; | |
1332 | ||
1333 | (ty::BareFnTy { | |
1334 | unsafety: unsafety, | |
1335 | abi: abi, | |
1336 | sig: ty::Binder(ty::FnSig { | |
1337 | inputs: self_and_input_tys, | |
1338 | output: output_ty, | |
1339 | variadic: decl.variadic | |
1340 | }), | |
1341 | }, explicit_self_category_result) | |
1342 | } | |
1343 | ||
1344 | fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>, | |
1345 | rscope: &RegionScope, | |
1346 | self_info: &SelfInfo<'a, 'tcx>) | |
1347 | -> ty::ExplicitSelfCategory | |
1348 | { | |
1349 | return match self_info.explicit_self.node { | |
1350 | ast::SelfStatic => ty::StaticExplicitSelfCategory, | |
1351 | ast::SelfValue(_) => ty::ByValueExplicitSelfCategory, | |
1352 | ast::SelfRegion(ref lifetime, mutability, _) => { | |
1353 | let region = | |
1354 | opt_ast_region_to_region(this, | |
1355 | rscope, | |
1356 | self_info.explicit_self.span, | |
1357 | lifetime); | |
1358 | ty::ByReferenceExplicitSelfCategory(region, mutability) | |
1359 | } | |
1360 | ast::SelfExplicit(ref ast_type, _) => { | |
1361 | let explicit_type = ast_ty_to_ty(this, rscope, &**ast_type); | |
1362 | ||
1363 | // We wish to (for now) categorize an explicit self | |
1364 | // declaration like `self: SomeType` into either `self`, | |
1365 | // `&self`, `&mut self`, or `Box<self>`. We do this here | |
1366 | // by some simple pattern matching. A more precise check | |
1367 | // is done later in `check_method_self_type()`. | |
1368 | // | |
1369 | // Examples: | |
1370 | // | |
1371 | // ``` | |
1372 | // impl Foo for &T { | |
1373 | // // Legal declarations: | |
1374 | // fn method1(self: &&T); // ByReferenceExplicitSelfCategory | |
1375 | // fn method2(self: &T); // ByValueExplicitSelfCategory | |
1376 | // fn method3(self: Box<&T>); // ByBoxExplicitSelfCategory | |
1377 | // | |
1378 | // // Invalid cases will be caught later by `check_method_self_type`: | |
1379 | // fn method_err1(self: &mut T); // ByReferenceExplicitSelfCategory | |
1380 | // } | |
1381 | // ``` | |
1382 | // | |
1383 | // To do the check we just count the number of "modifiers" | |
1384 | // on each type and compare them. If they are the same or | |
1385 | // the impl has more, we call it "by value". Otherwise, we | |
1386 | // look at the outermost modifier on the method decl and | |
1387 | // call it by-ref, by-box as appropriate. For method1, for | |
1388 | // example, the impl type has one modifier, but the method | |
1389 | // type has two, so we end up with | |
1390 | // ByReferenceExplicitSelfCategory. | |
1391 | ||
1392 | let impl_modifiers = count_modifiers(self_info.untransformed_self_ty); | |
1393 | let method_modifiers = count_modifiers(explicit_type); | |
1394 | ||
1395 | debug!("determine_explicit_self_category(self_info.untransformed_self_ty={} \ | |
1396 | explicit_type={} \ | |
1397 | modifiers=({},{})", | |
1398 | self_info.untransformed_self_ty.repr(this.tcx()), | |
1399 | explicit_type.repr(this.tcx()), | |
1400 | impl_modifiers, | |
1401 | method_modifiers); | |
1402 | ||
1403 | if impl_modifiers >= method_modifiers { | |
1404 | ty::ByValueExplicitSelfCategory | |
1405 | } else { | |
1406 | match explicit_type.sty { | |
1407 | ty::ty_rptr(r, mt) => ty::ByReferenceExplicitSelfCategory(*r, mt.mutbl), | |
1408 | ty::ty_uniq(_) => ty::ByBoxExplicitSelfCategory, | |
1409 | _ => ty::ByValueExplicitSelfCategory, | |
1410 | } | |
1411 | } | |
1412 | } | |
1413 | }; | |
1414 | ||
1415 | fn count_modifiers(ty: Ty) -> uint { | |
1416 | match ty.sty { | |
1417 | ty::ty_rptr(_, mt) => count_modifiers(mt.ty) + 1, | |
1418 | ty::ty_uniq(t) => count_modifiers(t) + 1, | |
1419 | _ => 0, | |
1420 | } | |
1421 | } | |
1422 | } | |
1423 | ||
1424 | pub fn ty_of_closure<'tcx>( | |
1425 | this: &AstConv<'tcx>, | |
1426 | unsafety: ast::Unsafety, | |
1427 | onceness: ast::Onceness, | |
1428 | bounds: ty::ExistentialBounds<'tcx>, | |
1429 | store: ty::TraitStore, | |
1430 | decl: &ast::FnDecl, | |
1431 | abi: abi::Abi, | |
1432 | expected_sig: Option<ty::FnSig<'tcx>>) | |
1433 | -> ty::ClosureTy<'tcx> | |
1434 | { | |
1435 | debug!("ty_of_closure(expected_sig={})", | |
1436 | expected_sig.repr(this.tcx())); | |
1437 | ||
1438 | // new region names that appear inside of the fn decl are bound to | |
1439 | // that function type | |
1440 | let rb = rscope::BindingRscope::new(); | |
1441 | ||
1442 | let input_tys: Vec<_> = decl.inputs.iter().enumerate().map(|(i, a)| { | |
1443 | let expected_arg_ty = expected_sig.as_ref().and_then(|e| { | |
1444 | // no guarantee that the correct number of expected args | |
1445 | // were supplied | |
1446 | if i < e.inputs.len() { | |
1447 | Some(e.inputs[i]) | |
1448 | } else { | |
1449 | None | |
1450 | } | |
1451 | }); | |
1452 | ty_of_arg(this, &rb, a, expected_arg_ty) | |
1453 | }).collect(); | |
1454 | ||
1455 | let expected_ret_ty = expected_sig.map(|e| e.output); | |
1456 | ||
1457 | let output_ty = match decl.output { | |
1458 | ast::Return(ref output) if output.node == ast::TyInfer && expected_ret_ty.is_some() => | |
1459 | expected_ret_ty.unwrap(), | |
1460 | ast::Return(ref output) if output.node == ast::TyInfer => | |
1461 | ty::FnConverging(this.ty_infer(output.span)), | |
1462 | ast::Return(ref output) => | |
1463 | ty::FnConverging(ast_ty_to_ty(this, &rb, &**output)), | |
1464 | ast::NoReturn(_) => ty::FnDiverging | |
1465 | }; | |
1466 | ||
1467 | debug!("ty_of_closure: input_tys={}", input_tys.repr(this.tcx())); | |
1468 | debug!("ty_of_closure: output_ty={}", output_ty.repr(this.tcx())); | |
1469 | ||
1470 | ty::ClosureTy { | |
1471 | unsafety: unsafety, | |
1472 | onceness: onceness, | |
1473 | store: store, | |
1474 | bounds: bounds, | |
1475 | abi: abi, | |
1476 | sig: ty::Binder(ty::FnSig {inputs: input_tys, | |
1477 | output: output_ty, | |
1478 | variadic: decl.variadic}), | |
1479 | } | |
1480 | } | |
1481 | ||
1482 | /// Given an existential type like `Foo+'a+Bar`, this routine converts the `'a` and `Bar` intos an | |
1483 | /// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent | |
1484 | /// for closures. Eventually this should all be normalized, I think, so that there is no "main | |
1485 | /// trait ref" and instead we just have a flat list of bounds as the existential type. | |
1486 | pub fn conv_existential_bounds<'tcx>( | |
1487 | this: &AstConv<'tcx>, | |
1488 | rscope: &RegionScope, | |
1489 | span: Span, | |
1490 | principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures | |
1491 | projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, | |
1492 | ast_bounds: &[ast::TyParamBound]) | |
1493 | -> ty::ExistentialBounds<'tcx> | |
1494 | { | |
1495 | let partitioned_bounds = | |
1496 | partition_bounds(this.tcx(), span, ast_bounds); | |
1497 | ||
1498 | conv_existential_bounds_from_partitioned_bounds( | |
1499 | this, rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds) | |
1500 | } | |
1501 | ||
1502 | fn conv_ty_poly_trait_ref<'tcx>( | |
1503 | this: &AstConv<'tcx>, | |
1504 | rscope: &RegionScope, | |
1505 | span: Span, | |
1506 | ast_bounds: &[ast::TyParamBound]) | |
1507 | -> Ty<'tcx> | |
1508 | { | |
1509 | let mut partitioned_bounds = partition_bounds(this.tcx(), span, &ast_bounds[]); | |
1510 | ||
1511 | let mut projection_bounds = Vec::new(); | |
1512 | let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() { | |
1513 | let trait_bound = partitioned_bounds.trait_bounds.remove(0); | |
1514 | Some(instantiate_poly_trait_ref(this, | |
1515 | rscope, | |
1516 | trait_bound, | |
1517 | None, | |
1518 | &mut projection_bounds)) | |
1519 | } else { | |
1520 | this.tcx().sess.span_err( | |
1521 | span, | |
1522 | "at least one non-builtin trait is required for an object type"); | |
1523 | None | |
1524 | }; | |
1525 | ||
1526 | let bounds = | |
1527 | conv_existential_bounds_from_partitioned_bounds(this, | |
1528 | rscope, | |
1529 | span, | |
1530 | main_trait_bound.clone(), | |
1531 | projection_bounds, | |
1532 | partitioned_bounds); | |
1533 | ||
1534 | match main_trait_bound { | |
1535 | None => this.tcx().types.err, | |
1536 | Some(principal) => ty::mk_trait(this.tcx(), principal, bounds) | |
1537 | } | |
1538 | } | |
1539 | ||
1540 | pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( | |
1541 | this: &AstConv<'tcx>, | |
1542 | rscope: &RegionScope, | |
1543 | span: Span, | |
1544 | principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures | |
1545 | mut projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures | |
1546 | partitioned_bounds: PartitionedBounds) | |
1547 | -> ty::ExistentialBounds<'tcx> | |
1548 | { | |
1549 | let PartitionedBounds { builtin_bounds, | |
1550 | trait_bounds, | |
1551 | region_bounds } = | |
1552 | partitioned_bounds; | |
1553 | ||
1554 | if !trait_bounds.is_empty() { | |
1555 | let b = &trait_bounds[0]; | |
1556 | this.tcx().sess.span_err( | |
1557 | b.trait_ref.path.span, | |
1558 | &format!("only the builtin traits can be used \ | |
1559 | as closure or object bounds")[]); | |
1560 | } | |
1561 | ||
1562 | let region_bound = compute_region_bound(this, | |
1563 | rscope, | |
1564 | span, | |
1565 | region_bounds.as_slice(), | |
1566 | principal_trait_ref, | |
1567 | builtin_bounds); | |
1568 | ||
1569 | ty::sort_bounds_list(projection_bounds.as_mut_slice()); | |
1570 | ||
1571 | ty::ExistentialBounds { | |
1572 | region_bound: region_bound, | |
1573 | builtin_bounds: builtin_bounds, | |
1574 | projection_bounds: projection_bounds, | |
1575 | } | |
1576 | } | |
1577 | ||
1578 | /// Given the bounds on a type parameter / existential type, determines what single region bound | |
1579 | /// (if any) we can use to summarize this type. The basic idea is that we will use the bound the | |
1580 | /// user provided, if they provided one, and otherwise search the supertypes of trait bounds for | |
1581 | /// region bounds. It may be that we can derive no bound at all, in which case we return `None`. | |
1582 | fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, | |
1583 | span: Span, | |
1584 | explicit_region_bounds: &[&ast::Lifetime], | |
1585 | principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, | |
1586 | builtin_bounds: ty::BuiltinBounds) | |
1587 | -> Option<ty::Region> | |
1588 | { | |
1589 | debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \ | |
1590 | principal_trait_ref={}, builtin_bounds={})", | |
1591 | explicit_region_bounds, | |
1592 | principal_trait_ref.repr(tcx), | |
1593 | builtin_bounds.repr(tcx)); | |
1594 | ||
1595 | if explicit_region_bounds.len() > 1 { | |
1596 | tcx.sess.span_err( | |
1597 | explicit_region_bounds[1].span, | |
1598 | format!("only a single explicit lifetime bound is permitted").as_slice()); | |
1599 | } | |
1600 | ||
1601 | if explicit_region_bounds.len() != 0 { | |
1602 | // Explicitly specified region bound. Use that. | |
1603 | let r = explicit_region_bounds[0]; | |
1604 | return Some(ast_region_to_region(tcx, r)); | |
1605 | } | |
1606 | ||
1607 | // No explicit region bound specified. Therefore, examine trait | |
1608 | // bounds and see if we can derive region bounds from those. | |
1609 | let derived_region_bounds = | |
1610 | ty::object_region_bounds(tcx, principal_trait_ref.as_ref(), builtin_bounds); | |
1611 | ||
1612 | // If there are no derived region bounds, then report back that we | |
1613 | // can find no region bound. | |
1614 | if derived_region_bounds.len() == 0 { | |
1615 | return None; | |
1616 | } | |
1617 | ||
1618 | // If any of the derived region bounds are 'static, that is always | |
1619 | // the best choice. | |
1620 | if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) { | |
1621 | return Some(ty::ReStatic); | |
1622 | } | |
1623 | ||
1624 | // Determine whether there is exactly one unique region in the set | |
1625 | // of derived region bounds. If so, use that. Otherwise, report an | |
1626 | // error. | |
1627 | let r = derived_region_bounds[0]; | |
1628 | if derived_region_bounds.slice_from(1).iter().any(|r1| r != *r1) { | |
1629 | tcx.sess.span_err( | |
1630 | span, | |
1631 | &format!("ambiguous lifetime bound, \ | |
1632 | explicit lifetime bound required")[]); | |
1633 | } | |
1634 | return Some(r); | |
1635 | } | |
1636 | ||
1637 | /// A version of `compute_opt_region_bound` for use where some region bound is required | |
1638 | /// (existential types, basically). Reports an error if no region bound can be derived and we are | |
1639 | /// in an `rscope` that does not provide a default. | |
1640 | fn compute_region_bound<'tcx>( | |
1641 | this: &AstConv<'tcx>, | |
1642 | rscope: &RegionScope, | |
1643 | span: Span, | |
1644 | region_bounds: &[&ast::Lifetime], | |
1645 | principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for closures | |
1646 | builtin_bounds: ty::BuiltinBounds) | |
1647 | -> ty::Region | |
1648 | { | |
1649 | match compute_opt_region_bound(this.tcx(), span, region_bounds, | |
1650 | principal_trait_ref, builtin_bounds) { | |
1651 | Some(r) => r, | |
1652 | None => { | |
1653 | match rscope.default_region_bound(span) { | |
1654 | Some(r) => { r } | |
1655 | None => { | |
1656 | this.tcx().sess.span_err( | |
1657 | span, | |
1658 | &format!("explicit lifetime bound required")[]); | |
1659 | ty::ReStatic | |
1660 | } | |
1661 | } | |
1662 | } | |
1663 | } | |
1664 | } | |
1665 | ||
1666 | pub struct PartitionedBounds<'a> { | |
1667 | pub builtin_bounds: ty::BuiltinBounds, | |
1668 | pub trait_bounds: Vec<&'a ast::PolyTraitRef>, | |
1669 | pub region_bounds: Vec<&'a ast::Lifetime>, | |
1670 | } | |
1671 | ||
1672 | /// Divides a list of bounds from the AST into three groups: builtin bounds (Copy, Sized etc), | |
1673 | /// general trait bounds, and region bounds. | |
1674 | pub fn partition_bounds<'a>(tcx: &ty::ctxt, | |
1675 | _span: Span, | |
1676 | ast_bounds: &'a [ast::TyParamBound]) | |
1677 | -> PartitionedBounds<'a> | |
1678 | { | |
1679 | let mut builtin_bounds = ty::empty_builtin_bounds(); | |
1680 | let mut region_bounds = Vec::new(); | |
1681 | let mut trait_bounds = Vec::new(); | |
1682 | let mut trait_def_ids = DefIdMap::new(); | |
1683 | for ast_bound in ast_bounds.iter() { | |
1684 | match *ast_bound { | |
1685 | ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => { | |
1686 | match ::lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { | |
1687 | def::DefTrait(trait_did) => { | |
1688 | match trait_def_ids.get(&trait_did) { | |
1689 | // Already seen this trait. We forbid | |
1690 | // duplicates in the list (for some | |
1691 | // reason). | |
1692 | Some(span) => { | |
1693 | span_err!( | |
1694 | tcx.sess, b.trait_ref.path.span, E0127, | |
1695 | "trait `{}` already appears in the \ | |
1696 | list of bounds", | |
1697 | b.trait_ref.path.user_string(tcx)); | |
1698 | tcx.sess.span_note( | |
1699 | *span, | |
1700 | "previous appearance is here"); | |
1701 | ||
1702 | continue; | |
1703 | } | |
1704 | ||
1705 | None => { } | |
1706 | } | |
1707 | ||
1708 | trait_def_ids.insert(trait_did, b.trait_ref.path.span); | |
1709 | ||
1710 | if ty::try_add_builtin_trait(tcx, | |
1711 | trait_did, | |
1712 | &mut builtin_bounds) { | |
1713 | // FIXME(#20302) -- we should check for things like Copy<T> | |
1714 | continue; // success | |
1715 | } | |
1716 | } | |
1717 | _ => { | |
1718 | // Not a trait? that's an error, but it'll get | |
1719 | // reported later. | |
1720 | } | |
1721 | } | |
1722 | trait_bounds.push(b); | |
1723 | } | |
1724 | ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) => {} | |
1725 | ast::RegionTyParamBound(ref l) => { | |
1726 | region_bounds.push(l); | |
1727 | } | |
1728 | } | |
1729 | } | |
1730 | ||
1731 | PartitionedBounds { | |
1732 | builtin_bounds: builtin_bounds, | |
1733 | trait_bounds: trait_bounds, | |
1734 | region_bounds: region_bounds, | |
1735 | } | |
1736 | } | |
1737 | ||
1738 | fn prohibit_projections<'tcx>(tcx: &ty::ctxt<'tcx>, | |
1739 | bindings: &[ConvertedBinding<'tcx>]) | |
1740 | { | |
1741 | for binding in bindings.iter().take(1) { | |
1742 | tcx.sess.span_err( | |
1743 | binding.span, | |
1744 | "associated type bindings are not allowed here"); | |
1745 | } | |
1746 | } |