]>
Commit | Line | Data |
---|---|---|
c34b1796 AL |
1 | // Copyright 2012-2013 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 | //! Generalized type relating mechanism. A type relation R relates a | |
12 | //! pair of values (A, B). A and B are usually types or regions but | |
13 | //! can be other things. Examples of type relations are subtyping, | |
14 | //! type equality, etc. | |
15 | ||
16 | use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs}; | |
17 | use middle::ty::{self, Ty}; | |
18 | use middle::ty_fold::TypeFoldable; | |
19 | use std::rc::Rc; | |
20 | use syntax::abi; | |
21 | use syntax::ast; | |
c34b1796 AL |
22 | |
23 | pub type RelateResult<'tcx, T> = Result<T, ty::type_err<'tcx>>; | |
24 | ||
62682a34 SL |
25 | #[derive(Clone, Debug)] |
26 | pub enum Cause { | |
27 | ExistentialRegionBound(bool), // if true, this is a default, else explicit | |
28 | } | |
29 | ||
c34b1796 AL |
30 | pub trait TypeRelation<'a,'tcx> : Sized { |
31 | fn tcx(&self) -> &'a ty::ctxt<'tcx>; | |
32 | ||
33 | /// Returns a static string we can use for printouts. | |
34 | fn tag(&self) -> &'static str; | |
35 | ||
36 | /// Returns true if the value `a` is the "expected" type in the | |
37 | /// relation. Just affects error messages. | |
38 | fn a_is_expected(&self) -> bool; | |
39 | ||
62682a34 SL |
40 | fn with_cause<F,R>(&mut self, _cause: Cause, f: F) -> R |
41 | where F: FnOnce(&mut Self) -> R | |
42 | { | |
43 | f(self) | |
44 | } | |
45 | ||
46 | /// Hack for deciding whether the lifetime bound defaults change | |
47 | /// will be a breaking change or not. The bools indicate whether | |
48 | /// `a`/`b` have a default that will change to `'static`; the | |
49 | /// result is true if this will potentially affect the affect of | |
50 | /// relating `a` and `b`. | |
51 | fn will_change(&mut self, a: bool, b: bool) -> bool; | |
52 | ||
c34b1796 AL |
53 | /// Generic relation routine suitable for most anything. |
54 | fn relate<T:Relate<'a,'tcx>>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> { | |
55 | Relate::relate(self, a, b) | |
56 | } | |
57 | ||
58 | /// Switch variance for the purpose of relating `a` and `b`. | |
59 | fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self, | |
60 | variance: ty::Variance, | |
61 | a: &T, | |
62 | b: &T) | |
63 | -> RelateResult<'tcx, T>; | |
64 | ||
65 | // Overrideable relations. You shouldn't typically call these | |
66 | // directly, instead call `relate()`, which in turn calls | |
67 | // these. This is both more uniform but also allows us to add | |
68 | // additional hooks for other types in the future if needed | |
69 | // without making older code, which called `relate`, obsolete. | |
70 | ||
71 | fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) | |
72 | -> RelateResult<'tcx, Ty<'tcx>>; | |
73 | ||
74 | fn regions(&mut self, a: ty::Region, b: ty::Region) | |
75 | -> RelateResult<'tcx, ty::Region>; | |
76 | ||
77 | fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>) | |
78 | -> RelateResult<'tcx, ty::Binder<T>> | |
79 | where T: Relate<'a,'tcx>; | |
80 | } | |
81 | ||
82 | pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> { | |
83 | fn relate<R:TypeRelation<'a,'tcx>>(relation: &mut R, | |
84 | a: &Self, | |
85 | b: &Self) | |
86 | -> RelateResult<'tcx, Self>; | |
87 | } | |
88 | ||
89 | /////////////////////////////////////////////////////////////////////////// | |
90 | // Relate impls | |
91 | ||
92 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::mt<'tcx> { | |
93 | fn relate<R>(relation: &mut R, | |
94 | a: &ty::mt<'tcx>, | |
95 | b: &ty::mt<'tcx>) | |
96 | -> RelateResult<'tcx, ty::mt<'tcx>> | |
97 | where R: TypeRelation<'a,'tcx> | |
98 | { | |
62682a34 | 99 | debug!("{}.mts({:?}, {:?})", |
c34b1796 | 100 | relation.tag(), |
62682a34 SL |
101 | a, |
102 | b); | |
c34b1796 AL |
103 | if a.mutbl != b.mutbl { |
104 | Err(ty::terr_mutability) | |
105 | } else { | |
106 | let mutbl = a.mutbl; | |
107 | let variance = match mutbl { | |
108 | ast::MutImmutable => ty::Covariant, | |
109 | ast::MutMutable => ty::Invariant, | |
110 | }; | |
111 | let ty = try!(relation.relate_with_variance(variance, &a.ty, &b.ty)); | |
112 | Ok(ty::mt {ty: ty, mutbl: mutbl}) | |
113 | } | |
114 | } | |
115 | } | |
116 | ||
117 | // substitutions are not themselves relatable without more context, | |
118 | // but they is an important subroutine for things that ARE relatable, | |
119 | // like traits etc. | |
120 | fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R, | |
121 | item_def_id: ast::DefId, | |
122 | a_subst: &Substs<'tcx>, | |
123 | b_subst: &Substs<'tcx>) | |
124 | -> RelateResult<'tcx, Substs<'tcx>> | |
125 | where R: TypeRelation<'a,'tcx> | |
126 | { | |
62682a34 SL |
127 | debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}", |
128 | item_def_id, | |
129 | a_subst, | |
130 | b_subst); | |
c34b1796 AL |
131 | |
132 | let variances; | |
133 | let opt_variances = if relation.tcx().variance_computed.get() { | |
134 | variances = ty::item_variances(relation.tcx(), item_def_id); | |
135 | Some(&*variances) | |
136 | } else { | |
137 | None | |
138 | }; | |
139 | relate_substs(relation, opt_variances, a_subst, b_subst) | |
140 | } | |
141 | ||
9346a6ac AL |
142 | fn relate_substs<'a,'tcx:'a,R>(relation: &mut R, |
143 | variances: Option<&ty::ItemVariances>, | |
144 | a_subst: &Substs<'tcx>, | |
145 | b_subst: &Substs<'tcx>) | |
146 | -> RelateResult<'tcx, Substs<'tcx>> | |
c34b1796 AL |
147 | where R: TypeRelation<'a,'tcx> |
148 | { | |
149 | let mut substs = Substs::empty(); | |
150 | ||
151 | for &space in &ParamSpace::all() { | |
152 | let a_tps = a_subst.types.get_slice(space); | |
153 | let b_tps = b_subst.types.get_slice(space); | |
154 | let t_variances = variances.map(|v| v.types.get_slice(space)); | |
155 | let tps = try!(relate_type_params(relation, t_variances, a_tps, b_tps)); | |
156 | substs.types.replace(space, tps); | |
157 | } | |
158 | ||
159 | match (&a_subst.regions, &b_subst.regions) { | |
160 | (&ErasedRegions, _) | (_, &ErasedRegions) => { | |
161 | substs.regions = ErasedRegions; | |
162 | } | |
163 | ||
164 | (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => { | |
165 | for &space in &ParamSpace::all() { | |
166 | let a_regions = a.get_slice(space); | |
167 | let b_regions = b.get_slice(space); | |
168 | let r_variances = variances.map(|v| v.regions.get_slice(space)); | |
169 | let regions = try!(relate_region_params(relation, | |
170 | r_variances, | |
171 | a_regions, | |
172 | b_regions)); | |
173 | substs.mut_regions().replace(space, regions); | |
174 | } | |
175 | } | |
176 | } | |
177 | ||
178 | Ok(substs) | |
179 | } | |
180 | ||
9346a6ac AL |
181 | fn relate_type_params<'a,'tcx:'a,R>(relation: &mut R, |
182 | variances: Option<&[ty::Variance]>, | |
183 | a_tys: &[Ty<'tcx>], | |
184 | b_tys: &[Ty<'tcx>]) | |
185 | -> RelateResult<'tcx, Vec<Ty<'tcx>>> | |
c34b1796 AL |
186 | where R: TypeRelation<'a,'tcx> |
187 | { | |
188 | if a_tys.len() != b_tys.len() { | |
189 | return Err(ty::terr_ty_param_size(expected_found(relation, | |
190 | &a_tys.len(), | |
191 | &b_tys.len()))); | |
192 | } | |
193 | ||
194 | (0 .. a_tys.len()) | |
195 | .map(|i| { | |
196 | let a_ty = a_tys[i]; | |
197 | let b_ty = b_tys[i]; | |
198 | let v = variances.map_or(ty::Invariant, |v| v[i]); | |
199 | relation.relate_with_variance(v, &a_ty, &b_ty) | |
200 | }) | |
201 | .collect() | |
202 | } | |
203 | ||
204 | fn relate_region_params<'a,'tcx:'a,R>(relation: &mut R, | |
205 | variances: Option<&[ty::Variance]>, | |
206 | a_rs: &[ty::Region], | |
207 | b_rs: &[ty::Region]) | |
208 | -> RelateResult<'tcx, Vec<ty::Region>> | |
209 | where R: TypeRelation<'a,'tcx> | |
210 | { | |
c34b1796 AL |
211 | let num_region_params = a_rs.len(); |
212 | ||
62682a34 SL |
213 | debug!("relate_region_params(a_rs={:?}, \ |
214 | b_rs={:?}, variances={:?})", | |
215 | a_rs, | |
216 | b_rs, | |
217 | variances); | |
c34b1796 AL |
218 | |
219 | assert_eq!(num_region_params, | |
220 | variances.map_or(num_region_params, | |
221 | |v| v.len())); | |
222 | ||
223 | assert_eq!(num_region_params, b_rs.len()); | |
224 | ||
225 | (0..a_rs.len()) | |
226 | .map(|i| { | |
227 | let a_r = a_rs[i]; | |
228 | let b_r = b_rs[i]; | |
229 | let variance = variances.map_or(ty::Invariant, |v| v[i]); | |
230 | relation.relate_with_variance(variance, &a_r, &b_r) | |
231 | }) | |
232 | .collect() | |
233 | } | |
234 | ||
235 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BareFnTy<'tcx> { | |
236 | fn relate<R>(relation: &mut R, | |
237 | a: &ty::BareFnTy<'tcx>, | |
238 | b: &ty::BareFnTy<'tcx>) | |
239 | -> RelateResult<'tcx, ty::BareFnTy<'tcx>> | |
240 | where R: TypeRelation<'a,'tcx> | |
241 | { | |
242 | let unsafety = try!(relation.relate(&a.unsafety, &b.unsafety)); | |
243 | let abi = try!(relation.relate(&a.abi, &b.abi)); | |
244 | let sig = try!(relation.relate(&a.sig, &b.sig)); | |
245 | Ok(ty::BareFnTy {unsafety: unsafety, | |
246 | abi: abi, | |
247 | sig: sig}) | |
248 | } | |
249 | } | |
250 | ||
251 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> { | |
252 | fn relate<R>(relation: &mut R, | |
253 | a: &ty::FnSig<'tcx>, | |
254 | b: &ty::FnSig<'tcx>) | |
255 | -> RelateResult<'tcx, ty::FnSig<'tcx>> | |
256 | where R: TypeRelation<'a,'tcx> | |
257 | { | |
258 | if a.variadic != b.variadic { | |
259 | return Err(ty::terr_variadic_mismatch( | |
260 | expected_found(relation, &a.variadic, &b.variadic))); | |
261 | } | |
262 | ||
263 | let inputs = try!(relate_arg_vecs(relation, | |
264 | &a.inputs, | |
265 | &b.inputs)); | |
266 | ||
267 | let output = try!(match (a.output, b.output) { | |
268 | (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => | |
269 | Ok(ty::FnConverging(try!(relation.relate(&a_ty, &b_ty)))), | |
270 | (ty::FnDiverging, ty::FnDiverging) => | |
271 | Ok(ty::FnDiverging), | |
272 | (a, b) => | |
273 | Err(ty::terr_convergence_mismatch( | |
274 | expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))), | |
275 | }); | |
276 | ||
277 | return Ok(ty::FnSig {inputs: inputs, | |
278 | output: output, | |
279 | variadic: a.variadic}); | |
280 | } | |
281 | } | |
282 | ||
9346a6ac AL |
283 | fn relate_arg_vecs<'a,'tcx:'a,R>(relation: &mut R, |
284 | a_args: &[Ty<'tcx>], | |
285 | b_args: &[Ty<'tcx>]) | |
286 | -> RelateResult<'tcx, Vec<Ty<'tcx>>> | |
c34b1796 AL |
287 | where R: TypeRelation<'a,'tcx> |
288 | { | |
289 | if a_args.len() != b_args.len() { | |
290 | return Err(ty::terr_arg_count); | |
291 | } | |
292 | ||
62682a34 | 293 | a_args.iter().zip(b_args) |
c34b1796 AL |
294 | .map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b)) |
295 | .collect() | |
296 | } | |
297 | ||
298 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ast::Unsafety { | |
299 | fn relate<R>(relation: &mut R, | |
300 | a: &ast::Unsafety, | |
301 | b: &ast::Unsafety) | |
302 | -> RelateResult<'tcx, ast::Unsafety> | |
303 | where R: TypeRelation<'a,'tcx> | |
304 | { | |
305 | if a != b { | |
306 | Err(ty::terr_unsafety_mismatch(expected_found(relation, a, b))) | |
307 | } else { | |
308 | Ok(*a) | |
309 | } | |
310 | } | |
311 | } | |
312 | ||
313 | impl<'a,'tcx:'a> Relate<'a,'tcx> for abi::Abi { | |
314 | fn relate<R>(relation: &mut R, | |
315 | a: &abi::Abi, | |
316 | b: &abi::Abi) | |
317 | -> RelateResult<'tcx, abi::Abi> | |
318 | where R: TypeRelation<'a,'tcx> | |
319 | { | |
320 | if a == b { | |
321 | Ok(*a) | |
322 | } else { | |
323 | Err(ty::terr_abi_mismatch(expected_found(relation, a, b))) | |
324 | } | |
325 | } | |
326 | } | |
327 | ||
328 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionTy<'tcx> { | |
329 | fn relate<R>(relation: &mut R, | |
330 | a: &ty::ProjectionTy<'tcx>, | |
331 | b: &ty::ProjectionTy<'tcx>) | |
332 | -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> | |
333 | where R: TypeRelation<'a,'tcx> | |
334 | { | |
335 | if a.item_name != b.item_name { | |
336 | Err(ty::terr_projection_name_mismatched( | |
337 | expected_found(relation, &a.item_name, &b.item_name))) | |
338 | } else { | |
d9579d0f AL |
339 | let trait_ref = try!(relation.relate(&a.trait_ref, &b.trait_ref)); |
340 | Ok(ty::ProjectionTy { trait_ref: trait_ref, item_name: a.item_name }) | |
c34b1796 AL |
341 | } |
342 | } | |
343 | } | |
344 | ||
345 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionPredicate<'tcx> { | |
346 | fn relate<R>(relation: &mut R, | |
347 | a: &ty::ProjectionPredicate<'tcx>, | |
348 | b: &ty::ProjectionPredicate<'tcx>) | |
349 | -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> | |
350 | where R: TypeRelation<'a,'tcx> | |
351 | { | |
352 | let projection_ty = try!(relation.relate(&a.projection_ty, &b.projection_ty)); | |
353 | let ty = try!(relation.relate(&a.ty, &b.ty)); | |
354 | Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty }) | |
355 | } | |
356 | } | |
357 | ||
358 | impl<'a,'tcx:'a> Relate<'a,'tcx> for Vec<ty::PolyProjectionPredicate<'tcx>> { | |
359 | fn relate<R>(relation: &mut R, | |
360 | a: &Vec<ty::PolyProjectionPredicate<'tcx>>, | |
361 | b: &Vec<ty::PolyProjectionPredicate<'tcx>>) | |
362 | -> RelateResult<'tcx, Vec<ty::PolyProjectionPredicate<'tcx>>> | |
363 | where R: TypeRelation<'a,'tcx> | |
364 | { | |
365 | // To be compatible, `a` and `b` must be for precisely the | |
366 | // same set of traits and item names. We always require that | |
367 | // projection bounds lists are sorted by trait-def-id and item-name, | |
368 | // so we can just iterate through the lists pairwise, so long as they are the | |
369 | // same length. | |
370 | if a.len() != b.len() { | |
371 | Err(ty::terr_projection_bounds_length(expected_found(relation, &a.len(), &b.len()))) | |
372 | } else { | |
62682a34 | 373 | a.iter().zip(b) |
c34b1796 AL |
374 | .map(|(a, b)| relation.relate(a, b)) |
375 | .collect() | |
376 | } | |
377 | } | |
378 | } | |
379 | ||
380 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ExistentialBounds<'tcx> { | |
381 | fn relate<R>(relation: &mut R, | |
382 | a: &ty::ExistentialBounds<'tcx>, | |
383 | b: &ty::ExistentialBounds<'tcx>) | |
384 | -> RelateResult<'tcx, ty::ExistentialBounds<'tcx>> | |
385 | where R: TypeRelation<'a,'tcx> | |
386 | { | |
62682a34 SL |
387 | let will_change = relation.will_change(a.region_bound_will_change, |
388 | b.region_bound_will_change); | |
389 | ||
390 | let r = | |
391 | try!(relation.with_cause( | |
392 | Cause::ExistentialRegionBound(will_change), | |
393 | |relation| relation.relate_with_variance(ty::Contravariant, | |
394 | &a.region_bound, | |
395 | &b.region_bound))); | |
c34b1796 AL |
396 | let nb = try!(relation.relate(&a.builtin_bounds, &b.builtin_bounds)); |
397 | let pb = try!(relation.relate(&a.projection_bounds, &b.projection_bounds)); | |
398 | Ok(ty::ExistentialBounds { region_bound: r, | |
399 | builtin_bounds: nb, | |
62682a34 SL |
400 | projection_bounds: pb, |
401 | region_bound_will_change: will_change }) | |
c34b1796 AL |
402 | } |
403 | } | |
404 | ||
405 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BuiltinBounds { | |
406 | fn relate<R>(relation: &mut R, | |
407 | a: &ty::BuiltinBounds, | |
408 | b: &ty::BuiltinBounds) | |
409 | -> RelateResult<'tcx, ty::BuiltinBounds> | |
410 | where R: TypeRelation<'a,'tcx> | |
411 | { | |
412 | // Two sets of builtin bounds are only relatable if they are | |
413 | // precisely the same (but see the coercion code). | |
414 | if a != b { | |
415 | Err(ty::terr_builtin_bounds(expected_found(relation, a, b))) | |
416 | } else { | |
417 | Ok(*a) | |
418 | } | |
419 | } | |
420 | } | |
421 | ||
422 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TraitRef<'tcx> { | |
423 | fn relate<R>(relation: &mut R, | |
424 | a: &ty::TraitRef<'tcx>, | |
425 | b: &ty::TraitRef<'tcx>) | |
426 | -> RelateResult<'tcx, ty::TraitRef<'tcx>> | |
427 | where R: TypeRelation<'a,'tcx> | |
428 | { | |
429 | // Different traits cannot be related | |
430 | if a.def_id != b.def_id { | |
431 | Err(ty::terr_traits(expected_found(relation, &a.def_id, &b.def_id))) | |
432 | } else { | |
433 | let substs = try!(relate_item_substs(relation, a.def_id, a.substs, b.substs)); | |
434 | Ok(ty::TraitRef { def_id: a.def_id, substs: relation.tcx().mk_substs(substs) }) | |
435 | } | |
436 | } | |
437 | } | |
438 | ||
439 | impl<'a,'tcx:'a> Relate<'a,'tcx> for Ty<'tcx> { | |
440 | fn relate<R>(relation: &mut R, | |
441 | a: &Ty<'tcx>, | |
442 | b: &Ty<'tcx>) | |
443 | -> RelateResult<'tcx, Ty<'tcx>> | |
444 | where R: TypeRelation<'a,'tcx> | |
445 | { | |
446 | relation.tys(a, b) | |
447 | } | |
448 | } | |
449 | ||
450 | /// The main "type relation" routine. Note that this does not handle | |
451 | /// inference artifacts, so you should filter those out before calling | |
452 | /// it. | |
453 | pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, | |
454 | a: Ty<'tcx>, | |
455 | b: Ty<'tcx>) | |
456 | -> RelateResult<'tcx, Ty<'tcx>> | |
457 | where R: TypeRelation<'a,'tcx> | |
458 | { | |
459 | let tcx = relation.tcx(); | |
460 | let a_sty = &a.sty; | |
461 | let b_sty = &b.sty; | |
462 | debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); | |
463 | match (a_sty, b_sty) { | |
62682a34 SL |
464 | (&ty::TyInfer(_), _) | |
465 | (_, &ty::TyInfer(_)) => | |
c34b1796 AL |
466 | { |
467 | // The caller should handle these cases! | |
468 | tcx.sess.bug("var types encountered in super_relate_tys") | |
469 | } | |
470 | ||
62682a34 | 471 | (&ty::TyError, _) | (_, &ty::TyError) => |
c34b1796 AL |
472 | { |
473 | Ok(tcx.types.err) | |
474 | } | |
475 | ||
62682a34 SL |
476 | (&ty::TyChar, _) | |
477 | (&ty::TyBool, _) | | |
478 | (&ty::TyInt(_), _) | | |
479 | (&ty::TyUint(_), _) | | |
480 | (&ty::TyFloat(_), _) | | |
481 | (&ty::TyStr, _) | |
c34b1796 AL |
482 | if a == b => |
483 | { | |
484 | Ok(a) | |
485 | } | |
486 | ||
62682a34 | 487 | (&ty::TyParam(ref a_p), &ty::TyParam(ref b_p)) |
c34b1796 AL |
488 | if a_p.idx == b_p.idx && a_p.space == b_p.space => |
489 | { | |
490 | Ok(a) | |
491 | } | |
492 | ||
62682a34 | 493 | (&ty::TyEnum(a_id, a_substs), &ty::TyEnum(b_id, b_substs)) |
c34b1796 AL |
494 | if a_id == b_id => |
495 | { | |
496 | let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); | |
497 | Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs))) | |
498 | } | |
499 | ||
62682a34 | 500 | (&ty::TyTrait(ref a_), &ty::TyTrait(ref b_)) => |
c34b1796 AL |
501 | { |
502 | let principal = try!(relation.relate(&a_.principal, &b_.principal)); | |
503 | let bounds = try!(relation.relate(&a_.bounds, &b_.bounds)); | |
504 | Ok(ty::mk_trait(tcx, principal, bounds)) | |
505 | } | |
506 | ||
62682a34 | 507 | (&ty::TyStruct(a_id, a_substs), &ty::TyStruct(b_id, b_substs)) |
c34b1796 AL |
508 | if a_id == b_id => |
509 | { | |
510 | let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); | |
511 | Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs))) | |
512 | } | |
513 | ||
62682a34 SL |
514 | (&ty::TyClosure(a_id, a_substs), |
515 | &ty::TyClosure(b_id, b_substs)) | |
c34b1796 AL |
516 | if a_id == b_id => |
517 | { | |
62682a34 | 518 | // All TyClosure types with the same id represent |
c34b1796 AL |
519 | // the (anonymous) type of the same closure expression. So |
520 | // all of their regions should be equated. | |
521 | let substs = try!(relate_substs(relation, None, a_substs, b_substs)); | |
522 | Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs))) | |
523 | } | |
524 | ||
62682a34 | 525 | (&ty::TyBox(a_inner), &ty::TyBox(b_inner)) => |
c34b1796 AL |
526 | { |
527 | let typ = try!(relation.relate(&a_inner, &b_inner)); | |
528 | Ok(ty::mk_uniq(tcx, typ)) | |
529 | } | |
530 | ||
62682a34 | 531 | (&ty::TyRawPtr(ref a_mt), &ty::TyRawPtr(ref b_mt)) => |
c34b1796 AL |
532 | { |
533 | let mt = try!(relation.relate(a_mt, b_mt)); | |
534 | Ok(ty::mk_ptr(tcx, mt)) | |
535 | } | |
536 | ||
62682a34 | 537 | (&ty::TyRef(a_r, ref a_mt), &ty::TyRef(b_r, ref b_mt)) => |
c34b1796 AL |
538 | { |
539 | let r = try!(relation.relate_with_variance(ty::Contravariant, a_r, b_r)); | |
540 | let mt = try!(relation.relate(a_mt, b_mt)); | |
541 | Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt)) | |
542 | } | |
543 | ||
62682a34 | 544 | (&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) => |
c34b1796 AL |
545 | { |
546 | let t = try!(relation.relate(&a_t, &b_t)); | |
547 | if sz_a == sz_b { | |
548 | Ok(ty::mk_vec(tcx, t, Some(sz_a))) | |
549 | } else { | |
550 | Err(ty::terr_fixed_array_size(expected_found(relation, &sz_a, &sz_b))) | |
551 | } | |
552 | } | |
553 | ||
62682a34 | 554 | (&ty::TySlice(a_t), &ty::TySlice(b_t)) => |
c34b1796 AL |
555 | { |
556 | let t = try!(relation.relate(&a_t, &b_t)); | |
557 | Ok(ty::mk_vec(tcx, t, None)) | |
558 | } | |
559 | ||
62682a34 | 560 | (&ty::TyTuple(ref as_), &ty::TyTuple(ref bs)) => |
c34b1796 AL |
561 | { |
562 | if as_.len() == bs.len() { | |
62682a34 | 563 | let ts = try!(as_.iter().zip(bs) |
c34b1796 AL |
564 | .map(|(a, b)| relation.relate(a, b)) |
565 | .collect::<Result<_, _>>()); | |
566 | Ok(ty::mk_tup(tcx, ts)) | |
9346a6ac | 567 | } else if !(as_.is_empty() || bs.is_empty()) { |
c34b1796 AL |
568 | Err(ty::terr_tuple_size( |
569 | expected_found(relation, &as_.len(), &bs.len()))) | |
570 | } else { | |
571 | Err(ty::terr_sorts(expected_found(relation, &a, &b))) | |
572 | } | |
573 | } | |
574 | ||
62682a34 | 575 | (&ty::TyBareFn(a_opt_def_id, a_fty), &ty::TyBareFn(b_opt_def_id, b_fty)) |
c34b1796 AL |
576 | if a_opt_def_id == b_opt_def_id => |
577 | { | |
578 | let fty = try!(relation.relate(a_fty, b_fty)); | |
579 | Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty))) | |
580 | } | |
581 | ||
62682a34 | 582 | (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) => |
c34b1796 AL |
583 | { |
584 | let projection_ty = try!(relation.relate(a_data, b_data)); | |
585 | Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name)) | |
586 | } | |
587 | ||
588 | _ => | |
589 | { | |
590 | Err(ty::terr_sorts(expected_found(relation, &a, &b))) | |
591 | } | |
592 | } | |
593 | } | |
594 | ||
595 | impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::Region { | |
596 | fn relate<R>(relation: &mut R, | |
597 | a: &ty::Region, | |
598 | b: &ty::Region) | |
599 | -> RelateResult<'tcx, ty::Region> | |
600 | where R: TypeRelation<'a,'tcx> | |
601 | { | |
602 | relation.regions(*a, *b) | |
603 | } | |
604 | } | |
605 | ||
606 | impl<'a,'tcx:'a,T> Relate<'a,'tcx> for ty::Binder<T> | |
607 | where T: Relate<'a,'tcx> | |
608 | { | |
609 | fn relate<R>(relation: &mut R, | |
610 | a: &ty::Binder<T>, | |
611 | b: &ty::Binder<T>) | |
612 | -> RelateResult<'tcx, ty::Binder<T>> | |
613 | where R: TypeRelation<'a,'tcx> | |
614 | { | |
615 | relation.binders(a, b) | |
616 | } | |
617 | } | |
618 | ||
619 | impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Rc<T> | |
620 | where T: Relate<'a,'tcx> | |
621 | { | |
622 | fn relate<R>(relation: &mut R, | |
623 | a: &Rc<T>, | |
624 | b: &Rc<T>) | |
625 | -> RelateResult<'tcx, Rc<T>> | |
626 | where R: TypeRelation<'a,'tcx> | |
627 | { | |
628 | let a: &T = a; | |
629 | let b: &T = b; | |
630 | Ok(Rc::new(try!(relation.relate(a, b)))) | |
631 | } | |
632 | } | |
633 | ||
634 | impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box<T> | |
635 | where T: Relate<'a,'tcx> | |
636 | { | |
637 | fn relate<R>(relation: &mut R, | |
638 | a: &Box<T>, | |
639 | b: &Box<T>) | |
640 | -> RelateResult<'tcx, Box<T>> | |
641 | where R: TypeRelation<'a,'tcx> | |
642 | { | |
643 | let a: &T = a; | |
644 | let b: &T = b; | |
645 | Ok(Box::new(try!(relation.relate(a, b)))) | |
646 | } | |
647 | } | |
648 | ||
649 | /////////////////////////////////////////////////////////////////////////// | |
650 | // Error handling | |
651 | ||
9346a6ac AL |
652 | pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R, |
653 | a: &T, | |
654 | b: &T) | |
655 | -> ty::expected_found<T> | |
c34b1796 AL |
656 | where R: TypeRelation<'a,'tcx>, T: Clone |
657 | { | |
658 | expected_found_bool(relation.a_is_expected(), a, b) | |
659 | } | |
660 | ||
661 | pub fn expected_found_bool<T>(a_is_expected: bool, | |
662 | a: &T, | |
663 | b: &T) | |
664 | -> ty::expected_found<T> | |
665 | where T: Clone | |
666 | { | |
667 | let a = a.clone(); | |
668 | let b = b.clone(); | |
669 | if a_is_expected { | |
670 | ty::expected_found {expected: a, found: b} | |
671 | } else { | |
672 | ty::expected_found {expected: b, found: a} | |
673 | } | |
674 | } |