]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/infer/coercion.rs
/*! -> //!
[rust.git] / src / librustc / middle / typeck / infer / coercion.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! # Type Coercion
12 //!
13 //! Under certain circumstances we will coerce from one type to another,
14 //! for example by auto-borrowing.  This occurs in situations where the
15 //! compiler has a firm 'expected type' that was supplied from the user,
16 //! and where the actual type is similar to that expected type in purpose
17 //! but not in representation (so actual subtyping is inappropriate).
18 //!
19 //! ## Reborrowing
20 //!
21 //! Note that if we are expecting a reference, we will *reborrow*
22 //! even if the argument provided was already a reference.  This is
23 //! useful for freezing mut/const things (that is, when the expected is &T
24 //! but you have &const T or &mut T) and also for avoiding the linearity
25 //! of mut things (when the expected is &mut T and you have &mut T).  See
26 //! the various `src/test/run-pass/coerce-reborrow-*.rs` tests for
27 //! examples of where this is useful.
28 //!
29 //! ## Subtle note
30 //!
31 //! When deciding what type coercions to consider, we do not attempt to
32 //! resolve any type variables we may encounter.  This is because `b`
33 //! represents the expected type "as the user wrote it", meaning that if
34 //! the user defined a generic function like
35 //!
36 //!    fn foo<A>(a: A, b: A) { ... }
37 //!
38 //! and then we wrote `foo(&1, @2)`, we will not auto-borrow
39 //! either argument.  In older code we went to some lengths to
40 //! resolve the `b` variable, which could mean that we'd
41 //! auto-borrow later arguments but not earlier ones, which
42 //! seems very confusing.
43 //!
44 //! ## Subtler note
45 //!
46 //! However, right now, if the user manually specifies the
47 //! values for the type variables, as so:
48 //!
49 //!    foo::<&int>(@1, @2)
50 //!
51 //! then we *will* auto-borrow, because we can't distinguish this from a
52 //! function that declared `&int`.  This is inconsistent but it's easiest
53 //! at the moment. The right thing to do, I think, is to consider the
54 //! *unsubstituted* type when deciding whether to auto-borrow, but the
55 //! *substituted* type when considering the bounds and so forth. But most
56 //! of our methods don't give access to the unsubstituted type, and
57 //! rightly so because they'd be error-prone.  So maybe the thing to do is
58 //! to actually determine the kind of coercions that should occur
59 //! separately and pass them in.  Or maybe it's ok as is.  Anyway, it's
60 //! sort of a minor point so I've opted to leave it for later---after all
61 //! we may want to adjust precisely when coercions occur.
62
63 use middle::subst;
64 use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe};
65 use middle::ty::{mt};
66 use middle::ty::{mod, Ty};
67 use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
68 use middle::typeck::infer::combine::{CombineFields, Combine};
69 use middle::typeck::infer::sub::Sub;
70 use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
71 use util::ppaux;
72 use util::ppaux::Repr;
73
74 use syntax::abi;
75 use syntax::ast;
76
77 // Note: Coerce is not actually a combiner, in that it does not
78 // conform to the same interface, though it performs a similar
79 // function.
80 pub struct Coerce<'f, 'tcx: 'f>(pub CombineFields<'f, 'tcx>);
81
82 impl<'f, 'tcx> Coerce<'f, 'tcx> {
83     pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f, 'tcx> {
84         let Coerce(ref v) = *self; v
85     }
86
87     pub fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
88         debug!("Coerce.tys({} => {})",
89                a.repr(self.get_ref().infcx.tcx),
90                b.repr(self.get_ref().infcx.tcx));
91
92         // Consider coercing the subtype to a DST
93         let unsize = self.unpack_actual_value(a, |sty_a| {
94             self.coerce_unsized(a, sty_a, b)
95         });
96         if unsize.is_ok() {
97             return unsize;
98         }
99
100         // Examine the supertype and consider auto-borrowing.
101         //
102         // Note: does not attempt to resolve type variables we encounter.
103         // See above for details.
104         match b.sty {
105             ty::ty_ptr(mt_b) => {
106                 match mt_b.ty.sty {
107                     ty::ty_str => {
108                         return self.unpack_actual_value(a, |sty_a| {
109                             self.coerce_unsafe_ptr(a, sty_a, b, ast::MutImmutable)
110                         });
111                     }
112
113                     ty::ty_trait(..) => {
114                         let result = self.unpack_actual_value(a, |sty_a| {
115                             self.coerce_unsafe_object(a, sty_a, b, mt_b.mutbl)
116                         });
117
118                         match result {
119                             Ok(t) => return Ok(t),
120                             Err(..) => {}
121                         }
122                     }
123
124                     _ => {
125                         return self.unpack_actual_value(a, |sty_a| {
126                             self.coerce_unsafe_ptr(a, sty_a, b, mt_b.mutbl)
127                         });
128                     }
129                 };
130             }
131
132             ty::ty_rptr(_, mt_b) => {
133                 match mt_b.ty.sty {
134                     ty::ty_str => {
135                         return self.unpack_actual_value(a, |sty_a| {
136                             self.coerce_borrowed_pointer(a, sty_a, b, ast::MutImmutable)
137                         });
138                     }
139
140                     ty::ty_trait(..) => {
141                         let result = self.unpack_actual_value(a, |sty_a| {
142                             self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
143                         });
144
145                         match result {
146                             Ok(t) => return Ok(t),
147                             Err(..) => {}
148                         }
149                     }
150
151                     _ => {
152                         return self.unpack_actual_value(a, |sty_a| {
153                             self.coerce_borrowed_pointer(a, sty_a, b, mt_b.mutbl)
154                         });
155                     }
156                 };
157             }
158
159             ty::ty_closure(box ty::ClosureTy {
160                     store: ty::RegionTraitStore(..),
161                     ..
162                 }) => {
163                 return self.unpack_actual_value(a, |sty_a| {
164                     self.coerce_borrowed_fn(a, sty_a, b)
165                 });
166             }
167
168             _ => {}
169         }
170
171         self.unpack_actual_value(a, |sty_a| {
172             match *sty_a {
173                 ty::ty_bare_fn(ref a_f) => {
174                     // Bare functions are coercible to any closure type.
175                     //
176                     // FIXME(#3320) this should go away and be
177                     // replaced with proper inference, got a patch
178                     // underway - ndm
179                     self.coerce_from_bare_fn(a, a_f, b)
180                 }
181                 _ => {
182                     // Otherwise, just use subtyping rules.
183                     self.subtype(a, b)
184                 }
185             }
186         })
187     }
188
189     pub fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
190         match Sub(self.get_ref().clone()).tys(a, b) {
191             Ok(_) => Ok(None),         // No coercion required.
192             Err(ref e) => Err(*e)
193         }
194     }
195
196     pub fn unpack_actual_value<T>(&self, a: Ty<'tcx>, f: |&ty::sty<'tcx>| -> T)
197                                   -> T {
198         match resolve_type(self.get_ref().infcx, None,
199                            a, try_resolve_tvar_shallow) {
200             Ok(t) => {
201                 f(&t.sty)
202             }
203             Err(e) => {
204                 self.get_ref().infcx.tcx.sess.span_bug(
205                     self.get_ref().trace.origin.span(),
206                     format!("failed to resolve even without \
207                              any force options: {}", e).as_slice());
208             }
209         }
210     }
211
212     // ~T -> &T or &mut T -> &T (including where T = [U] or str)
213     pub fn coerce_borrowed_pointer(&self,
214                                    a: Ty<'tcx>,
215                                    sty_a: &ty::sty<'tcx>,
216                                    b: Ty<'tcx>,
217                                    mutbl_b: ast::Mutability)
218                                    -> CoerceResult<'tcx> {
219         debug!("coerce_borrowed_pointer(a={}, sty_a={}, b={})",
220                a.repr(self.get_ref().infcx.tcx), sty_a,
221                b.repr(self.get_ref().infcx.tcx));
222
223         // If we have a parameter of type `&M T_a` and the value
224         // provided is `expr`, we will be adding an implicit borrow,
225         // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
226         // to type check, we will construct the type that `&M*expr` would
227         // yield.
228
229         let sub = Sub(self.get_ref().clone());
230         let coercion = Coercion(self.get_ref().trace.clone());
231         let r_borrow = self.get_ref().infcx.next_region_var(coercion);
232
233         let inner_ty = match *sty_a {
234             ty::ty_uniq(_) => return Err(ty::terr_mismatch),
235             ty::ty_rptr(_, mt_a) => mt_a.ty,
236             _ => {
237                 return self.subtype(a, b);
238             }
239         };
240
241         let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
242                                      r_borrow,
243                                      mt {ty: inner_ty, mutbl: mutbl_b});
244         try!(sub.tys(a_borrowed, b));
245
246         Ok(Some(AdjustDerefRef(AutoDerefRef {
247             autoderefs: 1,
248             autoref: Some(AutoPtr(r_borrow, mutbl_b, None))
249         })))
250     }
251
252
253     // &[T, ..n] or &mut [T, ..n] -> &[T]
254     // or &mut [T, ..n] -> &mut [T]
255     // or &Concrete -> &Trait, etc.
256     fn coerce_unsized(&self,
257                       a: Ty<'tcx>,
258                       sty_a: &ty::sty<'tcx>,
259                       b: Ty<'tcx>)
260                       -> CoerceResult<'tcx> {
261         debug!("coerce_unsized(a={}, sty_a={}, b={})",
262                a.repr(self.get_ref().infcx.tcx), sty_a,
263                b.repr(self.get_ref().infcx.tcx));
264
265         // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
266         // a DST unless we have to. This currently comes out in the wash since
267         // we can't unify [T] with U. But to properly support DST, we need to allow
268         // that, at which point we will need extra checks on b here.
269
270         let sub = Sub(self.get_ref().clone());
271
272         let sty_b = &b.sty;
273         match (sty_a, sty_b) {
274             (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
275                 self.unpack_actual_value(t_a, |sty_a| {
276                     match self.unsize_ty(t_a, sty_a, mt_b.ty) {
277                         Some((ty, kind)) => {
278                             if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
279                                 return Err(ty::terr_mutability);
280                             }
281
282                             let coercion = Coercion(self.get_ref().trace.clone());
283                             let r_borrow = self.get_ref().infcx.next_region_var(coercion);
284                             let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
285                                                  r_borrow,
286                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
287                             try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
288                             debug!("Success, coerced with AutoDerefRef(1, \
289                                     AutoPtr(AutoUnsize({})))", kind);
290                             Ok(Some(AdjustDerefRef(AutoDerefRef {
291                                 autoderefs: 1,
292                                 autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
293                                                           Some(box AutoUnsize(kind))))
294                             })))
295                         }
296                         _ => Err(ty::terr_mismatch)
297                     }
298                 })
299             }
300             (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
301                 self.unpack_actual_value(t_a, |sty_a| {
302                     match self.unsize_ty(t_a, sty_a, mt_b.ty) {
303                         Some((ty, kind)) => {
304                             if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
305                                 return Err(ty::terr_mutability);
306                             }
307
308                             let ty = ty::mk_ptr(self.get_ref().infcx.tcx,
309                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
310                             try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
311                             debug!("Success, coerced with AutoDerefRef(1, \
312                                     AutoPtr(AutoUnsize({})))", kind);
313                             Ok(Some(AdjustDerefRef(AutoDerefRef {
314                                 autoderefs: 1,
315                                 autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
316                                                              Some(box AutoUnsize(kind))))
317                             })))
318                         }
319                         _ => Err(ty::terr_mismatch)
320                     }
321                 })
322             }
323             (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
324                 self.unpack_actual_value(t_a, |sty_a| {
325                     match self.unsize_ty(t_a, sty_a, t_b) {
326                         Some((ty, kind)) => {
327                             let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
328                             try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
329                             debug!("Success, coerced with AutoDerefRef(1, \
330                                     AutoUnsizeUniq({}))", kind);
331                             Ok(Some(AdjustDerefRef(AutoDerefRef {
332                                 autoderefs: 1,
333                                 autoref: Some(ty::AutoUnsizeUniq(kind))
334                             })))
335                         }
336                         _ => Err(ty::terr_mismatch)
337                     }
338                 })
339             }
340             _ => Err(ty::terr_mismatch)
341         }
342     }
343
344     // Takes a type and returns an unsized version along with the adjustment
345     // performed to unsize it.
346     // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
347     fn unsize_ty(&self,
348                  ty_a: Ty<'tcx>,
349                  sty_a: &ty::sty<'tcx>,
350                  ty_b: Ty<'tcx>)
351                  -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
352         debug!("unsize_ty(sty_a={}, ty_b={})", sty_a, ty_b.repr(self.get_ref().infcx.tcx));
353
354         let tcx = self.get_ref().infcx.tcx;
355
356         self.unpack_actual_value(ty_b, |sty_b|
357             match (sty_a, sty_b) {
358                 (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
359                     let ty = ty::mk_vec(tcx, t_a, None);
360                     Some((ty, ty::UnsizeLength(len)))
361                 }
362                 (&ty::ty_trait(..), &ty::ty_trait(..)) => {
363                     None
364                 }
365                 (_, &ty::ty_trait(box ty::TyTrait { ref principal, bounds })) => {
366                     // FIXME what is the purpose of `ty`?
367                     let ty = ty::mk_trait(tcx, (*principal).clone(), bounds);
368                     Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: (*principal).clone(),
369                                                              bounds: bounds },
370                                                ty_a)))
371                 }
372                 (&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref substs_b))
373                   if did_a == did_b => {
374                     debug!("unsizing a struct");
375                     // Try unsizing each type param in turn to see if we end up with ty_b.
376                     let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
377                     let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
378                     assert!(ty_substs_a.len() == ty_substs_b.len());
379
380                     let sub = Sub(self.get_ref().clone());
381
382                     let mut result = None;
383                     let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
384                     for (i, (tp_a, tp_b)) in tps {
385                         if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() {
386                             continue;
387                         }
388                         match
389                             self.unpack_actual_value(
390                                 *tp_a,
391                                 |tp| self.unsize_ty(*tp_a, tp, *tp_b))
392                         {
393                             Some((new_tp, k)) => {
394                                 // Check that the whole types match.
395                                 let mut new_substs = substs_a.clone();
396                                 new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
397                                 let ty = ty::mk_struct(tcx, did_a, new_substs);
398                                 if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() {
399                                     debug!("Unsized type parameter '{}', but still \
400                                             could not match types {} and {}",
401                                            ppaux::ty_to_string(tcx, *tp_a),
402                                            ppaux::ty_to_string(tcx, ty),
403                                            ppaux::ty_to_string(tcx, ty_b));
404                                     // We can only unsize a single type parameter, so
405                                     // if we unsize one and it doesn't give us the
406                                     // type we want, then we won't succeed later.
407                                     break;
408                                 }
409
410                                 result = Some((ty, ty::UnsizeStruct(box k, i)));
411                                 break;
412                             }
413                             None => {}
414                         }
415                     }
416                     result
417                 }
418                 _ => None
419             }
420         )
421     }
422
423     fn coerce_borrowed_object(&self,
424                               a: Ty<'tcx>,
425                               sty_a: &ty::sty<'tcx>,
426                               b: Ty<'tcx>,
427                               b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
428     {
429         let tcx = self.get_ref().infcx.tcx;
430
431         debug!("coerce_borrowed_object(a={}, sty_a={}, b={}, b_mutbl={})",
432                a.repr(tcx), sty_a,
433                b.repr(tcx), b_mutbl);
434
435         let coercion = Coercion(self.get_ref().trace.clone());
436         let r_a = self.get_ref().infcx.next_region_var(coercion);
437
438         self.coerce_object(a, sty_a, b, b_mutbl,
439                            |tr| ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr }),
440                            || AutoPtr(r_a, b_mutbl, None))
441     }
442
443     fn coerce_unsafe_object(&self,
444                             a: Ty<'tcx>,
445                             sty_a: &ty::sty<'tcx>,
446                             b: Ty<'tcx>,
447                             b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
448     {
449         let tcx = self.get_ref().infcx.tcx;
450
451         debug!("coerce_unsafe_object(a={}, sty_a={}, b={}, b_mutbl={})",
452                a.repr(tcx), sty_a,
453                b.repr(tcx), b_mutbl);
454
455         self.coerce_object(a, sty_a, b, b_mutbl,
456                            |tr| ty::mk_ptr(tcx, ty::mt{ mutbl: b_mutbl, ty: tr }),
457                            || AutoUnsafe(b_mutbl, None))
458     }
459
460     fn coerce_object(&self,
461                      a: Ty<'tcx>,
462                      sty_a: &ty::sty<'tcx>,
463                      b: Ty<'tcx>,
464                      b_mutbl: ast::Mutability,
465                      mk_ty: |Ty<'tcx>| -> Ty<'tcx>,
466                      mk_adjust: || -> ty::AutoRef<'tcx>) -> CoerceResult<'tcx>
467     {
468         let tcx = self.get_ref().infcx.tcx;
469
470         match *sty_a {
471             ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty.sty {
472                 ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
473                     debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl);
474                     // FIXME what is purpose of this type `tr`?
475                     let tr = ty::mk_trait(tcx, (*principal).clone(), bounds);
476                     try!(self.subtype(mk_ty(tr), b));
477                     Ok(Some(AdjustDerefRef(AutoDerefRef {
478                         autoderefs: 1,
479                         autoref: Some(mk_adjust())
480                     })))
481                 }
482                 _ => {
483                     self.subtype(a, b)
484                 }
485             },
486             _ => {
487                 self.subtype(a, b)
488             }
489         }
490     }
491
492     pub fn coerce_borrowed_fn(&self,
493                               a: Ty<'tcx>,
494                               sty_a: &ty::sty<'tcx>,
495                               b: Ty<'tcx>)
496                               -> CoerceResult<'tcx> {
497         debug!("coerce_borrowed_fn(a={}, sty_a={}, b={})",
498                a.repr(self.get_ref().infcx.tcx), sty_a,
499                b.repr(self.get_ref().infcx.tcx));
500
501         match *sty_a {
502             ty::ty_bare_fn(ref f) => {
503                 self.coerce_from_bare_fn(a, f, b)
504             }
505             _ => {
506                 self.subtype(a, b)
507             }
508         }
509     }
510
511     ///  Attempts to coerce from a bare Rust function (`extern "Rust" fn`) into a closure or a
512     ///  `proc`.
513     fn coerce_from_bare_fn(&self, a: Ty<'tcx>, fn_ty_a: &ty::BareFnTy<'tcx>, b: Ty<'tcx>)
514                            -> CoerceResult<'tcx> {
515         self.unpack_actual_value(b, |sty_b| {
516
517             debug!("coerce_from_bare_fn(a={}, b={})",
518                    a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
519
520             if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
521                 return self.subtype(a, b);
522             }
523
524             let fn_ty_b = match *sty_b {
525                 ty::ty_closure(ref f) => (*f).clone(),
526                 _ => return self.subtype(a, b)
527             };
528
529             let adj = ty::AdjustAddEnv(fn_ty_b.store);
530             let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
531                                            ty::ClosureTy {
532                                                 sig: fn_ty_a.sig.clone(),
533                                                 .. *fn_ty_b
534                                            });
535             try!(self.subtype(a_closure, b));
536             Ok(Some(adj))
537         })
538     }
539
540     pub fn coerce_unsafe_ptr(&self,
541                              a: Ty<'tcx>,
542                              sty_a: &ty::sty<'tcx>,
543                              b: Ty<'tcx>,
544                              mutbl_b: ast::Mutability)
545                              -> CoerceResult<'tcx> {
546         debug!("coerce_unsafe_ptr(a={}, sty_a={}, b={})",
547                a.repr(self.get_ref().infcx.tcx), sty_a,
548                b.repr(self.get_ref().infcx.tcx));
549
550         let mt_a = match *sty_a {
551             ty::ty_rptr(_, mt) => mt,
552             _ => {
553                 return self.subtype(a, b);
554             }
555         };
556
557         // Check that the types which they point at are compatible.
558         // Note that we don't adjust the mutability here. We cannot change
559         // the mutability and the kind of pointer in a single coercion.
560         let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
561         try!(self.subtype(a_unsafe, b));
562
563         // Although references and unsafe ptrs have the same
564         // representation, we still register an AutoDerefRef so that
565         // regionck knows that the region for `a` must be valid here.
566         Ok(Some(AdjustDerefRef(AutoDerefRef {
567             autoderefs: 1,
568             autoref: Some(ty::AutoUnsafe(mutbl_b, None))
569         })))
570     }
571 }
572
573 fn can_coerce_mutbls(from_mutbl: ast::Mutability,
574                      to_mutbl: ast::Mutability)
575                      -> bool {
576     match (from_mutbl, to_mutbl) {
577         (ast::MutMutable, ast::MutMutable) => true,
578         (ast::MutImmutable, ast::MutImmutable) => true,
579         (ast::MutMutable, ast::MutImmutable) => true,
580         (ast::MutImmutable, ast::MutMutable) => false,
581     }
582 }