diff options
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/coerce.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/regression.rs | 49 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 198 |
6 files changed, 291 insertions, 8 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 927896d6f..c8fd54861 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -21,7 +21,7 @@ impl Diagnostic for NoSuchField { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | fn source(&self) -> InFile<SyntaxNodePtr> { | 23 | fn source(&self) -> InFile<SyntaxNodePtr> { |
24 | InFile { file_id: self.file, value: self.field.clone().into() } | 24 | InFile::new(self.file, self.field.clone().into()) |
25 | } | 25 | } |
26 | 26 | ||
27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 246b0e9be..b6d9b3438 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -682,10 +682,10 @@ mod diagnostics { | |||
682 | ) { | 682 | ) { |
683 | match self { | 683 | match self { |
684 | InferenceDiagnostic::NoSuchField { expr, field } => { | 684 | InferenceDiagnostic::NoSuchField { expr, field } => { |
685 | let file = owner.lookup(db.upcast()).source(db.upcast()).file_id; | 685 | let source = owner.lookup(db.upcast()).source(db.upcast()); |
686 | let (_, source_map) = db.body_with_source_map(owner.into()); | 686 | let (_, source_map) = db.body_with_source_map(owner.into()); |
687 | let field = source_map.field_syntax(*expr, *field); | 687 | let field = source_map.field_syntax(*expr, *field); |
688 | sink.push(NoSuchField { file, field }) | 688 | sink.push(NoSuchField { file: source.file_id, field: field.value }) |
689 | } | 689 | } |
690 | } | 690 | } |
691 | } | 691 | } |
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 959b1e212..89200255a 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs | |||
@@ -51,7 +51,7 @@ impl<'a> InferenceContext<'a> { | |||
51 | // Trivial cases, this should go after `never` check to | 51 | // Trivial cases, this should go after `never` check to |
52 | // avoid infer result type to be never | 52 | // avoid infer result type to be never |
53 | _ => { | 53 | _ => { |
54 | if self.table.unify_inner_trivial(&from_ty, &to_ty) { | 54 | if self.table.unify_inner_trivial(&from_ty, &to_ty, 0) { |
55 | return true; | 55 | return true; |
56 | } | 56 | } |
57 | } | 57 | } |
@@ -175,7 +175,7 @@ impl<'a> InferenceContext<'a> { | |||
175 | return self.table.unify_substs(st1, st2, 0); | 175 | return self.table.unify_substs(st1, st2, 0); |
176 | } | 176 | } |
177 | _ => { | 177 | _ => { |
178 | if self.table.unify_inner_trivial(&derefed_ty, &to_ty) { | 178 | if self.table.unify_inner_trivial(&derefed_ty, &to_ty, 0) { |
179 | return true; | 179 | return true; |
180 | } | 180 | } |
181 | } | 181 | } |
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index 5f6cea8d3..ab0bc8b70 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -8,7 +8,8 @@ use test_utils::tested_by; | |||
8 | 8 | ||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use crate::{ |
11 | BoundVar, Canonical, DebruijnIndex, InEnvironment, InferTy, Substs, Ty, TypeCtor, TypeWalk, | 11 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, |
12 | TypeCtor, TypeWalk, | ||
12 | }; | 13 | }; |
13 | 14 | ||
14 | impl<'a> InferenceContext<'a> { | 15 | impl<'a> InferenceContext<'a> { |
@@ -226,16 +227,26 @@ impl InferenceTable { | |||
226 | (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { | 227 | (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { |
227 | self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) | 228 | self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) |
228 | } | 229 | } |
229 | _ => self.unify_inner_trivial(&ty1, &ty2), | 230 | |
231 | _ => self.unify_inner_trivial(&ty1, &ty2, depth), | ||
230 | } | 232 | } |
231 | } | 233 | } |
232 | 234 | ||
233 | pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 235 | pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { |
234 | match (ty1, ty2) { | 236 | match (ty1, ty2) { |
235 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, | 237 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, |
236 | 238 | ||
237 | (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, | 239 | (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, |
238 | 240 | ||
241 | (Ty::Dyn(dyn1), Ty::Dyn(dyn2)) if dyn1.len() == dyn2.len() => { | ||
242 | for (pred1, pred2) in dyn1.iter().zip(dyn2.iter()) { | ||
243 | if !self.unify_preds(pred1, pred2, depth + 1) { | ||
244 | return false; | ||
245 | } | ||
246 | } | ||
247 | true | ||
248 | } | ||
249 | |||
239 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | 250 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) |
240 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | 251 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) |
241 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) | 252 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) |
@@ -268,6 +279,31 @@ impl InferenceTable { | |||
268 | } | 279 | } |
269 | } | 280 | } |
270 | 281 | ||
282 | fn unify_preds( | ||
283 | &mut self, | ||
284 | pred1: &GenericPredicate, | ||
285 | pred2: &GenericPredicate, | ||
286 | depth: usize, | ||
287 | ) -> bool { | ||
288 | match (pred1, pred2) { | ||
289 | (GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2)) | ||
290 | if tr1.trait_ == tr2.trait_ => | ||
291 | { | ||
292 | self.unify_substs(&tr1.substs, &tr2.substs, depth + 1) | ||
293 | } | ||
294 | (GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2)) | ||
295 | if proj1.projection_ty.associated_ty == proj2.projection_ty.associated_ty => | ||
296 | { | ||
297 | self.unify_substs( | ||
298 | &proj1.projection_ty.parameters, | ||
299 | &proj2.projection_ty.parameters, | ||
300 | depth + 1, | ||
301 | ) && self.unify_inner(&proj1.ty, &proj2.ty, depth + 1) | ||
302 | } | ||
303 | _ => false, | ||
304 | } | ||
305 | } | ||
306 | |||
271 | /// If `ty` is a type variable with known type, returns that type; | 307 | /// If `ty` is a type variable with known type, returns that type; |
272 | /// otherwise, return ty. | 308 | /// otherwise, return ty. |
273 | pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { | 309 | pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { |
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index d69115a2f..61284d672 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs | |||
@@ -484,3 +484,52 @@ fn main() { | |||
484 | 484 | ||
485 | assert_eq!("()", super::type_at_pos(&db, pos)); | 485 | assert_eq!("()", super::type_at_pos(&db, pos)); |
486 | } | 486 | } |
487 | |||
488 | #[test] | ||
489 | fn issue_3999_slice() { | ||
490 | assert_snapshot!( | ||
491 | infer(r#" | ||
492 | fn foo(params: &[usize]) { | ||
493 | match params { | ||
494 | [ps @ .., _] => {} | ||
495 | } | ||
496 | } | ||
497 | "#), | ||
498 | @r###" | ||
499 | [8; 14) 'params': &[usize] | ||
500 | [26; 81) '{ ... } }': () | ||
501 | [32; 79) 'match ... }': () | ||
502 | [38; 44) 'params': &[usize] | ||
503 | [55; 67) '[ps @ .., _]': [usize] | ||
504 | [65; 66) '_': usize | ||
505 | [71; 73) '{}': () | ||
506 | "### | ||
507 | ); | ||
508 | } | ||
509 | |||
510 | #[test] | ||
511 | fn issue_3999_struct() { | ||
512 | // rust-analyzer should not panic on seeing this malformed | ||
513 | // record pattern. | ||
514 | assert_snapshot!( | ||
515 | infer(r#" | ||
516 | struct Bar { | ||
517 | a: bool, | ||
518 | } | ||
519 | fn foo(b: Bar) { | ||
520 | match b { | ||
521 | Bar { a: .. } => {}, | ||
522 | } | ||
523 | } | ||
524 | "#), | ||
525 | @r###" | ||
526 | [36; 37) 'b': Bar | ||
527 | [44; 96) '{ ... } }': () | ||
528 | [50; 94) 'match ... }': () | ||
529 | [56; 57) 'b': Bar | ||
530 | [68; 81) 'Bar { a: .. }': Bar | ||
531 | [77; 79) '..': bool | ||
532 | [85; 87) '{}': () | ||
533 | "### | ||
534 | ); | ||
535 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 36f53b264..a46f03b7f 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -2240,3 +2240,201 @@ fn test(x: Box<dyn Trait>) { | |||
2240 | ); | 2240 | ); |
2241 | assert_eq!(t, "()"); | 2241 | assert_eq!(t, "()"); |
2242 | } | 2242 | } |
2243 | |||
2244 | #[test] | ||
2245 | fn string_to_owned() { | ||
2246 | let t = type_at( | ||
2247 | r#" | ||
2248 | //- /main.rs | ||
2249 | struct String {} | ||
2250 | pub trait ToOwned { | ||
2251 | type Owned; | ||
2252 | fn to_owned(&self) -> Self::Owned; | ||
2253 | } | ||
2254 | impl ToOwned for str { | ||
2255 | type Owned = String; | ||
2256 | } | ||
2257 | fn test() { | ||
2258 | "foo".to_owned()<|>; | ||
2259 | } | ||
2260 | "#, | ||
2261 | ); | ||
2262 | assert_eq!(t, "String"); | ||
2263 | } | ||
2264 | |||
2265 | #[test] | ||
2266 | fn iterator_chain() { | ||
2267 | assert_snapshot!( | ||
2268 | infer(r#" | ||
2269 | //- /main.rs | ||
2270 | #[lang = "fn_once"] | ||
2271 | trait FnOnce<Args> { | ||
2272 | type Output; | ||
2273 | } | ||
2274 | #[lang = "fn_mut"] | ||
2275 | trait FnMut<Args>: FnOnce<Args> { } | ||
2276 | |||
2277 | enum Option<T> { Some(T), None } | ||
2278 | use Option::*; | ||
2279 | |||
2280 | pub trait Iterator { | ||
2281 | type Item; | ||
2282 | |||
2283 | fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> | ||
2284 | where | ||
2285 | F: FnMut(Self::Item) -> Option<B>, | ||
2286 | { loop {} } | ||
2287 | |||
2288 | fn for_each<F>(self, f: F) | ||
2289 | where | ||
2290 | F: FnMut(Self::Item), | ||
2291 | { loop {} } | ||
2292 | } | ||
2293 | |||
2294 | pub trait IntoIterator { | ||
2295 | type Item; | ||
2296 | type IntoIter: Iterator<Item = Self::Item>; | ||
2297 | fn into_iter(self) -> Self::IntoIter; | ||
2298 | } | ||
2299 | |||
2300 | pub struct FilterMap<I, F> { } | ||
2301 | impl<B, I: Iterator, F> Iterator for FilterMap<I, F> | ||
2302 | where | ||
2303 | F: FnMut(I::Item) -> Option<B>, | ||
2304 | { | ||
2305 | type Item = B; | ||
2306 | } | ||
2307 | |||
2308 | #[stable(feature = "rust1", since = "1.0.0")] | ||
2309 | impl<I: Iterator> IntoIterator for I { | ||
2310 | type Item = I::Item; | ||
2311 | type IntoIter = I; | ||
2312 | |||
2313 | fn into_iter(self) -> I { | ||
2314 | self | ||
2315 | } | ||
2316 | } | ||
2317 | |||
2318 | struct Vec<T> {} | ||
2319 | impl<T> Vec<T> { | ||
2320 | fn new() -> Self { loop {} } | ||
2321 | } | ||
2322 | |||
2323 | impl<T> IntoIterator for Vec<T> { | ||
2324 | type Item = T; | ||
2325 | type IntoIter = IntoIter<T>; | ||
2326 | } | ||
2327 | |||
2328 | pub struct IntoIter<T> { } | ||
2329 | impl<T> Iterator for IntoIter<T> { | ||
2330 | type Item = T; | ||
2331 | } | ||
2332 | |||
2333 | fn main() { | ||
2334 | Vec::<i32>::new().into_iter() | ||
2335 | .filter_map(|x| if x > 0 { Some(x as u32) } else { None }) | ||
2336 | .for_each(|y| { y; }); | ||
2337 | } | ||
2338 | "#), | ||
2339 | @r###" | ||
2340 | [240; 244) 'self': Self | ||
2341 | [246; 247) 'f': F | ||
2342 | [331; 342) '{ loop {} }': FilterMap<Self, F> | ||
2343 | [333; 340) 'loop {}': ! | ||
2344 | [338; 340) '{}': () | ||
2345 | [363; 367) 'self': Self | ||
2346 | [369; 370) 'f': F | ||
2347 | [419; 430) '{ loop {} }': () | ||
2348 | [421; 428) 'loop {}': ! | ||
2349 | [426; 428) '{}': () | ||
2350 | [539; 543) 'self': Self | ||
2351 | [868; 872) 'self': I | ||
2352 | [879; 899) '{ ... }': I | ||
2353 | [889; 893) 'self': I | ||
2354 | [958; 969) '{ loop {} }': Vec<T> | ||
2355 | [960; 967) 'loop {}': ! | ||
2356 | [965; 967) '{}': () | ||
2357 | [1156; 1287) '{ ... }); }': () | ||
2358 | [1162; 1177) 'Vec::<i32>::new': fn new<i32>() -> Vec<i32> | ||
2359 | [1162; 1179) 'Vec::<...:new()': Vec<i32> | ||
2360 | [1162; 1191) 'Vec::<...iter()': IntoIter<i32> | ||
2361 | [1162; 1256) 'Vec::<...one })': FilterMap<IntoIter<i32>, |i32| -> Option<u32>> | ||
2362 | [1162; 1284) 'Vec::<... y; })': () | ||
2363 | [1210; 1255) '|x| if...None }': |i32| -> Option<u32> | ||
2364 | [1211; 1212) 'x': i32 | ||
2365 | [1214; 1255) 'if x >...None }': Option<u32> | ||
2366 | [1217; 1218) 'x': i32 | ||
2367 | [1217; 1222) 'x > 0': bool | ||
2368 | [1221; 1222) '0': i32 | ||
2369 | [1223; 1241) '{ Some...u32) }': Option<u32> | ||
2370 | [1225; 1229) 'Some': Some<u32>(u32) -> Option<u32> | ||
2371 | [1225; 1239) 'Some(x as u32)': Option<u32> | ||
2372 | [1230; 1231) 'x': i32 | ||
2373 | [1230; 1238) 'x as u32': u32 | ||
2374 | [1247; 1255) '{ None }': Option<u32> | ||
2375 | [1249; 1253) 'None': Option<u32> | ||
2376 | [1273; 1283) '|y| { y; }': |u32| -> () | ||
2377 | [1274; 1275) 'y': u32 | ||
2378 | [1277; 1283) '{ y; }': () | ||
2379 | [1279; 1280) 'y': u32 | ||
2380 | "### | ||
2381 | ); | ||
2382 | } | ||
2383 | |||
2384 | #[test] | ||
2385 | fn nested_assoc() { | ||
2386 | let t = type_at( | ||
2387 | r#" | ||
2388 | //- /main.rs | ||
2389 | struct Bar; | ||
2390 | struct Foo; | ||
2391 | |||
2392 | trait A { | ||
2393 | type OutputA; | ||
2394 | } | ||
2395 | |||
2396 | impl A for Bar { | ||
2397 | type OutputA = Foo; | ||
2398 | } | ||
2399 | |||
2400 | trait B { | ||
2401 | type Output; | ||
2402 | fn foo() -> Self::Output; | ||
2403 | } | ||
2404 | |||
2405 | impl<T:A> B for T { | ||
2406 | type Output = T::OutputA; | ||
2407 | fn foo() -> Self::Output { loop {} } | ||
2408 | } | ||
2409 | |||
2410 | fn main() { | ||
2411 | Bar::foo()<|>; | ||
2412 | } | ||
2413 | "#, | ||
2414 | ); | ||
2415 | assert_eq!(t, "Foo"); | ||
2416 | } | ||
2417 | |||
2418 | #[test] | ||
2419 | fn trait_object_no_coercion() { | ||
2420 | assert_snapshot!( | ||
2421 | infer_with_mismatches(r#" | ||
2422 | trait Foo {} | ||
2423 | |||
2424 | fn foo(x: &dyn Foo) {} | ||
2425 | |||
2426 | fn test(x: &dyn Foo) { | ||
2427 | foo(x); | ||
2428 | } | ||
2429 | "#, true), | ||
2430 | @r###" | ||
2431 | [22; 23) 'x': &dyn Foo | ||
2432 | [35; 37) '{}': () | ||
2433 | [47; 48) 'x': &dyn Foo | ||
2434 | [60; 75) '{ foo(x); }': () | ||
2435 | [66; 69) 'foo': fn foo(&dyn Foo) | ||
2436 | [66; 72) 'foo(x)': () | ||
2437 | [70; 71) 'x': &dyn Foo | ||
2438 | "### | ||
2439 | ); | ||
2440 | } | ||