diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 137 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 59 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/macros.rs | 103 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/regression.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/simple.rs | 32 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 68 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/utils.rs | 48 |
9 files changed, 424 insertions, 72 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 6a53be621..bd4ef69a0 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -667,7 +667,7 @@ impl Expectation { | |||
667 | } | 667 | } |
668 | 668 | ||
669 | mod diagnostics { | 669 | mod diagnostics { |
670 | use hir_def::{expr::ExprId, src::HasSource, FunctionId, Lookup}; | 670 | use hir_def::{expr::ExprId, FunctionId}; |
671 | use hir_expand::diagnostics::DiagnosticSink; | 671 | use hir_expand::diagnostics::DiagnosticSink; |
672 | 672 | ||
673 | use crate::{db::HirDatabase, diagnostics::NoSuchField}; | 673 | use crate::{db::HirDatabase, diagnostics::NoSuchField}; |
@@ -686,10 +686,9 @@ mod diagnostics { | |||
686 | ) { | 686 | ) { |
687 | match self { | 687 | match self { |
688 | InferenceDiagnostic::NoSuchField { expr, field } => { | 688 | InferenceDiagnostic::NoSuchField { expr, field } => { |
689 | let source = owner.lookup(db.upcast()).source(db.upcast()); | ||
690 | let (_, source_map) = db.body_with_source_map(owner.into()); | 689 | let (_, source_map) = db.body_with_source_map(owner.into()); |
691 | let field = source_map.field_syntax(*expr, *field); | 690 | let field = source_map.field_syntax(*expr, *field); |
692 | sink.push(NoSuchField { file: source.file_id, field: field.value }) | 691 | sink.push(NoSuchField { file: field.file_id, field: field.value }) |
693 | } | 692 | } |
694 | } | 693 | } |
695 | } | 694 | } |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 279c06d65..a6f56c661 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -66,7 +66,8 @@ pub use autoderef::autoderef; | |||
66 | pub use infer::{InferTy, InferenceResult}; | 66 | pub use infer::{InferTy, InferenceResult}; |
67 | pub use lower::CallableDef; | 67 | pub use lower::CallableDef; |
68 | pub use lower::{ | 68 | pub use lower::{ |
69 | callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, | 69 | associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, |
70 | TyLoweringContext, ValueTyDefId, | ||
70 | }; | 71 | }; |
71 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 72 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
72 | 73 | ||
@@ -487,6 +488,18 @@ impl<T> Binders<T> { | |||
487 | pub fn new(num_binders: usize, value: T) -> Self { | 488 | pub fn new(num_binders: usize, value: T) -> Self { |
488 | Self { num_binders, value } | 489 | Self { num_binders, value } |
489 | } | 490 | } |
491 | |||
492 | pub fn as_ref(&self) -> Binders<&T> { | ||
493 | Binders { num_binders: self.num_binders, value: &self.value } | ||
494 | } | ||
495 | |||
496 | pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> { | ||
497 | Binders { num_binders: self.num_binders, value: f(self.value) } | ||
498 | } | ||
499 | |||
500 | pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> { | ||
501 | Some(Binders { num_binders: self.num_binders, value: f(self.value)? }) | ||
502 | } | ||
490 | } | 503 | } |
491 | 504 | ||
492 | impl<T: Clone> Binders<&T> { | 505 | impl<T: Clone> Binders<&T> { |
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index b57214296..9ad6dbe07 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -17,9 +17,9 @@ use hir_def::{ | |||
17 | path::{GenericArg, Path, PathSegment, PathSegments}, | 17 | path::{GenericArg, Path, PathSegment, PathSegments}, |
18 | resolver::{HasResolver, Resolver, TypeNs}, | 18 | resolver::{HasResolver, Resolver, TypeNs}, |
19 | type_ref::{TypeBound, TypeRef}, | 19 | type_ref::{TypeBound, TypeRef}, |
20 | AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, | 20 | AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, |
21 | ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, | 21 | HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, |
22 | VariantId, | 22 | UnionId, VariantId, |
23 | }; | 23 | }; |
24 | use ra_arena::map::ArenaMap; | 24 | use ra_arena::map::ArenaMap; |
25 | use ra_db::CrateId; | 25 | use ra_db::CrateId; |
@@ -28,12 +28,13 @@ use crate::{ | |||
28 | db::HirDatabase, | 28 | db::HirDatabase, |
29 | primitive::{FloatTy, IntTy}, | 29 | primitive::{FloatTy, IntTy}, |
30 | utils::{ | 30 | utils::{ |
31 | all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice, | 31 | all_super_trait_refs, associated_type_by_name_including_super_traits, generics, |
32 | variant_data, | 32 | make_mut_slice, variant_data, |
33 | }, | 33 | }, |
34 | Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, | 34 | Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, |
35 | ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, | 35 | ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, |
36 | }; | 36 | }; |
37 | use hir_expand::name::Name; | ||
37 | 38 | ||
38 | #[derive(Debug)] | 39 | #[derive(Debug)] |
39 | pub struct TyLoweringContext<'a> { | 40 | pub struct TyLoweringContext<'a> { |
@@ -256,7 +257,7 @@ impl Ty { | |||
256 | if remaining_segments.len() == 1 { | 257 | if remaining_segments.len() == 1 { |
257 | // resolve unselected assoc types | 258 | // resolve unselected assoc types |
258 | let segment = remaining_segments.first().unwrap(); | 259 | let segment = remaining_segments.first().unwrap(); |
259 | (Ty::select_associated_type(ctx, ty, res, segment), None) | 260 | (Ty::select_associated_type(ctx, res, segment), None) |
260 | } else if remaining_segments.len() > 1 { | 261 | } else if remaining_segments.len() > 1 { |
261 | // FIXME report error (ambiguous associated type) | 262 | // FIXME report error (ambiguous associated type) |
262 | (Ty::Unknown, None) | 263 | (Ty::Unknown, None) |
@@ -380,48 +381,41 @@ impl Ty { | |||
380 | 381 | ||
381 | fn select_associated_type( | 382 | fn select_associated_type( |
382 | ctx: &TyLoweringContext<'_>, | 383 | ctx: &TyLoweringContext<'_>, |
383 | self_ty: Ty, | ||
384 | res: Option<TypeNs>, | 384 | res: Option<TypeNs>, |
385 | segment: PathSegment<'_>, | 385 | segment: PathSegment<'_>, |
386 | ) -> Ty { | 386 | ) -> Ty { |
387 | let traits_from_env: Vec<_> = match res { | 387 | if let Some(res) = res { |
388 | Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { | 388 | let ty = |
389 | None => return Ty::Unknown, | 389 | associated_type_shorthand_candidates(ctx.db, res, move |name, t, associated_ty| { |
390 | Some(trait_ref) => vec![trait_ref.value.trait_], | 390 | if name == segment.name { |
391 | }, | 391 | let substs = match ctx.type_param_mode { |
392 | Some(TypeNs::GenericParam(param_id)) => { | 392 | TypeParamLoweringMode::Placeholder => { |
393 | let predicates = ctx.db.generic_predicates_for_param(param_id); | 393 | // if we're lowering to placeholders, we have to put |
394 | let mut traits_: Vec<_> = predicates | 394 | // them in now |
395 | .iter() | 395 | let s = Substs::type_params( |
396 | .filter_map(|pred| match &pred.value { | 396 | ctx.db, |
397 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | 397 | ctx.resolver.generic_def().expect( |
398 | _ => None, | 398 | "there should be generics if there's a generic param", |
399 | }) | 399 | ), |
400 | .collect(); | 400 | ); |
401 | // Handle `Self::Type` referring to own associated type in trait definitions | 401 | t.substs.clone().subst_bound_vars(&s) |
402 | if let GenericDefId::TraitId(trait_id) = param_id.parent { | 402 | } |
403 | let generics = generics(ctx.db.upcast(), trait_id.into()); | 403 | TypeParamLoweringMode::Variable => t.substs.clone(), |
404 | if generics.params.types[param_id.local_id].provenance | 404 | }; |
405 | == TypeParamProvenance::TraitSelf | 405 | // FIXME handle type parameters on the segment |
406 | { | 406 | return Some(Ty::Projection(ProjectionTy { |
407 | traits_.push(trait_id); | 407 | associated_ty, |
408 | parameters: substs, | ||
409 | })); | ||
408 | } | 410 | } |
409 | } | 411 | |
410 | traits_ | 412 | None |
411 | } | 413 | }); |
412 | _ => return Ty::Unknown, | 414 | |
413 | }; | 415 | ty.unwrap_or(Ty::Unknown) |
414 | let traits = traits_from_env.into_iter().flat_map(|t| all_super_traits(ctx.db.upcast(), t)); | 416 | } else { |
415 | for t in traits { | 417 | Ty::Unknown |
416 | if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name) | ||
417 | { | ||
418 | let substs = | ||
419 | Substs::build_for_def(ctx.db, t).push(self_ty).fill_with_unknown().build(); | ||
420 | // FIXME handle type parameters on the segment | ||
421 | return Ty::Projection(ProjectionTy { associated_ty, parameters: substs }); | ||
422 | } | ||
423 | } | 418 | } |
424 | Ty::Unknown | ||
425 | } | 419 | } |
426 | 420 | ||
427 | fn from_hir_path_inner( | 421 | fn from_hir_path_inner( |
@@ -678,6 +672,61 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { | |||
678 | } | 672 | } |
679 | } | 673 | } |
680 | 674 | ||
675 | pub fn associated_type_shorthand_candidates<R>( | ||
676 | db: &dyn HirDatabase, | ||
677 | res: TypeNs, | ||
678 | mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>, | ||
679 | ) -> Option<R> { | ||
680 | let traits_from_env: Vec<_> = match res { | ||
681 | TypeNs::SelfType(impl_id) => match db.impl_trait(impl_id) { | ||
682 | None => vec![], | ||
683 | Some(trait_ref) => vec![trait_ref.value], | ||
684 | }, | ||
685 | TypeNs::GenericParam(param_id) => { | ||
686 | let predicates = db.generic_predicates_for_param(param_id); | ||
687 | let mut traits_: Vec<_> = predicates | ||
688 | .iter() | ||
689 | .filter_map(|pred| match &pred.value { | ||
690 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
691 | _ => None, | ||
692 | }) | ||
693 | .collect(); | ||
694 | // Handle `Self::Type` referring to own associated type in trait definitions | ||
695 | if let GenericDefId::TraitId(trait_id) = param_id.parent { | ||
696 | let generics = generics(db.upcast(), trait_id.into()); | ||
697 | if generics.params.types[param_id.local_id].provenance | ||
698 | == TypeParamProvenance::TraitSelf | ||
699 | { | ||
700 | let trait_ref = TraitRef { | ||
701 | trait_: trait_id, | ||
702 | substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST), | ||
703 | }; | ||
704 | traits_.push(trait_ref); | ||
705 | } | ||
706 | } | ||
707 | traits_ | ||
708 | } | ||
709 | _ => vec![], | ||
710 | }; | ||
711 | |||
712 | for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) { | ||
713 | let data = db.trait_data(t.trait_); | ||
714 | |||
715 | for (name, assoc_id) in &data.items { | ||
716 | match assoc_id { | ||
717 | AssocItemId::TypeAliasId(alias) => { | ||
718 | if let Some(result) = cb(name, &t, *alias) { | ||
719 | return Some(result); | ||
720 | } | ||
721 | } | ||
722 | AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => {} | ||
723 | } | ||
724 | } | ||
725 | } | ||
726 | |||
727 | None | ||
728 | } | ||
729 | |||
681 | /// Build the type of all specific fields of a struct or enum variant. | 730 | /// Build the type of all specific fields of a struct or enum variant. |
682 | pub(crate) fn field_types_query( | 731 | pub(crate) fn field_types_query( |
683 | db: &dyn HirDatabase, | 732 | db: &dyn HirDatabase, |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index b6a96bb5c..d60732e19 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -361,6 +361,33 @@ fn no_such_field_with_feature_flag_diagnostics() { | |||
361 | } | 361 | } |
362 | 362 | ||
363 | #[test] | 363 | #[test] |
364 | fn no_such_field_enum_with_feature_flag_diagnostics() { | ||
365 | let diagnostics = TestDB::with_files( | ||
366 | r#" | ||
367 | //- /lib.rs crate:foo cfg:feature=foo | ||
368 | enum Foo { | ||
369 | #[cfg(not(feature = "foo"))] | ||
370 | Buz, | ||
371 | #[cfg(feature = "foo")] | ||
372 | Bar, | ||
373 | Baz | ||
374 | } | ||
375 | |||
376 | fn test_fn(f: Foo) { | ||
377 | match f { | ||
378 | Foo::Bar => {}, | ||
379 | Foo::Baz => {}, | ||
380 | } | ||
381 | } | ||
382 | "#, | ||
383 | ) | ||
384 | .diagnostics() | ||
385 | .0; | ||
386 | |||
387 | assert_snapshot!(diagnostics, @r###""###); | ||
388 | } | ||
389 | |||
390 | #[test] | ||
364 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | 391 | fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { |
365 | let diagnostics = TestDB::with_files( | 392 | let diagnostics = TestDB::with_files( |
366 | r#" | 393 | r#" |
@@ -391,6 +418,38 @@ fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { | |||
391 | } | 418 | } |
392 | 419 | ||
393 | #[test] | 420 | #[test] |
421 | fn no_such_field_with_feature_flag_diagnostics_on_block_expr() { | ||
422 | let diagnostics = TestDB::with_files( | ||
423 | r#" | ||
424 | //- /lib.rs crate:foo cfg:feature=foo | ||
425 | struct S { | ||
426 | #[cfg(feature = "foo")] | ||
427 | foo: u32, | ||
428 | #[cfg(not(feature = "foo"))] | ||
429 | bar: u32, | ||
430 | } | ||
431 | |||
432 | impl S { | ||
433 | fn new(bar: u32) -> Self { | ||
434 | #[cfg(feature = "foo")] | ||
435 | { | ||
436 | Self { foo: bar } | ||
437 | } | ||
438 | #[cfg(not(feature = "foo"))] | ||
439 | { | ||
440 | Self { bar } | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | "#, | ||
445 | ) | ||
446 | .diagnostics() | ||
447 | .0; | ||
448 | |||
449 | assert_snapshot!(diagnostics, @r###""###); | ||
450 | } | ||
451 | |||
452 | #[test] | ||
394 | fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() { | 453 | fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() { |
395 | let diagnostics = TestDB::with_files( | 454 | let diagnostics = TestDB::with_files( |
396 | r#" | 455 | r#" |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 6b5267232..07398ddcc 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -269,7 +269,7 @@ fn test() { S.foo()<|>; } | |||
269 | } | 269 | } |
270 | 270 | ||
271 | #[test] | 271 | #[test] |
272 | fn infer_impl_items_generated_by_macros() { | 272 | fn infer_assoc_items_generated_by_macros() { |
273 | let t = type_at( | 273 | let t = type_at( |
274 | r#" | 274 | r#" |
275 | //- /main.rs | 275 | //- /main.rs |
@@ -288,7 +288,7 @@ fn test() { S.foo()<|>; } | |||
288 | } | 288 | } |
289 | 289 | ||
290 | #[test] | 290 | #[test] |
291 | fn infer_impl_items_generated_by_macros_chain() { | 291 | fn infer_assoc_items_generated_by_macros_chain() { |
292 | let t = type_at( | 292 | let t = type_at( |
293 | r#" | 293 | r#" |
294 | //- /main.rs | 294 | //- /main.rs |
@@ -339,6 +339,46 @@ pub fn baz() -> usize { 31usize } | |||
339 | } | 339 | } |
340 | 340 | ||
341 | #[test] | 341 | #[test] |
342 | fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { | ||
343 | let (db, pos) = TestDB::with_position( | ||
344 | r#" | ||
345 | //- /main.rs crate:main deps:foo | ||
346 | use foo::Trait; | ||
347 | |||
348 | fn test() { | ||
349 | let msg = foo::Message(foo::MessageRef); | ||
350 | let r = msg.deref(); | ||
351 | r<|>; | ||
352 | } | ||
353 | |||
354 | //- /lib.rs crate:foo | ||
355 | pub struct MessageRef; | ||
356 | pub struct Message(MessageRef); | ||
357 | |||
358 | pub trait Trait { | ||
359 | type Target; | ||
360 | fn deref(&self) -> &Self::Target; | ||
361 | } | ||
362 | |||
363 | #[macro_export] | ||
364 | macro_rules! expand { | ||
365 | () => { | ||
366 | impl Trait for Message { | ||
367 | type Target = $crate::MessageRef; | ||
368 | fn deref(&self) -> &Self::Target { | ||
369 | &self.0 | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | } | ||
374 | |||
375 | expand!(); | ||
376 | "#, | ||
377 | ); | ||
378 | assert_eq!("&MessageRef", type_at_pos(&db, pos)); | ||
379 | } | ||
380 | |||
381 | #[test] | ||
342 | fn infer_type_value_non_legacy_macro_use_as() { | 382 | fn infer_type_value_non_legacy_macro_use_as() { |
343 | assert_snapshot!( | 383 | assert_snapshot!( |
344 | infer(r#" | 384 | infer(r#" |
@@ -388,6 +428,32 @@ fn main() { | |||
388 | } | 428 | } |
389 | 429 | ||
390 | #[test] | 430 | #[test] |
431 | fn infer_local_inner_macros() { | ||
432 | let (db, pos) = TestDB::with_position( | ||
433 | r#" | ||
434 | //- /main.rs crate:main deps:foo | ||
435 | fn test() { | ||
436 | let x = foo::foo!(1); | ||
437 | x<|>; | ||
438 | } | ||
439 | |||
440 | //- /lib.rs crate:foo | ||
441 | #[macro_export(local_inner_macros)] | ||
442 | macro_rules! foo { | ||
443 | (1) => { bar!() }; | ||
444 | } | ||
445 | |||
446 | #[macro_export] | ||
447 | macro_rules! bar { | ||
448 | () => { 42 } | ||
449 | } | ||
450 | |||
451 | "#, | ||
452 | ); | ||
453 | assert_eq!("i32", type_at_pos(&db, pos)); | ||
454 | } | ||
455 | |||
456 | #[test] | ||
391 | fn infer_builtin_macros_line() { | 457 | fn infer_builtin_macros_line() { |
392 | assert_snapshot!( | 458 | assert_snapshot!( |
393 | infer(r#" | 459 | infer(r#" |
@@ -622,14 +688,31 @@ fn main() { | |||
622 | fn infer_derive_clone_simple() { | 688 | fn infer_derive_clone_simple() { |
623 | let (db, pos) = TestDB::with_position( | 689 | let (db, pos) = TestDB::with_position( |
624 | r#" | 690 | r#" |
625 | //- /main.rs crate:main deps:std | 691 | //- /main.rs crate:main deps:core |
626 | #[derive(Clone)] | 692 | #[derive(Clone)] |
627 | struct S; | 693 | struct S; |
628 | fn test() { | 694 | fn test() { |
629 | S.clone()<|>; | 695 | S.clone()<|>; |
630 | } | 696 | } |
631 | 697 | ||
632 | //- /lib.rs crate:std | 698 | //- /lib.rs crate:core |
699 | #[prelude_import] | ||
700 | use clone::*; | ||
701 | mod clone { | ||
702 | trait Clone { | ||
703 | fn clone(&self) -> Self; | ||
704 | } | ||
705 | } | ||
706 | "#, | ||
707 | ); | ||
708 | assert_eq!("S", type_at_pos(&db, pos)); | ||
709 | } | ||
710 | |||
711 | #[test] | ||
712 | fn infer_derive_clone_in_core() { | ||
713 | let (db, pos) = TestDB::with_position( | ||
714 | r#" | ||
715 | //- /lib.rs crate:core | ||
633 | #[prelude_import] | 716 | #[prelude_import] |
634 | use clone::*; | 717 | use clone::*; |
635 | mod clone { | 718 | mod clone { |
@@ -637,6 +720,14 @@ mod clone { | |||
637 | fn clone(&self) -> Self; | 720 | fn clone(&self) -> Self; |
638 | } | 721 | } |
639 | } | 722 | } |
723 | #[derive(Clone)] | ||
724 | pub struct S; | ||
725 | |||
726 | //- /main.rs crate:main deps:core | ||
727 | use core::S; | ||
728 | fn test() { | ||
729 | S.clone()<|>; | ||
730 | } | ||
640 | "#, | 731 | "#, |
641 | ); | 732 | ); |
642 | assert_eq!("S", type_at_pos(&db, pos)); | 733 | assert_eq!("S", type_at_pos(&db, pos)); |
@@ -646,7 +737,7 @@ mod clone { | |||
646 | fn infer_derive_clone_with_params() { | 737 | fn infer_derive_clone_with_params() { |
647 | let (db, pos) = TestDB::with_position( | 738 | let (db, pos) = TestDB::with_position( |
648 | r#" | 739 | r#" |
649 | //- /main.rs crate:main deps:std | 740 | //- /main.rs crate:main deps:core |
650 | #[derive(Clone)] | 741 | #[derive(Clone)] |
651 | struct S; | 742 | struct S; |
652 | #[derive(Clone)] | 743 | #[derive(Clone)] |
@@ -656,7 +747,7 @@ fn test() { | |||
656 | (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; | 747 | (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; |
657 | } | 748 | } |
658 | 749 | ||
659 | //- /lib.rs crate:std | 750 | //- /lib.rs crate:core |
660 | #[prelude_import] | 751 | #[prelude_import] |
661 | use clone::*; | 752 | use clone::*; |
662 | mod clone { | 753 | mod clone { |
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index 8a1292c7a..115ad8328 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs | |||
@@ -535,6 +535,35 @@ fn foo(b: Bar) { | |||
535 | } | 535 | } |
536 | 536 | ||
537 | #[test] | 537 | #[test] |
538 | fn issue_4235_name_conflicts() { | ||
539 | assert_snapshot!( | ||
540 | infer(r#" | ||
541 | struct FOO {} | ||
542 | static FOO:FOO = FOO {}; | ||
543 | |||
544 | impl FOO { | ||
545 | fn foo(&self) {} | ||
546 | } | ||
547 | |||
548 | fn main() { | ||
549 | let a = &FOO; | ||
550 | a.foo(); | ||
551 | } | ||
552 | "#), @r###" | ||
553 | 32..38 'FOO {}': FOO | ||
554 | 64..68 'self': &FOO | ||
555 | 70..72 '{}': () | ||
556 | 86..120 '{ ...o(); }': () | ||
557 | 96..97 'a': &FOO | ||
558 | 100..104 '&FOO': &FOO | ||
559 | 101..104 'FOO': FOO | ||
560 | 110..111 'a': &FOO | ||
561 | 110..117 'a.foo()': () | ||
562 | "### | ||
563 | ); | ||
564 | } | ||
565 | |||
566 | #[test] | ||
538 | fn issue_4053_diesel_where_clauses() { | 567 | fn issue_4053_diesel_where_clauses() { |
539 | assert_snapshot!( | 568 | assert_snapshot!( |
540 | infer(r#" | 569 | infer(r#" |
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 56abc65b8..3d3088965 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -1755,3 +1755,35 @@ fn main() { | |||
1755 | "### | 1755 | "### |
1756 | ); | 1756 | ); |
1757 | } | 1757 | } |
1758 | |||
1759 | #[test] | ||
1760 | fn effects_smoke_test() { | ||
1761 | assert_snapshot!( | ||
1762 | infer(r#" | ||
1763 | fn main() { | ||
1764 | let x = unsafe { 92 }; | ||
1765 | let y = async { async { () }.await }; | ||
1766 | let z = try { () }; | ||
1767 | let t = 'a: { 92 }; | ||
1768 | } | ||
1769 | "#), | ||
1770 | @r###" | ||
1771 | 11..131 '{ ...2 }; }': () | ||
1772 | 21..22 'x': i32 | ||
1773 | 32..38 '{ 92 }': i32 | ||
1774 | 34..36 '92': i32 | ||
1775 | 48..49 'y': {unknown} | ||
1776 | 58..80 '{ asyn...wait }': {unknown} | ||
1777 | 60..78 'async ....await': {unknown} | ||
1778 | 66..72 '{ () }': () | ||
1779 | 68..70 '()': () | ||
1780 | 90..91 'z': {unknown} | ||
1781 | 94..104 'try { () }': {unknown} | ||
1782 | 98..104 '{ () }': () | ||
1783 | 100..102 '()': () | ||
1784 | 114..115 't': i32 | ||
1785 | 122..128 '{ 92 }': i32 | ||
1786 | 124..126 '92': i32 | ||
1787 | "### | ||
1788 | ) | ||
1789 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index f51cdd496..9d32cbc7a 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -1898,6 +1898,36 @@ fn test() { | |||
1898 | } | 1898 | } |
1899 | 1899 | ||
1900 | #[test] | 1900 | #[test] |
1901 | fn unselected_projection_chalk_fold() { | ||
1902 | let t = type_at( | ||
1903 | r#" | ||
1904 | //- /main.rs | ||
1905 | trait Interner {} | ||
1906 | trait Fold<I: Interner, TI = I> { | ||
1907 | type Result; | ||
1908 | } | ||
1909 | |||
1910 | struct Ty<I: Interner> {} | ||
1911 | impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> { | ||
1912 | type Result = Ty<TI>; | ||
1913 | } | ||
1914 | |||
1915 | fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result | ||
1916 | where | ||
1917 | T: Fold<I, I>, | ||
1918 | { | ||
1919 | loop {} | ||
1920 | } | ||
1921 | |||
1922 | fn foo<I: Interner>(interner: &I, t: Ty<I>) { | ||
1923 | fold(interner, t)<|>; | ||
1924 | } | ||
1925 | "#, | ||
1926 | ); | ||
1927 | assert_eq!(t, "Ty<I>"); | ||
1928 | } | ||
1929 | |||
1930 | #[test] | ||
1901 | fn trait_impl_self_ty() { | 1931 | fn trait_impl_self_ty() { |
1902 | let t = type_at( | 1932 | let t = type_at( |
1903 | r#" | 1933 | r#" |
@@ -2025,7 +2055,7 @@ fn test<I: Iterator<Item: Iterator<Item = u32>>>() { | |||
2025 | #[test] | 2055 | #[test] |
2026 | fn proc_macro_server_types() { | 2056 | fn proc_macro_server_types() { |
2027 | assert_snapshot!( | 2057 | assert_snapshot!( |
2028 | infer_with_mismatches(r#" | 2058 | infer(r#" |
2029 | macro_rules! with_api { | 2059 | macro_rules! with_api { |
2030 | ($S:ident, $self:ident, $m:ident) => { | 2060 | ($S:ident, $self:ident, $m:ident) => { |
2031 | $m! { | 2061 | $m! { |
@@ -2039,9 +2069,9 @@ macro_rules! with_api { | |||
2039 | } | 2069 | } |
2040 | macro_rules! associated_item { | 2070 | macro_rules! associated_item { |
2041 | (type TokenStream) => | 2071 | (type TokenStream) => |
2042 | (type TokenStream: 'static + Clone;); | 2072 | (type TokenStream: 'static;); |
2043 | (type Group) => | 2073 | (type Group) => |
2044 | (type Group: 'static + Clone;); | 2074 | (type Group: 'static;); |
2045 | ($($item:tt)*) => ($($item)*;) | 2075 | ($($item:tt)*) => ($($item)*;) |
2046 | } | 2076 | } |
2047 | macro_rules! declare_server_traits { | 2077 | macro_rules! declare_server_traits { |
@@ -2053,21 +2083,23 @@ macro_rules! declare_server_traits { | |||
2053 | } | 2083 | } |
2054 | 2084 | ||
2055 | $(pub trait $name: Types { | 2085 | $(pub trait $name: Types { |
2056 | $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* | 2086 | $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)* |
2057 | })* | 2087 | })* |
2058 | 2088 | ||
2059 | pub trait Server: Types $(+ $name)* {} | 2089 | pub trait Server: Types $(+ $name)* {} |
2060 | impl<S: Types $(+ $name)*> Server for S {} | 2090 | impl<S: Types $(+ $name)*> Server for S {} |
2061 | } | 2091 | } |
2062 | } | 2092 | } |
2093 | |||
2063 | with_api!(Self, self_, declare_server_traits); | 2094 | with_api!(Self, self_, declare_server_traits); |
2064 | struct Group {} | 2095 | struct G {} |
2065 | struct TokenStream {} | 2096 | struct T {} |
2066 | struct Rustc; | 2097 | struct Rustc; |
2067 | impl Types for Rustc { | 2098 | impl Types for Rustc { |
2068 | type TokenStream = TokenStream; | 2099 | type TokenStream = T; |
2069 | type Group = Group; | 2100 | type Group = G; |
2070 | } | 2101 | } |
2102 | |||
2071 | fn make<T>() -> T { loop {} } | 2103 | fn make<T>() -> T { loop {} } |
2072 | impl TokenStream for Rustc { | 2104 | impl TokenStream for Rustc { |
2073 | fn new() -> Self::TokenStream { | 2105 | fn new() -> Self::TokenStream { |
@@ -2075,17 +2107,17 @@ impl TokenStream for Rustc { | |||
2075 | make() | 2107 | make() |
2076 | } | 2108 | } |
2077 | } | 2109 | } |
2078 | "#, true), | 2110 | "#), |
2079 | @r###" | 2111 | @r###" |
2080 | 1115..1126 '{ loop {} }': T | 2112 | 1062..1073 '{ loop {} }': T |
2081 | 1117..1124 'loop {}': ! | 2113 | 1064..1071 'loop {}': ! |
2082 | 1122..1124 '{}': () | 2114 | 1069..1071 '{}': () |
2083 | 1190..1253 '{ ... }': {unknown} | 2115 | 1137..1200 '{ ... }': T |
2084 | 1204..1209 'group': {unknown} | 2116 | 1151..1156 'group': G |
2085 | 1225..1229 'make': fn make<{unknown}>() -> {unknown} | 2117 | 1172..1176 'make': fn make<G>() -> G |
2086 | 1225..1231 'make()': {unknown} | 2118 | 1172..1178 'make()': G |
2087 | 1241..1245 'make': fn make<{unknown}>() -> {unknown} | 2119 | 1188..1192 'make': fn make<T>() -> T |
2088 | 1241..1247 'make()': {unknown} | 2120 | 1188..1194 'make()': T |
2089 | "### | 2121 | "### |
2090 | ); | 2122 | ); |
2091 | } | 2123 | } |
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 1e5022fa4..f98350bf9 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs | |||
@@ -14,6 +14,8 @@ use hir_def::{ | |||
14 | }; | 14 | }; |
15 | use hir_expand::name::{name, Name}; | 15 | use hir_expand::name::{name, Name}; |
16 | 16 | ||
17 | use crate::{db::HirDatabase, GenericPredicate, TraitRef}; | ||
18 | |||
17 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 19 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { |
18 | let resolver = trait_.resolver(db); | 20 | let resolver = trait_.resolver(db); |
19 | // returning the iterator directly doesn't easily work because of | 21 | // returning the iterator directly doesn't easily work because of |
@@ -41,6 +43,28 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | |||
41 | .collect() | 43 | .collect() |
42 | } | 44 | } |
43 | 45 | ||
46 | fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<TraitRef> { | ||
47 | // returning the iterator directly doesn't easily work because of | ||
48 | // lifetime problems, but since there usually shouldn't be more than a | ||
49 | // few direct traits this should be fine (we could even use some kind of | ||
50 | // SmallVec if performance is a concern) | ||
51 | let generic_params = db.generic_params(trait_ref.trait_.into()); | ||
52 | let trait_self = match generic_params.find_trait_self_param() { | ||
53 | Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p }, | ||
54 | None => return Vec::new(), | ||
55 | }; | ||
56 | db.generic_predicates_for_param(trait_self) | ||
57 | .iter() | ||
58 | .filter_map(|pred| { | ||
59 | pred.as_ref().filter_map(|pred| match pred { | ||
60 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
61 | _ => None, | ||
62 | }) | ||
63 | }) | ||
64 | .map(|pred| pred.subst(&trait_ref.substs)) | ||
65 | .collect() | ||
66 | } | ||
67 | |||
44 | /// Returns an iterator over the whole super trait hierarchy (including the | 68 | /// Returns an iterator over the whole super trait hierarchy (including the |
45 | /// trait itself). | 69 | /// trait itself). |
46 | pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 70 | pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { |
@@ -62,6 +86,30 @@ pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<Tra | |||
62 | result | 86 | result |
63 | } | 87 | } |
64 | 88 | ||
89 | /// Given a trait ref (`Self: Trait`), builds all the implied trait refs for | ||
90 | /// super traits. The original trait ref will be included. So the difference to | ||
91 | /// `all_super_traits` is that we keep track of type parameters; for example if | ||
92 | /// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get | ||
93 | /// `Self: OtherTrait<i32>`. | ||
94 | pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> { | ||
95 | // we need to take care a bit here to avoid infinite loops in case of cycles | ||
96 | // (i.e. if we have `trait A: B; trait B: A;`) | ||
97 | let mut result = vec![trait_ref]; | ||
98 | let mut i = 0; | ||
99 | while i < result.len() { | ||
100 | let t = &result[i]; | ||
101 | // yeah this is quadratic, but trait hierarchies should be flat | ||
102 | // enough that this doesn't matter | ||
103 | for tt in direct_super_trait_refs(db, t) { | ||
104 | if !result.iter().any(|tr| tr.trait_ == tt.trait_) { | ||
105 | result.push(tt); | ||
106 | } | ||
107 | } | ||
108 | i += 1; | ||
109 | } | ||
110 | result | ||
111 | } | ||
112 | |||
65 | /// Finds a path from a trait to one of its super traits. Returns an empty | 113 | /// Finds a path from a trait to one of its super traits. Returns an empty |
66 | /// vector if there is no path. | 114 | /// vector if there is no path. |
67 | pub(super) fn find_super_trait_path( | 115 | pub(super) fn find_super_trait_path( |