]> git.proxmox.com Git - rustc.git/blame - src/librustc_traits/chalk/db.rs
New upstream version 1.45.0+dfsg1
[rustc.git] / src / librustc_traits / chalk / db.rs
CommitLineData
f9f354fc
XL
1//! Provides the `RustIrDatabase` implementation for `chalk-solve`
2//!
3//! The purpose of the `chalk_solve::RustIrDatabase` is to get data about
4//! specific types, such as bounds, where clauses, or fields. This file contains
5//! the minimal logic to assemble the types for `chalk-solve` by calling out to
6//! either the `TyCtxt` (for information about types) or
7//! `crate::chalk::lowering` (to lower rustc types into Chalk types).
8
9use rustc_middle::traits::{ChalkRustDefId as RustDefId, ChalkRustInterner as RustInterner};
10use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
11use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt};
12
13use rustc_hir::def_id::DefId;
14
15use rustc_span::symbol::sym;
16
17use std::fmt;
18use std::sync::Arc;
19
20use crate::chalk::lowering::LowerInto;
21
22pub struct RustIrDatabase<'tcx> {
23 pub tcx: TyCtxt<'tcx>,
24 pub interner: RustInterner<'tcx>,
25}
26
27impl fmt::Debug for RustIrDatabase<'_> {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 write!(f, "RustIrDatabase")
30 }
31}
32
33impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'tcx> {
34 fn interner(&self) -> &RustInterner<'tcx> {
35 &self.interner
36 }
37
38 fn associated_ty_data(
39 &self,
40 assoc_type_id: chalk_ir::AssocTypeId<RustInterner<'tcx>>,
41 ) -> Arc<chalk_rust_ir::AssociatedTyDatum<RustInterner<'tcx>>> {
42 let def_id = match assoc_type_id.0 {
43 RustDefId::AssocTy(def_id) => def_id,
44 _ => bug!("Did not use `AssocTy` variant when expecting associated type."),
45 };
46 let assoc_item = self.tcx.associated_item(def_id);
47 let trait_def_id = match assoc_item.container {
48 AssocItemContainer::TraitContainer(def_id) => def_id,
49 _ => unimplemented!("Not possible??"),
50 };
51 match assoc_item.kind {
52 AssocKind::Type => {}
53 _ => unimplemented!("Not possible??"),
54 }
55 let bound_vars = bound_vars_for_item(self.tcx, def_id);
56 let binders = binders_for(&self.interner, bound_vars);
57 // FIXME(chalk): this really isn't right I don't think. The functions
58 // for GATs are a bit hard to figure out. Are these supposed to be where
59 // clauses or bounds?
60 let predicates = self.tcx.predicates_defined_on(def_id).predicates;
61 let where_clauses: Vec<_> = predicates
62 .iter()
63 .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
64 .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
65
66 Arc::new(chalk_rust_ir::AssociatedTyDatum {
67 trait_id: chalk_ir::TraitId(RustDefId::Trait(trait_def_id)),
68 id: assoc_type_id,
69 name: (),
70 binders: chalk_ir::Binders::new(
71 binders,
72 chalk_rust_ir::AssociatedTyDatumBound { bounds: vec![], where_clauses },
73 ),
74 })
75 }
76
77 fn trait_datum(
78 &self,
79 trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
80 ) -> Arc<chalk_rust_ir::TraitDatum<RustInterner<'tcx>>> {
81 let def_id = match trait_id.0 {
82 RustDefId::Trait(def_id) => def_id,
83 _ => bug!("Did not use `Trait` variant when expecting trait."),
84 };
85 let trait_def = self.tcx.trait_def(def_id);
86
87 let bound_vars = bound_vars_for_item(self.tcx, def_id);
88 let binders = binders_for(&self.interner, bound_vars);
89 let predicates = self.tcx.predicates_defined_on(def_id).predicates;
90 let where_clauses: Vec<_> = predicates
91 .iter()
92 .map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
93 .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
94
95 let well_known =
96 if self.tcx.lang_items().sized_trait().map(|t| def_id == t).unwrap_or(false) {
97 Some(chalk_rust_ir::WellKnownTrait::SizedTrait)
98 } else if self.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) {
99 Some(chalk_rust_ir::WellKnownTrait::CopyTrait)
100 } else if self.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) {
101 Some(chalk_rust_ir::WellKnownTrait::CloneTrait)
102 } else {
103 None
104 };
105 Arc::new(chalk_rust_ir::TraitDatum {
106 id: trait_id,
107 binders: chalk_ir::Binders::new(
108 binders,
109 chalk_rust_ir::TraitDatumBound { where_clauses },
110 ),
111 flags: chalk_rust_ir::TraitFlags {
112 auto: trait_def.has_auto_impl,
113 marker: trait_def.is_marker,
114 upstream: !def_id.is_local(),
115 fundamental: self.tcx.has_attr(def_id, sym::fundamental),
116 non_enumerable: true,
117 coinductive: false,
118 },
119 associated_ty_ids: vec![],
120 well_known,
121 })
122 }
123
124 fn struct_datum(
125 &self,
126 struct_id: chalk_ir::StructId<RustInterner<'tcx>>,
127 ) -> Arc<chalk_rust_ir::StructDatum<RustInterner<'tcx>>> {
128 match struct_id.0 {
129 RustDefId::Adt(adt_def_id) => {
130 let adt_def = self.tcx.adt_def(adt_def_id);
131
132 let bound_vars = bound_vars_for_item(self.tcx, adt_def_id);
133 let binders = binders_for(&self.interner, bound_vars);
134
135 let predicates = self.tcx.predicates_of(adt_def_id).predicates;
136 let where_clauses: Vec<_> = predicates
137 .iter()
138 .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
139 .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner))
140 .collect();
141 let fields = match adt_def.adt_kind() {
142 ty::AdtKind::Struct | ty::AdtKind::Union => {
143 let variant = adt_def.non_enum_variant();
144 variant
145 .fields
146 .iter()
147 .map(|field| {
148 self.tcx
149 .type_of(field.did)
150 .subst(self.tcx, bound_vars)
151 .lower_into(&self.interner)
152 })
153 .collect()
154 }
155 // FIXME(chalk): handle enums; force_impl_for requires this
156 ty::AdtKind::Enum => vec![],
157 };
158 let struct_datum = Arc::new(chalk_rust_ir::StructDatum {
159 id: struct_id,
160 binders: chalk_ir::Binders::new(
161 binders,
162 chalk_rust_ir::StructDatumBound { fields, where_clauses },
163 ),
164 flags: chalk_rust_ir::StructFlags {
165 upstream: !adt_def_id.is_local(),
166 fundamental: adt_def.is_fundamental(),
167 },
168 });
169 struct_datum
170 }
171 RustDefId::Ref(_) => Arc::new(chalk_rust_ir::StructDatum {
172 id: struct_id,
173 binders: chalk_ir::Binders::new(
174 chalk_ir::ParameterKinds::from(
175 &self.interner,
176 vec![
177 chalk_ir::ParameterKind::Lifetime(()),
178 chalk_ir::ParameterKind::Ty(()),
179 ],
180 ),
181 chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
182 ),
183 flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
184 }),
185 RustDefId::Array | RustDefId::Slice => Arc::new(chalk_rust_ir::StructDatum {
186 id: struct_id,
187 binders: chalk_ir::Binders::new(
188 chalk_ir::ParameterKinds::from(
189 &self.interner,
190 Some(chalk_ir::ParameterKind::Ty(())),
191 ),
192 chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
193 ),
194 flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
195 }),
196 RustDefId::Str | RustDefId::Never | RustDefId::FnDef(_) => {
197 Arc::new(chalk_rust_ir::StructDatum {
198 id: struct_id,
199 binders: chalk_ir::Binders::new(
200 chalk_ir::ParameterKinds::new(&self.interner),
201 chalk_rust_ir::StructDatumBound { fields: vec![], where_clauses: vec![] },
202 ),
203 flags: chalk_rust_ir::StructFlags { upstream: false, fundamental: false },
204 })
205 }
206
207 _ => bug!("Used not struct variant when expecting struct variant."),
208 }
209 }
210
211 fn impl_datum(
212 &self,
213 impl_id: chalk_ir::ImplId<RustInterner<'tcx>>,
214 ) -> Arc<chalk_rust_ir::ImplDatum<RustInterner<'tcx>>> {
215 let def_id = match impl_id.0 {
216 RustDefId::Impl(def_id) => def_id,
217 _ => bug!("Did not use `Impl` variant when expecting impl."),
218 };
219 let bound_vars = bound_vars_for_item(self.tcx, def_id);
220 let binders = binders_for(&self.interner, bound_vars);
221
222 let trait_ref = self.tcx.impl_trait_ref(def_id).expect("not an impl");
223 let trait_ref = trait_ref.subst(self.tcx, bound_vars);
224
225 let predicates = self.tcx.predicates_of(def_id).predicates;
226 let where_clauses: Vec<_> = predicates
227 .iter()
228 .map(|(wc, _)| wc.subst(self.tcx, bound_vars))
229 .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
230
231 let value = chalk_rust_ir::ImplDatumBound {
232 trait_ref: trait_ref.lower_into(&self.interner),
233 where_clauses,
234 };
235
236 Arc::new(chalk_rust_ir::ImplDatum {
237 polarity: chalk_rust_ir::Polarity::Positive,
238 binders: chalk_ir::Binders::new(binders, value),
239 impl_type: chalk_rust_ir::ImplType::Local,
240 associated_ty_value_ids: vec![],
241 })
242 }
243
244 fn impls_for_trait(
245 &self,
246 trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
247 parameters: &[chalk_ir::Parameter<RustInterner<'tcx>>],
248 ) -> Vec<chalk_ir::ImplId<RustInterner<'tcx>>> {
249 let def_id: DefId = match trait_id.0 {
250 RustDefId::Trait(def_id) => def_id,
251 _ => bug!("Did not use `Trait` variant when expecting trait."),
252 };
253
254 // FIXME(chalk): use TraitDef::for_each_relevant_impl, but that will
255 // require us to be able to interconvert `Ty<'tcx>`, and we're
256 // not there yet.
257
258 let all_impls = self.tcx.all_impls(def_id);
259 let matched_impls = all_impls.filter(|impl_def_id| {
260 use chalk_ir::could_match::CouldMatch;
261 let trait_ref = self.tcx.impl_trait_ref(*impl_def_id).unwrap();
262 let bound_vars = bound_vars_for_item(self.tcx, *impl_def_id);
263
264 let self_ty = trait_ref.self_ty();
265 let self_ty = self_ty.subst(self.tcx, bound_vars);
266 let lowered_ty = self_ty.lower_into(&self.interner);
267
268 parameters[0].assert_ty_ref(&self.interner).could_match(&self.interner, &lowered_ty)
269 });
270
271 let impls = matched_impls
272 .map(|matched_impl| chalk_ir::ImplId(RustDefId::Impl(matched_impl)))
273 .collect();
274 impls
275 }
276
277 fn impl_provided_for(
278 &self,
279 auto_trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
280 struct_id: chalk_ir::StructId<RustInterner<'tcx>>,
281 ) -> bool {
282 let trait_def_id: DefId = match auto_trait_id.0 {
283 RustDefId::Trait(def_id) => def_id,
284 _ => bug!("Did not use `Trait` variant when expecting trait."),
285 };
286 let adt_def_id: DefId = match struct_id.0 {
287 RustDefId::Adt(def_id) => def_id,
288 _ => bug!("Did not use `Adt` variant when expecting adt."),
289 };
290 let all_impls = self.tcx.all_impls(trait_def_id);
291 for impl_def_id in all_impls {
292 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
293 let self_ty = trait_ref.self_ty();
294 match self_ty.kind {
295 ty::Adt(adt_def, _) => {
296 if adt_def.did == adt_def_id {
297 return true;
298 }
299 }
300 _ => {}
301 }
302 }
303 false
304 }
305
306 fn associated_ty_value(
307 &self,
308 associated_ty_id: chalk_rust_ir::AssociatedTyValueId<RustInterner<'tcx>>,
309 ) -> Arc<chalk_rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
310 let def_id = match associated_ty_id.0 {
311 RustDefId::AssocTy(def_id) => def_id,
312 _ => bug!("Did not use `AssocTy` variant when expecting associated type."),
313 };
314 let assoc_item = self.tcx.associated_item(def_id);
315 let impl_id = match assoc_item.container {
316 AssocItemContainer::TraitContainer(def_id) => def_id,
317 _ => unimplemented!("Not possible??"),
318 };
319 match assoc_item.kind {
320 AssocKind::Type => {}
321 _ => unimplemented!("Not possible??"),
322 }
323 let bound_vars = bound_vars_for_item(self.tcx, def_id);
324 let binders = binders_for(&self.interner, bound_vars);
325 let ty = self.tcx.type_of(def_id);
326
327 Arc::new(chalk_rust_ir::AssociatedTyValue {
328 impl_id: chalk_ir::ImplId(RustDefId::Impl(impl_id)),
329 associated_ty_id: chalk_ir::AssocTypeId(RustDefId::AssocTy(def_id)),
330 value: chalk_ir::Binders::new(
331 binders,
332 chalk_rust_ir::AssociatedTyValueBound { ty: ty.lower_into(&self.interner) },
333 ),
334 })
335 }
336
337 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<RustInterner<'tcx>>> {
338 vec![]
339 }
340
341 fn local_impls_to_coherence_check(
342 &self,
343 _trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
344 ) -> Vec<chalk_ir::ImplId<RustInterner<'tcx>>> {
345 unimplemented!()
346 }
347
348 fn opaque_ty_data(
349 &self,
350 _id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
351 ) -> Arc<chalk_rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> {
352 unimplemented!()
353 }
354
355 /// Since Chalk can't handle all Rust types currently, we have to handle
356 /// some specially for now. Over time, these `Some` returns will change to
357 /// `None` and eventually this function will be removed.
358 fn force_impl_for(
359 &self,
360 well_known: chalk_rust_ir::WellKnownTrait,
361 ty: &chalk_ir::TyData<RustInterner<'tcx>>,
362 ) -> Option<bool> {
363 use chalk_ir::TyData::*;
364 match well_known {
365 chalk_rust_ir::WellKnownTrait::SizedTrait => match ty {
366 Apply(apply) => match apply.name {
367 chalk_ir::TypeName::Struct(chalk_ir::StructId(rust_def_id)) => {
368 use rustc_middle::traits::ChalkRustDefId::*;
369 match rust_def_id {
370 Never | Array | RawPtr | FnDef(_) | Ref(_) => Some(true),
371
372 Adt(adt_def_id) => {
373 let adt_def = self.tcx.adt_def(adt_def_id);
374 match adt_def.adt_kind() {
375 ty::AdtKind::Struct | ty::AdtKind::Union => None,
376 ty::AdtKind::Enum => {
377 let constraint = self.tcx.adt_sized_constraint(adt_def_id);
378 if !constraint.0.is_empty() {
379 unimplemented!()
380 } else {
381 Some(true)
382 }
383 }
384 }
385 }
386
387 Str | Slice => Some(false),
388
389 Trait(_) | Impl(_) | AssocTy(_) => panic!(),
390 }
391 }
392 _ => None,
393 },
394 Dyn(_) | Alias(_) | Placeholder(_) | Function(_) | InferenceVar(_)
395 | BoundVar(_) => None,
396 },
397 chalk_rust_ir::WellKnownTrait::CopyTrait
398 | chalk_rust_ir::WellKnownTrait::CloneTrait => match ty {
399 Apply(apply) => match apply.name {
400 chalk_ir::TypeName::Struct(chalk_ir::StructId(rust_def_id)) => {
401 use rustc_middle::traits::ChalkRustDefId::*;
402 match rust_def_id {
403 Never | RawPtr | Ref(_) | Str | Slice => Some(false),
404 FnDef(_) | Array => Some(true),
405 Adt(adt_def_id) => {
406 let adt_def = self.tcx.adt_def(adt_def_id);
407 match adt_def.adt_kind() {
408 ty::AdtKind::Struct | ty::AdtKind::Union => None,
409 ty::AdtKind::Enum => {
410 let constraint = self.tcx.adt_sized_constraint(adt_def_id);
411 if !constraint.0.is_empty() {
412 unimplemented!()
413 } else {
414 Some(true)
415 }
416 }
417 }
418 }
419 Trait(_) | Impl(_) | AssocTy(_) => panic!(),
420 }
421 }
422 _ => None,
423 },
424 Dyn(_) | Alias(_) | Placeholder(_) | Function(_) | InferenceVar(_)
425 | BoundVar(_) => None,
426 },
427 chalk_rust_ir::WellKnownTrait::DropTrait => None,
428 }
429 }
430
431 fn program_clauses_for_env(
432 &self,
433 environment: &chalk_ir::Environment<RustInterner<'tcx>>,
434 ) -> chalk_ir::ProgramClauses<RustInterner<'tcx>> {
435 chalk_solve::program_clauses_for_env(self, environment)
436 }
437
438 fn well_known_trait_id(
439 &self,
440 well_known_trait: chalk_rust_ir::WellKnownTrait,
441 ) -> Option<chalk_ir::TraitId<RustInterner<'tcx>>> {
442 use chalk_rust_ir::WellKnownTrait::*;
443 let t = match well_known_trait {
444 SizedTrait => self
445 .tcx
446 .lang_items()
447 .sized_trait()
448 .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
449 .unwrap(),
450 CopyTrait => self
451 .tcx
452 .lang_items()
453 .copy_trait()
454 .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
455 .unwrap(),
456 CloneTrait => self
457 .tcx
458 .lang_items()
459 .clone_trait()
460 .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
461 .unwrap(),
462 DropTrait => self
463 .tcx
464 .lang_items()
465 .drop_trait()
466 .map(|t| chalk_ir::TraitId(RustDefId::Trait(t)))
467 .unwrap(),
468 };
469 Some(t)
470 }
471}
472
473/// Creates a `InternalSubsts` that maps each generic parameter to a higher-ranked
474/// var bound at index `0`. For types, we use a `BoundVar` index equal to
475/// the type parameter index. For regions, we use the `BoundRegion::BrNamed`
476/// variant (which has a `DefId`).
477fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
478 InternalSubsts::for_item(tcx, def_id, |param, substs| match param.kind {
479 ty::GenericParamDefKind::Type { .. } => tcx
480 .mk_ty(ty::Bound(
481 ty::INNERMOST,
482 ty::BoundTy {
483 var: ty::BoundVar::from(param.index),
484 kind: ty::BoundTyKind::Param(param.name),
485 },
486 ))
487 .into(),
488
489 ty::GenericParamDefKind::Lifetime => tcx
490 .mk_region(ty::RegionKind::ReLateBound(
491 ty::INNERMOST,
492 ty::BoundRegion::BrAnon(substs.len() as u32),
493 ))
494 .into(),
495
496 ty::GenericParamDefKind::Const => tcx
497 .mk_const(ty::Const {
498 val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
499 ty: tcx.type_of(param.def_id),
500 })
501 .into(),
502 })
503}
504
505fn binders_for<'tcx>(
506 interner: &RustInterner<'tcx>,
507 bound_vars: SubstsRef<'tcx>,
508) -> chalk_ir::ParameterKinds<RustInterner<'tcx>> {
509 chalk_ir::ParameterKinds::from(
510 interner,
511 bound_vars.iter().map(|arg| match arg.unpack() {
512 ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::ParameterKind::Lifetime(()),
513 ty::subst::GenericArgKind::Type(_ty) => chalk_ir::ParameterKind::Ty(()),
514 ty::subst::GenericArgKind::Const(_const) => chalk_ir::ParameterKind::Ty(()),
515 }),
516 )
517}