aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/traits
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/traits')
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs92
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs231
2 files changed, 277 insertions, 46 deletions
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 1bc0f0713..e05fea843 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -16,10 +16,12 @@ use ra_db::{
16 16
17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
18use crate::{ 18use crate::{
19 db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate, 19 db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
20 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 20 ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
21}; 21};
22 22
23pub(super) mod tls;
24
23#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] 25#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
24pub struct Interner; 26pub struct Interner;
25 27
@@ -33,90 +35,85 @@ impl chalk_ir::interner::Interner for Interner {
33 type Identifier = TypeAliasId; 35 type Identifier = TypeAliasId;
34 type DefId = InternId; 36 type DefId = InternId;
35 37
36 // FIXME: implement these
37 fn debug_struct_id( 38 fn debug_struct_id(
38 _type_kind_id: chalk_ir::StructId<Self>, 39 type_kind_id: StructId,
39 _fmt: &mut fmt::Formatter<'_>, 40 fmt: &mut fmt::Formatter<'_>,
40 ) -> Option<fmt::Result> { 41 ) -> Option<fmt::Result> {
41 None 42 tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
42 } 43 }
43 44
44 fn debug_trait_id( 45 fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
45 _type_kind_id: chalk_ir::TraitId<Self>, 46 tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
46 _fmt: &mut fmt::Formatter<'_>,
47 ) -> Option<fmt::Result> {
48 None
49 } 47 }
50 48
51 fn debug_assoc_type_id( 49 fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
52 _id: chalk_ir::AssocTypeId<Self>, 50 tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
53 _fmt: &mut fmt::Formatter<'_>,
54 ) -> Option<fmt::Result> {
55 None
56 } 51 }
57 52
58 fn debug_alias( 53 fn debug_alias(
59 _projection: &chalk_ir::AliasTy<Self>, 54 alias: &chalk_ir::AliasTy<Interner>,
60 _fmt: &mut fmt::Formatter<'_>, 55 fmt: &mut fmt::Formatter<'_>,
61 ) -> Option<fmt::Result> { 56 ) -> Option<fmt::Result> {
62 None 57 tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt)))
63 } 58 }
64 59
65 fn debug_ty(_ty: &chalk_ir::Ty<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 60 fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
66 None 61 tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt)))
67 } 62 }
68 63
69 fn debug_lifetime( 64 fn debug_lifetime(
70 _lifetime: &chalk_ir::Lifetime<Self>, 65 lifetime: &chalk_ir::Lifetime<Interner>,
71 _fmt: &mut fmt::Formatter<'_>, 66 fmt: &mut fmt::Formatter<'_>,
72 ) -> Option<fmt::Result> { 67 ) -> Option<fmt::Result> {
73 None 68 tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt)))
74 } 69 }
75 70
76 fn debug_parameter( 71 fn debug_parameter(
77 _parameter: &Parameter<Self>, 72 parameter: &Parameter<Interner>,
78 _fmt: &mut fmt::Formatter<'_>, 73 fmt: &mut fmt::Formatter<'_>,
79 ) -> Option<fmt::Result> { 74 ) -> Option<fmt::Result> {
80 None 75 tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt)))
81 } 76 }
82 77
83 fn debug_goal(_goal: &Goal<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 78 fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
84 None 79 tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt)))
85 } 80 }
86 81
87 fn debug_goals( 82 fn debug_goals(
88 _goals: &chalk_ir::Goals<Self>, 83 goals: &chalk_ir::Goals<Interner>,
89 _fmt: &mut fmt::Formatter<'_>, 84 fmt: &mut fmt::Formatter<'_>,
90 ) -> Option<fmt::Result> { 85 ) -> Option<fmt::Result> {
91 None 86 tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt)))
92 } 87 }
93 88
94 fn debug_program_clause_implication( 89 fn debug_program_clause_implication(
95 _pci: &chalk_ir::ProgramClauseImplication<Self>, 90 pci: &chalk_ir::ProgramClauseImplication<Interner>,
96 _fmt: &mut fmt::Formatter<'_>, 91 fmt: &mut fmt::Formatter<'_>,
97 ) -> Option<fmt::Result> { 92 ) -> Option<fmt::Result> {
98 None 93 tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt)))
99 } 94 }
100 95
101 fn debug_application_ty( 96 fn debug_application_ty(
102 _application_ty: &chalk_ir::ApplicationTy<Self>, 97 application_ty: &chalk_ir::ApplicationTy<Interner>,
103 _fmt: &mut fmt::Formatter<'_>, 98 fmt: &mut fmt::Formatter<'_>,
104 ) -> Option<fmt::Result> { 99 ) -> Option<fmt::Result> {
105 None 100 tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt)))
106 } 101 }
107 102
108 fn debug_substitution( 103 fn debug_substitution(
109 _substitution: &chalk_ir::Substitution<Self>, 104 substitution: &chalk_ir::Substitution<Interner>,
110 _fmt: &mut fmt::Formatter<'_>, 105 fmt: &mut fmt::Formatter<'_>,
111 ) -> Option<fmt::Result> { 106 ) -> Option<fmt::Result> {
112 None 107 tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt)))
113 } 108 }
114 109
115 fn debug_separator_trait_ref( 110 fn debug_separator_trait_ref(
116 _separator_trait_ref: &chalk_ir::SeparatorTraitRef<Self>, 111 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
117 _fmt: &mut fmt::Formatter<'_>, 112 fmt: &mut fmt::Formatter<'_>,
118 ) -> Option<fmt::Result> { 113 ) -> Option<fmt::Result> {
119 None 114 tls::with_current_program(|prog| {
115 Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt))
116 })
120 } 117 }
121 118
122 fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { 119 fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {
@@ -650,19 +647,22 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
650 debug!("impls_for_trait {:?}", trait_id); 647 debug!("impls_for_trait {:?}", trait_id);
651 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); 648 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
652 649
650 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
651
652 let self_ty_fp = TyFingerprint::for_impl(&ty);
653
653 // Note: Since we're using impls_for_trait, only impls where the trait 654 // Note: Since we're using impls_for_trait, only impls where the trait
654 // can be resolved should ever reach Chalk. `impl_datum` relies on that 655 // can be resolved should ever reach Chalk. `impl_datum` relies on that
655 // and will panic if the trait can't be resolved. 656 // and will panic if the trait can't be resolved.
656 let mut result: Vec<_> = self 657 let mut result: Vec<_> = self
657 .db 658 .db
658 .impls_for_trait(self.krate, trait_) 659 .impls_for_trait(self.krate, trait_, self_ty_fp)
659 .iter() 660 .iter()
660 .copied() 661 .copied()
661 .map(Impl::ImplDef) 662 .map(Impl::ImplDef)
662 .map(|impl_| impl_.to_chalk(self.db)) 663 .map(|impl_| impl_.to_chalk(self.db))
663 .collect(); 664 .collect();
664 665
665 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
666 let arg: Option<Ty> = 666 let arg: Option<Ty> =
667 parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone())); 667 parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone()));
668 668
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs
new file mode 100644
index 000000000..d9bbb54a5
--- /dev/null
+++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs
@@ -0,0 +1,231 @@
1//! Implementation of Chalk debug helper functions using TLS.
2use std::fmt;
3
4use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName};
5
6use super::{from_chalk, Interner};
7use crate::{db::HirDatabase, CallableDef, TypeCtor};
8use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
9
10pub use unsafe_tls::{set_current_program, with_current_program};
11
12pub struct DebugContext<'a>(&'a (dyn HirDatabase + 'a));
13
14impl DebugContext<'_> {
15 pub fn debug_struct_id(
16 &self,
17 id: super::StructId,
18 f: &mut fmt::Formatter<'_>,
19 ) -> Result<(), fmt::Error> {
20 let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Struct(id));
21 match type_ctor {
22 TypeCtor::Bool => write!(f, "bool")?,
23 TypeCtor::Char => write!(f, "char")?,
24 TypeCtor::Int(t) => write!(f, "{}", t)?,
25 TypeCtor::Float(t) => write!(f, "{}", t)?,
26 TypeCtor::Str => write!(f, "str")?,
27 TypeCtor::Slice => write!(f, "slice")?,
28 TypeCtor::Array => write!(f, "array")?,
29 TypeCtor::RawPtr(m) => write!(f, "*{}", m.as_keyword_for_ptr())?,
30 TypeCtor::Ref(m) => write!(f, "&{}", m.as_keyword_for_ref())?,
31 TypeCtor::Never => write!(f, "!")?,
32 TypeCtor::Tuple { .. } => {
33 write!(f, "()")?;
34 }
35 TypeCtor::FnPtr { .. } => {
36 write!(f, "fn")?;
37 }
38 TypeCtor::FnDef(def) => {
39 let name = match def {
40 CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(),
41 CallableDef::StructId(s) => self.0.struct_data(s).name.clone(),
42 CallableDef::EnumVariantId(e) => {
43 let enum_data = self.0.enum_data(e.parent);
44 enum_data.variants[e.local_id].name.clone()
45 }
46 };
47 match def {
48 CallableDef::FunctionId(_) => write!(f, "{{fn {}}}", name)?,
49 CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
50 write!(f, "{{ctor {}}}", name)?
51 }
52 }
53 }
54 TypeCtor::Adt(def_id) => {
55 let name = match def_id {
56 AdtId::StructId(it) => self.0.struct_data(it).name.clone(),
57 AdtId::UnionId(it) => self.0.union_data(it).name.clone(),
58 AdtId::EnumId(it) => self.0.enum_data(it).name.clone(),
59 };
60 write!(f, "{}", name)?;
61 }
62 TypeCtor::AssociatedType(type_alias) => {
63 let trait_ = match type_alias.lookup(self.0.upcast()).container {
64 AssocContainerId::TraitId(it) => it,
65 _ => panic!("not an associated type"),
66 };
67 let trait_name = self.0.trait_data(trait_).name.clone();
68 let name = self.0.type_alias_data(type_alias).name.clone();
69 write!(f, "{}::{}", trait_name, name)?;
70 }
71 TypeCtor::Closure { def, expr } => {
72 write!(f, "{{closure {:?} in {:?}}}", expr.into_raw(), def)?;
73 }
74 }
75 Ok(())
76 }
77
78 pub fn debug_trait_id(
79 &self,
80 id: super::TraitId,
81 fmt: &mut fmt::Formatter<'_>,
82 ) -> Result<(), fmt::Error> {
83 let trait_: hir_def::TraitId = from_chalk(self.0, id);
84 let trait_data = self.0.trait_data(trait_);
85 write!(fmt, "{}", trait_data.name)
86 }
87
88 pub fn debug_assoc_type_id(
89 &self,
90 id: super::AssocTypeId,
91 fmt: &mut fmt::Formatter<'_>,
92 ) -> Result<(), fmt::Error> {
93 let type_alias: TypeAliasId = from_chalk(self.0, id);
94 let type_alias_data = self.0.type_alias_data(type_alias);
95 let trait_ = match type_alias.lookup(self.0.upcast()).container {
96 AssocContainerId::TraitId(t) => t,
97 _ => panic!("associated type not in trait"),
98 };
99 let trait_data = self.0.trait_data(trait_);
100 write!(fmt, "{}::{}", trait_data.name, type_alias_data.name)
101 }
102
103 pub fn debug_alias(
104 &self,
105 alias: &AliasTy<Interner>,
106 fmt: &mut fmt::Formatter<'_>,
107 ) -> Result<(), fmt::Error> {
108 let type_alias: TypeAliasId = from_chalk(self.0, alias.associated_ty_id);
109 let type_alias_data = self.0.type_alias_data(type_alias);
110 let trait_ = match type_alias.lookup(self.0.upcast()).container {
111 AssocContainerId::TraitId(t) => t,
112 _ => panic!("associated type not in trait"),
113 };
114 let trait_data = self.0.trait_data(trait_);
115 let params = alias.substitution.parameters(&Interner);
116 write!(
117 fmt,
118 "<{:?} as {}<{:?}>>::{}",
119 &params[0],
120 trait_data.name,
121 &params[1..],
122 type_alias_data.name
123 )
124 }
125
126 pub fn debug_ty(
127 &self,
128 ty: &chalk_ir::Ty<Interner>,
129 fmt: &mut fmt::Formatter<'_>,
130 ) -> Result<(), fmt::Error> {
131 write!(fmt, "{:?}", ty.data(&Interner))
132 }
133
134 pub fn debug_lifetime(
135 &self,
136 lifetime: &Lifetime<Interner>,
137 fmt: &mut fmt::Formatter<'_>,
138 ) -> Result<(), fmt::Error> {
139 write!(fmt, "{:?}", lifetime.data(&Interner))
140 }
141
142 pub fn debug_parameter(
143 &self,
144 parameter: &Parameter<Interner>,
145 fmt: &mut fmt::Formatter<'_>,
146 ) -> Result<(), fmt::Error> {
147 write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())
148 }
149
150 pub fn debug_goal(
151 &self,
152 goal: &Goal<Interner>,
153 fmt: &mut fmt::Formatter<'_>,
154 ) -> Result<(), fmt::Error> {
155 let goal_data = goal.data(&Interner);
156 write!(fmt, "{:?}", goal_data)
157 }
158
159 pub fn debug_goals(
160 &self,
161 goals: &Goals<Interner>,
162 fmt: &mut fmt::Formatter<'_>,
163 ) -> Result<(), fmt::Error> {
164 write!(fmt, "{:?}", goals.debug(&Interner))
165 }
166
167 pub fn debug_program_clause_implication(
168 &self,
169 pci: &ProgramClauseImplication<Interner>,
170 fmt: &mut fmt::Formatter<'_>,
171 ) -> Result<(), fmt::Error> {
172 write!(fmt, "{:?}", pci.debug(&Interner))
173 }
174
175 pub fn debug_application_ty(
176 &self,
177 application_ty: &chalk_ir::ApplicationTy<Interner>,
178 fmt: &mut fmt::Formatter<'_>,
179 ) -> Result<(), fmt::Error> {
180 write!(fmt, "{:?}", application_ty.debug(&Interner))
181 }
182
183 pub fn debug_substitution(
184 &self,
185 substitution: &chalk_ir::Substitution<Interner>,
186 fmt: &mut fmt::Formatter<'_>,
187 ) -> Result<(), fmt::Error> {
188 write!(fmt, "{:?}", substitution.debug(&Interner))
189 }
190
191 pub fn debug_separator_trait_ref(
192 &self,
193 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
194 fmt: &mut fmt::Formatter<'_>,
195 ) -> Result<(), fmt::Error> {
196 write!(fmt, "{:?}", separator_trait_ref.debug(&Interner))
197 }
198}
199
200mod unsafe_tls {
201 use super::DebugContext;
202 use crate::db::HirDatabase;
203 use scoped_tls::scoped_thread_local;
204
205 scoped_thread_local!(static PROGRAM: DebugContext);
206
207 pub fn with_current_program<R>(
208 op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R,
209 ) -> R {
210 if PROGRAM.is_set() {
211 PROGRAM.with(|prog| op(Some(prog)))
212 } else {
213 op(None)
214 }
215 }
216
217 pub fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R
218 where
219 OP: FnOnce() -> R,
220 {
221 let ctx = DebugContext(p);
222 // we're transmuting the lifetime in the DebugContext to static. This is
223 // fine because we only keep the reference for the lifetime of this
224 // function, *and* the only way to access the context is through
225 // `with_current_program`, which hides the lifetime through the `for`
226 // type.
227 let static_p: &DebugContext<'static> =
228 unsafe { std::mem::transmute::<&DebugContext, &DebugContext<'static>>(&ctx) };
229 PROGRAM.set(static_p, || op())
230 }
231}