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.
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.
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.
16 use hir
::def_id
::DefId
;
17 use ty
::subst
::{Kind, Substs}
;
18 use ty
::{self, Ty, TyCtxt, TypeFoldable}
;
19 use ty
::error
::{ExpectedFound, TypeError}
;
24 use rustc_data_structures
::accumulate_vec
::AccumulateVec
;
26 pub type RelateResult
<'tcx
, T
> = Result
<T
, TypeError
<'tcx
>>;
28 #[derive(Clone, Debug)]
30 ExistentialRegionBound
, // relating an existential region bound
33 pub trait TypeRelation
<'a
, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
> : Sized
{
34 fn tcx(&self) -> TyCtxt
<'a
, 'gcx
, 'tcx
>;
36 /// Returns a static string we can use for printouts.
37 fn tag(&self) -> &'
static str;
39 /// Returns true if the value `a` is the "expected" type in the
40 /// relation. Just affects error messages.
41 fn a_is_expected(&self) -> bool
;
43 fn with_cause
<F
,R
>(&mut self, _cause
: Cause
, f
: F
) -> R
44 where F
: FnOnce(&mut Self) -> R
49 /// Generic relation routine suitable for most anything.
50 fn relate
<T
: Relate
<'tcx
>>(&mut self, a
: &T
, b
: &T
) -> RelateResult
<'tcx
, T
> {
51 Relate
::relate(self, a
, b
)
54 /// Relate the two substitutions for the given item. The default
55 /// is to look up the variance for the item and proceed
57 fn relate_item_substs(&mut self,
59 a_subst
: &'tcx Substs
<'tcx
>,
60 b_subst
: &'tcx Substs
<'tcx
>)
61 -> RelateResult
<'tcx
, &'tcx Substs
<'tcx
>>
63 debug
!("relate_item_substs(item_def_id={:?}, a_subst={:?}, b_subst={:?})",
68 let opt_variances
= self.tcx().variances_of(item_def_id
);
69 relate_substs(self, Some(&opt_variances
), a_subst
, b_subst
)
72 /// Switch variance for the purpose of relating `a` and `b`.
73 fn relate_with_variance
<T
: Relate
<'tcx
>>(&mut self,
74 variance
: ty
::Variance
,
77 -> RelateResult
<'tcx
, T
>;
79 // Overrideable relations. You shouldn't typically call these
80 // directly, instead call `relate()`, which in turn calls
81 // these. This is both more uniform but also allows us to add
82 // additional hooks for other types in the future if needed
83 // without making older code, which called `relate`, obsolete.
85 fn tys(&mut self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>)
86 -> RelateResult
<'tcx
, Ty
<'tcx
>>;
88 fn regions(&mut self, a
: ty
::Region
<'tcx
>, b
: ty
::Region
<'tcx
>)
89 -> RelateResult
<'tcx
, ty
::Region
<'tcx
>>;
91 fn binders
<T
>(&mut self, a
: &ty
::Binder
<T
>, b
: &ty
::Binder
<T
>)
92 -> RelateResult
<'tcx
, ty
::Binder
<T
>>
93 where T
: Relate
<'tcx
>;
96 pub trait Relate
<'tcx
>: TypeFoldable
<'tcx
> {
97 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
, a
: &Self, b
: &Self)
98 -> RelateResult
<'tcx
, Self>
99 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
;
102 ///////////////////////////////////////////////////////////////////////////
105 impl<'tcx
> Relate
<'tcx
> for ty
::TypeAndMut
<'tcx
> {
106 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
107 a
: &ty
::TypeAndMut
<'tcx
>,
108 b
: &ty
::TypeAndMut
<'tcx
>)
109 -> RelateResult
<'tcx
, ty
::TypeAndMut
<'tcx
>>
110 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
112 debug
!("{}.mts({:?}, {:?})",
116 if a
.mutbl
!= b
.mutbl
{
117 Err(TypeError
::Mutability
)
120 let variance
= match mutbl
{
121 ast
::Mutability
::MutImmutable
=> ty
::Covariant
,
122 ast
::Mutability
::MutMutable
=> ty
::Invariant
,
124 let ty
= relation
.relate_with_variance(variance
, &a
.ty
, &b
.ty
)?
;
125 Ok(ty
::TypeAndMut {ty: ty, mutbl: mutbl}
)
130 pub fn relate_substs
<'a
, 'gcx
, 'tcx
, R
>(relation
: &mut R
,
131 variances
: Option
<&Vec
<ty
::Variance
>>,
132 a_subst
: &'tcx Substs
<'tcx
>,
133 b_subst
: &'tcx Substs
<'tcx
>)
134 -> RelateResult
<'tcx
, &'tcx Substs
<'tcx
>>
135 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
137 let tcx
= relation
.tcx();
139 let params
= a_subst
.iter().zip(b_subst
).enumerate().map(|(i
, (a
, b
))| {
140 let variance
= variances
.map_or(ty
::Invariant
, |v
| v
[i
]);
141 if let (Some(a_ty
), Some(b_ty
)) = (a
.as_type(), b
.as_type()) {
142 Ok(Kind
::from(relation
.relate_with_variance(variance
, &a_ty
, &b_ty
)?
))
143 } else if let (Some(a_r
), Some(b_r
)) = (a
.as_region(), b
.as_region()) {
144 Ok(Kind
::from(relation
.relate_with_variance(variance
, &a_r
, &b_r
)?
))
150 Ok(tcx
.mk_substs(params
)?
)
153 impl<'tcx
> Relate
<'tcx
> for ty
::FnSig
<'tcx
> {
154 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
157 -> RelateResult
<'tcx
, ty
::FnSig
<'tcx
>>
158 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
160 if a
.variadic
!= b
.variadic
{
161 return Err(TypeError
::VariadicMismatch(
162 expected_found(relation
, &a
.variadic
, &b
.variadic
)));
164 let unsafety
= relation
.relate(&a
.unsafety
, &b
.unsafety
)?
;
165 let abi
= relation
.relate(&a
.abi
, &b
.abi
)?
;
167 if a
.inputs().len() != b
.inputs().len() {
168 return Err(TypeError
::ArgCount
);
171 let inputs_and_output
= a
.inputs().iter().cloned()
172 .zip(b
.inputs().iter().cloned())
174 .chain(iter
::once(((a
.output(), b
.output()), true)))
175 .map(|((a
, b
), is_output
)| {
177 relation
.relate(&a
, &b
)
179 relation
.relate_with_variance(ty
::Contravariant
, &a
, &b
)
181 }).collect
::<Result
<AccumulateVec
<[_
; 8]>, _
>>()?
;
183 inputs_and_output
: relation
.tcx().intern_type_list(&inputs_and_output
),
184 variadic
: a
.variadic
,
191 impl<'tcx
> Relate
<'tcx
> for ast
::Unsafety
{
192 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
195 -> RelateResult
<'tcx
, ast
::Unsafety
>
196 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
199 Err(TypeError
::UnsafetyMismatch(expected_found(relation
, a
, b
)))
206 impl<'tcx
> Relate
<'tcx
> for abi
::Abi
{
207 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
210 -> RelateResult
<'tcx
, abi
::Abi
>
211 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
216 Err(TypeError
::AbiMismatch(expected_found(relation
, a
, b
)))
221 impl<'tcx
> Relate
<'tcx
> for ty
::ProjectionTy
<'tcx
> {
222 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
223 a
: &ty
::ProjectionTy
<'tcx
>,
224 b
: &ty
::ProjectionTy
<'tcx
>)
225 -> RelateResult
<'tcx
, ty
::ProjectionTy
<'tcx
>>
226 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
228 if a
.item_def_id
!= b
.item_def_id
{
229 Err(TypeError
::ProjectionMismatched(
230 expected_found(relation
, &a
.item_def_id
, &b
.item_def_id
)))
232 let substs
= relation
.relate(&a
.substs
, &b
.substs
)?
;
233 Ok(ty
::ProjectionTy
{
234 item_def_id
: a
.item_def_id
,
241 impl<'tcx
> Relate
<'tcx
> for ty
::ExistentialProjection
<'tcx
> {
242 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
243 a
: &ty
::ExistentialProjection
<'tcx
>,
244 b
: &ty
::ExistentialProjection
<'tcx
>)
245 -> RelateResult
<'tcx
, ty
::ExistentialProjection
<'tcx
>>
246 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
248 if a
.item_def_id
!= b
.item_def_id
{
249 Err(TypeError
::ProjectionMismatched(
250 expected_found(relation
, &a
.item_def_id
, &b
.item_def_id
)))
252 let ty
= relation
.relate(&a
.ty
, &b
.ty
)?
;
253 let substs
= relation
.relate(&a
.substs
, &b
.substs
)?
;
254 Ok(ty
::ExistentialProjection
{
255 item_def_id
: a
.item_def_id
,
263 impl<'tcx
> Relate
<'tcx
> for Vec
<ty
::PolyExistentialProjection
<'tcx
>> {
264 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
265 a
: &Vec
<ty
::PolyExistentialProjection
<'tcx
>>,
266 b
: &Vec
<ty
::PolyExistentialProjection
<'tcx
>>)
267 -> RelateResult
<'tcx
, Vec
<ty
::PolyExistentialProjection
<'tcx
>>>
268 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
270 // To be compatible, `a` and `b` must be for precisely the
271 // same set of traits and item names. We always require that
272 // projection bounds lists are sorted by trait-def-id and item-name,
273 // so we can just iterate through the lists pairwise, so long as they are the
275 if a
.len() != b
.len() {
276 Err(TypeError
::ProjectionBoundsLength(expected_found(relation
, &a
.len(), &b
.len())))
279 .map(|(a
, b
)| relation
.relate(a
, b
))
285 impl<'tcx
> Relate
<'tcx
> for ty
::TraitRef
<'tcx
> {
286 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
287 a
: &ty
::TraitRef
<'tcx
>,
288 b
: &ty
::TraitRef
<'tcx
>)
289 -> RelateResult
<'tcx
, ty
::TraitRef
<'tcx
>>
290 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
292 // Different traits cannot be related
293 if a
.def_id
!= b
.def_id
{
294 Err(TypeError
::Traits(expected_found(relation
, &a
.def_id
, &b
.def_id
)))
296 let substs
= relate_substs(relation
, None
, a
.substs
, b
.substs
)?
;
297 Ok(ty
::TraitRef { def_id: a.def_id, substs: substs }
)
302 impl<'tcx
> Relate
<'tcx
> for ty
::ExistentialTraitRef
<'tcx
> {
303 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
304 a
: &ty
::ExistentialTraitRef
<'tcx
>,
305 b
: &ty
::ExistentialTraitRef
<'tcx
>)
306 -> RelateResult
<'tcx
, ty
::ExistentialTraitRef
<'tcx
>>
307 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
309 // Different traits cannot be related
310 if a
.def_id
!= b
.def_id
{
311 Err(TypeError
::Traits(expected_found(relation
, &a
.def_id
, &b
.def_id
)))
313 let substs
= relate_substs(relation
, None
, a
.substs
, b
.substs
)?
;
314 Ok(ty
::ExistentialTraitRef { def_id: a.def_id, substs: substs }
)
319 impl<'tcx
> Relate
<'tcx
> for Ty
<'tcx
> {
320 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
323 -> RelateResult
<'tcx
, Ty
<'tcx
>>
324 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
330 /// The main "type relation" routine. Note that this does not handle
331 /// inference artifacts, so you should filter those out before calling
333 pub fn super_relate_tys
<'a
, 'gcx
, 'tcx
, R
>(relation
: &mut R
,
336 -> RelateResult
<'tcx
, Ty
<'tcx
>>
337 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
339 let tcx
= relation
.tcx();
342 debug
!("super_tys: a_sty={:?} b_sty={:?}", a_sty
, b_sty
);
343 match (a_sty
, b_sty
) {
344 (&ty
::TyInfer(_
), _
) |
345 (_
, &ty
::TyInfer(_
)) =>
347 // The caller should handle these cases!
348 bug
!("var types encountered in super_relate_tys")
351 (&ty
::TyError
, _
) | (_
, &ty
::TyError
) =>
360 (&ty
::TyUint(_
), _
) |
361 (&ty
::TyFloat(_
), _
) |
368 (&ty
::TyParam(ref a_p
), &ty
::TyParam(ref b_p
))
369 if a_p
.idx
== b_p
.idx
=>
374 (&ty
::TyAdt(a_def
, a_substs
), &ty
::TyAdt(b_def
, b_substs
))
377 let substs
= relation
.relate_item_substs(a_def
.did
, a_substs
, b_substs
)?
;
378 Ok(tcx
.mk_adt(a_def
, substs
))
381 (&ty
::TyDynamic(ref a_obj
, ref a_region
), &ty
::TyDynamic(ref b_obj
, ref b_region
)) => {
382 let region_bound
= relation
.with_cause(Cause
::ExistentialRegionBound
,
384 relation
.relate_with_variance(
389 Ok(tcx
.mk_dynamic(relation
.relate(a_obj
, b_obj
)?
, region_bound
))
392 (&ty
::TyClosure(a_id
, a_substs
),
393 &ty
::TyClosure(b_id
, b_substs
))
396 // All TyClosure types with the same id represent
397 // the (anonymous) type of the same closure expression. So
398 // all of their regions should be equated.
399 let substs
= relation
.relate(&a_substs
, &b_substs
)?
;
400 Ok(tcx
.mk_closure_from_closure_substs(a_id
, substs
))
403 (&ty
::TyRawPtr(ref a_mt
), &ty
::TyRawPtr(ref b_mt
)) =>
405 let mt
= relation
.relate(a_mt
, b_mt
)?
;
409 (&ty
::TyRef(a_r
, ref a_mt
), &ty
::TyRef(b_r
, ref b_mt
)) =>
411 let r
= relation
.relate_with_variance(ty
::Contravariant
, &a_r
, &b_r
)?
;
412 let mt
= relation
.relate(a_mt
, b_mt
)?
;
413 Ok(tcx
.mk_ref(r
, mt
))
416 (&ty
::TyArray(a_t
, sz_a
), &ty
::TyArray(b_t
, sz_b
)) =>
418 let t
= relation
.relate(&a_t
, &b_t
)?
;
420 Ok(tcx
.mk_array(t
, sz_a
))
422 Err(TypeError
::FixedArraySize(expected_found(relation
, &sz_a
, &sz_b
)))
426 (&ty
::TySlice(a_t
), &ty
::TySlice(b_t
)) =>
428 let t
= relation
.relate(&a_t
, &b_t
)?
;
432 (&ty
::TyTuple(as_
, a_defaulted
), &ty
::TyTuple(bs
, b_defaulted
)) =>
434 if as_
.len() == bs
.len() {
435 let defaulted
= a_defaulted
|| b_defaulted
;
436 Ok(tcx
.mk_tup(as_
.iter().zip(bs
).map(|(a
, b
)| relation
.relate(a
, b
)), defaulted
)?
)
437 } else if !(as_
.is_empty() || bs
.is_empty()) {
438 Err(TypeError
::TupleSize(
439 expected_found(relation
, &as_
.len(), &bs
.len())))
441 Err(TypeError
::Sorts(expected_found(relation
, &a
, &b
)))
445 (&ty
::TyFnDef(a_def_id
, a_substs
), &ty
::TyFnDef(b_def_id
, b_substs
))
446 if a_def_id
== b_def_id
=>
448 let substs
= relation
.relate_item_substs(a_def_id
, a_substs
, b_substs
)?
;
449 Ok(tcx
.mk_fn_def(a_def_id
, substs
))
452 (&ty
::TyFnPtr(a_fty
), &ty
::TyFnPtr(b_fty
)) =>
454 let fty
= relation
.relate(&a_fty
, &b_fty
)?
;
455 Ok(tcx
.mk_fn_ptr(fty
))
458 (&ty
::TyProjection(ref a_data
), &ty
::TyProjection(ref b_data
)) =>
460 let projection_ty
= relation
.relate(a_data
, b_data
)?
;
461 Ok(tcx
.mk_projection(projection_ty
.item_def_id
, projection_ty
.substs
))
464 (&ty
::TyAnon(a_def_id
, a_substs
), &ty
::TyAnon(b_def_id
, b_substs
))
465 if a_def_id
== b_def_id
=>
467 let substs
= relate_substs(relation
, None
, a_substs
, b_substs
)?
;
468 Ok(tcx
.mk_anon(a_def_id
, substs
))
473 Err(TypeError
::Sorts(expected_found(relation
, &a
, &b
)))
478 impl<'tcx
> Relate
<'tcx
> for &'tcx ty
::Slice
<ty
::ExistentialPredicate
<'tcx
>> {
479 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
482 -> RelateResult
<'tcx
, Self>
483 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
{
485 if a
.len() != b
.len() {
486 return Err(TypeError
::ExistentialMismatch(expected_found(relation
, a
, b
)));
489 let tcx
= relation
.tcx();
490 let v
= a
.iter().zip(b
.iter()).map(|(ep_a
, ep_b
)| {
491 use ty
::ExistentialPredicate
::*;
492 match (*ep_a
, *ep_b
) {
493 (Trait(ref a
), Trait(ref b
)) => Ok(Trait(relation
.relate(a
, b
)?
)),
494 (Projection(ref a
), Projection(ref b
)) => Ok(Projection(relation
.relate(a
, b
)?
)),
495 (AutoTrait(ref a
), AutoTrait(ref b
)) if a
== b
=> Ok(AutoTrait(*a
)),
496 _
=> Err(TypeError
::ExistentialMismatch(expected_found(relation
, a
, b
)))
499 Ok(tcx
.mk_existential_predicates(v
)?
)
503 impl<'tcx
> Relate
<'tcx
> for ty
::ClosureSubsts
<'tcx
> {
504 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
505 a
: &ty
::ClosureSubsts
<'tcx
>,
506 b
: &ty
::ClosureSubsts
<'tcx
>)
507 -> RelateResult
<'tcx
, ty
::ClosureSubsts
<'tcx
>>
508 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
510 let substs
= relate_substs(relation
, None
, a
.substs
, b
.substs
)?
;
511 Ok(ty
::ClosureSubsts { substs: substs }
)
515 impl<'tcx
> Relate
<'tcx
> for &'tcx Substs
<'tcx
> {
516 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
517 a
: &&'tcx Substs
<'tcx
>,
518 b
: &&'tcx Substs
<'tcx
>)
519 -> RelateResult
<'tcx
, &'tcx Substs
<'tcx
>>
520 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
522 relate_substs(relation
, None
, a
, b
)
526 impl<'tcx
> Relate
<'tcx
> for ty
::Region
<'tcx
> {
527 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
528 a
: &ty
::Region
<'tcx
>,
529 b
: &ty
::Region
<'tcx
>)
530 -> RelateResult
<'tcx
, ty
::Region
<'tcx
>>
531 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
533 relation
.regions(*a
, *b
)
537 impl<'tcx
, T
: Relate
<'tcx
>> Relate
<'tcx
> for ty
::Binder
<T
> {
538 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
541 -> RelateResult
<'tcx
, ty
::Binder
<T
>>
542 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
544 relation
.binders(a
, b
)
548 impl<'tcx
, T
: Relate
<'tcx
>> Relate
<'tcx
> for Rc
<T
> {
549 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
552 -> RelateResult
<'tcx
, Rc
<T
>>
553 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
557 Ok(Rc
::new(relation
.relate(a
, b
)?
))
561 impl<'tcx
, T
: Relate
<'tcx
>> Relate
<'tcx
> for Box
<T
> {
562 fn relate
<'a
, 'gcx
, R
>(relation
: &mut R
,
565 -> RelateResult
<'tcx
, Box
<T
>>
566 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
570 Ok(Box
::new(relation
.relate(a
, b
)?
))
574 ///////////////////////////////////////////////////////////////////////////
577 pub fn expected_found
<'a
, 'gcx
, 'tcx
, R
, T
>(relation
: &mut R
,
581 where R
: TypeRelation
<'a
, 'gcx
, 'tcx
>, T
: Clone
, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
583 expected_found_bool(relation
.a_is_expected(), a
, b
)
586 pub fn expected_found_bool
<T
>(a_is_expected
: bool
,
595 ExpectedFound {expected: a, found: b}
597 ExpectedFound {expected: b, found: a}