diff options
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/Cargo.toml | 6 | ||||
-rw-r--r-- | crates/hir_ty/src/autoderef.rs | 2 | ||||
-rw-r--r-- | crates/hir_ty/src/db.rs | 20 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/decl_check.rs | 169 | ||||
-rw-r--r-- | crates/hir_ty/src/display.rs | 15 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/unify.rs | 4 | ||||
-rw-r--r-- | crates/hir_ty/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/hir_ty/src/lower.rs | 103 | ||||
-rw-r--r-- | crates/hir_ty/src/method_resolution.rs | 42 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/macros.rs | 199 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/method_resolution.rs | 37 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/regression.rs | 38 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/simple.rs | 54 | ||||
-rw-r--r-- | crates/hir_ty/src/utils.rs | 54 |
14 files changed, 667 insertions, 77 deletions
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index abc0e7532..66b3418f2 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -18,9 +18,9 @@ ena = "0.14.0" | |||
18 | log = "0.4.8" | 18 | log = "0.4.8" |
19 | rustc-hash = "1.1.0" | 19 | rustc-hash = "1.1.0" |
20 | scoped-tls = "1" | 20 | scoped-tls = "1" |
21 | chalk-solve = { version = "0.60", default-features = false } | 21 | chalk-solve = { version = "0.64", default-features = false } |
22 | chalk-ir = "0.60" | 22 | chalk-ir = "0.64" |
23 | chalk-recursive = "0.60" | 23 | chalk-recursive = "0.64" |
24 | la-arena = { version = "0.2.0", path = "../../lib/arena" } | 24 | la-arena = { version = "0.2.0", path = "../../lib/arena" } |
25 | 25 | ||
26 | stdx = { path = "../stdx", version = "0.0.0" } | 26 | stdx = { path = "../stdx", version = "0.0.0" } |
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs index 71bc436e6..2c07494a9 100644 --- a/crates/hir_ty/src/autoderef.rs +++ b/crates/hir_ty/src/autoderef.rs | |||
@@ -36,6 +36,7 @@ pub(crate) fn deref( | |||
36 | krate: CrateId, | 36 | krate: CrateId, |
37 | ty: InEnvironment<&Canonical<Ty>>, | 37 | ty: InEnvironment<&Canonical<Ty>>, |
38 | ) -> Option<Canonical<Ty>> { | 38 | ) -> Option<Canonical<Ty>> { |
39 | let _p = profile::span("deref"); | ||
39 | if let Some(derefed) = builtin_deref(&ty.goal.value) { | 40 | if let Some(derefed) = builtin_deref(&ty.goal.value) { |
40 | Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }) | 41 | Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }) |
41 | } else { | 42 | } else { |
@@ -56,6 +57,7 @@ fn deref_by_trait( | |||
56 | krate: CrateId, | 57 | krate: CrateId, |
57 | ty: InEnvironment<&Canonical<Ty>>, | 58 | ty: InEnvironment<&Canonical<Ty>>, |
58 | ) -> Option<Canonical<Ty>> { | 59 | ) -> Option<Canonical<Ty>> { |
60 | let _p = profile::span("deref_by_trait"); | ||
59 | let deref_trait = match db.lang_item(krate, "deref".into())? { | 61 | let deref_trait = match db.lang_item(krate, "deref".into())? { |
60 | LangItemTarget::TraitId(it) => it, | 62 | LangItemTarget::TraitId(it) => it, |
61 | _ => return None, | 63 | _ => return None, |
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs index 1690926ad..9da0a02e3 100644 --- a/crates/hir_ty/src/db.rs +++ b/crates/hir_ty/src/db.rs | |||
@@ -70,6 +70,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
70 | fn trait_environment(&self, def: GenericDefId) -> Arc<crate::TraitEnvironment>; | 70 | fn trait_environment(&self, def: GenericDefId) -> Arc<crate::TraitEnvironment>; |
71 | 71 | ||
72 | #[salsa::invoke(crate::lower::generic_defaults_query)] | 72 | #[salsa::invoke(crate::lower::generic_defaults_query)] |
73 | #[salsa::cycle(crate::lower::generic_defaults_recover)] | ||
73 | fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>; | 74 | fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>; |
74 | 75 | ||
75 | #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] | 76 | #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] |
@@ -128,13 +129,21 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
128 | id: chalk_db::AssociatedTyValueId, | 129 | id: chalk_db::AssociatedTyValueId, |
129 | ) -> Arc<chalk_db::AssociatedTyValue>; | 130 | ) -> Arc<chalk_db::AssociatedTyValue>; |
130 | 131 | ||
131 | #[salsa::invoke(crate::traits::trait_solve_query)] | 132 | #[salsa::invoke(trait_solve_wait)] |
133 | #[salsa::transparent] | ||
132 | fn trait_solve( | 134 | fn trait_solve( |
133 | &self, | 135 | &self, |
134 | krate: CrateId, | 136 | krate: CrateId, |
135 | goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, | 137 | goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, |
136 | ) -> Option<crate::Solution>; | 138 | ) -> Option<crate::Solution>; |
137 | 139 | ||
140 | #[salsa::invoke(crate::traits::trait_solve_query)] | ||
141 | fn trait_solve_query( | ||
142 | &self, | ||
143 | krate: CrateId, | ||
144 | goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, | ||
145 | ) -> Option<crate::Solution>; | ||
146 | |||
138 | #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)] | 147 | #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)] |
139 | fn program_clauses_for_chalk_env( | 148 | fn program_clauses_for_chalk_env( |
140 | &self, | 149 | &self, |
@@ -156,6 +165,15 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> | |||
156 | db.infer_query(def) | 165 | db.infer_query(def) |
157 | } | 166 | } |
158 | 167 | ||
168 | fn trait_solve_wait( | ||
169 | db: &dyn HirDatabase, | ||
170 | krate: CrateId, | ||
171 | goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, | ||
172 | ) -> Option<crate::Solution> { | ||
173 | let _p = profile::span("trait_solve::wait"); | ||
174 | db.trait_solve_query(krate, goal) | ||
175 | } | ||
176 | |||
159 | #[test] | 177 | #[test] |
160 | fn hir_database_is_object_safe() { | 178 | fn hir_database_is_object_safe() { |
161 | fn _assert_object_safe(_: &dyn HirDatabase) {} | 179 | fn _assert_object_safe(_: &dyn HirDatabase) {} |
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index 1c9f9ede7..075dc4131 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs | |||
@@ -35,6 +35,8 @@ use crate::{ | |||
35 | }; | 35 | }; |
36 | 36 | ||
37 | mod allow { | 37 | mod allow { |
38 | pub(super) const BAD_STYLE: &str = "bad_style"; | ||
39 | pub(super) const NONSTANDARD_STYLE: &str = "nonstandard_style"; | ||
38 | pub(super) const NON_SNAKE_CASE: &str = "non_snake_case"; | 40 | pub(super) const NON_SNAKE_CASE: &str = "non_snake_case"; |
39 | pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals"; | 41 | pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals"; |
40 | pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; | 42 | pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; |
@@ -83,10 +85,39 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
83 | } | 85 | } |
84 | 86 | ||
85 | /// Checks whether not following the convention is allowed for this item. | 87 | /// Checks whether not following the convention is allowed for this item. |
86 | /// | 88 | fn allowed(&self, id: AttrDefId, allow_name: &str, recursing: bool) -> bool { |
87 | /// Currently this method doesn't check parent attributes. | 89 | let is_allowed = |def_id| { |
88 | fn allowed(&self, id: AttrDefId, allow_name: &str) -> bool { | 90 | let attrs = self.db.attrs(def_id); |
89 | self.db.attrs(id).by_key("allow").tt_values().any(|tt| tt.to_string().contains(allow_name)) | 91 | // don't bug the user about directly no_mangle annotated stuff, they can't do anything about it |
92 | (!recursing && attrs.by_key("no_mangle").exists()) | ||
93 | || attrs.by_key("allow").tt_values().any(|tt| { | ||
94 | let allows = tt.to_string(); | ||
95 | allows.contains(allow_name) | ||
96 | || allows.contains(allow::BAD_STYLE) | ||
97 | || allows.contains(allow::NONSTANDARD_STYLE) | ||
98 | }) | ||
99 | }; | ||
100 | |||
101 | is_allowed(id) | ||
102 | // go upwards one step or give up | ||
103 | || match id { | ||
104 | AttrDefId::ModuleId(m) => m.containing_module(self.db.upcast()).map(|v| v.into()), | ||
105 | AttrDefId::FunctionId(f) => Some(f.lookup(self.db.upcast()).container.into()), | ||
106 | AttrDefId::StaticId(sid) => Some(sid.lookup(self.db.upcast()).container.into()), | ||
107 | AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()), | ||
108 | AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()), | ||
109 | AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()), | ||
110 | // These warnings should not explore macro definitions at all | ||
111 | AttrDefId::MacroDefId(_) => None, | ||
112 | // Will never occur under an enum/struct/union/type alias | ||
113 | AttrDefId::AdtId(_) => None, | ||
114 | AttrDefId::FieldId(_) => None, | ||
115 | AttrDefId::EnumVariantId(_) => None, | ||
116 | AttrDefId::TypeAliasId(_) => None, | ||
117 | AttrDefId::GenericParamId(_) => None, | ||
118 | } | ||
119 | .map(|mid| self.allowed(mid, allow_name, true)) | ||
120 | .unwrap_or(false) | ||
90 | } | 121 | } |
91 | 122 | ||
92 | fn validate_func(&mut self, func: FunctionId) { | 123 | fn validate_func(&mut self, func: FunctionId) { |
@@ -109,7 +140,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
109 | } | 140 | } |
110 | 141 | ||
111 | // Check whether non-snake case identifiers are allowed for this function. | 142 | // Check whether non-snake case identifiers are allowed for this function. |
112 | if self.allowed(func.into(), allow::NON_SNAKE_CASE) { | 143 | if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) { |
113 | return; | 144 | return; |
114 | } | 145 | } |
115 | 146 | ||
@@ -328,8 +359,9 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
328 | fn validate_struct(&mut self, struct_id: StructId) { | 359 | fn validate_struct(&mut self, struct_id: StructId) { |
329 | let data = self.db.struct_data(struct_id); | 360 | let data = self.db.struct_data(struct_id); |
330 | 361 | ||
331 | let non_camel_case_allowed = self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES); | 362 | let non_camel_case_allowed = |
332 | let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE); | 363 | self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES, false); |
364 | let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE, false); | ||
333 | 365 | ||
334 | // Check the structure name. | 366 | // Check the structure name. |
335 | let struct_name = data.name.to_string(); | 367 | let struct_name = data.name.to_string(); |
@@ -461,7 +493,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
461 | let data = self.db.enum_data(enum_id); | 493 | let data = self.db.enum_data(enum_id); |
462 | 494 | ||
463 | // Check whether non-camel case names are allowed for this enum. | 495 | // Check whether non-camel case names are allowed for this enum. |
464 | if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES) { | 496 | if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) { |
465 | return; | 497 | return; |
466 | } | 498 | } |
467 | 499 | ||
@@ -584,7 +616,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
584 | fn validate_const(&mut self, const_id: ConstId) { | 616 | fn validate_const(&mut self, const_id: ConstId) { |
585 | let data = self.db.const_data(const_id); | 617 | let data = self.db.const_data(const_id); |
586 | 618 | ||
587 | if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL) { | 619 | if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { |
588 | return; | 620 | return; |
589 | } | 621 | } |
590 | 622 | ||
@@ -632,7 +664,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
632 | return; | 664 | return; |
633 | } | 665 | } |
634 | 666 | ||
635 | if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL) { | 667 | if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { |
636 | return; | 668 | return; |
637 | } | 669 | } |
638 | 670 | ||
@@ -867,23 +899,116 @@ fn main() { | |||
867 | fn allow_attributes() { | 899 | fn allow_attributes() { |
868 | check_diagnostics( | 900 | check_diagnostics( |
869 | r#" | 901 | r#" |
870 | #[allow(non_snake_case)] | 902 | #[allow(non_snake_case)] |
871 | fn NonSnakeCaseName(SOME_VAR: u8) -> u8{ | 903 | fn NonSnakeCaseName(SOME_VAR: u8) -> u8{ |
872 | let OtherVar = SOME_VAR + 1; | 904 | // cov_flags generated output from elsewhere in this file |
873 | OtherVar | 905 | extern "C" { |
906 | #[no_mangle] | ||
907 | static lower_case: u8; | ||
874 | } | 908 | } |
875 | 909 | ||
876 | #[allow(non_snake_case, non_camel_case_types)] | 910 | let OtherVar = SOME_VAR + 1; |
877 | pub struct some_type { | 911 | OtherVar |
878 | SOME_FIELD: u8, | 912 | } |
879 | SomeField: u16, | 913 | |
914 | #[allow(nonstandard_style)] | ||
915 | mod CheckNonstandardStyle { | ||
916 | fn HiImABadFnName() {} | ||
917 | } | ||
918 | |||
919 | #[allow(bad_style)] | ||
920 | mod CheckBadStyle { | ||
921 | fn HiImABadFnName() {} | ||
922 | } | ||
923 | |||
924 | mod F { | ||
925 | #![allow(non_snake_case)] | ||
926 | fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {} | ||
927 | } | ||
928 | |||
929 | #[allow(non_snake_case, non_camel_case_types)] | ||
930 | pub struct some_type { | ||
931 | SOME_FIELD: u8, | ||
932 | SomeField: u16, | ||
933 | } | ||
934 | |||
935 | #[allow(non_upper_case_globals)] | ||
936 | pub const some_const: u8 = 10; | ||
937 | |||
938 | #[allow(non_upper_case_globals)] | ||
939 | pub static SomeStatic: u8 = 10; | ||
940 | "#, | ||
941 | ); | ||
880 | } | 942 | } |
881 | 943 | ||
882 | #[allow(non_upper_case_globals)] | 944 | #[test] |
883 | pub const some_const: u8 = 10; | 945 | fn allow_attributes_crate_attr() { |
946 | check_diagnostics( | ||
947 | r#" | ||
948 | #![allow(non_snake_case)] | ||
884 | 949 | ||
885 | #[allow(non_upper_case_globals)] | 950 | mod F { |
886 | pub static SomeStatic: u8 = 10; | 951 | fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {} |
952 | } | ||
953 | "#, | ||
954 | ); | ||
955 | } | ||
956 | |||
957 | #[test] | ||
958 | #[ignore] | ||
959 | fn bug_trait_inside_fn() { | ||
960 | // FIXME: | ||
961 | // This is broken, and in fact, should not even be looked at by this | ||
962 | // lint in the first place. There's weird stuff going on in the | ||
963 | // collection phase. | ||
964 | // It's currently being brought in by: | ||
965 | // * validate_func on `a` recursing into modules | ||
966 | // * then it finds the trait and then the function while iterating | ||
967 | // through modules | ||
968 | // * then validate_func is called on Dirty | ||
969 | // * ... which then proceeds to look at some unknown module taking no | ||
970 | // attrs from either the impl or the fn a, and then finally to the root | ||
971 | // module | ||
972 | // | ||
973 | // It should find the attribute on the trait, but it *doesn't even see | ||
974 | // the trait* as far as I can tell. | ||
975 | |||
976 | check_diagnostics( | ||
977 | r#" | ||
978 | trait T { fn a(); } | ||
979 | struct U {} | ||
980 | impl T for U { | ||
981 | fn a() { | ||
982 | // this comes out of bitflags, mostly | ||
983 | #[allow(non_snake_case)] | ||
984 | trait __BitFlags { | ||
985 | const HiImAlsoBad: u8 = 2; | ||
986 | #[inline] | ||
987 | fn Dirty(&self) -> bool { | ||
988 | false | ||
989 | } | ||
990 | } | ||
991 | |||
992 | } | ||
993 | } | ||
994 | "#, | ||
995 | ); | ||
996 | } | ||
997 | |||
998 | #[test] | ||
999 | #[ignore] | ||
1000 | fn bug_traits_arent_checked() { | ||
1001 | // FIXME: Traits and functions in traits aren't currently checked by | ||
1002 | // r-a, even though rustc will complain about them. | ||
1003 | check_diagnostics( | ||
1004 | r#" | ||
1005 | trait BAD_TRAIT { | ||
1006 | // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` | ||
1007 | fn BAD_FUNCTION(); | ||
1008 | // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` | ||
1009 | fn BadFunction(); | ||
1010 | // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function` | ||
1011 | } | ||
887 | "#, | 1012 | "#, |
888 | ); | 1013 | ); |
889 | } | 1014 | } |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index e7c9dabc2..4fb7d9cf2 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -9,6 +9,7 @@ use std::{ | |||
9 | 9 | ||
10 | use chalk_ir::BoundVar; | 10 | use chalk_ir::BoundVar; |
11 | use hir_def::{ | 11 | use hir_def::{ |
12 | body, | ||
12 | db::DefDatabase, | 13 | db::DefDatabase, |
13 | find_path, | 14 | find_path, |
14 | generics::TypeParamProvenance, | 15 | generics::TypeParamProvenance, |
@@ -18,7 +19,7 @@ use hir_def::{ | |||
18 | visibility::Visibility, | 19 | visibility::Visibility, |
19 | AssocContainerId, Lookup, ModuleId, TraitId, | 20 | AssocContainerId, Lookup, ModuleId, TraitId, |
20 | }; | 21 | }; |
21 | use hir_expand::name::Name; | 22 | use hir_expand::{hygiene::Hygiene, name::Name}; |
22 | 23 | ||
23 | use crate::{ | 24 | use crate::{ |
24 | const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id, | 25 | const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id, |
@@ -997,6 +998,18 @@ impl HirDisplay for TypeRef { | |||
997 | write!(f, "dyn ")?; | 998 | write!(f, "dyn ")?; |
998 | f.write_joined(bounds, " + ")?; | 999 | f.write_joined(bounds, " + ")?; |
999 | } | 1000 | } |
1001 | TypeRef::Macro(macro_call) => { | ||
1002 | let macro_call = macro_call.to_node(f.db.upcast()); | ||
1003 | let ctx = body::LowerCtx::with_hygiene(&Hygiene::new_unhygienic()); | ||
1004 | match macro_call.path() { | ||
1005 | Some(path) => match Path::from_src(path, &ctx) { | ||
1006 | Some(path) => path.hir_fmt(f)?, | ||
1007 | None => write!(f, "{{macro}}")?, | ||
1008 | }, | ||
1009 | None => write!(f, "{{macro}}")?, | ||
1010 | } | ||
1011 | write!(f, "!(..)")?; | ||
1012 | } | ||
1000 | TypeRef::Error => write!(f, "{{error}}")?, | 1013 | TypeRef::Error => write!(f, "{{error}}")?, |
1001 | } | 1014 | } |
1002 | Ok(()) | 1015 | Ok(()) |
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index a887e20b0..d8e0b4320 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs | |||
@@ -332,6 +332,10 @@ impl InferenceTable { | |||
332 | | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1), | 332 | | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1), |
333 | _ => true, /* we checked equals_ctor already */ | 333 | _ => true, /* we checked equals_ctor already */ |
334 | } | 334 | } |
335 | } else if let (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) = | ||
336 | (ty1.kind(&Interner), ty2.kind(&Interner)) | ||
337 | { | ||
338 | self.unify_substs(substs1, substs2, depth + 1) | ||
335 | } else { | 339 | } else { |
336 | self.unify_inner_trivial(&ty1, &ty2, depth) | 340 | self.unify_inner_trivial(&ty1, &ty2, depth) |
337 | } | 341 | } |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 113234fa4..0505fa4ae 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -56,6 +56,7 @@ pub use mapping::{ | |||
56 | to_foreign_def_id, to_placeholder_idx, | 56 | to_foreign_def_id, to_placeholder_idx, |
57 | }; | 57 | }; |
58 | pub use traits::TraitEnvironment; | 58 | pub use traits::TraitEnvironment; |
59 | pub use utils::all_super_traits; | ||
59 | pub use walk::TypeWalk; | 60 | pub use walk::TypeWalk; |
60 | 61 | ||
61 | pub use chalk_ir::{ | 62 | pub use chalk_ir::{ |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index a035686bc..c99dd8d0a 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -5,12 +5,14 @@ | |||
5 | //! - Building the type for an item: This happens through the `type_for_def` query. | 5 | //! - Building the type for an item: This happens through the `type_for_def` query. |
6 | //! | 6 | //! |
7 | //! This usually involves resolving names, collecting generic arguments etc. | 7 | //! This usually involves resolving names, collecting generic arguments etc. |
8 | use std::cell::{Cell, RefCell}; | ||
8 | use std::{iter, sync::Arc}; | 9 | use std::{iter, sync::Arc}; |
9 | 10 | ||
10 | use base_db::CrateId; | 11 | use base_db::CrateId; |
11 | use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; | 12 | use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; |
12 | use hir_def::{ | 13 | use hir_def::{ |
13 | adt::StructKind, | 14 | adt::StructKind, |
15 | body::{Expander, LowerCtx}, | ||
14 | builtin_type::BuiltinType, | 16 | builtin_type::BuiltinType, |
15 | generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, | 17 | generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, |
16 | path::{GenericArg, Path, PathSegment, PathSegments}, | 18 | path::{GenericArg, Path, PathSegment, PathSegments}, |
@@ -20,10 +22,11 @@ use hir_def::{ | |||
20 | GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, | 22 | GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, |
21 | TypeAliasId, TypeParamId, UnionId, VariantId, | 23 | TypeAliasId, TypeParamId, UnionId, VariantId, |
22 | }; | 24 | }; |
23 | use hir_expand::name::Name; | 25 | use hir_expand::{name::Name, ExpandResult}; |
24 | use la_arena::ArenaMap; | 26 | use la_arena::ArenaMap; |
25 | use smallvec::SmallVec; | 27 | use smallvec::SmallVec; |
26 | use stdx::impl_from; | 28 | use stdx::impl_from; |
29 | use syntax::ast; | ||
27 | 30 | ||
28 | use crate::{ | 31 | use crate::{ |
29 | db::HirDatabase, | 32 | db::HirDatabase, |
@@ -50,7 +53,7 @@ pub struct TyLoweringContext<'a> { | |||
50 | /// possible currently, so this should be fine for now. | 53 | /// possible currently, so this should be fine for now. |
51 | pub type_param_mode: TypeParamLoweringMode, | 54 | pub type_param_mode: TypeParamLoweringMode, |
52 | pub impl_trait_mode: ImplTraitLoweringMode, | 55 | pub impl_trait_mode: ImplTraitLoweringMode, |
53 | impl_trait_counter: std::cell::Cell<u16>, | 56 | impl_trait_counter: Cell<u16>, |
54 | /// When turning `impl Trait` into opaque types, we have to collect the | 57 | /// When turning `impl Trait` into opaque types, we have to collect the |
55 | /// bounds at the same time to get the IDs correct (without becoming too | 58 | /// bounds at the same time to get the IDs correct (without becoming too |
56 | /// complicated). I don't like using interior mutability (as for the | 59 | /// complicated). I don't like using interior mutability (as for the |
@@ -59,16 +62,17 @@ pub struct TyLoweringContext<'a> { | |||
59 | /// we're grouping the mutable data (the counter and this field) together | 62 | /// we're grouping the mutable data (the counter and this field) together |
60 | /// with the immutable context (the references to the DB and resolver). | 63 | /// with the immutable context (the references to the DB and resolver). |
61 | /// Splitting this up would be a possible fix. | 64 | /// Splitting this up would be a possible fix. |
62 | opaque_type_data: std::cell::RefCell<Vec<ReturnTypeImplTrait>>, | 65 | opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>, |
66 | expander: RefCell<Option<Expander>>, | ||
63 | } | 67 | } |
64 | 68 | ||
65 | impl<'a> TyLoweringContext<'a> { | 69 | impl<'a> TyLoweringContext<'a> { |
66 | pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { | 70 | pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { |
67 | let impl_trait_counter = std::cell::Cell::new(0); | 71 | let impl_trait_counter = Cell::new(0); |
68 | let impl_trait_mode = ImplTraitLoweringMode::Disallowed; | 72 | let impl_trait_mode = ImplTraitLoweringMode::Disallowed; |
69 | let type_param_mode = TypeParamLoweringMode::Placeholder; | 73 | let type_param_mode = TypeParamLoweringMode::Placeholder; |
70 | let in_binders = DebruijnIndex::INNERMOST; | 74 | let in_binders = DebruijnIndex::INNERMOST; |
71 | let opaque_type_data = std::cell::RefCell::new(Vec::new()); | 75 | let opaque_type_data = RefCell::new(Vec::new()); |
72 | Self { | 76 | Self { |
73 | db, | 77 | db, |
74 | resolver, | 78 | resolver, |
@@ -77,6 +81,7 @@ impl<'a> TyLoweringContext<'a> { | |||
77 | impl_trait_counter, | 81 | impl_trait_counter, |
78 | type_param_mode, | 82 | type_param_mode, |
79 | opaque_type_data, | 83 | opaque_type_data, |
84 | expander: RefCell::new(None), | ||
80 | } | 85 | } |
81 | } | 86 | } |
82 | 87 | ||
@@ -86,15 +91,18 @@ impl<'a> TyLoweringContext<'a> { | |||
86 | f: impl FnOnce(&TyLoweringContext) -> T, | 91 | f: impl FnOnce(&TyLoweringContext) -> T, |
87 | ) -> T { | 92 | ) -> T { |
88 | let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); | 93 | let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); |
94 | let expander = self.expander.replace(None); | ||
89 | let new_ctx = Self { | 95 | let new_ctx = Self { |
90 | in_binders: debruijn, | 96 | in_binders: debruijn, |
91 | impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), | 97 | impl_trait_counter: Cell::new(self.impl_trait_counter.get()), |
92 | opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec), | 98 | opaque_type_data: RefCell::new(opaque_ty_data_vec), |
99 | expander: RefCell::new(expander), | ||
93 | ..*self | 100 | ..*self |
94 | }; | 101 | }; |
95 | let result = f(&new_ctx); | 102 | let result = f(&new_ctx); |
96 | self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); | 103 | self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); |
97 | self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); | 104 | self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); |
105 | self.expander.replace(new_ctx.expander.into_inner()); | ||
98 | result | 106 | result |
99 | } | 107 | } |
100 | 108 | ||
@@ -287,6 +295,53 @@ impl<'a> TyLoweringContext<'a> { | |||
287 | } | 295 | } |
288 | } | 296 | } |
289 | } | 297 | } |
298 | TypeRef::Macro(macro_call) => { | ||
299 | let (expander, recursion_start) = { | ||
300 | let mut expander = self.expander.borrow_mut(); | ||
301 | if expander.is_some() { | ||
302 | (Some(expander), false) | ||
303 | } else { | ||
304 | if let Some(module_id) = self.resolver.module() { | ||
305 | *expander = Some(Expander::new( | ||
306 | self.db.upcast(), | ||
307 | macro_call.file_id, | ||
308 | module_id, | ||
309 | )); | ||
310 | (Some(expander), true) | ||
311 | } else { | ||
312 | (None, false) | ||
313 | } | ||
314 | } | ||
315 | }; | ||
316 | let ty = if let Some(mut expander) = expander { | ||
317 | let expander_mut = expander.as_mut().unwrap(); | ||
318 | let macro_call = macro_call.to_node(self.db.upcast()); | ||
319 | match expander_mut.enter_expand::<ast::Type>(self.db.upcast(), macro_call) { | ||
320 | Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { | ||
321 | let ctx = | ||
322 | LowerCtx::new(self.db.upcast(), expander_mut.current_file_id()); | ||
323 | let type_ref = TypeRef::from_ast(&ctx, expanded); | ||
324 | |||
325 | drop(expander); | ||
326 | let ty = self.lower_ty(&type_ref); | ||
327 | |||
328 | self.expander | ||
329 | .borrow_mut() | ||
330 | .as_mut() | ||
331 | .unwrap() | ||
332 | .exit(self.db.upcast(), mark); | ||
333 | Some(ty) | ||
334 | } | ||
335 | _ => None, | ||
336 | } | ||
337 | } else { | ||
338 | None | ||
339 | }; | ||
340 | if recursion_start { | ||
341 | *self.expander.borrow_mut() = None; | ||
342 | } | ||
343 | ty.unwrap_or_else(|| TyKind::Error.intern(&Interner)) | ||
344 | } | ||
290 | TypeRef::Error => TyKind::Error.intern(&Interner), | 345 | TypeRef::Error => TyKind::Error.intern(&Interner), |
291 | }; | 346 | }; |
292 | (ty, res) | 347 | (ty, res) |
@@ -359,17 +414,16 @@ impl<'a> TyLoweringContext<'a> { | |||
359 | self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty); | 414 | self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty); |
360 | let ty = if remaining_segments.len() == 1 { | 415 | let ty = if remaining_segments.len() == 1 { |
361 | let segment = remaining_segments.first().unwrap(); | 416 | let segment = remaining_segments.first().unwrap(); |
362 | let found = associated_type_by_name_including_super_traits( | 417 | let found = self |
363 | self.db, | 418 | .db |
364 | trait_ref, | 419 | .trait_data(trait_ref.hir_trait_id()) |
365 | &segment.name, | 420 | .associated_type_by_name(&segment.name); |
366 | ); | ||
367 | match found { | 421 | match found { |
368 | Some((super_trait_ref, associated_ty)) => { | 422 | Some(associated_ty) => { |
369 | // FIXME handle type parameters on the segment | 423 | // FIXME handle type parameters on the segment |
370 | TyKind::Alias(AliasTy::Projection(ProjectionTy { | 424 | TyKind::Alias(AliasTy::Projection(ProjectionTy { |
371 | associated_ty_id: to_assoc_type_id(associated_ty), | 425 | associated_ty_id: to_assoc_type_id(associated_ty), |
372 | substitution: super_trait_ref.substitution, | 426 | substitution: trait_ref.substitution, |
373 | })) | 427 | })) |
374 | .intern(&Interner) | 428 | .intern(&Interner) |
375 | } | 429 | } |
@@ -1034,6 +1088,27 @@ pub(crate) fn generic_defaults_query( | |||
1034 | defaults | 1088 | defaults |
1035 | } | 1089 | } |
1036 | 1090 | ||
1091 | pub(crate) fn generic_defaults_recover( | ||
1092 | db: &dyn HirDatabase, | ||
1093 | _cycle: &[String], | ||
1094 | def: &GenericDefId, | ||
1095 | ) -> Arc<[Binders<Ty>]> { | ||
1096 | let generic_params = generics(db.upcast(), *def); | ||
1097 | |||
1098 | // we still need one default per parameter | ||
1099 | let defaults = generic_params | ||
1100 | .iter() | ||
1101 | .enumerate() | ||
1102 | .map(|(idx, _)| { | ||
1103 | let ty = TyKind::Error.intern(&Interner); | ||
1104 | |||
1105 | crate::make_only_type_binders(idx, ty) | ||
1106 | }) | ||
1107 | .collect(); | ||
1108 | |||
1109 | defaults | ||
1110 | } | ||
1111 | |||
1037 | fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { | 1112 | fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { |
1038 | let data = db.function_data(def); | 1113 | let data = db.function_data(def); |
1039 | let resolver = def.resolver(db.upcast()); | 1114 | let resolver = def.resolver(db.upcast()); |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index 3693e3284..48bbcfd9f 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -246,29 +246,39 @@ pub struct InherentImpls { | |||
246 | 246 | ||
247 | impl InherentImpls { | 247 | impl InherentImpls { |
248 | pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { | 248 | pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { |
249 | let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default(); | 249 | let mut impls = Self { map: FxHashMap::default() }; |
250 | 250 | ||
251 | let crate_def_map = db.crate_def_map(krate); | 251 | let crate_def_map = db.crate_def_map(krate); |
252 | for (_module_id, module_data) in crate_def_map.modules() { | 252 | collect_def_map(db, &crate_def_map, &mut impls); |
253 | for impl_id in module_data.scope.impls() { | 253 | |
254 | let data = db.impl_data(impl_id); | 254 | return Arc::new(impls); |
255 | if data.target_trait.is_some() { | 255 | |
256 | continue; | 256 | fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut InherentImpls) { |
257 | for (_module_id, module_data) in def_map.modules() { | ||
258 | for impl_id in module_data.scope.impls() { | ||
259 | let data = db.impl_data(impl_id); | ||
260 | if data.target_trait.is_some() { | ||
261 | continue; | ||
262 | } | ||
263 | |||
264 | let self_ty = db.impl_self_ty(impl_id); | ||
265 | let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders()); | ||
266 | if let Some(fp) = fp { | ||
267 | impls.map.entry(fp).or_default().push(impl_id); | ||
268 | } | ||
269 | // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution) | ||
257 | } | 270 | } |
258 | 271 | ||
259 | let self_ty = db.impl_self_ty(impl_id); | 272 | // To better support custom derives, collect impls in all unnamed const items. |
260 | let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders()); | 273 | // const _: () = { ... }; |
261 | if let Some(fp) = fp { | 274 | for konst in module_data.scope.unnamed_consts() { |
262 | map.entry(fp).or_default().push(impl_id); | 275 | let body = db.body(konst.into()); |
276 | for (_, block_def_map) in body.blocks(db.upcast()) { | ||
277 | collect_def_map(db, &block_def_map, impls); | ||
278 | } | ||
263 | } | 279 | } |
264 | // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution) | ||
265 | } | 280 | } |
266 | } | 281 | } |
267 | |||
268 | // NOTE: We're not collecting inherent impls from unnamed consts here, we intentionally only | ||
269 | // support trait impls there. | ||
270 | |||
271 | Arc::new(Self { map }) | ||
272 | } | 282 | } |
273 | 283 | ||
274 | pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { | 284 | pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index b8e373ed8..6588aa46c 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -1074,3 +1074,202 @@ fn macro_in_arm() { | |||
1074 | "#]], | 1074 | "#]], |
1075 | ); | 1075 | ); |
1076 | } | 1076 | } |
1077 | |||
1078 | #[test] | ||
1079 | fn macro_in_type_alias_position() { | ||
1080 | check_infer( | ||
1081 | r#" | ||
1082 | macro_rules! U32 { | ||
1083 | () => { u32 }; | ||
1084 | } | ||
1085 | |||
1086 | trait Foo { | ||
1087 | type Ty; | ||
1088 | } | ||
1089 | |||
1090 | impl<T> Foo for T { | ||
1091 | type Ty = U32!(); | ||
1092 | } | ||
1093 | |||
1094 | type TayTo = U32!(); | ||
1095 | |||
1096 | fn testy() { | ||
1097 | let a: <() as Foo>::Ty; | ||
1098 | let b: TayTo; | ||
1099 | } | ||
1100 | "#, | ||
1101 | expect![[r#" | ||
1102 | 147..196 '{ ...yTo; }': () | ||
1103 | 157..158 'a': u32 | ||
1104 | 185..186 'b': u32 | ||
1105 | "#]], | ||
1106 | ); | ||
1107 | } | ||
1108 | |||
1109 | #[test] | ||
1110 | fn nested_macro_in_type_alias_position() { | ||
1111 | check_infer( | ||
1112 | r#" | ||
1113 | macro_rules! U32Inner2 { | ||
1114 | () => { u32 }; | ||
1115 | } | ||
1116 | |||
1117 | macro_rules! U32Inner1 { | ||
1118 | () => { U32Inner2!() }; | ||
1119 | } | ||
1120 | |||
1121 | macro_rules! U32 { | ||
1122 | () => { U32Inner1!() }; | ||
1123 | } | ||
1124 | |||
1125 | trait Foo { | ||
1126 | type Ty; | ||
1127 | } | ||
1128 | |||
1129 | impl<T> Foo for T { | ||
1130 | type Ty = U32!(); | ||
1131 | } | ||
1132 | |||
1133 | type TayTo = U32!(); | ||
1134 | |||
1135 | fn testy() { | ||
1136 | let a: <() as Foo>::Ty; | ||
1137 | let b: TayTo; | ||
1138 | } | ||
1139 | "#, | ||
1140 | expect![[r#" | ||
1141 | 259..308 '{ ...yTo; }': () | ||
1142 | 269..270 'a': u32 | ||
1143 | 297..298 'b': u32 | ||
1144 | "#]], | ||
1145 | ); | ||
1146 | } | ||
1147 | |||
1148 | #[test] | ||
1149 | fn macros_in_type_alias_position_generics() { | ||
1150 | check_infer( | ||
1151 | r#" | ||
1152 | struct Foo<A, B>(A, B); | ||
1153 | |||
1154 | macro_rules! U32 { | ||
1155 | () => { u32 }; | ||
1156 | } | ||
1157 | |||
1158 | macro_rules! Bar { | ||
1159 | () => { Foo<U32!(), U32!()> }; | ||
1160 | } | ||
1161 | |||
1162 | trait Moo { | ||
1163 | type Ty; | ||
1164 | } | ||
1165 | |||
1166 | impl<T> Moo for T { | ||
1167 | type Ty = Bar!(); | ||
1168 | } | ||
1169 | |||
1170 | type TayTo = Bar!(); | ||
1171 | |||
1172 | fn main() { | ||
1173 | let a: <() as Moo>::Ty; | ||
1174 | let b: TayTo; | ||
1175 | } | ||
1176 | "#, | ||
1177 | expect![[r#" | ||
1178 | 228..277 '{ ...yTo; }': () | ||
1179 | 238..239 'a': Foo<u32, u32> | ||
1180 | 266..267 'b': Foo<u32, u32> | ||
1181 | "#]], | ||
1182 | ); | ||
1183 | } | ||
1184 | |||
1185 | #[test] | ||
1186 | fn macros_in_type_position() { | ||
1187 | check_infer( | ||
1188 | r#" | ||
1189 | struct Foo<A, B>(A, B); | ||
1190 | |||
1191 | macro_rules! U32 { | ||
1192 | () => { u32 }; | ||
1193 | } | ||
1194 | |||
1195 | macro_rules! Bar { | ||
1196 | () => { Foo<U32!(), U32!()> }; | ||
1197 | } | ||
1198 | |||
1199 | fn main() { | ||
1200 | let a: Bar!(); | ||
1201 | } | ||
1202 | "#, | ||
1203 | expect![[r#" | ||
1204 | 133..155 '{ ...!(); }': () | ||
1205 | 143..144 'a': Foo<u32, u32> | ||
1206 | "#]], | ||
1207 | ); | ||
1208 | } | ||
1209 | |||
1210 | #[test] | ||
1211 | fn macros_in_type_generics() { | ||
1212 | check_infer( | ||
1213 | r#" | ||
1214 | struct Foo<A, B>(A, B); | ||
1215 | |||
1216 | macro_rules! U32 { | ||
1217 | () => { u32 }; | ||
1218 | } | ||
1219 | |||
1220 | macro_rules! Bar { | ||
1221 | () => { Foo<U32!(), U32!()> }; | ||
1222 | } | ||
1223 | |||
1224 | trait Moo { | ||
1225 | type Ty; | ||
1226 | } | ||
1227 | |||
1228 | impl<T> Moo for T { | ||
1229 | type Ty = Foo<Bar!(), Bar!()>; | ||
1230 | } | ||
1231 | |||
1232 | type TayTo = Foo<Bar!(), U32!()>; | ||
1233 | |||
1234 | fn main() { | ||
1235 | let a: <() as Moo>::Ty; | ||
1236 | let b: TayTo; | ||
1237 | } | ||
1238 | "#, | ||
1239 | expect![[r#" | ||
1240 | 254..303 '{ ...yTo; }': () | ||
1241 | 264..265 'a': Foo<Foo<u32, u32>, Foo<u32, u32>> | ||
1242 | 292..293 'b': Foo<Foo<u32, u32>, u32> | ||
1243 | "#]], | ||
1244 | ); | ||
1245 | } | ||
1246 | |||
1247 | #[test] | ||
1248 | fn infinitely_recursive_macro_type() { | ||
1249 | check_infer( | ||
1250 | r#" | ||
1251 | struct Bar<T, X>(T, X); | ||
1252 | |||
1253 | macro_rules! Foo { | ||
1254 | () => { Foo!() } | ||
1255 | } | ||
1256 | |||
1257 | macro_rules! U32 { | ||
1258 | () => { u32 } | ||
1259 | } | ||
1260 | |||
1261 | type A = Foo!(); | ||
1262 | type B = Bar<Foo!(), U32!()>; | ||
1263 | |||
1264 | fn main() { | ||
1265 | let a: A; | ||
1266 | let b: B; | ||
1267 | } | ||
1268 | "#, | ||
1269 | expect![[r#" | ||
1270 | 166..197 '{ ...: B; }': () | ||
1271 | 176..177 'a': {unknown} | ||
1272 | 190..191 'b': Bar<{unknown}, u32> | ||
1273 | "#]], | ||
1274 | ); | ||
1275 | } | ||
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index 4b2c82b41..a4c132bc5 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -1294,7 +1294,7 @@ mod b { | |||
1294 | } | 1294 | } |
1295 | 1295 | ||
1296 | #[test] | 1296 | #[test] |
1297 | fn impl_in_unnamed_const() { | 1297 | fn trait_impl_in_unnamed_const() { |
1298 | check_types( | 1298 | check_types( |
1299 | r#" | 1299 | r#" |
1300 | struct S; | 1300 | struct S; |
@@ -1314,3 +1314,38 @@ fn f() { | |||
1314 | "#, | 1314 | "#, |
1315 | ); | 1315 | ); |
1316 | } | 1316 | } |
1317 | |||
1318 | #[test] | ||
1319 | fn inherent_impl_in_unnamed_const() { | ||
1320 | check_types( | ||
1321 | r#" | ||
1322 | struct S; | ||
1323 | |||
1324 | const _: () = { | ||
1325 | impl S { | ||
1326 | fn method(&self) -> u16 { 0 } | ||
1327 | |||
1328 | pub(super) fn super_method(&self) -> u16 { 0 } | ||
1329 | |||
1330 | pub(crate) fn crate_method(&self) -> u16 { 0 } | ||
1331 | |||
1332 | pub fn pub_method(&self) -> u16 { 0 } | ||
1333 | } | ||
1334 | }; | ||
1335 | |||
1336 | fn f() { | ||
1337 | S.method(); | ||
1338 | //^^^^^^^^^^ u16 | ||
1339 | |||
1340 | S.super_method(); | ||
1341 | //^^^^^^^^^^^^^^^^ u16 | ||
1342 | |||
1343 | S.crate_method(); | ||
1344 | //^^^^^^^^^^^^^^^^ u16 | ||
1345 | |||
1346 | S.pub_method(); | ||
1347 | //^^^^^^^^^^^^^^ u16 | ||
1348 | } | ||
1349 | "#, | ||
1350 | ); | ||
1351 | } | ||
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 9cd9f473d..d14f5c9bb 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs | |||
@@ -1012,3 +1012,41 @@ fn lifetime_from_chalk_during_deref() { | |||
1012 | "#, | 1012 | "#, |
1013 | ) | 1013 | ) |
1014 | } | 1014 | } |
1015 | |||
1016 | #[test] | ||
1017 | fn issue_8686() { | ||
1018 | check_infer( | ||
1019 | r#" | ||
1020 | pub trait Try: FromResidual { | ||
1021 | type Output; | ||
1022 | type Residual; | ||
1023 | } | ||
1024 | pub trait FromResidual<R = <Self as Try>::Residual> { | ||
1025 | fn from_residual(residual: R) -> Self; | ||
1026 | } | ||
1027 | |||
1028 | struct ControlFlow<B, C>; | ||
1029 | impl<B, C> Try for ControlFlow<B, C> { | ||
1030 | type Output = C; | ||
1031 | type Residual = ControlFlow<B, !>; | ||
1032 | } | ||
1033 | impl<B, C> FromResidual for ControlFlow<B, C> { | ||
1034 | fn from_residual(r: ControlFlow<B, !>) -> Self { ControlFlow } | ||
1035 | } | ||
1036 | |||
1037 | fn test() { | ||
1038 | ControlFlow::from_residual(ControlFlow::<u32, !>); | ||
1039 | } | ||
1040 | "#, | ||
1041 | expect![[r#" | ||
1042 | 144..152 'residual': R | ||
1043 | 365..366 'r': ControlFlow<B, !> | ||
1044 | 395..410 '{ ControlFlow }': ControlFlow<B, C> | ||
1045 | 397..408 'ControlFlow': ControlFlow<B, C> | ||
1046 | 424..482 '{ ...!>); }': () | ||
1047 | 430..456 'Contro...sidual': fn from_residual<ControlFlow<u32, {unknown}>, ControlFlow<u32, !>>(ControlFlow<u32, !>) -> ControlFlow<u32, {unknown}> | ||
1048 | 430..479 'Contro...2, !>)': ControlFlow<u32, {unknown}> | ||
1049 | 457..478 'Contro...32, !>': ControlFlow<u32, !> | ||
1050 | "#]], | ||
1051 | ); | ||
1052 | } | ||
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 84c5c05fd..0eefd70f2 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -1029,6 +1029,42 @@ fn infer_in_elseif() { | |||
1029 | } | 1029 | } |
1030 | 1030 | ||
1031 | #[test] | 1031 | #[test] |
1032 | fn infer_closure_unify() { | ||
1033 | check_infer( | ||
1034 | r#" | ||
1035 | fn foo(f: bool) { | ||
1036 | let a = |x| x; | ||
1037 | let b = |x| x; | ||
1038 | let id = if f { a } else { b }; | ||
1039 | id(123); | ||
1040 | } | ||
1041 | "#, | ||
1042 | expect![[r#" | ||
1043 | 7..8 'f': bool | ||
1044 | 16..106 '{ ...23); }': () | ||
1045 | 26..27 'a': |i32| -> i32 | ||
1046 | 30..35 '|x| x': |i32| -> i32 | ||
1047 | 31..32 'x': i32 | ||
1048 | 34..35 'x': i32 | ||
1049 | 45..46 'b': |i32| -> i32 | ||
1050 | 49..54 '|x| x': |i32| -> i32 | ||
1051 | 50..51 'x': i32 | ||
1052 | 53..54 'x': i32 | ||
1053 | 64..66 'id': |i32| -> i32 | ||
1054 | 69..90 'if f {... { b }': |i32| -> i32 | ||
1055 | 72..73 'f': bool | ||
1056 | 74..79 '{ a }': |i32| -> i32 | ||
1057 | 76..77 'a': |i32| -> i32 | ||
1058 | 85..90 '{ b }': |i32| -> i32 | ||
1059 | 87..88 'b': |i32| -> i32 | ||
1060 | 96..98 'id': |i32| -> i32 | ||
1061 | 96..103 'id(123)': i32 | ||
1062 | 99..102 '123': i32 | ||
1063 | "#]], | ||
1064 | ) | ||
1065 | } | ||
1066 | |||
1067 | #[test] | ||
1032 | fn infer_if_match_with_return() { | 1068 | fn infer_if_match_with_return() { |
1033 | check_infer( | 1069 | check_infer( |
1034 | r#" | 1070 | r#" |
@@ -1765,6 +1801,24 @@ fn main() { | |||
1765 | } | 1801 | } |
1766 | 1802 | ||
1767 | #[test] | 1803 | #[test] |
1804 | fn shadowing_primitive_with_inner_items() { | ||
1805 | check_types( | ||
1806 | r#" | ||
1807 | struct i32; | ||
1808 | struct Foo; | ||
1809 | |||
1810 | impl i32 { fn foo(&self) -> Foo { Foo } } | ||
1811 | |||
1812 | fn main() { | ||
1813 | fn inner() {} | ||
1814 | let x: i32 = i32; | ||
1815 | x.foo(); | ||
1816 | //^ Foo | ||
1817 | }"#, | ||
1818 | ); | ||
1819 | } | ||
1820 | |||
1821 | #[test] | ||
1768 | fn not_shadowing_primitive_by_module() { | 1822 | fn not_shadowing_primitive_by_module() { |
1769 | check_types( | 1823 | check_types( |
1770 | r#" | 1824 | r#" |
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs index 5f6cb052a..2f490fb92 100644 --- a/crates/hir_ty/src/utils.rs +++ b/crates/hir_ty/src/utils.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | //! Helper functions for working with def, which don't need to be a separate | 1 | //! Helper functions for working with def, which don't need to be a separate |
2 | //! query, but can't be computed directly from `*Data` (ie, which need a `db`). | 2 | //! query, but can't be computed directly from `*Data` (ie, which need a `db`). |
3 | 3 | ||
4 | use std::iter; | ||
5 | |||
4 | use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex}; | 6 | use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex}; |
5 | use hir_def::{ | 7 | use hir_def::{ |
6 | db::DefDatabase, | 8 | db::DefDatabase, |
@@ -14,8 +16,12 @@ use hir_def::{ | |||
14 | AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, | 16 | AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, |
15 | }; | 17 | }; |
16 | use hir_expand::name::{name, Name}; | 18 | use hir_expand::name::{name, Name}; |
19 | use rustc_hash::FxHashSet; | ||
17 | 20 | ||
18 | use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, WhereClause}; | 21 | use crate::{ |
22 | db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, TyKind, | ||
23 | WhereClause, | ||
24 | }; | ||
19 | 25 | ||
20 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 26 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { |
21 | let resolver = trait_.resolver(db); | 27 | let resolver = trait_.resolver(db); |
@@ -78,7 +84,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr | |||
78 | 84 | ||
79 | /// Returns an iterator over the whole super trait hierarchy (including the | 85 | /// Returns an iterator over the whole super trait hierarchy (including the |
80 | /// trait itself). | 86 | /// trait itself). |
81 | pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 87 | pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { |
82 | // we need to take care a bit here to avoid infinite loops in case of cycles | 88 | // we need to take care a bit here to avoid infinite loops in case of cycles |
83 | // (i.e. if we have `trait A: B; trait B: A;`) | 89 | // (i.e. if we have `trait A: B; trait B: A;`) |
84 | let mut result = vec![trait_]; | 90 | let mut result = vec![trait_]; |
@@ -102,25 +108,35 @@ pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<Tra | |||
102 | /// `all_super_traits` is that we keep track of type parameters; for example if | 108 | /// `all_super_traits` is that we keep track of type parameters; for example if |
103 | /// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get | 109 | /// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get |
104 | /// `Self: OtherTrait<i32>`. | 110 | /// `Self: OtherTrait<i32>`. |
105 | pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> { | 111 | pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> SuperTraits { |
106 | // FIXME: replace by Chalk's `super_traits`, maybe make this a query | 112 | SuperTraits { db, seen: iter::once(trait_ref.trait_id).collect(), stack: vec![trait_ref] } |
113 | } | ||
107 | 114 | ||
108 | // we need to take care a bit here to avoid infinite loops in case of cycles | 115 | pub(super) struct SuperTraits<'a> { |
109 | // (i.e. if we have `trait A: B; trait B: A;`) | 116 | db: &'a dyn HirDatabase, |
110 | let mut result = vec![trait_ref]; | 117 | stack: Vec<TraitRef>, |
111 | let mut i = 0; | 118 | seen: FxHashSet<ChalkTraitId>, |
112 | while i < result.len() { | 119 | } |
113 | let t = &result[i]; | 120 | |
114 | // yeah this is quadratic, but trait hierarchies should be flat | 121 | impl<'a> SuperTraits<'a> { |
115 | // enough that this doesn't matter | 122 | fn elaborate(&mut self, trait_ref: &TraitRef) { |
116 | for tt in direct_super_trait_refs(db, t) { | 123 | let mut trait_refs = direct_super_trait_refs(self.db, trait_ref); |
117 | if !result.iter().any(|tr| tr.trait_id == tt.trait_id) { | 124 | trait_refs.retain(|tr| !self.seen.contains(&tr.trait_id)); |
118 | result.push(tt); | 125 | self.stack.extend(trait_refs); |
119 | } | 126 | } |
127 | } | ||
128 | |||
129 | impl<'a> Iterator for SuperTraits<'a> { | ||
130 | type Item = TraitRef; | ||
131 | |||
132 | fn next(&mut self) -> Option<Self::Item> { | ||
133 | if let Some(next) = self.stack.pop() { | ||
134 | self.elaborate(&next); | ||
135 | Some(next) | ||
136 | } else { | ||
137 | None | ||
120 | } | 138 | } |
121 | i += 1; | ||
122 | } | 139 | } |
123 | result | ||
124 | } | 140 | } |
125 | 141 | ||
126 | pub(super) fn associated_type_by_name_including_super_traits( | 142 | pub(super) fn associated_type_by_name_including_super_traits( |
@@ -128,7 +144,7 @@ pub(super) fn associated_type_by_name_including_super_traits( | |||
128 | trait_ref: TraitRef, | 144 | trait_ref: TraitRef, |
129 | name: &Name, | 145 | name: &Name, |
130 | ) -> Option<(TraitRef, TypeAliasId)> { | 146 | ) -> Option<(TraitRef, TypeAliasId)> { |
131 | all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| { | 147 | all_super_trait_refs(db, trait_ref).find_map(|t| { |
132 | let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?; | 148 | let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?; |
133 | Some((t, assoc_type)) | 149 | Some((t, assoc_type)) |
134 | }) | 150 | }) |