1use tracing::{debug, instrument};
2
3use self::combine::{PredicateEmittingRelation, super_combine_consts, super_combine_tys};
4use crate::data_structures::DelayedSet;
5use crate::relate::combine::combine_ty_args;
6pub use crate::relate::*;
7use crate::solve::Goal;
8use crate::{self as ty, InferCtxtLike, Interner};
9
10pub trait RelateExt: InferCtxtLike {
11 fn relate<T: Relate<Self::Interner>>(
12 &self,
13 param_env: <Self::Interner as Interner>::ParamEnv,
14 lhs: T,
15 variance: ty::Variance,
16 rhs: T,
17 span: <Self::Interner as Interner>::Span,
18 ) -> Result<
19 Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
20 TypeError<Self::Interner>,
21 >;
22
23 fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
24 &self,
25 param_env: <Self::Interner as Interner>::ParamEnv,
26 lhs: T,
27 rhs: T,
28 span: <Self::Interner as Interner>::Span,
29 ) -> Result<
30 Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
31 TypeError<Self::Interner>,
32 >;
33}
34
35impl<Infcx: InferCtxtLike> RelateExt for Infcx {
36 fn relate<T: Relate<Self::Interner>>(
37 &self,
38 param_env: <Self::Interner as Interner>::ParamEnv,
39 lhs: T,
40 variance: ty::Variance,
41 rhs: T,
42 span: <Self::Interner as Interner>::Span,
43 ) -> Result<
44 Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
45 TypeError<Self::Interner>,
46 > {
47 let mut relate =
48 SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env, span);
49 relate.relate(lhs, rhs)?;
50 Ok(relate.goals)
51 }
52
53 fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
54 &self,
55 param_env: <Self::Interner as Interner>::ParamEnv,
56 lhs: T,
57 rhs: T,
58 span: <Self::Interner as Interner>::Span,
59 ) -> Result<
60 Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
61 TypeError<Self::Interner>,
62 > {
63 let mut relate = SolverRelating::new(
64 self,
65 StructurallyRelateAliases::Yes,
66 ty::Invariant,
67 param_env,
68 span,
69 );
70 relate.relate(lhs, rhs)?;
71 Ok(relate.goals)
72 }
73}
74
75pub struct SolverRelating<'infcx, Infcx, I: Interner> {
77 infcx: &'infcx Infcx,
78 structurally_relate_aliases: StructurallyRelateAliases,
80 param_env: I::ParamEnv,
81 span: I::Span,
82 ambient_variance: ty::Variance,
84 goals: Vec<Goal<I, I::Predicate>>,
85 cache: DelayedSet<(ty::Variance, I::Ty, I::Ty)>,
108}
109
110impl<'infcx, Infcx, I> SolverRelating<'infcx, Infcx, I>
111where
112 Infcx: InferCtxtLike<Interner = I>,
113 I: Interner,
114{
115 pub fn new(
116 infcx: &'infcx Infcx,
117 structurally_relate_aliases: StructurallyRelateAliases,
118 ambient_variance: ty::Variance,
119 param_env: I::ParamEnv,
120 span: I::Span,
121 ) -> Self {
122 SolverRelating {
123 infcx,
124 structurally_relate_aliases,
125 span,
126 ambient_variance,
127 param_env,
128 goals: ::alloc::vec::Vec::new()vec![],
129 cache: Default::default(),
130 }
131 }
132}
133
134impl<Infcx, I> TypeRelation<I> for SolverRelating<'_, Infcx, I>
135where
136 Infcx: InferCtxtLike<Interner = I>,
137 I: Interner,
138{
139 fn cx(&self) -> I {
140 self.infcx.cx()
141 }
142
143 fn relate_ty_args(
144 &mut self,
145 a_ty: I::Ty,
146 b_ty: I::Ty,
147 def_id: I::DefId,
148 a_args: I::GenericArgs,
149 b_args: I::GenericArgs,
150 _: impl FnOnce(I::GenericArgs) -> I::Ty,
151 ) -> RelateResult<I, I::Ty> {
152 if self.ambient_variance == ty::Invariant {
153 relate_args_invariantly(self, a_args, b_args)?;
157 Ok(a_ty)
158 } else {
159 let variances = self.cx().variances_of(def_id);
160 combine_ty_args(self.infcx, self, a_ty, b_ty, variances, a_args, b_args, |_| a_ty)
161 }
162 }
163 fn relate_with_variance<T: Relate<I>>(
164 &mut self,
165 variance: ty::Variance,
166 _info: VarianceDiagInfo<I>,
167 a: T,
168 b: T,
169 ) -> RelateResult<I, T> {
170 let old_ambient_variance = self.ambient_variance;
171 self.ambient_variance = self.ambient_variance.xform(variance);
172 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_type_ir/src/relate/solver_relating.rs:172",
"rustc_type_ir::relate::solver_relating",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/solver_relating.rs"),
::tracing_core::__macro_support::Option::Some(172u32),
::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::solver_relating"),
::tracing_core::field::FieldSet::new(&["message",
"self.ambient_variance"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("new ambient variance")
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&self.ambient_variance)
as &dyn Value))])
});
} else { ; }
};debug!(?self.ambient_variance, "new ambient variance");
173
174 let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) };
175
176 self.ambient_variance = old_ambient_variance;
177 r
178 }
179
180 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("tys",
"rustc_type_ir::relate::solver_relating",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/solver_relating.rs"),
::tracing_core::__macro_support::Option::Some(180u32),
::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::solver_relating"),
::tracing_core::field::FieldSet::new(&["a", "b"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&a)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&b)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: RelateResult<I, I::Ty> = loop {};
return __tracing_attr_fake_return;
}
{
if a == b { return Ok(a); }
let infcx = self.infcx;
let a = infcx.shallow_resolve(a);
let b = infcx.shallow_resolve(b);
if self.cache.contains(&(self.ambient_variance, a, b)) {
return Ok(a);
}
match (a.kind(), b.kind()) {
(ty::Infer(ty::TyVar(a_id)), ty::Infer(ty::TyVar(b_id))) => {
match self.ambient_variance {
ty::Covariant => {
self.goals.push(Goal::new(self.cx(), self.param_env,
ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: true,
a,
b,
}))));
}
ty::Contravariant => {
self.goals.push(Goal::new(self.cx(), self.param_env,
ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: false,
a: b,
b: a,
}))));
}
ty::Invariant => { infcx.equate_ty_vids_raw(a_id, b_id); }
ty::Bivariant => {
{
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Expected bivariance to be handled in relate_with_variance")));
}
}
}
}
(ty::Infer(ty::TyVar(a_vid)), _) => {
infcx.instantiate_ty_var_raw(self, true, a_vid,
self.ambient_variance, b)?;
}
(_, ty::Infer(ty::TyVar(b_vid))) => {
infcx.instantiate_ty_var_raw(self, false, b_vid,
self.ambient_variance.xform(ty::Contravariant), a)?;
}
_ => { super_combine_tys(self.infcx, self, a, b)?; }
}
if !self.cache.insert((self.ambient_variance, a, b)) {
::core::panicking::panic("assertion failed: self.cache.insert((self.ambient_variance, a, b))")
};
Ok(a)
}
}
}#[instrument(skip(self), level = "trace")]
181 fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty> {
182 if a == b {
183 return Ok(a);
184 }
185
186 let infcx = self.infcx;
187 let a = infcx.shallow_resolve(a);
188 let b = infcx.shallow_resolve(b);
189
190 if self.cache.contains(&(self.ambient_variance, a, b)) {
191 return Ok(a);
192 }
193
194 match (a.kind(), b.kind()) {
195 (ty::Infer(ty::TyVar(a_id)), ty::Infer(ty::TyVar(b_id))) => {
196 match self.ambient_variance {
197 ty::Covariant => {
198 self.goals.push(Goal::new(
201 self.cx(),
202 self.param_env,
203 ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
204 a_is_expected: true,
205 a,
206 b,
207 })),
208 ));
209 }
210 ty::Contravariant => {
211 self.goals.push(Goal::new(
214 self.cx(),
215 self.param_env,
216 ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
217 a_is_expected: false,
218 a: b,
219 b: a,
220 })),
221 ));
222 }
223 ty::Invariant => {
224 infcx.equate_ty_vids_raw(a_id, b_id);
225 }
226 ty::Bivariant => {
227 unreachable!("Expected bivariance to be handled in relate_with_variance")
228 }
229 }
230 }
231
232 (ty::Infer(ty::TyVar(a_vid)), _) => {
233 infcx.instantiate_ty_var_raw(self, true, a_vid, self.ambient_variance, b)?;
234 }
235 (_, ty::Infer(ty::TyVar(b_vid))) => {
236 infcx.instantiate_ty_var_raw(
237 self,
238 false,
239 b_vid,
240 self.ambient_variance.xform(ty::Contravariant),
241 a,
242 )?;
243 }
244
245 _ => {
246 super_combine_tys(self.infcx, self, a, b)?;
247 }
248 }
249
250 assert!(self.cache.insert((self.ambient_variance, a, b)));
251
252 Ok(a)
253 }
254
255 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("regions",
"rustc_type_ir::relate::solver_relating",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/solver_relating.rs"),
::tracing_core::__macro_support::Option::Some(255u32),
::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::solver_relating"),
::tracing_core::field::FieldSet::new(&["a", "b"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&a)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&b)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: RelateResult<I, I::Region> =
loop {};
return __tracing_attr_fake_return;
}
{
match self.ambient_variance {
ty::Covariant => self.infcx.sub_regions(b, a, self.span),
ty::Contravariant => self.infcx.sub_regions(a, b, self.span),
ty::Invariant => self.infcx.equate_regions(a, b, self.span),
ty::Bivariant => {
{
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Expected bivariance to be handled in relate_with_variance")));
}
}
}
Ok(a)
}
}
}#[instrument(skip(self), level = "trace")]
256 fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region> {
257 match self.ambient_variance {
258 ty::Covariant => self.infcx.sub_regions(b, a, self.span),
260 ty::Contravariant => self.infcx.sub_regions(a, b, self.span),
262 ty::Invariant => self.infcx.equate_regions(a, b, self.span),
263 ty::Bivariant => {
264 unreachable!("Expected bivariance to be handled in relate_with_variance")
265 }
266 }
267
268 Ok(a)
269 }
270
271 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("consts",
"rustc_type_ir::relate::solver_relating",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/relate/solver_relating.rs"),
::tracing_core::__macro_support::Option::Some(271u32),
::tracing_core::__macro_support::Option::Some("rustc_type_ir::relate::solver_relating"),
::tracing_core::field::FieldSet::new(&["a", "b"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&a)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&b)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: RelateResult<I, I::Const> =
loop {};
return __tracing_attr_fake_return;
}
{ super_combine_consts(self.infcx, self, a, b) }
}
}#[instrument(skip(self), level = "trace")]
272 fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const> {
273 super_combine_consts(self.infcx, self, a, b)
274 }
275
276 fn binders<T>(
277 &mut self,
278 a: ty::Binder<I, T>,
279 b: ty::Binder<I, T>,
280 ) -> RelateResult<I, ty::Binder<I, T>>
281 where
282 T: Relate<I>,
283 {
284 if a == b {
286 return Ok(a);
287 }
288
289 if let Some(a_inner) = a.no_bound_vars()
291 && let Some(b_inner) = b.no_bound_vars()
292 {
293 self.relate(a_inner, b_inner)?;
294 return Ok(a);
295 }
296
297 match self.ambient_variance {
298 ty::Covariant => {
314 self.infcx.enter_forall(b, |b| {
315 let a = self.infcx.instantiate_binder_with_infer(a);
316 self.relate(a, b)
317 })?;
318 }
319 ty::Contravariant => {
320 self.infcx.enter_forall(a, |a| {
321 let b = self.infcx.instantiate_binder_with_infer(b);
322 self.relate(a, b)
323 })?;
324 }
325
326 ty::Invariant => {
337 self.infcx.enter_forall(b, |b| {
338 let a = self.infcx.instantiate_binder_with_infer(a);
339 self.relate(a, b)
340 })?;
341
342 self.infcx.enter_forall(a, |a| {
344 let b = self.infcx.instantiate_binder_with_infer(b);
345 self.relate(a, b)
346 })?;
347 }
348 ty::Bivariant => {
349 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Expected bivariance to be handled in relate_with_variance")));
}unreachable!("Expected bivariance to be handled in relate_with_variance")
350 }
351 }
352 Ok(a)
353 }
354}
355
356impl<Infcx, I> PredicateEmittingRelation<Infcx> for SolverRelating<'_, Infcx, I>
357where
358 Infcx: InferCtxtLike<Interner = I>,
359 I: Interner,
360{
361 fn span(&self) -> I::Span {
362 Span::dummy()
363 }
364
365 fn param_env(&self) -> I::ParamEnv {
366 self.param_env
367 }
368
369 fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
370 self.structurally_relate_aliases
371 }
372
373 fn register_predicates(
374 &mut self,
375 obligations: impl IntoIterator<Item: ty::Upcast<I, I::Predicate>>,
376 ) {
377 self.goals.extend(
378 obligations.into_iter().map(|pred| Goal::new(self.infcx.cx(), self.param_env, pred)),
379 );
380 }
381
382 fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>) {
383 self.goals.extend(obligations);
384 }
385
386 fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty) {
387 self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
388 ty::Covariant => ty::PredicateKind::AliasRelate(
389 a.into(),
390 b.into(),
391 ty::AliasRelationDirection::Subtype,
392 ),
393 ty::Contravariant => ty::PredicateKind::AliasRelate(
395 b.into(),
396 a.into(),
397 ty::AliasRelationDirection::Subtype,
398 ),
399 ty::Invariant => ty::PredicateKind::AliasRelate(
400 a.into(),
401 b.into(),
402 ty::AliasRelationDirection::Equate,
403 ),
404 ty::Bivariant => {
405 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Expected bivariance to be handled in relate_with_variance")));
}unreachable!("Expected bivariance to be handled in relate_with_variance")
406 }
407 })]);
408 }
409}