diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-22 23:01:38 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-22 23:01:38 +0100 |
commit | c2d9cca4e42ad052cf8a37ba3f6d9eacae07cbea (patch) | |
tree | 9f800613bde5ef6b80ab6a637990a6be69995dd4 /crates | |
parent | efcbca95595d31bb4c2c6782530d5a7a64a4191f (diff) | |
parent | bc905d202c613a831f7c1abb846b612900a9b43a (diff) |
Merge #1895
1895: Handle associated type shorthand (`T::Item`) (Second attempt) r=flodiebold a=flodiebold
This is only allowed for generic parameters (including `Self` in traits), and
special care needs to be taken to not run into cycles while resolving it,
because we use the where clauses of the generic parameter to find candidates for
the trait containing the associated type, but the where clauses may themselves
contain instances of short-hand associated types.
In some cases this is even fine, e.g. we might have `T: Trait<U::Item>, U:
Iterator`. If there is a cycle, we'll currently panic, which isn't great, but
better than overflowing the stack...
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/db.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/generics.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 97 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 64 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 6 |
7 files changed, 173 insertions, 23 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index f7f124904..05259dcbb 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -164,6 +164,13 @@ pub trait HirDatabase: DefDatabase + AstDatabase { | |||
164 | #[salsa::invoke(crate::ty::callable_item_sig)] | 164 | #[salsa::invoke(crate::ty::callable_item_sig)] |
165 | fn callable_item_signature(&self, def: CallableDef) -> FnSig; | 165 | fn callable_item_signature(&self, def: CallableDef) -> FnSig; |
166 | 166 | ||
167 | #[salsa::invoke(crate::ty::generic_predicates_for_param_query)] | ||
168 | fn generic_predicates_for_param( | ||
169 | &self, | ||
170 | def: GenericDef, | ||
171 | param_idx: u32, | ||
172 | ) -> Arc<[GenericPredicate]>; | ||
173 | |||
167 | #[salsa::invoke(crate::ty::generic_predicates_query)] | 174 | #[salsa::invoke(crate::ty::generic_predicates_query)] |
168 | fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>; | 175 | fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>; |
169 | 176 | ||
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 77fb76bfc..ccb777492 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -26,8 +26,9 @@ pub struct GenericParam { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | /// Data about the generic parameters of a function, struct, impl, etc. | 28 | /// Data about the generic parameters of a function, struct, impl, etc. |
29 | #[derive(Clone, PartialEq, Eq, Debug, Default)] | 29 | #[derive(Clone, PartialEq, Eq, Debug)] |
30 | pub struct GenericParams { | 30 | pub struct GenericParams { |
31 | pub(crate) def: GenericDef, | ||
31 | pub(crate) parent_params: Option<Arc<GenericParams>>, | 32 | pub(crate) parent_params: Option<Arc<GenericParams>>, |
32 | pub(crate) params: Vec<GenericParam>, | 33 | pub(crate) params: Vec<GenericParam>, |
33 | pub(crate) where_predicates: Vec<WherePredicate>, | 34 | pub(crate) where_predicates: Vec<WherePredicate>, |
@@ -69,7 +70,6 @@ impl GenericParams { | |||
69 | db: &(impl DefDatabase + AstDatabase), | 70 | db: &(impl DefDatabase + AstDatabase), |
70 | def: GenericDef, | 71 | def: GenericDef, |
71 | ) -> Arc<GenericParams> { | 72 | ) -> Arc<GenericParams> { |
72 | let mut generics = GenericParams::default(); | ||
73 | let parent = match def { | 73 | let parent = match def { |
74 | GenericDef::Function(it) => it.container(db).map(GenericDef::from), | 74 | GenericDef::Function(it) => it.container(db).map(GenericDef::from), |
75 | GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from), | 75 | GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from), |
@@ -77,7 +77,12 @@ impl GenericParams { | |||
77 | GenericDef::Adt(_) | GenericDef::Trait(_) => None, | 77 | GenericDef::Adt(_) | GenericDef::Trait(_) => None, |
78 | GenericDef::ImplBlock(_) => None, | 78 | GenericDef::ImplBlock(_) => None, |
79 | }; | 79 | }; |
80 | generics.parent_params = parent.map(|p| db.generic_params(p)); | 80 | let mut generics = GenericParams { |
81 | def, | ||
82 | params: Vec::new(), | ||
83 | parent_params: parent.map(|p| db.generic_params(p)), | ||
84 | where_predicates: Vec::new(), | ||
85 | }; | ||
81 | let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32; | 86 | let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32; |
82 | // FIXME: add `: Sized` bound for everything except for `Self` in traits | 87 | // FIXME: add `: Sized` bound for everything except for `Self` in traits |
83 | match def { | 88 | match def { |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 254d1a964..39f8e1d8a 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -344,6 +344,13 @@ impl Resolver { | |||
344 | }) | 344 | }) |
345 | .flat_map(|params| params.where_predicates.iter()) | 345 | .flat_map(|params| params.where_predicates.iter()) |
346 | } | 346 | } |
347 | |||
348 | pub(crate) fn generic_def(&self) -> Option<crate::generics::GenericDef> { | ||
349 | self.scopes.iter().find_map(|scope| match scope { | ||
350 | Scope::GenericParams(params) => Some(params.def), | ||
351 | _ => None, | ||
352 | }) | ||
353 | } | ||
347 | } | 354 | } |
348 | 355 | ||
349 | impl Resolver { | 356 | impl Resolver { |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index a223e120a..36bfb10ce 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -23,8 +23,8 @@ pub(crate) use autoderef::autoderef; | |||
23 | pub(crate) use infer::{infer_query, InferTy, InferenceResult}; | 23 | pub(crate) use infer::{infer_query, InferTy, InferenceResult}; |
24 | pub use lower::CallableDef; | 24 | pub use lower::CallableDef; |
25 | pub(crate) use lower::{ | 25 | pub(crate) use lower::{ |
26 | callable_item_sig, generic_defaults_query, generic_predicates_query, type_for_def, | 26 | callable_item_sig, generic_defaults_query, generic_predicates_for_param_query, |
27 | type_for_field, TypableDef, | 27 | generic_predicates_query, type_for_def, type_for_field, TypableDef, |
28 | }; | 28 | }; |
29 | pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 29 | pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
30 | 30 | ||
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index a83842b0f..8d71abc95 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -86,6 +86,35 @@ impl Ty { | |||
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | /// This is only for `generic_predicates_for_param`, where we can't just | ||
90 | /// lower the self types of the predicates since that could lead to cycles. | ||
91 | /// So we just check here if the `type_ref` resolves to a generic param, and which. | ||
92 | fn from_hir_only_param( | ||
93 | db: &impl HirDatabase, | ||
94 | resolver: &Resolver, | ||
95 | type_ref: &TypeRef, | ||
96 | ) -> Option<u32> { | ||
97 | let path = match type_ref { | ||
98 | TypeRef::Path(path) => path, | ||
99 | _ => return None, | ||
100 | }; | ||
101 | if let crate::PathKind::Type(_) = &path.kind { | ||
102 | return None; | ||
103 | } | ||
104 | if path.segments.len() > 1 { | ||
105 | return None; | ||
106 | } | ||
107 | let resolution = match resolver.resolve_path_in_type_ns(db, path) { | ||
108 | Some((it, None)) => it, | ||
109 | _ => return None, | ||
110 | }; | ||
111 | if let TypeNs::GenericParam(idx) = resolution { | ||
112 | Some(idx) | ||
113 | } else { | ||
114 | None | ||
115 | } | ||
116 | } | ||
117 | |||
89 | pub(crate) fn from_type_relative_path( | 118 | pub(crate) fn from_type_relative_path( |
90 | db: &impl HirDatabase, | 119 | db: &impl HirDatabase, |
91 | resolver: &Resolver, | 120 | resolver: &Resolver, |
@@ -189,11 +218,37 @@ impl Ty { | |||
189 | } | 218 | } |
190 | 219 | ||
191 | fn select_associated_type( | 220 | fn select_associated_type( |
192 | _db: &impl HirDatabase, | 221 | db: &impl HirDatabase, |
193 | _resolver: &Resolver, | 222 | resolver: &Resolver, |
194 | _self_ty: Ty, | 223 | self_ty: Ty, |
195 | _segment: &PathSegment, | 224 | segment: &PathSegment, |
196 | ) -> Ty { | 225 | ) -> Ty { |
226 | let param_idx = match self_ty { | ||
227 | Ty::Param { idx, .. } => idx, | ||
228 | _ => return Ty::Unknown, // Error: Ambiguous associated type | ||
229 | }; | ||
230 | let def = match resolver.generic_def() { | ||
231 | Some(def) => def, | ||
232 | None => return Ty::Unknown, // this can't actually happen | ||
233 | }; | ||
234 | let predicates = db.generic_predicates_for_param(def, param_idx); | ||
235 | let traits_from_env = predicates.iter().filter_map(|pred| match pred { | ||
236 | GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_), | ||
237 | _ => None, | ||
238 | }); | ||
239 | let traits = traits_from_env.flat_map(|t| t.all_super_traits(db)); | ||
240 | for t in traits { | ||
241 | if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) { | ||
242 | let generics = t.generic_params(db); | ||
243 | let mut substs = Vec::new(); | ||
244 | substs.push(self_ty.clone()); | ||
245 | substs.extend( | ||
246 | iter::repeat(Ty::Unknown).take(generics.count_params_including_parent() - 1), | ||
247 | ); | ||
248 | // FIXME handle type parameters on the segment | ||
249 | return Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() }); | ||
250 | } | ||
251 | } | ||
197 | Ty::Unknown | 252 | Ty::Unknown |
198 | } | 253 | } |
199 | 254 | ||
@@ -269,9 +324,10 @@ pub(super) fn substs_from_path_segment( | |||
269 | add_self_param: bool, | 324 | add_self_param: bool, |
270 | ) -> Substs { | 325 | ) -> Substs { |
271 | let mut substs = Vec::new(); | 326 | let mut substs = Vec::new(); |
272 | let def_generics = def_generic.map(|def| def.generic_params(db)).unwrap_or_default(); | 327 | let def_generics = def_generic.map(|def| def.generic_params(db)); |
273 | 328 | ||
274 | let parent_param_count = def_generics.count_parent_params(); | 329 | let (parent_param_count, param_count) = |
330 | def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); | ||
275 | substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); | 331 | substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); |
276 | if add_self_param { | 332 | if add_self_param { |
277 | // FIXME this add_self_param argument is kind of a hack: Traits have the | 333 | // FIXME this add_self_param argument is kind of a hack: Traits have the |
@@ -283,7 +339,7 @@ pub(super) fn substs_from_path_segment( | |||
283 | if let Some(generic_args) = &segment.args_and_bindings { | 339 | if let Some(generic_args) = &segment.args_and_bindings { |
284 | // if args are provided, it should be all of them, but we can't rely on that | 340 | // if args are provided, it should be all of them, but we can't rely on that |
285 | let self_param_correction = if add_self_param { 1 } else { 0 }; | 341 | let self_param_correction = if add_self_param { 1 } else { 0 }; |
286 | let param_count = def_generics.params.len() - self_param_correction; | 342 | let param_count = param_count - self_param_correction; |
287 | for arg in generic_args.args.iter().take(param_count) { | 343 | for arg in generic_args.args.iter().take(param_count) { |
288 | match arg { | 344 | match arg { |
289 | GenericArg::Type(type_ref) => { | 345 | GenericArg::Type(type_ref) => { |
@@ -295,10 +351,10 @@ pub(super) fn substs_from_path_segment( | |||
295 | } | 351 | } |
296 | // add placeholders for args that were not provided | 352 | // add placeholders for args that were not provided |
297 | let supplied_params = substs.len(); | 353 | let supplied_params = substs.len(); |
298 | for _ in supplied_params..def_generics.count_params_including_parent() { | 354 | for _ in supplied_params..parent_param_count + param_count { |
299 | substs.push(Ty::Unknown); | 355 | substs.push(Ty::Unknown); |
300 | } | 356 | } |
301 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | 357 | assert_eq!(substs.len(), parent_param_count + param_count); |
302 | 358 | ||
303 | // handle defaults | 359 | // handle defaults |
304 | if let Some(def_generic) = def_generic { | 360 | if let Some(def_generic) = def_generic { |
@@ -491,6 +547,29 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { | |||
491 | Ty::from_hir(db, &resolver, type_ref) | 547 | Ty::from_hir(db, &resolver, type_ref) |
492 | } | 548 | } |
493 | 549 | ||
550 | /// This query exists only to be used when resolving short-hand associated types | ||
551 | /// like `T::Item`. | ||
552 | /// | ||
553 | /// See the analogous query in rustc and its comment: | ||
554 | /// https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46 | ||
555 | /// This is a query mostly to handle cycles somewhat gracefully; e.g. the | ||
556 | /// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but | ||
557 | /// these are fine: `T: Foo<U::Item>, U: Foo<()>`. | ||
558 | pub(crate) fn generic_predicates_for_param_query( | ||
559 | db: &impl HirDatabase, | ||
560 | def: GenericDef, | ||
561 | param_idx: u32, | ||
562 | ) -> Arc<[GenericPredicate]> { | ||
563 | let resolver = def.resolver(db); | ||
564 | let predicates = resolver | ||
565 | .where_predicates_in_scope() | ||
566 | // we have to filter out all other predicates *first*, before attempting to lower them | ||
567 | .filter(|pred| Ty::from_hir_only_param(db, &resolver, &pred.type_ref) == Some(param_idx)) | ||
568 | .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) | ||
569 | .collect::<Vec<_>>(); | ||
570 | predicates.into() | ||
571 | } | ||
572 | |||
494 | pub(crate) fn trait_env( | 573 | pub(crate) fn trait_env( |
495 | db: &impl HirDatabase, | 574 | db: &impl HirDatabase, |
496 | resolver: &Resolver, | 575 | resolver: &Resolver, |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 3b0a99460..3ac1fbdd5 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2740,17 +2740,17 @@ fn test() { | |||
2740 | [202; 203) 't': T | 2740 | [202; 203) 't': T |
2741 | [221; 223) '{}': () | 2741 | [221; 223) '{}': () |
2742 | [234; 300) '{ ...(S); }': () | 2742 | [234; 300) '{ ...(S); }': () |
2743 | [244; 245) 'x': {unknown} | 2743 | [244; 245) 'x': u32 |
2744 | [248; 252) 'foo1': fn foo1<S>(T) -> {unknown} | 2744 | [248; 252) 'foo1': fn foo1<S>(T) -> <T as Iterable>::Item |
2745 | [248; 255) 'foo1(S)': {unknown} | 2745 | [248; 255) 'foo1(S)': u32 |
2746 | [253; 254) 'S': S | 2746 | [253; 254) 'S': S |
2747 | [265; 266) 'y': u32 | 2747 | [265; 266) 'y': u32 |
2748 | [269; 273) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item | 2748 | [269; 273) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item |
2749 | [269; 276) 'foo2(S)': u32 | 2749 | [269; 276) 'foo2(S)': u32 |
2750 | [274; 275) 'S': S | 2750 | [274; 275) 'S': S |
2751 | [286; 287) 'z': {unknown} | 2751 | [286; 287) 'z': u32 |
2752 | [290; 294) 'foo3': fn foo3<S>(T) -> {unknown} | 2752 | [290; 294) 'foo3': fn foo3<S>(T) -> <T as Iterable>::Item |
2753 | [290; 297) 'foo3(S)': {unknown} | 2753 | [290; 297) 'foo3(S)': u32 |
2754 | [295; 296) 'S': S | 2754 | [295; 296) 'S': S |
2755 | "### | 2755 | "### |
2756 | ); | 2756 | ); |
@@ -4080,7 +4080,7 @@ fn test<F: FnOnce(u32) -> u64>(f: F) { | |||
4080 | } | 4080 | } |
4081 | 4081 | ||
4082 | #[test] | 4082 | #[test] |
4083 | fn unselected_projection_in_trait_env() { | 4083 | fn unselected_projection_in_trait_env_1() { |
4084 | let t = type_at( | 4084 | let t = type_at( |
4085 | r#" | 4085 | r#" |
4086 | //- /main.rs | 4086 | //- /main.rs |
@@ -4102,7 +4102,33 @@ fn test<T: Trait>() where T::Item: Trait2 { | |||
4102 | } | 4102 | } |
4103 | 4103 | ||
4104 | #[test] | 4104 | #[test] |
4105 | fn unselected_projection_in_trait_env_cycle() { | 4105 | fn unselected_projection_in_trait_env_2() { |
4106 | let t = type_at( | ||
4107 | r#" | ||
4108 | //- /main.rs | ||
4109 | trait Trait<T> { | ||
4110 | type Item; | ||
4111 | } | ||
4112 | |||
4113 | trait Trait2 { | ||
4114 | fn foo(&self) -> u32; | ||
4115 | } | ||
4116 | |||
4117 | fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { | ||
4118 | let x: T::Item = no_matter; | ||
4119 | x.foo()<|>; | ||
4120 | } | ||
4121 | "#, | ||
4122 | ); | ||
4123 | assert_eq!(t, "u32"); | ||
4124 | } | ||
4125 | |||
4126 | #[test] | ||
4127 | // FIXME this is currently a Salsa panic; it would be nicer if it just returned | ||
4128 | // in Unknown, and we should be able to do that once Salsa allows us to handle | ||
4129 | // the cycle. But at least it doesn't overflow for now. | ||
4130 | #[should_panic] | ||
4131 | fn unselected_projection_in_trait_env_cycle_1() { | ||
4106 | let t = type_at( | 4132 | let t = type_at( |
4107 | r#" | 4133 | r#" |
4108 | //- /main.rs | 4134 | //- /main.rs |
@@ -4121,6 +4147,28 @@ fn test<T: Trait>() where T: Trait2<T::Item> { | |||
4121 | assert_eq!(t, "{unknown}"); | 4147 | assert_eq!(t, "{unknown}"); |
4122 | } | 4148 | } |
4123 | 4149 | ||
4150 | #[test] | ||
4151 | // FIXME this is currently a Salsa panic; it would be nicer if it just returned | ||
4152 | // in Unknown, and we should be able to do that once Salsa allows us to handle | ||
4153 | // the cycle. But at least it doesn't overflow for now. | ||
4154 | #[should_panic] | ||
4155 | fn unselected_projection_in_trait_env_cycle_2() { | ||
4156 | let t = type_at( | ||
4157 | r#" | ||
4158 | //- /main.rs | ||
4159 | trait Trait<T> { | ||
4160 | type Item; | ||
4161 | } | ||
4162 | |||
4163 | fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | ||
4164 | let x: T::Item = no_matter<|>; | ||
4165 | } | ||
4166 | "#, | ||
4167 | ); | ||
4168 | // this is a legitimate cycle | ||
4169 | assert_eq!(t, "{unknown}"); | ||
4170 | } | ||
4171 | |||
4124 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 4172 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
4125 | let file = db.parse(pos.file_id).ok().unwrap(); | 4173 | let file = db.parse(pos.file_id).ok().unwrap(); |
4126 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 4174 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 693d9b28f..cfecf75ee 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -104,7 +104,11 @@ impl ToChalk for Ty { | |||
104 | } | 104 | } |
105 | } | 105 | } |
106 | } | 106 | } |
107 | chalk_ir::Ty::Projection(_) => unimplemented!(), | 107 | chalk_ir::Ty::Projection(proj) => { |
108 | let associated_ty = from_chalk(db, proj.associated_ty_id); | ||
109 | let parameters = from_chalk(db, proj.parameters); | ||
110 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | ||
111 | } | ||
108 | chalk_ir::Ty::ForAll(_) => unimplemented!(), | 112 | chalk_ir::Ty::ForAll(_) => unimplemented!(), |
109 | chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), | 113 | chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), |
110 | chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"), | 114 | chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"), |