diff options
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 81 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 63 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/regression.rs | 151 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 223 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/utils.rs | 14 |
10 files changed, 553 insertions, 50 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 2c7298714..ebd9cb08f 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -6,7 +6,7 @@ use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; | |||
6 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; | 6 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; |
7 | use stdx::format_to; | 7 | use stdx::format_to; |
8 | 8 | ||
9 | pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm}; | 9 | pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path}; |
10 | pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; | 10 | pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; |
11 | 11 | ||
12 | #[derive(Debug)] | 12 | #[derive(Debug)] |
@@ -29,6 +29,16 @@ impl Diagnostic for NoSuchField { | |||
29 | } | 29 | } |
30 | } | 30 | } |
31 | 31 | ||
32 | impl AstDiagnostic for NoSuchField { | ||
33 | type AST = ast::RecordField; | ||
34 | |||
35 | fn ast(&self, db: &impl AstDatabase) -> Self::AST { | ||
36 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
37 | let node = self.source().value.to_node(&root); | ||
38 | ast::RecordField::cast(node).unwrap() | ||
39 | } | ||
40 | } | ||
41 | |||
32 | #[derive(Debug)] | 42 | #[derive(Debug)] |
33 | pub struct MissingFields { | 43 | pub struct MissingFields { |
34 | pub file: HirFileId, | 44 | pub file: HirFileId, |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 9fd310f69..a9565a58d 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -10,12 +10,12 @@ use hir_def::{ | |||
10 | resolver::resolver_for_expr, | 10 | resolver::resolver_for_expr, |
11 | AdtId, AssocContainerId, FieldId, Lookup, | 11 | AdtId, AssocContainerId, FieldId, Lookup, |
12 | }; | 12 | }; |
13 | use hir_expand::name::Name; | 13 | use hir_expand::name::{name, Name}; |
14 | use ra_syntax::ast::RangeOp; | 14 | use ra_syntax::ast::RangeOp; |
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | autoderef, method_resolution, op, | 17 | autoderef, method_resolution, op, |
18 | traits::InEnvironment, | 18 | traits::{FnTrait, InEnvironment}, |
19 | utils::{generics, variant_data, Generics}, | 19 | utils::{generics, variant_data, Generics}, |
20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, | 20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, |
21 | TraitRef, Ty, TypeCtor, | 21 | TraitRef, Ty, TypeCtor, |
@@ -63,6 +63,58 @@ impl<'a> InferenceContext<'a> { | |||
63 | self.resolve_ty_as_possible(ty) | 63 | self.resolve_ty_as_possible(ty) |
64 | } | 64 | } |
65 | 65 | ||
66 | fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
67 | let krate = self.resolver.krate()?; | ||
68 | let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; | ||
69 | let output_assoc_type = | ||
70 | self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; | ||
71 | let generic_params = generics(self.db.upcast(), fn_once_trait.into()); | ||
72 | if generic_params.len() != 2 { | ||
73 | return None; | ||
74 | } | ||
75 | |||
76 | let mut param_builder = Substs::builder(num_args); | ||
77 | let mut arg_tys = vec![]; | ||
78 | for _ in 0..num_args { | ||
79 | let arg = self.table.new_type_var(); | ||
80 | param_builder = param_builder.push(arg.clone()); | ||
81 | arg_tys.push(arg); | ||
82 | } | ||
83 | let parameters = param_builder.build(); | ||
84 | let arg_ty = Ty::Apply(ApplicationTy { | ||
85 | ctor: TypeCtor::Tuple { cardinality: num_args as u16 }, | ||
86 | parameters, | ||
87 | }); | ||
88 | let substs = Substs::build_for_generics(&generic_params) | ||
89 | .push(ty.clone()) | ||
90 | .push(arg_ty.clone()) | ||
91 | .build(); | ||
92 | |||
93 | let trait_env = Arc::clone(&self.trait_env); | ||
94 | let implements_fn_trait = | ||
95 | Obligation::Trait(TraitRef { trait_: fn_once_trait, substs: substs.clone() }); | ||
96 | let goal = self.canonicalizer().canonicalize_obligation(InEnvironment { | ||
97 | value: implements_fn_trait.clone(), | ||
98 | environment: trait_env, | ||
99 | }); | ||
100 | if self.db.trait_solve(krate, goal.value).is_some() { | ||
101 | self.obligations.push(implements_fn_trait); | ||
102 | let output_proj_ty = | ||
103 | crate::ProjectionTy { associated_ty: output_assoc_type, parameters: substs }; | ||
104 | let return_ty = self.normalize_projection_ty(output_proj_ty); | ||
105 | Some((arg_tys, return_ty)) | ||
106 | } else { | ||
107 | None | ||
108 | } | ||
109 | } | ||
110 | |||
111 | pub fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
112 | match ty.callable_sig(self.db) { | ||
113 | Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())), | ||
114 | None => self.callable_sig_from_fn_trait(ty, num_args), | ||
115 | } | ||
116 | } | ||
117 | |||
66 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 118 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
67 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 119 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
68 | let ty = match &body[tgt_expr] { | 120 | let ty = match &body[tgt_expr] { |
@@ -198,14 +250,23 @@ impl<'a> InferenceContext<'a> { | |||
198 | } | 250 | } |
199 | Expr::Call { callee, args } => { | 251 | Expr::Call { callee, args } => { |
200 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); | 252 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); |
201 | let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) { | 253 | let canonicalized = self.canonicalizer().canonicalize_ty(callee_ty.clone()); |
202 | Some(sig) => (sig.params().to_vec(), sig.ret().clone()), | 254 | let mut derefs = autoderef( |
203 | None => { | 255 | self.db, |
204 | // Not callable | 256 | self.resolver.krate(), |
205 | // FIXME: report an error | 257 | InEnvironment { |
206 | (Vec::new(), Ty::Unknown) | 258 | value: canonicalized.value.clone(), |
207 | } | 259 | environment: self.trait_env.clone(), |
208 | }; | 260 | }, |
261 | ); | ||
262 | let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs | ||
263 | .find_map(|callee_deref_ty| { | ||
264 | self.callable_sig( | ||
265 | &canonicalized.decanonicalize_ty(callee_deref_ty.value), | ||
266 | args.len(), | ||
267 | ) | ||
268 | }) | ||
269 | .unwrap_or((Vec::new(), Ty::Unknown)); | ||
209 | self.register_obligations_for_call(&callee_ty); | 270 | self.register_obligations_for_call(&callee_ty); |
210 | self.check_call_arguments(args, ¶m_tys); | 271 | self.check_call_arguments(args, ¶m_tys); |
211 | self.normalize_associated_types_in(ret_ty) | 272 | self.normalize_associated_types_in(ret_ty) |
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 1ad0d8397..80d7ed10e 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs | |||
@@ -81,7 +81,7 @@ impl<'a> InferenceContext<'a> { | |||
81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | 81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); |
82 | let substs = Substs::type_params_for_generics(&generics); | 82 | let substs = Substs::type_params_for_generics(&generics); |
83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | 83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); |
84 | if let Some((AdtId::StructId(struct_id), _)) = ty.as_adt() { | 84 | if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { |
85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); | 85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); |
86 | return Some(ty); | 86 | return Some(ty); |
87 | } else { | 87 | } else { |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 2b9372b4b..f22232324 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -73,6 +73,7 @@ pub use lower::{ | |||
73 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 73 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
74 | 74 | ||
75 | pub use chalk_ir::{BoundVar, DebruijnIndex}; | 75 | pub use chalk_ir::{BoundVar, DebruijnIndex}; |
76 | use itertools::Itertools; | ||
76 | 77 | ||
77 | /// A type constructor or type name: this might be something like the primitive | 78 | /// A type constructor or type name: this might be something like the primitive |
78 | /// type `bool`, a struct like `Vec`, or things like function pointers or | 79 | /// type `bool`, a struct like `Vec`, or things like function pointers or |
@@ -815,6 +816,11 @@ impl Ty { | |||
815 | } | 816 | } |
816 | } | 817 | } |
817 | 818 | ||
819 | /// If this is a `dyn Trait`, returns that trait. | ||
820 | pub fn dyn_trait(&self) -> Option<TraitId> { | ||
821 | self.dyn_trait_ref().map(|it| it.trait_) | ||
822 | } | ||
823 | |||
818 | fn builtin_deref(&self) -> Option<Ty> { | 824 | fn builtin_deref(&self) -> Option<Ty> { |
819 | match self { | 825 | match self { |
820 | Ty::Apply(a_ty) => match a_ty.ctor { | 826 | Ty::Apply(a_ty) => match a_ty.ctor { |
@@ -867,13 +873,56 @@ impl Ty { | |||
867 | } | 873 | } |
868 | } | 874 | } |
869 | 875 | ||
870 | /// If this is a `dyn Trait`, returns that trait. | 876 | pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> { |
871 | pub fn dyn_trait(&self) -> Option<TraitId> { | ||
872 | match self { | 877 | match self { |
873 | Ty::Dyn(predicates) => predicates.iter().find_map(|pred| match pred { | 878 | Ty::Opaque(opaque_ty) => { |
874 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | 879 | let predicates = match opaque_ty.opaque_ty_id { |
875 | _ => None, | 880 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
876 | }), | 881 | db.return_type_impl_traits(func).map(|it| { |
882 | let data = (*it) | ||
883 | .as_ref() | ||
884 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
885 | data.clone().subst(&opaque_ty.parameters) | ||
886 | }) | ||
887 | } | ||
888 | }; | ||
889 | |||
890 | predicates.map(|it| it.value) | ||
891 | } | ||
892 | Ty::Placeholder(id) => { | ||
893 | let generic_params = db.generic_params(id.parent); | ||
894 | let param_data = &generic_params.types[id.local_id]; | ||
895 | match param_data.provenance { | ||
896 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { | ||
897 | let predicates = db | ||
898 | .generic_predicates_for_param(*id) | ||
899 | .into_iter() | ||
900 | .map(|pred| pred.value.clone()) | ||
901 | .collect_vec(); | ||
902 | |||
903 | Some(predicates) | ||
904 | } | ||
905 | _ => None, | ||
906 | } | ||
907 | } | ||
908 | _ => None, | ||
909 | } | ||
910 | } | ||
911 | |||
912 | pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> { | ||
913 | match self { | ||
914 | Ty::Apply(ApplicationTy { ctor: TypeCtor::AssociatedType(type_alias_id), .. }) => { | ||
915 | match type_alias_id.lookup(db.upcast()).container { | ||
916 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
917 | _ => None, | ||
918 | } | ||
919 | } | ||
920 | Ty::Projection(projection_ty) => { | ||
921 | match projection_ty.associated_ty.lookup(db.upcast()).container { | ||
922 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
923 | _ => None, | ||
924 | } | ||
925 | } | ||
877 | _ => None, | 926 | _ => None, |
878 | } | 927 | } |
879 | } | 928 | } |
@@ -1057,5 +1106,5 @@ pub struct ReturnTypeImplTraits { | |||
1057 | 1106 | ||
1058 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 1107 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
1059 | pub(crate) struct ReturnTypeImplTrait { | 1108 | pub(crate) struct ReturnTypeImplTrait { |
1060 | pub(crate) bounds: Binders<Vec<GenericPredicate>>, | 1109 | pub bounds: Binders<Vec<GenericPredicate>>, |
1061 | } | 1110 | } |
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 42713928f..d5154f436 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -337,17 +337,17 @@ impl Ty { | |||
337 | TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); | 337 | TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); |
338 | let ty = if remaining_segments.len() == 1 { | 338 | let ty = if remaining_segments.len() == 1 { |
339 | let segment = remaining_segments.first().unwrap(); | 339 | let segment = remaining_segments.first().unwrap(); |
340 | let associated_ty = associated_type_by_name_including_super_traits( | 340 | let found = associated_type_by_name_including_super_traits( |
341 | ctx.db.upcast(), | 341 | ctx.db, |
342 | trait_ref.trait_, | 342 | trait_ref.clone(), |
343 | &segment.name, | 343 | &segment.name, |
344 | ); | 344 | ); |
345 | match associated_ty { | 345 | match found { |
346 | Some(associated_ty) => { | 346 | Some((super_trait_ref, associated_ty)) => { |
347 | // FIXME handle type parameters on the segment | 347 | // FIXME handle type parameters on the segment |
348 | Ty::Projection(ProjectionTy { | 348 | Ty::Projection(ProjectionTy { |
349 | associated_ty, | 349 | associated_ty, |
350 | parameters: trait_ref.substs, | 350 | parameters: super_trait_ref.substs, |
351 | }) | 351 | }) |
352 | } | 352 | } |
353 | None => { | 353 | None => { |
@@ -467,6 +467,9 @@ impl Ty { | |||
467 | } | 467 | } |
468 | TypeParamLoweringMode::Variable => t.substs.clone(), | 468 | TypeParamLoweringMode::Variable => t.substs.clone(), |
469 | }; | 469 | }; |
470 | // We need to shift in the bound vars, since | ||
471 | // associated_type_shorthand_candidates does not do that | ||
472 | let substs = substs.shift_bound_vars(ctx.in_binders); | ||
470 | // FIXME handle type parameters on the segment | 473 | // FIXME handle type parameters on the segment |
471 | return Some(Ty::Projection(ProjectionTy { | 474 | return Some(Ty::Projection(ProjectionTy { |
472 | associated_ty, | 475 | associated_ty, |
@@ -706,17 +709,17 @@ fn assoc_type_bindings_from_type_bound<'a>( | |||
706 | .flat_map(|segment| segment.args_and_bindings.into_iter()) | 709 | .flat_map(|segment| segment.args_and_bindings.into_iter()) |
707 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) | 710 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) |
708 | .flat_map(move |binding| { | 711 | .flat_map(move |binding| { |
709 | let associated_ty = associated_type_by_name_including_super_traits( | 712 | let found = associated_type_by_name_including_super_traits( |
710 | ctx.db.upcast(), | 713 | ctx.db, |
711 | trait_ref.trait_, | 714 | trait_ref.clone(), |
712 | &binding.name, | 715 | &binding.name, |
713 | ); | 716 | ); |
714 | let associated_ty = match associated_ty { | 717 | let (super_trait_ref, associated_ty) = match found { |
715 | None => return SmallVec::<[GenericPredicate; 1]>::new(), | 718 | None => return SmallVec::<[GenericPredicate; 1]>::new(), |
716 | Some(t) => t, | 719 | Some(t) => t, |
717 | }; | 720 | }; |
718 | let projection_ty = | 721 | let projection_ty = |
719 | ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; | 722 | ProjectionTy { associated_ty, parameters: super_trait_ref.substs.clone() }; |
720 | let mut preds = SmallVec::with_capacity( | 723 | let mut preds = SmallVec::with_capacity( |
721 | binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), | 724 | binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), |
722 | ); | 725 | ); |
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index 1f004bd63..4da2e972b 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs | |||
@@ -633,3 +633,154 @@ where | |||
633 | "### | 633 | "### |
634 | ); | 634 | ); |
635 | } | 635 | } |
636 | |||
637 | #[test] | ||
638 | fn issue_4953() { | ||
639 | assert_snapshot!( | ||
640 | infer(r#" | ||
641 | pub struct Foo(pub i64); | ||
642 | impl Foo { | ||
643 | fn test() -> Self { Self(0i64) } | ||
644 | } | ||
645 | "#), | ||
646 | @r###" | ||
647 | 59..73 '{ Self(0i64) }': Foo | ||
648 | 61..65 'Self': Foo(i64) -> Foo | ||
649 | 61..71 'Self(0i64)': Foo | ||
650 | 66..70 '0i64': i64 | ||
651 | "### | ||
652 | ); | ||
653 | assert_snapshot!( | ||
654 | infer(r#" | ||
655 | pub struct Foo<T>(pub T); | ||
656 | impl Foo<i64> { | ||
657 | fn test() -> Self { Self(0i64) } | ||
658 | } | ||
659 | "#), | ||
660 | @r###" | ||
661 | 65..79 '{ Self(0i64) }': Foo<i64> | ||
662 | 67..71 'Self': Foo<i64>(i64) -> Foo<i64> | ||
663 | 67..77 'Self(0i64)': Foo<i64> | ||
664 | 72..76 '0i64': i64 | ||
665 | "### | ||
666 | ); | ||
667 | } | ||
668 | |||
669 | #[test] | ||
670 | fn issue_4931() { | ||
671 | assert_snapshot!( | ||
672 | infer(r#" | ||
673 | trait Div<T> { | ||
674 | type Output; | ||
675 | } | ||
676 | |||
677 | trait CheckedDiv: Div<()> {} | ||
678 | |||
679 | trait PrimInt: CheckedDiv<Output = ()> { | ||
680 | fn pow(self); | ||
681 | } | ||
682 | |||
683 | fn check<T: PrimInt>(i: T) { | ||
684 | i.pow(); | ||
685 | } | ||
686 | "#), | ||
687 | @r###" | ||
688 | 118..122 'self': Self | ||
689 | 149..150 'i': T | ||
690 | 155..171 '{ ...w(); }': () | ||
691 | 161..162 'i': T | ||
692 | 161..168 'i.pow()': () | ||
693 | "### | ||
694 | ); | ||
695 | } | ||
696 | |||
697 | #[test] | ||
698 | fn issue_4885() { | ||
699 | assert_snapshot!( | ||
700 | infer(r#" | ||
701 | #[lang = "coerce_unsized"] | ||
702 | pub trait CoerceUnsized<T> {} | ||
703 | |||
704 | trait Future { | ||
705 | type Output; | ||
706 | } | ||
707 | trait Foo<R> { | ||
708 | type Bar; | ||
709 | } | ||
710 | fn foo<R, K>(key: &K) -> impl Future<Output = K::Bar> | ||
711 | where | ||
712 | K: Foo<R>, | ||
713 | { | ||
714 | bar(key) | ||
715 | } | ||
716 | fn bar<R, K>(key: &K) -> impl Future<Output = K::Bar> | ||
717 | where | ||
718 | K: Foo<R>, | ||
719 | { | ||
720 | } | ||
721 | "#), | ||
722 | @r###" | ||
723 | 137..140 'key': &K | ||
724 | 199..215 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar> | ||
725 | 205..208 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar> | ||
726 | 205..213 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar> | ||
727 | 209..212 'key': &K | ||
728 | 229..232 'key': &K | ||
729 | 291..294 '{ }': () | ||
730 | "### | ||
731 | ); | ||
732 | } | ||
733 | |||
734 | #[test] | ||
735 | fn issue_4800() { | ||
736 | assert_snapshot!( | ||
737 | infer(r#" | ||
738 | trait Debug {} | ||
739 | |||
740 | struct Foo<T>; | ||
741 | |||
742 | type E1<T> = (T, T, T); | ||
743 | type E2<T> = E1<E1<E1<(T, T, T)>>>; | ||
744 | |||
745 | impl Debug for Foo<E2<()>> {} | ||
746 | |||
747 | struct Request; | ||
748 | |||
749 | pub trait Future { | ||
750 | type Output; | ||
751 | } | ||
752 | |||
753 | pub struct PeerSet<D>; | ||
754 | |||
755 | impl<D> Service<Request> for PeerSet<D> | ||
756 | where | ||
757 | D: Discover, | ||
758 | D::Key: Debug, | ||
759 | { | ||
760 | type Error = (); | ||
761 | type Future = dyn Future<Output = Self::Error>; | ||
762 | |||
763 | fn call(&mut self) -> Self::Future { | ||
764 | loop {} | ||
765 | } | ||
766 | } | ||
767 | |||
768 | pub trait Discover { | ||
769 | type Key; | ||
770 | } | ||
771 | |||
772 | pub trait Service<Request> { | ||
773 | type Error; | ||
774 | type Future: Future<Output = Self::Error>; | ||
775 | fn call(&mut self) -> Self::Future; | ||
776 | } | ||
777 | "#), | ||
778 | @r###" | ||
779 | 380..384 'self': &mut PeerSet<D> | ||
780 | 402..425 '{ ... }': dyn Future<Output = ()> | ||
781 | 412..419 'loop {}': ! | ||
782 | 417..419 '{}': () | ||
783 | 576..580 'self': &mut Self | ||
784 | "### | ||
785 | ); | ||
786 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index e81193a3c..961be4abd 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -2888,3 +2888,226 @@ impl<A: Step> iter::Iterator for ops::Range<A> { | |||
2888 | ); | 2888 | ); |
2889 | assert_eq!(t, "i32"); | 2889 | assert_eq!(t, "i32"); |
2890 | } | 2890 | } |
2891 | |||
2892 | #[test] | ||
2893 | fn infer_closure_arg() { | ||
2894 | assert_snapshot!( | ||
2895 | infer( | ||
2896 | r#" | ||
2897 | //- /lib.rs | ||
2898 | |||
2899 | enum Option<T> { | ||
2900 | None, | ||
2901 | Some(T) | ||
2902 | } | ||
2903 | |||
2904 | fn foo() { | ||
2905 | let s = Option::None; | ||
2906 | let f = |x: Option<i32>| {}; | ||
2907 | (&f)(s) | ||
2908 | } | ||
2909 | "# | ||
2910 | ), | ||
2911 | @r###" | ||
2912 | 137..259 '{ ... }': () | ||
2913 | 159..160 's': Option<i32> | ||
2914 | 163..175 'Option::None': Option<i32> | ||
2915 | 197..198 'f': |Option<i32>| -> () | ||
2916 | 201..220 '|x: Op...2>| {}': |Option<i32>| -> () | ||
2917 | 202..203 'x': Option<i32> | ||
2918 | 218..220 '{}': () | ||
2919 | 238..245 '(&f)(s)': () | ||
2920 | 239..241 '&f': &|Option<i32>| -> () | ||
2921 | 240..241 'f': |Option<i32>| -> () | ||
2922 | 243..244 's': Option<i32> | ||
2923 | "### | ||
2924 | ); | ||
2925 | } | ||
2926 | |||
2927 | #[test] | ||
2928 | fn infer_fn_trait_arg() { | ||
2929 | assert_snapshot!( | ||
2930 | infer( | ||
2931 | r#" | ||
2932 | //- /lib.rs deps:std | ||
2933 | |||
2934 | #[lang = "fn_once"] | ||
2935 | pub trait FnOnce<Args> { | ||
2936 | type Output; | ||
2937 | |||
2938 | extern "rust-call" fn call_once(&self, args: Args) -> Self::Output; | ||
2939 | } | ||
2940 | |||
2941 | #[lang = "fn"] | ||
2942 | pub trait Fn<Args>:FnOnce<Args> { | ||
2943 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
2944 | } | ||
2945 | |||
2946 | enum Option<T> { | ||
2947 | None, | ||
2948 | Some(T) | ||
2949 | } | ||
2950 | |||
2951 | fn foo<F, T>(f: F) -> T | ||
2952 | where | ||
2953 | F: Fn(Option<i32>) -> T, | ||
2954 | { | ||
2955 | let s = None; | ||
2956 | f(s) | ||
2957 | } | ||
2958 | "# | ||
2959 | ), | ||
2960 | @r###" | ||
2961 | 183..187 'self': &Self | ||
2962 | 189..193 'args': Args | ||
2963 | 350..354 'self': &Self | ||
2964 | 356..360 'args': Args | ||
2965 | 515..516 'f': F | ||
2966 | 597..663 '{ ... }': T | ||
2967 | 619..620 's': Option<i32> | ||
2968 | 623..627 'None': Option<i32> | ||
2969 | 645..646 'f': F | ||
2970 | 645..649 'f(s)': T | ||
2971 | 647..648 's': Option<i32> | ||
2972 | "### | ||
2973 | ); | ||
2974 | } | ||
2975 | |||
2976 | #[test] | ||
2977 | fn infer_box_fn_arg() { | ||
2978 | assert_snapshot!( | ||
2979 | infer( | ||
2980 | r#" | ||
2981 | //- /lib.rs deps:std | ||
2982 | |||
2983 | #[lang = "fn_once"] | ||
2984 | pub trait FnOnce<Args> { | ||
2985 | type Output; | ||
2986 | |||
2987 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
2988 | } | ||
2989 | |||
2990 | #[lang = "deref"] | ||
2991 | pub trait Deref { | ||
2992 | type Target: ?Sized; | ||
2993 | |||
2994 | fn deref(&self) -> &Self::Target; | ||
2995 | } | ||
2996 | |||
2997 | #[lang = "owned_box"] | ||
2998 | pub struct Box<T: ?Sized> { | ||
2999 | inner: *mut T, | ||
3000 | } | ||
3001 | |||
3002 | impl<T: ?Sized> Deref for Box<T> { | ||
3003 | type Target = T; | ||
3004 | |||
3005 | fn deref(&self) -> &T { | ||
3006 | &self.inner | ||
3007 | } | ||
3008 | } | ||
3009 | |||
3010 | enum Option<T> { | ||
3011 | None, | ||
3012 | Some(T) | ||
3013 | } | ||
3014 | |||
3015 | fn foo() { | ||
3016 | let s = Option::None; | ||
3017 | let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {}); | ||
3018 | f(&s) | ||
3019 | } | ||
3020 | "# | ||
3021 | ), | ||
3022 | @r###" | ||
3023 | 182..186 'self': Self | ||
3024 | 188..192 'args': Args | ||
3025 | 356..360 'self': &Self | ||
3026 | 622..626 'self': &Box<T> | ||
3027 | 634..685 '{ ... }': &T | ||
3028 | 656..667 '&self.inner': &*mut T | ||
3029 | 657..661 'self': &Box<T> | ||
3030 | 657..667 'self.inner': *mut T | ||
3031 | 812..957 '{ ... }': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | ||
3032 | 834..835 's': Option<i32> | ||
3033 | 838..850 'Option::None': Option<i32> | ||
3034 | 872..873 'f': Box<dyn FnOnce<(&Option<i32>,)>> | ||
3035 | 907..920 'box (|ps| {})': Box<|{unknown}| -> ()> | ||
3036 | 912..919 '|ps| {}': |{unknown}| -> () | ||
3037 | 913..915 'ps': {unknown} | ||
3038 | 917..919 '{}': () | ||
3039 | 938..939 'f': Box<dyn FnOnce<(&Option<i32>,)>> | ||
3040 | 938..943 'f(&s)': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | ||
3041 | 940..942 '&s': &Option<i32> | ||
3042 | 941..942 's': Option<i32> | ||
3043 | "### | ||
3044 | ); | ||
3045 | } | ||
3046 | |||
3047 | #[test] | ||
3048 | fn infer_dyn_fn_output() { | ||
3049 | assert_snapshot!( | ||
3050 | infer( | ||
3051 | r#" | ||
3052 | //- /lib.rs deps:std | ||
3053 | |||
3054 | #[lang = "fn_once"] | ||
3055 | pub trait FnOnce<Args> { | ||
3056 | type Output; | ||
3057 | |||
3058 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
3059 | } | ||
3060 | |||
3061 | #[lang = "fn"] | ||
3062 | pub trait Fn<Args>:FnOnce<Args> { | ||
3063 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
3064 | } | ||
3065 | |||
3066 | #[lang = "deref"] | ||
3067 | pub trait Deref { | ||
3068 | type Target: ?Sized; | ||
3069 | |||
3070 | fn deref(&self) -> &Self::Target; | ||
3071 | } | ||
3072 | |||
3073 | #[lang = "owned_box"] | ||
3074 | pub struct Box<T: ?Sized> { | ||
3075 | inner: *mut T, | ||
3076 | } | ||
3077 | |||
3078 | impl<T: ?Sized> Deref for Box<T> { | ||
3079 | type Target = T; | ||
3080 | |||
3081 | fn deref(&self) -> &T { | ||
3082 | &self.inner | ||
3083 | } | ||
3084 | } | ||
3085 | |||
3086 | fn foo() { | ||
3087 | let f: Box<dyn Fn() -> i32> = box(|| 5); | ||
3088 | let x = f(); | ||
3089 | } | ||
3090 | "# | ||
3091 | ), | ||
3092 | @r###" | ||
3093 | 182..186 'self': Self | ||
3094 | 188..192 'args': Args | ||
3095 | 349..353 'self': &Self | ||
3096 | 355..359 'args': Args | ||
3097 | 523..527 'self': &Self | ||
3098 | 789..793 'self': &Box<T> | ||
3099 | 801..852 '{ ... }': &T | ||
3100 | 823..834 '&self.inner': &*mut T | ||
3101 | 824..828 'self': &Box<T> | ||
3102 | 824..834 'self.inner': *mut T | ||
3103 | 889..990 '{ ... }': () | ||
3104 | 911..912 'f': Box<dyn Fn<(), Output = i32>> | ||
3105 | 937..946 'box(|| 5)': Box<|| -> i32> | ||
3106 | 941..945 '|| 5': || -> i32 | ||
3107 | 944..945 '5': i32 | ||
3108 | 968..969 'x': FnOnce::Output<dyn Fn<(), Output = i32>, ()> | ||
3109 | 972..973 'f': Box<dyn Fn<(), Output = i32>> | ||
3110 | 972..975 'f()': FnOnce::Output<dyn Fn<(), Output = i32>, ()> | ||
3111 | "### | ||
3112 | ); | ||
3113 | } | ||
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 99d7a9616..6f43c3a22 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -2,7 +2,9 @@ | |||
2 | use std::{panic, sync::Arc}; | 2 | use std::{panic, sync::Arc}; |
3 | 3 | ||
4 | use chalk_ir::cast::Cast; | 4 | use chalk_ir::cast::Cast; |
5 | use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; | 5 | use hir_def::{ |
6 | expr::ExprId, lang_item::LangItemTarget, DefWithBodyId, ImplId, TraitId, TypeAliasId, | ||
7 | }; | ||
6 | use ra_db::{impl_intern_key, salsa, CrateId}; | 8 | use ra_db::{impl_intern_key, salsa, CrateId}; |
7 | use ra_prof::profile; | 9 | use ra_prof::profile; |
8 | 10 | ||
@@ -269,6 +271,14 @@ impl FnTrait { | |||
269 | FnTrait::Fn => "fn", | 271 | FnTrait::Fn => "fn", |
270 | } | 272 | } |
271 | } | 273 | } |
274 | |||
275 | pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> { | ||
276 | let target = db.lang_item(krate, self.lang_item_name().into())?; | ||
277 | match target { | ||
278 | LangItemTarget::TraitId(t) => Some(t), | ||
279 | _ => None, | ||
280 | } | ||
281 | } | ||
272 | } | 282 | } |
273 | 283 | ||
274 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 284 | #[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 88a422d2c..6d5f2d46a 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs | |||
@@ -40,7 +40,7 @@ pub(super) fn get_builtin_impls( | |||
40 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { | 40 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { |
41 | for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() | 41 | for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() |
42 | { | 42 | { |
43 | if let Some(actual_trait) = get_fn_trait(db, krate, fn_trait) { | 43 | if let Some(actual_trait) = fn_trait.get_id(db, krate) { |
44 | if trait_ == actual_trait { | 44 | if trait_ == actual_trait { |
45 | let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait }; | 45 | let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait }; |
46 | if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) { | 46 | if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) { |
@@ -128,7 +128,7 @@ fn check_closure_fn_trait_impl_prerequisites( | |||
128 | data: super::ClosureFnTraitImplData, | 128 | data: super::ClosureFnTraitImplData, |
129 | ) -> bool { | 129 | ) -> bool { |
130 | // the respective Fn/FnOnce/FnMut trait needs to exist | 130 | // the respective Fn/FnOnce/FnMut trait needs to exist |
131 | if get_fn_trait(db, krate, data.fn_trait).is_none() { | 131 | if data.fn_trait.get_id(db, krate).is_none() { |
132 | return false; | 132 | return false; |
133 | } | 133 | } |
134 | 134 | ||
@@ -136,7 +136,7 @@ fn check_closure_fn_trait_impl_prerequisites( | |||
136 | // the traits having no type params, FnOnce being a supertrait | 136 | // the traits having no type params, FnOnce being a supertrait |
137 | 137 | ||
138 | // the FnOnce trait needs to exist and have an assoc type named Output | 138 | // the FnOnce trait needs to exist and have an assoc type named Output |
139 | let fn_once_trait = match get_fn_trait(db, krate, super::FnTrait::FnOnce) { | 139 | let fn_once_trait = match (super::FnTrait::FnOnce).get_id(db, krate) { |
140 | Some(t) => t, | 140 | Some(t) => t, |
141 | None => return false, | 141 | None => return false, |
142 | }; | 142 | }; |
@@ -151,7 +151,9 @@ fn closure_fn_trait_impl_datum( | |||
151 | // for some closure |X, Y| -> Z: | 151 | // for some closure |X, Y| -> Z: |
152 | // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } | 152 | // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } |
153 | 153 | ||
154 | let trait_ = get_fn_trait(db, krate, data.fn_trait) // get corresponding fn trait | 154 | let trait_ = data |
155 | .fn_trait | ||
156 | .get_id(db, krate) // get corresponding fn trait | ||
155 | // the existence of the Fn trait has been checked before | 157 | // the existence of the Fn trait has been checked before |
156 | .expect("fn trait for closure impl missing"); | 158 | .expect("fn trait for closure impl missing"); |
157 | 159 | ||
@@ -211,7 +213,7 @@ fn closure_fn_trait_output_assoc_ty_value( | |||
211 | let output_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, num_args.into())); | 213 | let output_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, num_args.into())); |
212 | 214 | ||
213 | let fn_once_trait = | 215 | let fn_once_trait = |
214 | get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist"); | 216 | (super::FnTrait::FnOnce).get_id(db, krate).expect("assoc ty value should not exist"); |
215 | 217 | ||
216 | let output_ty_id = db | 218 | let output_ty_id = db |
217 | .trait_data(fn_once_trait) | 219 | .trait_data(fn_once_trait) |
@@ -360,14 +362,6 @@ fn super_trait_object_unsize_impl_datum( | |||
360 | BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() } | 362 | BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() } |
361 | } | 363 | } |
362 | 364 | ||
363 | fn get_fn_trait(db: &dyn HirDatabase, krate: CrateId, fn_trait: super::FnTrait) -> Option<TraitId> { | ||
364 | let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; | ||
365 | match target { | ||
366 | LangItemTarget::TraitId(t) => Some(t), | ||
367 | _ => None, | ||
368 | } | ||
369 | } | ||
370 | |||
371 | fn get_unsize_trait(db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> { | 365 | fn get_unsize_trait(db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> { |
372 | let target = db.lang_item(krate, "unsize".into())?; | 366 | let target = db.lang_item(krate, "unsize".into())?; |
373 | match target { | 367 | match target { |
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index f98350bf9..c45820ff0 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs | |||
@@ -143,13 +143,14 @@ pub(super) fn find_super_trait_path( | |||
143 | } | 143 | } |
144 | 144 | ||
145 | pub(super) fn associated_type_by_name_including_super_traits( | 145 | pub(super) fn associated_type_by_name_including_super_traits( |
146 | db: &dyn DefDatabase, | 146 | db: &dyn HirDatabase, |
147 | trait_: TraitId, | 147 | trait_ref: TraitRef, |
148 | name: &Name, | 148 | name: &Name, |
149 | ) -> Option<TypeAliasId> { | 149 | ) -> Option<(TraitRef, TypeAliasId)> { |
150 | all_super_traits(db, trait_) | 150 | all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| { |
151 | .into_iter() | 151 | let assoc_type = db.trait_data(t.trait_).associated_type_by_name(name)?; |
152 | .find_map(|t| db.trait_data(t).associated_type_by_name(name)) | 152 | Some((t, assoc_type)) |
153 | }) | ||
153 | } | 154 | } |
154 | 155 | ||
155 | pub(super) fn variant_data(db: &dyn DefDatabase, var: VariantId) -> Arc<VariantData> { | 156 | pub(super) fn variant_data(db: &dyn DefDatabase, var: VariantId) -> Arc<VariantData> { |
@@ -176,6 +177,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { | |||
176 | Generics { def, params: db.generic_params(def), parent_generics } | 177 | Generics { def, params: db.generic_params(def), parent_generics } |
177 | } | 178 | } |
178 | 179 | ||
180 | #[derive(Debug)] | ||
179 | pub(crate) struct Generics { | 181 | pub(crate) struct Generics { |
180 | def: GenericDefId, | 182 | def: GenericDefId, |
181 | pub(crate) params: Arc<GenericParams>, | 183 | pub(crate) params: Arc<GenericParams>, |