diff options
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/coerce.rs | 205 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/coercion.rs | 82 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 61 |
5 files changed, 170 insertions, 187 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 76069eb9c..6e1d268de 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -206,12 +206,6 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
206 | /// closures, but currently this is the only field that will change there, | 206 | /// closures, but currently this is the only field that will change there, |
207 | /// so it doesn't make sense. | 207 | /// so it doesn't make sense. |
208 | return_ty: Ty, | 208 | return_ty: Ty, |
209 | |||
210 | /// Impls of `CoerceUnsized` used in coercion. | ||
211 | /// (from_ty_ctor, to_ty_ctor) => coerce_generic_index | ||
212 | // FIXME: Use trait solver for this. | ||
213 | // Chalk seems unable to work well with builtin impl of `Unsize` now. | ||
214 | coerce_unsized_map: FxHashMap<(TypeCtor, TypeCtor), usize>, | ||
215 | } | 209 | } |
216 | 210 | ||
217 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 211 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
@@ -222,7 +216,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
222 | obligations: Vec::default(), | 216 | obligations: Vec::default(), |
223 | return_ty: Ty::Unknown, // set in collect_fn_signature | 217 | return_ty: Ty::Unknown, // set in collect_fn_signature |
224 | trait_env: TraitEnvironment::lower(db, &resolver), | 218 | trait_env: TraitEnvironment::lower(db, &resolver), |
225 | coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), | ||
226 | db, | 219 | db, |
227 | owner, | 220 | owner, |
228 | body: db.body(owner), | 221 | body: db.body(owner), |
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index fb6a51b12..95ac3c713 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs | |||
@@ -4,11 +4,12 @@ | |||
4 | //! | 4 | //! |
5 | //! See: https://doc.rust-lang.org/nomicon/coercions.html | 5 | //! See: https://doc.rust-lang.org/nomicon/coercions.html |
6 | 6 | ||
7 | use hir_def::{lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AdtId}; | 7 | use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; |
8 | use rustc_hash::FxHashMap; | ||
9 | use test_utils::tested_by; | 8 | use test_utils::tested_by; |
10 | 9 | ||
11 | use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk}; | 10 | use crate::{ |
11 | autoderef, db::HirDatabase, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor, | ||
12 | }; | ||
12 | 13 | ||
13 | use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; | 14 | use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext}; |
14 | 15 | ||
@@ -39,44 +40,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
39 | } | 40 | } |
40 | } | 41 | } |
41 | 42 | ||
42 | pub(super) fn init_coerce_unsized_map( | ||
43 | db: &'a D, | ||
44 | resolver: &Resolver, | ||
45 | ) -> FxHashMap<(TypeCtor, TypeCtor), usize> { | ||
46 | let krate = resolver.krate().unwrap(); | ||
47 | let impls = match db.lang_item(krate, "coerce_unsized".into()) { | ||
48 | Some(LangItemTarget::TraitId(trait_)) => db.impls_for_trait(krate, trait_), | ||
49 | _ => return FxHashMap::default(), | ||
50 | }; | ||
51 | |||
52 | impls | ||
53 | .iter() | ||
54 | .filter_map(|&impl_id| { | ||
55 | let trait_ref = db.impl_trait(impl_id)?; | ||
56 | |||
57 | // `CoerseUnsized` has one generic parameter for the target type. | ||
58 | let cur_from_ty = trait_ref.value.substs.0.get(0)?; | ||
59 | let cur_to_ty = trait_ref.value.substs.0.get(1)?; | ||
60 | |||
61 | match (&cur_from_ty, cur_to_ty) { | ||
62 | (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => { | ||
63 | // FIXME: We return the first non-equal bound as the type parameter to coerce to unsized type. | ||
64 | // This works for smart-pointer-like coercion, which covers all impls from std. | ||
65 | st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| { | ||
66 | match (ty1, ty2) { | ||
67 | (Ty::Bound(idx1), Ty::Bound(idx2)) if idx1 != idx2 => { | ||
68 | Some(((*ctor1, *ctor2), i)) | ||
69 | } | ||
70 | _ => None, | ||
71 | } | ||
72 | }) | ||
73 | } | ||
74 | _ => None, | ||
75 | } | ||
76 | }) | ||
77 | .collect() | ||
78 | } | ||
79 | |||
80 | fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { | 43 | fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { |
81 | match (&from_ty, to_ty) { | 44 | match (&from_ty, to_ty) { |
82 | // Never type will make type variable to fallback to Never Type instead of Unknown. | 45 | // Never type will make type variable to fallback to Never Type instead of Unknown. |
@@ -157,154 +120,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
157 | /// | 120 | /// |
158 | /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html | 121 | /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html |
159 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> { | 122 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> { |
160 | let (ctor1, st1, ctor2, st2) = match (from_ty, to_ty) { | 123 | let krate = self.resolver.krate().unwrap(); |
161 | (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => (ctor1, st1, ctor2, st2), | 124 | let coerce_unsized_trait = match self.db.lang_item(krate, "coerce_unsized".into()) { |
125 | Some(LangItemTarget::TraitId(trait_)) => trait_, | ||
162 | _ => return None, | 126 | _ => return None, |
163 | }; | 127 | }; |
164 | 128 | ||
165 | let coerce_generic_index = *self.coerce_unsized_map.get(&(*ctor1, *ctor2))?; | 129 | let generic_params = crate::utils::generics(self.db, coerce_unsized_trait.into()); |
166 | 130 | if generic_params.len() != 2 { | |
167 | // Check `Unsize` first | 131 | // The CoerceUnsized trait should have two generic params: Self and T. |
168 | match self.check_unsize_and_coerce( | 132 | return None; |
169 | st1.0.get(coerce_generic_index)?, | ||
170 | st2.0.get(coerce_generic_index)?, | ||
171 | 0, | ||
172 | ) { | ||
173 | Some(true) => {} | ||
174 | ret => return ret, | ||
175 | } | 133 | } |
176 | 134 | ||
177 | let ret = st1 | 135 | let substs = Substs::build_for_generics(&generic_params) |
178 | .iter() | 136 | .push(from_ty.clone()) |
179 | .zip(st2.iter()) | 137 | .push(to_ty.clone()) |
180 | .enumerate() | 138 | .build(); |
181 | .filter(|&(idx, _)| idx != coerce_generic_index) | 139 | let trait_ref = TraitRef { trait_: coerce_unsized_trait, substs }; |
182 | .all(|(_, (ty1, ty2))| self.unify(ty1, ty2)); | 140 | let goal = InEnvironment::new(self.trait_env.clone(), Obligation::Trait(trait_ref)); |
183 | 141 | ||
184 | Some(ret) | 142 | let canonicalizer = self.canonicalizer(); |
185 | } | 143 | let canonicalized = canonicalizer.canonicalize_obligation(goal); |
186 | 144 | ||
187 | /// Check if `from_ty: Unsize<to_ty>`, and coerce to `to_ty` if it holds. | 145 | let solution = self.db.trait_solve(krate, canonicalized.value.clone())?; |
188 | /// | ||
189 | /// It should not be directly called. It is only used by `try_coerce_unsized`. | ||
190 | /// | ||
191 | /// See: https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html | ||
192 | fn check_unsize_and_coerce(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> Option<bool> { | ||
193 | if depth > 1000 { | ||
194 | panic!("Infinite recursion in coercion"); | ||
195 | } | ||
196 | |||
197 | match (&from_ty, &to_ty) { | ||
198 | // `[T; N]` -> `[T]` | ||
199 | (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => { | ||
200 | Some(self.unify(&st1[0], &st2[0])) | ||
201 | } | ||
202 | 146 | ||
203 | // `T` -> `dyn Trait` when `T: Trait` | 147 | match solution { |
204 | (_, Ty::Dyn(_)) => { | 148 | Solution::Unique(v) => { |
205 | // FIXME: Check predicates | 149 | canonicalized.apply_solution(self, v.0); |
206 | Some(true) | ||
207 | } | ||
208 | |||
209 | // `(..., T)` -> `(..., U)` when `T: Unsize<U>` | ||
210 | ( | ||
211 | ty_app!(TypeCtor::Tuple { cardinality: len1 }, st1), | ||
212 | ty_app!(TypeCtor::Tuple { cardinality: len2 }, st2), | ||
213 | ) => { | ||
214 | if len1 != len2 || *len1 == 0 { | ||
215 | return None; | ||
216 | } | ||
217 | |||
218 | match self.check_unsize_and_coerce( | ||
219 | st1.last().unwrap(), | ||
220 | st2.last().unwrap(), | ||
221 | depth + 1, | ||
222 | ) { | ||
223 | Some(true) => {} | ||
224 | ret => return ret, | ||
225 | } | ||
226 | |||
227 | let ret = st1[..st1.len() - 1] | ||
228 | .iter() | ||
229 | .zip(&st2[..st2.len() - 1]) | ||
230 | .all(|(ty1, ty2)| self.unify(ty1, ty2)); | ||
231 | |||
232 | Some(ret) | ||
233 | } | ||
234 | |||
235 | // Foo<..., T, ...> is Unsize<Foo<..., U, ...>> if: | ||
236 | // - T: Unsize<U> | ||
237 | // - Foo is a struct | ||
238 | // - Only the last field of Foo has a type involving T | ||
239 | // - T is not part of the type of any other fields | ||
240 | // - Bar<T>: Unsize<Bar<U>>, if the last field of Foo has type Bar<T> | ||
241 | ( | ||
242 | ty_app!(TypeCtor::Adt(AdtId::StructId(struct1)), st1), | ||
243 | ty_app!(TypeCtor::Adt(AdtId::StructId(struct2)), st2), | ||
244 | ) if struct1 == struct2 => { | ||
245 | let field_tys = self.db.field_types((*struct1).into()); | ||
246 | let struct_data = self.db.struct_data(*struct1); | ||
247 | |||
248 | let mut fields = struct_data.variant_data.fields().iter(); | ||
249 | let (last_field_id, _data) = fields.next_back()?; | ||
250 | |||
251 | // Get the generic parameter involved in the last field. | ||
252 | let unsize_generic_index = { | ||
253 | let mut index = None; | ||
254 | let mut multiple_param = false; | ||
255 | field_tys[last_field_id].value.walk(&mut |ty| { | ||
256 | if let &Ty::Bound(idx) = ty { | ||
257 | if index.is_none() { | ||
258 | index = Some(idx); | ||
259 | } else if Some(idx) != index { | ||
260 | multiple_param = true; | ||
261 | } | ||
262 | } | ||
263 | }); | ||
264 | |||
265 | if multiple_param { | ||
266 | return None; | ||
267 | } | ||
268 | index? | ||
269 | }; | ||
270 | |||
271 | // Check other fields do not involve it. | ||
272 | let mut multiple_used = false; | ||
273 | fields.for_each(|(field_id, _data)| { | ||
274 | field_tys[field_id].value.walk(&mut |ty| match ty { | ||
275 | &Ty::Bound(idx) if idx == unsize_generic_index => multiple_used = true, | ||
276 | _ => {} | ||
277 | }) | ||
278 | }); | ||
279 | if multiple_used { | ||
280 | return None; | ||
281 | } | ||
282 | |||
283 | let unsize_generic_index = unsize_generic_index as usize; | ||
284 | |||
285 | // Check `Unsize` first | ||
286 | match self.check_unsize_and_coerce( | ||
287 | st1.get(unsize_generic_index)?, | ||
288 | st2.get(unsize_generic_index)?, | ||
289 | depth + 1, | ||
290 | ) { | ||
291 | Some(true) => {} | ||
292 | ret => return ret, | ||
293 | } | ||
294 | |||
295 | // Then unify other parameters | ||
296 | let ret = st1 | ||
297 | .iter() | ||
298 | .zip(st2.iter()) | ||
299 | .enumerate() | ||
300 | .filter(|&(idx, _)| idx != unsize_generic_index) | ||
301 | .all(|(_, (ty1, ty2))| self.unify(ty1, ty2)); | ||
302 | |||
303 | Some(ret) | ||
304 | } | 150 | } |
151 | _ => return None, | ||
152 | }; | ||
305 | 153 | ||
306 | _ => None, | 154 | Some(true) |
307 | } | ||
308 | } | 155 | } |
309 | 156 | ||
310 | /// Unify `from_ty` to `to_ty` with optional auto Deref | 157 | /// Unify `from_ty` to `to_ty` with optional auto Deref |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 42330b269..aa2dfb5f0 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -548,3 +548,85 @@ impl<TT> S<TT> { | |||
548 | "### | 548 | "### |
549 | ); | 549 | ); |
550 | } | 550 | } |
551 | |||
552 | #[test] | ||
553 | fn coerce_unsize_array() { | ||
554 | assert_snapshot!( | ||
555 | infer_with_mismatches(r#" | ||
556 | #[lang = "unsize"] | ||
557 | pub trait Unsize<T> {} | ||
558 | #[lang = "coerce_unsized"] | ||
559 | pub trait CoerceUnsized<T> {} | ||
560 | |||
561 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
562 | |||
563 | fn test() { | ||
564 | let f: &[usize] = &[1, 2, 3]; | ||
565 | } | ||
566 | "#, true), | ||
567 | @r###" | ||
568 | [162; 199) '{ ... 3]; }': () | ||
569 | [172; 173) 'f': &[usize] | ||
570 | [186; 196) '&[1, 2, 3]': &[usize; _] | ||
571 | [187; 196) '[1, 2, 3]': [usize; _] | ||
572 | [188; 189) '1': usize | ||
573 | [191; 192) '2': usize | ||
574 | [194; 195) '3': usize | ||
575 | "### | ||
576 | ); | ||
577 | } | ||
578 | |||
579 | #[ignore] | ||
580 | #[test] | ||
581 | fn coerce_unsize_trait_object() { | ||
582 | assert_snapshot!( | ||
583 | infer_with_mismatches(r#" | ||
584 | #[lang = "unsize"] | ||
585 | pub trait Unsize<T> {} | ||
586 | #[lang = "coerce_unsized"] | ||
587 | pub trait CoerceUnsized<T> {} | ||
588 | |||
589 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
590 | |||
591 | trait Foo {} | ||
592 | trait Bar: Foo {} | ||
593 | struct S; | ||
594 | impl Foo for S {} | ||
595 | impl Bar for S {} | ||
596 | |||
597 | fn test() { | ||
598 | let obj: &dyn Bar = &S; | ||
599 | let obj: &dyn Foo = obj; | ||
600 | } | ||
601 | "#, true), | ||
602 | @r###" | ||
603 | "### | ||
604 | ); | ||
605 | } | ||
606 | |||
607 | #[ignore] | ||
608 | #[test] | ||
609 | fn coerce_unsize_generic() { | ||
610 | // FIXME: Implement this | ||
611 | // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions | ||
612 | assert_snapshot!( | ||
613 | infer_with_mismatches(r#" | ||
614 | #[lang = "unsize"] | ||
615 | pub trait Unsize<T> {} | ||
616 | #[lang = "coerce_unsized"] | ||
617 | pub trait CoerceUnsized<T> {} | ||
618 | |||
619 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | ||
620 | |||
621 | struct Foo<T> { t: T }; | ||
622 | struct Bar<T>(Foo<T>); | ||
623 | |||
624 | fn test() { | ||
625 | let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; | ||
626 | let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); | ||
627 | } | ||
628 | "#, true), | ||
629 | @r###" | ||
630 | "### | ||
631 | ); | ||
632 | } | ||
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index e83449957..c385f0098 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -343,6 +343,8 @@ pub enum Impl { | |||
343 | ImplBlock(ImplId), | 343 | ImplBlock(ImplId), |
344 | /// Closure types implement the Fn traits synthetically. | 344 | /// Closure types implement the Fn traits synthetically. |
345 | ClosureFnTraitImpl(ClosureFnTraitImplData), | 345 | ClosureFnTraitImpl(ClosureFnTraitImplData), |
346 | /// [T; n]: Unsize<[T]> | ||
347 | UnsizeArray, | ||
346 | } | 348 | } |
347 | /// This exists just for Chalk, because our ImplIds are only unique per module. | 349 | /// This exists just for Chalk, because our ImplIds are only unique per module. |
348 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 350 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index a537420a5..394232fd9 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs | |||
@@ -5,7 +5,7 @@ use hir_expand::name::name; | |||
5 | use ra_db::CrateId; | 5 | use ra_db::CrateId; |
6 | 6 | ||
7 | use super::{AssocTyValue, Impl}; | 7 | use super::{AssocTyValue, Impl}; |
8 | use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; | 8 | use crate::{db::HirDatabase, utils::generics, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; |
9 | 9 | ||
10 | pub(super) struct BuiltinImplData { | 10 | pub(super) struct BuiltinImplData { |
11 | pub num_vars: usize, | 11 | pub num_vars: usize, |
@@ -43,12 +43,22 @@ pub(super) fn get_builtin_impls( | |||
43 | } | 43 | } |
44 | } | 44 | } |
45 | } | 45 | } |
46 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty { | ||
47 | if let Some(actual_trait) = get_unsize_trait(db, krate) { | ||
48 | if trait_ == actual_trait { | ||
49 | if check_unsize_impl_prerequisites(db, krate) { | ||
50 | callback(Impl::UnsizeArray); | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | } | ||
46 | } | 55 | } |
47 | 56 | ||
48 | pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { | 57 | pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { |
49 | match impl_ { | 58 | match impl_ { |
50 | Impl::ImplBlock(_) => unreachable!(), | 59 | Impl::ImplBlock(_) => unreachable!(), |
51 | Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), | 60 | Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), |
61 | Impl::UnsizeArray => array_unsize_impl_datum(db, krate), | ||
52 | } | 62 | } |
53 | } | 63 | } |
54 | 64 | ||
@@ -65,6 +75,8 @@ pub(super) fn associated_ty_value( | |||
65 | } | 75 | } |
66 | } | 76 | } |
67 | 77 | ||
78 | // Closure Fn trait impls | ||
79 | |||
68 | fn check_closure_fn_trait_impl_prerequisites( | 80 | fn check_closure_fn_trait_impl_prerequisites( |
69 | db: &impl HirDatabase, | 81 | db: &impl HirDatabase, |
70 | krate: CrateId, | 82 | krate: CrateId, |
@@ -165,6 +177,45 @@ fn closure_fn_trait_output_assoc_ty_value( | |||
165 | } | 177 | } |
166 | } | 178 | } |
167 | 179 | ||
180 | // Array unsizing | ||
181 | |||
182 | fn check_unsize_impl_prerequisites(db: &impl HirDatabase, krate: CrateId) -> bool { | ||
183 | // the Unsize trait needs to exist and have two type parameters (Self and T) | ||
184 | let unsize_trait = match get_unsize_trait(db, krate) { | ||
185 | Some(t) => t, | ||
186 | None => return false, | ||
187 | }; | ||
188 | let generic_params = generics(db, unsize_trait.into()); | ||
189 | if generic_params.len() != 2 { | ||
190 | return false; | ||
191 | } | ||
192 | true | ||
193 | } | ||
194 | |||
195 | fn array_unsize_impl_datum(db: &impl HirDatabase, krate: CrateId) -> BuiltinImplData { | ||
196 | // impl<T> Unsize<[T]> for [T; _] | ||
197 | // (this can be a single impl because we don't distinguish array sizes currently) | ||
198 | |||
199 | let trait_ = get_unsize_trait(db, krate) // get unsize trait | ||
200 | // the existence of the Unsize trait has been checked before | ||
201 | .expect("Unsize trait missing"); | ||
202 | |||
203 | let var = Ty::Bound(0); | ||
204 | let substs = Substs::builder(2) | ||
205 | .push(Ty::apply_one(TypeCtor::Array, var.clone())) | ||
206 | .push(Ty::apply_one(TypeCtor::Slice, var)) | ||
207 | .build(); | ||
208 | |||
209 | let trait_ref = TraitRef { trait_, substs }; | ||
210 | |||
211 | BuiltinImplData { | ||
212 | num_vars: 1, | ||
213 | trait_ref, | ||
214 | where_clauses: Vec::new(), | ||
215 | assoc_ty_values: Vec::new(), | ||
216 | } | ||
217 | } | ||
218 | |||
168 | fn get_fn_trait( | 219 | fn get_fn_trait( |
169 | db: &impl HirDatabase, | 220 | db: &impl HirDatabase, |
170 | krate: CrateId, | 221 | krate: CrateId, |
@@ -176,3 +227,11 @@ fn get_fn_trait( | |||
176 | _ => None, | 227 | _ => None, |
177 | } | 228 | } |
178 | } | 229 | } |
230 | |||
231 | fn get_unsize_trait(db: &impl HirDatabase, krate: CrateId) -> Option<TraitId> { | ||
232 | let target = db.lang_item(krate, "unsize".into())?; | ||
233 | match target { | ||
234 | LangItemTarget::TraitId(t) => Some(t), | ||
235 | _ => None, | ||
236 | } | ||
237 | } | ||