1use super::{
2 term,
3 util::{ptr_to_name, try_make_int_or_float_term, var_name},
4};
5use crate::{
6 ds::vec::BoxedSlice,
7 etc::util::{push_colon_path, IntoPathSegments},
8 semantic::{
9 basic_traits::{EvaluateArrayLength, RawScope, Scope, Scoping},
10 entry::GlobalCx,
11 tree::ArrayLen,
12 },
13 ClauseIn, ExprIn, Map, NameIn, PredicateIn, Set, TermIn, TriResult,
14};
15use logic_eval::{Clause, ClauseIter, Database, Expr, Name, ProveCx, Term, VAR_PREFIX};
16use std::{borrow, hash::Hash, iter, ops};
17use syn_locator::Locate;
18
19const AUTO_VAR_PREFIX: &str = "$#";
21const CUSTOM_PREFIX_LETTERS: [char; 1] = ['#' ];
22const _: () = assert!(VAR_PREFIX == '$');
23
24pub(crate) trait Host<'gcx>: Scoping + EvaluateArrayLength<'gcx> {
25 fn ident_to_npath(&mut self, ident: &syn::Ident) -> TriResult<String, ()>;
26}
27
28pub(super) struct HostWrapper<'a, 'gcx, H> {
29 inner: &'a mut H,
30 scope_stack: Vec<RawScope>,
31 gcx: &'gcx GlobalCx<'gcx>,
32}
33
34impl<'a, 'gcx, H: Host<'gcx>> HostWrapper<'a, 'gcx, H> {
35 pub(super) fn new(gcx: &'gcx GlobalCx<'gcx>, host: &'a mut H) -> Self {
36 Self {
37 inner: host,
38 scope_stack: Vec::new(),
39 gcx,
40 }
41 }
42
43 fn on_enter_scope(&mut self, scope: Scope) {
44 self.inner.on_enter_scope(scope);
45 self.scope_stack.push(scope.into_raw());
46 }
47
48 fn on_exit_scope(&mut self) {
49 let raw_scope = self.scope_stack.pop().unwrap();
50 let exit_scope = Scope::from_raw(raw_scope);
51 self.inner.on_exit_scope(exit_scope);
52
53 if let Some(raw_scope) = self.scope_stack.last() {
54 let reenter_scope = Scope::from_raw(*raw_scope);
55 self.inner.on_enter_scope(reenter_scope);
56 }
57 }
58
59 pub(super) fn ident_to_term(
63 &mut self,
64 ident: &syn::Ident,
65 arg: TermIn<'gcx>,
66 ) -> TriResult<TermIn<'gcx>, ()> {
67 let npath = self.inner.ident_to_npath(ident)?;
68
69 if let Some(term) = try_make_int_or_float_term(&npath, self.gcx) {
71 debug_assert!(arg.args.is_empty());
72 return Ok(term);
73 }
74
75 if ["bool", "char"].contains(&npath.as_str()) {
77 debug_assert!(arg.args.is_empty());
78 return Ok(Term {
79 functor: Name::with_intern(&npath, self.gcx),
80 args: [].into(),
81 });
82 }
83
84 let num_seg = npath.segments().count();
85
86 let term = match num_seg as u32 {
87 0 => unreachable!(),
88 1 => Term {
89 functor: Name::with_intern(&npath, self.gcx),
90 args: [arg].into(),
91 },
92 2.. => {
93 let empty_arg = || term::arg_n([].into(), self.gcx);
94
95 let elems: Vec<TermIn<'gcx>> = npath
96 .segments()
97 .take(num_seg - 1)
98 .map(|segment| Term {
99 functor: Name::with_intern(segment, self.gcx),
100 args: [empty_arg()].into(),
101 })
102 .chain(iter::once(Term {
103 functor: Name::with_intern(npath.segments().last().unwrap(), self.gcx),
104 args: [arg].into(),
105 }))
106 .collect();
107
108 term::list_n(elems, self.gcx)
109 }
110 };
111 Ok(term)
112 }
113}
114
115impl<'gcx, H: Host<'gcx>> Host<'gcx> for HostWrapper<'_, 'gcx, H> {
116 fn ident_to_npath(&mut self, ident: &syn::Ident) -> TriResult<String, ()> {
117 Host::ident_to_npath(self.inner, ident)
118 }
119}
120
121impl<'gcx, H: Host<'gcx>> Scoping for HostWrapper<'_, 'gcx, H> {
122 fn on_enter_scope(&mut self, scope: Scope) {
123 <Self>::on_enter_scope(self, scope)
124 }
125
126 fn on_exit_scope(&mut self, _: Scope) {
127 <Self>::on_exit_scope(self)
128 }
129}
130
131impl<'gcx, H: Host<'gcx>> EvaluateArrayLength<'gcx> for HostWrapper<'_, 'gcx, H> {
132 fn eval_array_len(&mut self, expr: &syn::Expr) -> TriResult<crate::ArrayLen, ()> {
133 EvaluateArrayLength::eval_array_len(self.inner, expr)
134 }
135}
136
137trait Loadable {}
138impl Loadable for syn::File {}
139impl Loadable for syn::Item {}
140impl Loadable for syn::ItemImpl {}
141
142#[derive(Debug)]
145pub struct ImplLogic<'gcx> {
146 gcx: &'gcx GlobalCx<'gcx>,
147
148 db: DatabaseWrapper<'gcx>,
149
150 loaded: Set<*const ()>,
153
154 default_generics: DefaultGenericMap<'gcx>,
156}
157
158impl<'gcx> ImplLogic<'gcx> {
159 pub(crate) fn new(gcx: &'gcx GlobalCx<'gcx>) -> Self {
160 Self {
161 gcx,
162 db: DatabaseWrapper::new(gcx),
163 loaded: Set::default(),
164 default_generics: Map::default(),
165 }
166 }
167
168 pub fn query(&mut self, expr: ExprIn<'gcx>) -> ProveCx<'_, 'gcx, GlobalCx<'gcx>> {
169 self.db.query(expr)
170 }
171
172 pub fn clauses(&self) -> ClauseIter<'_, 'gcx, GlobalCx<'gcx>> {
173 self.db.clauses()
174 }
175
176 pub fn to_prolog(&self) -> String {
177 self.db.to_prolog()
178 }
179
180 pub fn insert_clause(&mut self, clause: ClauseIn<'gcx>) {
181 self.db.insert_clause(clause);
182 }
183
184 pub fn commit(&mut self) {
185 self.db.commit();
186 }
187
188 pub(crate) fn load_file<H: Host<'gcx>>(
190 &mut self,
191 host: &mut H,
192 file: &syn::File,
193 ) -> TriResult<(), ()> {
194 let gcx = self.gcx;
195 LoadCx {
196 gcx,
197 logic: self,
198 host: HostWrapper::new(gcx, host),
199 }
200 .load_file(file)
201 }
202
203 pub(crate) fn load_item_impl<H: Host<'gcx>>(
204 &mut self,
205 item_impl: &syn::ItemImpl,
206 host: &mut H,
207 ) -> TriResult<(), ()> {
208 let gcx = self.gcx;
209 LoadCx {
210 gcx,
211 logic: self,
212 host: HostWrapper::new(gcx, host),
213 }
214 .load_item_impl(item_impl)
215 }
216}
217
218struct LoadCx<'a, 'gcx, H> {
219 gcx: &'gcx GlobalCx<'gcx>,
220 logic: &'a mut ImplLogic<'gcx>,
221 host: HostWrapper<'a, 'gcx, H>,
222}
223
224impl<'a, 'gcx, H: Host<'gcx>> LoadCx<'a, 'gcx, H> {
225 fn load_file(&mut self, file: &syn::File) -> TriResult<(), ()> {
226 if self.has_loaded(file) {
227 return Ok(());
228 }
229
230 for item in &file.items {
231 self.load_item(item)?;
232 }
233
234 self.save_change(file);
235 Ok(())
236 }
237
238 fn load_item(&mut self, item: &syn::Item) -> TriResult<(), ()> {
239 if self.has_loaded(item) {
240 return Ok(());
241 }
242
243 match item {
244 syn::Item::Impl(v) => self.load_item_impl(v)?,
245 syn::Item::Mod(v) => self.load_item_mod(v)?,
246 syn::Item::Struct(v) => self.load_item_struct(v)?,
247 syn::Item::Trait(v) => self.load_item_trait(v)?,
248 _ => {}
249 }
250
251 self.save_change(item);
252 Ok(())
253 }
254
255 fn load_item_impl(&mut self, item_impl: &syn::ItemImpl) -> TriResult<(), ()> {
264 if self.has_loaded(item_impl) {
265 return Ok(());
266 }
267
268 let mut bound = Bound::new(self.gcx);
270 bound.push_generics(&item_impl.generics, &mut self.host)?;
271
272 let self_ty = Finder::new(self.gcx, &mut self.host, &mut bound)
274 .with_default_generic_context(&self.logic.default_generics, None)
275 .type_to_term(&item_impl.self_ty)?;
276
277 let (impl_, trait_) = if let Some((_, path, _)) = &item_impl.trait_ {
279 let trait_ = Finder::new(self.gcx, &mut self.host, &mut bound)
280 .with_default_generic_context(&self.logic.default_generics, Some(self_ty.clone()))
281 .path_to_term(path)?;
282 let impl_ = term::impl_2(self_ty.clone(), trait_.clone(), self.gcx);
283 (impl_, Some(trait_))
284 } else {
285 let impl_ = term::impl_1(self_ty.clone(), self.gcx);
286 (impl_, None)
287 };
288
289 self.logic.db.insert_clause(Clause {
291 head: impl_.clone(),
292 body: bound.take_bound_expr(),
293 });
294
295 if let Some(trait_) = trait_ {
298 LoadTraitImplItemCx {
299 gcx: self.gcx,
300 logic: self.logic,
301 host: &mut self.host,
302 bound: &mut bound,
303 self_ty: &self_ty,
304 trait_: &trait_,
305 }
306 .load_impl_items(&item_impl.items)?;
307 } else {
308 LoadInherentImplItemCx {
309 gcx: self.gcx,
310 logic: self.logic,
311 host: &mut self.host,
312 bound: &mut bound,
313 self_ty: &self_ty,
314 impl_: &impl_,
315 }
316 .load_impl_items(&item_impl.items)?;
317 }
318
319 self.save_change(item_impl);
320 Ok(())
321 }
322
323 fn load_item_mod(&mut self, item_mod: &syn::ItemMod) -> TriResult<(), ()> {
324 self.host.on_enter_scope(Scope::Mod(item_mod));
325
326 if let Some((_, items)) = &item_mod.content {
327 for item in items {
328 self.load_item(item)?;
329 }
330 }
331
332 self.host.on_exit_scope();
333 Ok(())
334 }
335
336 fn load_item_struct(&mut self, item_struct: &syn::ItemStruct) -> TriResult<(), ()> {
339 let mut bound = Bound::new(self.gcx);
341 bound.push_generics(&item_struct.generics, &mut self.host)?;
342
343 let arg = generics_to_arg(&item_struct.generics, self.gcx);
345 let struct_ = self.host.ident_to_term(&item_struct.ident, arg)?;
346
347 let path = self.host.ident_to_npath(&item_struct.ident)?;
349 let path = Name::with_intern(&path, self.gcx);
350 self.set_default_generics(path, &item_struct.generics, &mut bound)?;
351
352 let sized = Term {
354 functor: Name::with_intern("Sized", self.gcx),
355 args: [].into(),
356 };
357 let head = term::impl_2(struct_, sized.clone(), self.gcx);
358
359 let mut fill = |fields: syn::punctuated::Iter<'_, syn::Field>| -> TriResult<(), ()> {
361 for field in fields {
362 let field =
363 Finder::new(self.gcx, &mut self.host, &mut bound).type_to_term(&field.ty)?;
364 let impl_ = term::impl_2(field, sized.clone(), self.gcx);
365 bound.push_bound_term(impl_);
366 }
367 Ok(())
368 };
369 match &item_struct.fields {
370 syn::Fields::Named(fields) => fill(fields.named.iter())?,
371 syn::Fields::Unnamed(fields) => fill(fields.unnamed.iter())?,
372 syn::Fields::Unit => {}
373 }
374 let body = bound.take_bound_expr();
375
376 self.logic.db.insert_clause(Clause { head, body });
377 Ok(())
378 }
379
380 fn load_item_trait(&mut self, item_trait: &syn::ItemTrait) -> TriResult<(), ()> {
386 let mut bound = Bound::new(self.gcx);
388 bound.push_generics(&item_trait.generics, &mut self.host)?;
389
390 let arg = generics_to_arg(&item_trait.generics, self.gcx);
392 let trait_ = self.host.ident_to_term(&item_trait.ident, arg)?;
393
394 let path = self.host.ident_to_npath(&item_trait.ident)?;
396 let path = Name::with_intern(&path, self.gcx);
397 self.set_default_generics(path, &item_trait.generics, &mut bound)?;
398
399 let head = term::trait_1(trait_, self.gcx);
401 let body = bound.take_bound_expr();
402 self.logic.db.insert_clause(Clause {
403 head: head.clone(),
404 body,
405 });
406
407 LoadTraitItemCx {
409 gcx: self.gcx,
410 logic: self.logic,
411 host: &mut self.host,
412 bound: &mut bound,
413 trait_: &head,
414 }
415 .load_trait_items(&item_trait.items)
416 }
417
418 fn set_default_generics(
419 &mut self,
420 path: NameIn<'gcx>,
421 generics: &syn::Generics,
422 bound: &mut Bound<'gcx>,
423 ) -> TriResult<(), ()> {
424 let mut default_generics = Vec::with_capacity(generics.params.len());
425 for param in &generics.params {
426 match param {
427 syn::GenericParam::Type(ty_param) => {
428 let term = if let Some(ty) = &ty_param.default {
429 let term = Finder::new(self.gcx, &mut self.host, bound).type_to_term(ty)?;
430 Some(term)
431 } else {
432 None
433 };
434 default_generics.push(term);
435 }
436 _ => todo!(),
437 }
438 }
439
440 self.logic
441 .default_generics
442 .insert(path, default_generics.into());
443 Ok(())
444 }
445
446 fn has_loaded<T: Loadable>(&mut self, syn: &T) -> bool {
448 let ptr = syn as *const T as *const ();
449 self.logic.loaded.contains(&ptr)
450 }
451
452 fn save_change<T: Loadable>(&mut self, syn: &T) {
455 let ptr = syn as *const T as *const ();
456 self.logic.loaded.insert(ptr);
457
458 self.logic.db.commit();
460 }
461}
462
463struct LoadTraitImplItemCx<'i, 'o, 'gcx, H> {
466 gcx: &'gcx GlobalCx<'gcx>,
467 logic: &'o mut ImplLogic<'gcx>,
468 host: &'o mut HostWrapper<'i, 'gcx, H>,
469 bound: &'o mut Bound<'gcx>,
470 self_ty: &'o TermIn<'gcx>,
471 trait_: &'o TermIn<'gcx>,
472}
473
474impl<'i, 'o, 'gcx, H: Host<'gcx>> LoadTraitImplItemCx<'i, 'o, 'gcx, H> {
475 fn load_impl_items(&mut self, impl_items: &[syn::ImplItem]) -> TriResult<(), ()> {
476 for impl_item in impl_items {
477 match impl_item {
478 syn::ImplItem::Const(c) => self._load_impl_item_const(c)?,
479 syn::ImplItem::Fn(_) => { }
480 syn::ImplItem::Type(ty) => self._load_impl_item_type(ty)?,
481 _ => {}
482 }
483 }
484 Ok(())
485 }
486
487 fn _load_impl_item_const(&mut self, item_const: &syn::ImplItemConst) -> TriResult<(), ()> {
491 debug_assert!(self.bound.bound_terms.is_empty());
495
496 let arg = generics_to_arg(&item_const.generics, self.gcx);
498 let const_name = Term {
499 functor: Name::with_intern(&item_const.ident.to_string(), self.gcx),
500 args: [arg].into(),
501 };
502
503 let const_id = Term {
504 functor: ptr_to_name(&item_const.expr, self.gcx),
505 args: [].into(),
506 };
507
508 let const_ty = Finder::new(self.gcx, self.host, self.bound).type_to_term(&item_const.ty)?;
509
510 let head = term::assoc_const_val_4(
511 self.self_ty.clone(),
512 self.trait_.clone(),
513 const_name.clone(),
514 const_id,
515 self.gcx,
516 );
517 let body = term::assoc_const_ty_3(self.trait_.clone(), const_name, const_ty, self.gcx);
518 let body = Some(Expr::Term(body));
519 self.logic.db.insert_clause(Clause { head, body });
520
521 Ok(())
522 }
523
524 fn _load_impl_item_type(&mut self, item_ty: &syn::ImplItemType) -> TriResult<(), ()> {
527 debug_assert!(self.bound.bound_terms.is_empty());
529 self.bound.push_generics(&item_ty.generics, self.host)?;
530
531 let arg = generics_to_arg(&item_ty.generics, self.gcx);
532 let assoc_ty = Term {
533 functor: Name::with_intern(&item_ty.ident.to_string(), self.gcx),
534 args: [arg].into(),
535 };
536
537 let impl_ = term::impl_2(self.self_ty.clone(), self.trait_.clone(), self.gcx);
539 self.bound.push_bound_term(impl_);
540
541 let assign_ty = Finder::new(self.gcx, self.host, self.bound)
542 .with_default_generic_context(&self.logic.default_generics, Some(self.self_ty.clone()))
543 .type_to_term(&item_ty.ty)?;
544
545 let head = term::assoc_ty_4(
546 self.self_ty.clone(),
547 self.trait_.clone(),
548 assoc_ty,
549 assign_ty,
550 self.gcx,
551 );
552 let body = self.bound.take_bound_expr();
553 self.logic.db.insert_clause(Clause { head, body });
554
555 self.bound.pop_generics();
556 Ok(())
557 }
558}
559
560struct LoadTraitItemCx<'i, 'o, 'gcx, H> {
563 gcx: &'gcx GlobalCx<'gcx>,
564 logic: &'o mut ImplLogic<'gcx>,
565 host: &'o mut HostWrapper<'i, 'gcx, H>,
566 bound: &'o mut Bound<'gcx>,
567 trait_: &'o TermIn<'gcx>,
569}
570
571impl<'i, 'o, 'gcx, H: Host<'gcx>> LoadTraitItemCx<'i, 'o, 'gcx, H> {
572 fn load_trait_items(&mut self, trait_items: &[syn::TraitItem]) -> TriResult<(), ()> {
573 for trait_item in trait_items {
574 match trait_item {
575 syn::TraitItem::Const(c) => self.load_trait_item_const(c)?,
576 syn::TraitItem::Fn(f) => self.load_trait_item_fn(f)?,
577 syn::TraitItem::Type(_) => {}
578 o => todo!("{o:?}"),
579 }
580 }
581 Ok(())
582 }
583
584 fn load_trait_item_const(&mut self, item_const: &syn::TraitItemConst) -> TriResult<(), ()> {
588 debug_assert!(self.bound.bound_terms.is_empty());
593 self.bound.push_generics(&item_const.generics, self.host)?;
594
595 self.bound.push_bound_term(self.trait_.clone());
597
598 let trait_ = self.trait_.args[0].clone();
600
601 let arg = generics_to_arg(&item_const.generics, self.gcx);
603 let const_name = Term {
604 functor: Name::with_intern(&item_const.ident.to_string(), self.gcx),
605 args: [arg].into(),
606 };
607
608 let const_ty = Finder::new(self.gcx, self.host, self.bound).type_to_term(&item_const.ty)?;
609
610 let head = term::assoc_const_ty_3(trait_.clone(), const_name.clone(), const_ty, self.gcx);
612 let body = self.bound.take_bound_expr();
613 self.logic.db.insert_clause(Clause { head, body });
614
615 self.bound.pop_generics();
616
617 if let Some((_, expr)) = &item_const.default {
619 let const_id = Term {
620 functor: ptr_to_name(expr, self.gcx),
621 args: [].into(),
622 };
623 let head =
624 term::assoc_const_val_3(trait_.clone(), const_name.clone(), const_id, self.gcx);
625 let anonymous_ty = Term {
626 functor: var_name("_", self.gcx),
627 args: [].into(),
628 };
629 let body = term::assoc_const_ty_3(trait_, const_name, anonymous_ty, self.gcx);
630 let body = Some(Expr::Term(body));
631 self.logic.db.insert_clause(Clause { head, body });
632 }
633
634 Ok(())
635 }
636
637 fn load_trait_item_fn(&mut self, item_fn: &syn::TraitItemFn) -> TriResult<(), ()> {
640 let sig = &item_fn.sig;
641
642 debug_assert!(self.bound.bound_terms.is_empty());
644 self.bound.push_generics(&sig.generics, self.host)?;
645
646 self.bound.push_bound_term(self.trait_.clone());
648
649 let trait_ = self.trait_.args[0].clone();
651
652 let arg = generics_to_arg(&sig.generics, self.gcx);
654 let fn_name = Term {
655 functor: Name::with_intern(&sig.ident.to_string(), self.gcx),
656 args: [arg].into(),
657 };
658
659 let sig =
660 Finder::new(self.gcx, self.host, self.bound).trait_fn_sig_to_term(item_fn, &trait_)?;
661
662 let head = term::assoc_fn_3(trait_, fn_name, sig, self.gcx);
663 let body = self.bound.take_bound_expr();
664 self.logic.db.insert_clause(Clause { head, body });
665
666 self.bound.pop_generics();
667 Ok(())
668 }
669}
670
671struct LoadInherentImplItemCx<'i, 'o, 'gcx, H> {
674 gcx: &'gcx GlobalCx<'gcx>,
675 logic: &'o mut ImplLogic<'gcx>,
676 host: &'o mut HostWrapper<'i, 'gcx, H>,
677 bound: &'o mut Bound<'gcx>,
678 self_ty: &'o TermIn<'gcx>,
679 impl_: &'o TermIn<'gcx>,
680}
681
682impl<'i, 'o, 'gcx, H: Host<'gcx>> LoadInherentImplItemCx<'i, 'o, 'gcx, H> {
683 fn load_impl_items(&mut self, impl_items: &[syn::ImplItem]) -> TriResult<(), ()> {
684 for impl_item in impl_items {
685 match impl_item {
686 syn::ImplItem::Const(c) => self._load_impl_item_const(c)?,
687 syn::ImplItem::Fn(f) => self._load_impl_item_fn(f)?,
688 syn::ImplItem::Type(_) => {} _ => {}
690 }
691 }
692 Ok(())
693 }
694
695 fn _load_impl_item_const(&mut self, item_const: &syn::ImplItemConst) -> TriResult<(), ()> {
698 debug_assert!(self.bound.bound_terms.is_empty());
703 self.bound.push_generics(&item_const.generics, self.host)?;
704
705 self.bound.push_bound_term(self.impl_.clone());
707
708 let arg = generics_to_arg(&item_const.generics, self.gcx);
710 let const_name = Term {
711 functor: Name::with_intern(&item_const.ident.to_string(), self.gcx),
712 args: [arg].into(),
713 };
714
715 let const_ty = Finder::new(self.gcx, self.host, self.bound)
716 .with_default_generic_context(&self.logic.default_generics, Some(self.self_ty.clone()))
717 .type_to_term(&item_const.ty)?;
718
719 let const_id = Term {
721 functor: ptr_to_name(&item_const.expr, self.gcx),
722 args: [].into(),
723 };
724
725 let head = term::inher_const_4(
726 self.self_ty.clone(),
727 const_name,
728 const_ty,
729 const_id,
730 self.gcx,
731 );
732 let body = self.bound.take_bound_expr();
733 self.logic.db.insert_clause(Clause { head, body });
734
735 self.bound.pop_generics();
736 Ok(())
737 }
738
739 fn _load_impl_item_fn(&mut self, item_fn: &syn::ImplItemFn) -> TriResult<(), ()> {
742 let sig = &item_fn.sig;
743
744 debug_assert!(self.bound.bound_terms.is_empty());
746 self.bound.push_generics(&sig.generics, self.host)?;
747
748 self.bound.push_bound_term(self.impl_.clone());
750
751 let arg = generics_to_arg(&sig.generics, self.gcx);
753 let fn_name = Term {
754 functor: Name::with_intern(&sig.ident.to_string(), self.gcx),
755 args: [arg].into(),
756 };
757
758 let sig = Finder::new(self.gcx, self.host, self.bound)
759 .with_default_generic_context(&self.logic.default_generics, Some(self.self_ty.clone()))
760 .inherent_fn_sig_to_term(sig)?;
761
762 let head = term::inher_fn_3(self.self_ty.clone(), fn_name, sig, self.gcx);
763 let body = self.bound.take_bound_expr();
764 self.logic.db.insert_clause(Clause { head, body });
765
766 self.bound.pop_generics();
767 Ok(())
768 }
769}
770
771pub(super) struct Finder<'a, 'b, 'gcx, H> {
773 gcx: &'gcx GlobalCx<'gcx>,
774 host: &'b mut HostWrapper<'a, 'gcx, H>,
775 bound: &'b mut Bound<'gcx>,
776
777 default_cx: DefaultGenericCx<'b, 'gcx>,
779
780 trait_: Option<&'b TermIn<'gcx>>,
782 cx: u8,
783}
784
785impl<'a, 'b, 'gcx, H: Host<'gcx>> Finder<'a, 'b, 'gcx, H> {
786 const CX_UNKNOWN: u8 = 0;
787 const CX_TYPE: u8 = 1;
788
789 pub(super) fn new(
790 gcx: &'gcx GlobalCx<'gcx>,
791 host: &'b mut HostWrapper<'a, 'gcx, H>,
792 bound: &'b mut Bound<'gcx>,
793 ) -> Self {
794 Self {
795 gcx,
796 host,
797 bound,
798 default_cx: DefaultGenericCx {
799 map: None,
800 self_ty: None,
801 },
802 trait_: None,
803 cx: Self::CX_UNKNOWN,
804 }
805 }
806
807 fn with_default_generic_context(
808 &mut self,
809 map: &'b DefaultGenericMap<'gcx>,
810 self_ty: Option<TermIn<'gcx>>,
811 ) -> &mut Self {
812 self.default_cx.map = Some(map);
813 self.default_cx.self_ty = self_ty;
814 self
815 }
816
817 fn trait_fn_sig_to_term(
819 &mut self,
820 trait_item_fn: &syn::TraitItemFn,
821 trait_: &'b TermIn<'gcx>,
822 ) -> TriResult<TermIn<'gcx>, ()> {
823 debug_assert_ne!(trait_.functor.as_ref(), term::FUNCTOR_TRAIT);
824
825 self.trait_ = Some(trait_);
826 self._fn_sig_to_term(&trait_item_fn.sig)
827 }
828
829 fn inherent_fn_sig_to_term(&mut self, sig: &syn::Signature) -> TriResult<TermIn<'gcx>, ()> {
830 debug_assert!(self.trait_.is_none());
831 self._fn_sig_to_term(sig)
832 }
833
834 pub(super) fn type_to_term(&mut self, ty: &syn::Type) -> TriResult<TermIn<'gcx>, ()> {
835 self.cx = Self::CX_TYPE;
836
837 let term = match ty {
838 syn::Type::Path(syn::TypePath { qself, path }) => {
839 if let Some(qself) = qself {
840 self._qpath_to_term(&qself.ty, path.segments.iter())?
841 } else {
842 self.path_to_term(path)?
843 }
844 }
845 syn::Type::Reference(syn::TypeReference {
846 mutability, elem, ..
847 }) => {
848 let mut elem = self.type_to_term(elem)?;
849 if mutability.is_some() {
850 elem = term::mut_1(elem, self.gcx);
851 }
852 term::ref_1(elem, self.gcx)
853 }
854 syn::Type::Array(syn::TypeArray { elem, len, .. }) => {
855 let elem = self.type_to_term(elem)?;
856 let len = match self.host.eval_array_len(len)? {
857 ArrayLen::Fixed(n) => Term {
858 functor: Name::with_intern(&n.to_string(), self.gcx),
859 args: [].into(),
860 },
861 ArrayLen::Dynamic => unreachable!(),
862 ArrayLen::Generic => Term {
863 functor: var_name(&len.code(), self.gcx), args: [].into(),
865 },
866 };
867 term::array_2(elem, len, self.gcx)
868 }
869 syn::Type::Slice(syn::TypeSlice { elem, .. }) => {
870 let elem = self.type_to_term(elem)?;
871 term::array_1(elem, self.gcx)
872 }
873 syn::Type::Tuple(syn::TypeTuple { elems, .. }) => {
874 let elems: Vec<TermIn<'gcx>> = elems
875 .iter()
876 .map(|elem| self.type_to_term(elem))
877 .collect::<TriResult<_, ()>>()?;
878 term::tuple_n(elems, self.gcx)
879 }
880 o => unreachable!("{o:#?}"),
881 };
882 Ok(term)
883 }
884
885 fn path_to_term(&mut self, path: &syn::Path) -> TriResult<TermIn<'gcx>, ()> {
886 self.path_segments_to_term(path.segments.iter())
887 }
888
889 fn _fn_sig_to_term(&mut self, sig: &syn::Signature) -> TriResult<TermIn<'gcx>, ()> {
891 let mut args = Vec::with_capacity(sig.inputs.len() + 1);
892
893 let output_arg = match &sig.output {
894 syn::ReturnType::Default => term::unit_0(self.gcx),
895 syn::ReturnType::Type(_, ty) => self.type_to_term(ty)?,
896 };
897 args.push(output_arg);
898
899 for input in &sig.inputs {
900 let input_arg = match input {
901 syn::FnArg::Receiver(recv) => {
902 let self_ty = self.type_to_term(&recv.ty)?;
907
908 if let Some(trait_) = self.trait_ {
910 let self_var = Term {
911 functor: var_name("Self", self.gcx),
912 args: [].into(),
913 };
914 let impl_ = term::impl_2(self_var, trait_.clone(), self.gcx);
915 self.bound.push_bound_term(impl_);
916 }
917
918 self_ty
919 }
920 syn::FnArg::Typed(pat_ty) => self.type_to_term(&pat_ty.ty)?,
921 };
922 args.push(input_arg);
923 }
924
925 let sig_term = term::sig_n(args, self.gcx);
926 Ok(sig_term)
927 }
928
929 pub(super) fn path_segments_to_term<
930 'item,
931 I: ExactSizeIterator<Item = &'item syn::PathSegment> + Clone,
932 >(
933 &mut self,
934 mut segments: I,
935 ) -> TriResult<TermIn<'gcx>, ()> {
936 let num_segments = segments.len();
937
938 let first = segments.clone().next().unwrap();
941
942 if self.bound.contains_var(&first.ident) && self.trait_.is_some() && num_segments == 2 {
945 return self._qself_assoc_to_term(first, segments.nth(1).unwrap());
946 }
947
948 let mut elems = Vec::new();
949 let mut path = String::new();
950
951 if first.ident == "Self" && self.default_cx.get_self_type().is_some() {
952 debug_assert!(first.arguments.is_empty());
953 let self_ty = self.default_cx.get_self_type().unwrap();
954 elems.push(self_ty.clone());
955 } else if self.bound.contains_var(&first.ident) {
956 debug_assert!(first.arguments.is_empty());
957 let var = Term {
958 functor: var_name(&first.ident, self.gcx),
959 args: [].into(),
960 };
961 elems.push(var);
962 } else {
963 path = self.host.ident_to_npath(&first.ident)?;
964 let arg = self.path_arguments_to_arg(&path, &first.arguments)?;
965 let term = self.host.ident_to_term(&first.ident, arg)?;
966 if term.functor.as_ref() == term::FUNCTOR_LIST {
967 elems.extend(term.args);
968 } else {
969 elems.push(term);
970 }
971 }
972
973 let term = if elems.len() == 1 && num_segments == 1 {
975 elems.pop().unwrap()
976 } else {
977 for segment in segments.skip(1) {
978 let functor = Name::with_intern(&segment.ident.to_string(), self.gcx);
979
980 push_colon_path(&mut path, &segment.ident);
981 let arg = self.path_arguments_to_arg(&path, &segment.arguments)?;
982
983 elems.push(Term {
984 functor,
985 args: [arg].into(),
986 });
987 }
988 term::list_n(elems, self.gcx)
989 };
990 Ok(term)
991 }
992
993 fn _qself_assoc_to_term(
997 &mut self,
998 qself_segment: &syn::PathSegment,
999 assoc_segment: &syn::PathSegment,
1000 ) -> TriResult<TermIn<'gcx>, ()> {
1001 if let Some(trait_) = self.trait_ {
1002 debug_assert!(qself_segment.arguments.is_empty());
1003
1004 let self_ty = Term {
1005 functor: var_name(&qself_segment.ident, self.gcx),
1006 args: [].into(),
1007 };
1008
1009 let trait_ = trait_.clone();
1010
1011 let arg = self.path_arguments_to_arg("", &assoc_segment.arguments)?;
1012 let assoc_item = Term {
1013 functor: Name::with_intern(&assoc_segment.ident.to_string(), self.gcx),
1014 args: [arg].into(),
1015 };
1016
1017 let var = self._qpath_to_var(self_ty, trait_, assoc_item);
1018 Ok(var)
1019 } else {
1020 todo!()
1022 }
1023 }
1024
1025 fn _qpath_to_term<'item, I: ExactSizeIterator<Item = &'item syn::PathSegment> + Clone>(
1028 &mut self,
1029 qself_ty: &syn::Type,
1030 trait_path: I,
1031 ) -> TriResult<TermIn<'gcx>, ()> {
1032 let num_segments = trait_path.len();
1033 debug_assert!(num_segments > 1);
1034
1035 let self_ty = self.type_to_term(qself_ty)?;
1036
1037 self.default_cx.replace_self_type(self_ty.clone());
1039
1040 let trait_ = self.path_segments_to_term(trait_path.clone().take(num_segments - 1))?;
1041
1042 let last_segment = trait_path.clone().last().unwrap();
1043
1044 let mut iter = trait_path.clone();
1045 let mut path = self.host.ident_to_npath(&iter.next().unwrap().ident)?;
1046 for segment in iter {
1047 push_colon_path(&mut path, &segment.ident);
1048 }
1049
1050 let arg = self.path_arguments_to_arg(&path, &last_segment.arguments)?;
1051 let assoc_item = Term {
1052 functor: Name::with_intern(&last_segment.ident.to_string(), self.gcx),
1053 args: [arg].into(),
1054 };
1055
1056 let var = self._qpath_to_var(self_ty, trait_, assoc_item);
1057 Ok(var)
1058 }
1059
1060 fn _qpath_to_var(
1065 &mut self,
1066 self_ty: TermIn<'gcx>,
1067 trait_: TermIn<'gcx>,
1068 assoc_item: TermIn<'gcx>,
1069 ) -> TermIn<'gcx> {
1070 let auto_var = self.bound.next_auto_var();
1071
1072 let trait_assoc = if self.cx == Self::CX_TYPE {
1073 let impl_ = term::impl_2(self_ty.clone(), trait_.clone(), self.gcx);
1075 self.bound.push_bound_term(impl_);
1076
1077 term::assoc_ty_4(self_ty, trait_, assoc_item, auto_var.clone(), self.gcx)
1078 } else {
1079 todo!("no related term yet")
1080 };
1081
1082 self.bound.push_bound_term(trait_assoc);
1083
1084 auto_var
1085 }
1086
1087 pub(super) fn path_arguments_to_arg(
1091 &mut self,
1092 path: &str,
1093 args: &syn::PathArguments,
1094 ) -> TriResult<TermIn<'gcx>, ()> {
1095 let args = match args {
1096 syn::PathArguments::None => {
1097 if let Some(defaults) = self.default_cx.get_default_types(path) {
1098 defaults.map(|(_i, term)| term.clone()).collect()
1099 } else {
1100 [].into()
1101 }
1102 }
1103 syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
1104 args,
1105 ..
1106 }) => {
1107 let total = self.default_cx.get_generics_len(path).unwrap_or(args.len());
1108
1109 let mut buf = Vec::with_capacity(total);
1110
1111 for arg in args {
1112 let arg = match arg {
1113 syn::GenericArgument::Type(ty) => self.type_to_term(ty)?,
1114 _ => todo!(),
1115 };
1116 buf.push(arg);
1117 }
1118 if let Some(defaults) = self.default_cx.get_default_types(path) {
1119 for (j, default) in defaults {
1120 if j >= buf.len() {
1121 buf.push(default.clone());
1122 }
1123 }
1124 }
1125
1126 buf
1127 }
1128 syn::PathArguments::Parenthesized(_) => {
1129 todo!()
1130 }
1131 };
1132 Ok(term::arg_n(args, self.gcx))
1133 }
1134}
1135
1136pub(super) struct Bound<'gcx> {
1137 gcx: &'gcx GlobalCx<'gcx>,
1138
1139 bound_terms: Vec<TermIn<'gcx>>,
1143
1144 next_auto_var: u32,
1146
1147 var_symbols: Vec<String>,
1149}
1150
1151impl<'gcx> Bound<'gcx> {
1152 pub(super) fn new(gcx: &'gcx GlobalCx<'gcx>) -> Self {
1153 let var_symbols = vec!["Self".to_owned()];
1155
1156 Self {
1157 gcx,
1158 bound_terms: Vec::new(),
1159 next_auto_var: 0,
1160 var_symbols,
1161 }
1162 }
1163
1164 fn push_bound_term(&mut self, bound_term: TermIn<'gcx>) {
1165 if self.bound_terms.iter().all(|exist| exist != &bound_term) {
1167 self.bound_terms.push(bound_term);
1168 }
1169 }
1170
1171 fn take_bound_expr(&mut self) -> Option<ExprIn<'gcx>> {
1172 let mut redundant = Vec::new();
1176
1177 for (lt, (ri, rt)) in self
1178 .bound_terms
1179 .iter()
1180 .flat_map(|l| self.bound_terms.iter().enumerate().map(move |r| (l, r)))
1181 {
1182 if lt.functor.as_ref() == term::FUNCTOR_ASSOC_TY
1186 && rt.functor.as_ref() == term::FUNCTOR_IMPL
1187 && lt.args[0..2] == rt.args[0..2]
1188 {
1189 redundant.push(ri);
1190 }
1191 }
1192
1193 for r in redundant {
1194 self.bound_terms.remove(r);
1195 }
1196
1197 match self.bound_terms.len() as u32 {
1198 0 | 1 => {
1199 let term = self.bound_terms.pop()?;
1200 Some(Expr::Term(term))
1201 }
1202 2.. => {
1203 let args = self.bound_terms.drain(..).map(Expr::Term).collect();
1204 Some(Expr::And(args))
1205 }
1206 }
1207 }
1208
1209 fn push_generics<H: Host<'gcx>>(
1211 &mut self,
1212 generics: &syn::Generics,
1213 host: &mut HostWrapper<'_, 'gcx, H>,
1214 ) -> TriResult<(), ()> {
1215 self.var_symbols.push(String::new()); for param in &generics.params {
1219 match param {
1220 syn::GenericParam::Type(ty_param) => {
1221 self.var_symbols.push(ty_param.ident.to_string());
1222 }
1223 syn::GenericParam::Const(_) | syn::GenericParam::Lifetime(_) => {
1224 }
1226 }
1227 }
1228
1229 let mut sized: Vec<TermIn<'gcx>> = Vec::new();
1231
1232 for type_param in generics.type_params() {
1236 let bounded_term = Term {
1237 functor: var_name(&type_param.ident, self.gcx),
1238 args: [].into(),
1239 };
1240 sized.push(bounded_term.clone());
1241
1242 for param_bound in &type_param.bounds {
1243 let syn::TypeParamBound::Trait(trait_bound) = param_bound else {
1244 continue;
1246 };
1247
1248 push_trait_bound(self, host, &mut sized, &bounded_term, trait_bound)?;
1249 }
1250 }
1251
1252 if let Some(where_clause) = &generics.where_clause {
1253 for predicate in &where_clause.predicates {
1254 match predicate {
1255 syn::WherePredicate::Type(ty) => {
1256 let bounded_term =
1257 Finder::new(self.gcx, host, self).type_to_term(&ty.bounded_ty)?;
1258 for bound in &ty.bounds {
1259 match bound {
1260 syn::TypeParamBound::Trait(trait_bound) => {
1261 push_trait_bound(
1262 self,
1263 host,
1264 &mut sized,
1265 &bounded_term,
1266 trait_bound,
1267 )?;
1268 }
1269 _ => todo!(),
1270 }
1271 }
1272 }
1273 _ => todo!(),
1274 }
1275 }
1276 }
1277
1278 for bounded_term in sized {
1279 let trait_ = Term {
1281 functor: Name::with_intern("Sized", self.gcx),
1282 args: [].into(),
1283 };
1284 let trait_impl = term::impl_2(bounded_term, trait_, self.gcx);
1285 self.push_bound_term(trait_impl)
1286 }
1287
1288 return Ok(());
1289
1290 fn push_trait_bound<'gcx, H: Host<'gcx>>(
1293 this: &mut Bound<'gcx>,
1294 host: &mut HostWrapper<'_, 'gcx, H>,
1295 sized: &mut Vec<TermIn<'gcx>>,
1296 bounded_term: &TermIn<'gcx>,
1297 trait_bound: &syn::TraitBound,
1298 ) -> TriResult<(), ()> {
1299 let trait_ = Finder::new(this.gcx, host, this).path_to_term(&trait_bound.path)?;
1300
1301 if matches!(trait_bound.modifier, syn::TraitBoundModifier::Maybe(_)) {
1302 if trait_.functor.as_ref() == "Sized" {
1304 if let Some(i) = sized
1305 .iter()
1306 .enumerate()
1307 .find_map(|(i, term)| (term == bounded_term).then_some(i))
1308 {
1309 sized.swap_remove(i);
1310 }
1311 }
1312 return Ok(());
1313 }
1314
1315 let trait_impl = term::impl_2(bounded_term.clone(), trait_, this.gcx);
1317 this.push_bound_term(trait_impl);
1318 Ok(())
1319 }
1320 }
1321
1322 fn pop_generics(&mut self) {
1323 loop {
1324 match self.var_symbols.last() {
1325 Some(ident) if ident.is_empty() => {
1327 self.var_symbols.pop();
1328 break;
1329 }
1330 Some(_) => {
1331 self.var_symbols.pop();
1332 }
1333 None => break,
1334 }
1335 }
1336 }
1337
1338 fn contains_var<T: PartialEq<str>>(&self, ident: &T) -> bool {
1339 self.var_symbols
1340 .iter()
1341 .any(|generic| ident == generic.as_str())
1342 }
1343
1344 fn next_auto_var(&mut self) -> TermIn<'gcx> {
1345 let functor = if self.next_auto_var < 26 {
1346 format!(
1347 "{}{}",
1348 AUTO_VAR_PREFIX,
1349 (self.next_auto_var as u8 + b'A') as char
1350 )
1351 } else {
1352 format!("{}{}", AUTO_VAR_PREFIX, self.next_auto_var - 26)
1353 };
1354
1355 self.next_auto_var += 1;
1356
1357 Term {
1358 functor: Name::with_intern(&functor, self.gcx),
1359 args: [].into(),
1360 }
1361 }
1362}
1363
1364type DefaultGenericMap<'gcx> = Map<NameIn<'gcx>, BoxedSlice<Option<TermIn<'gcx>>>>;
1367
1368struct DefaultGenericCx<'a, 'gcx> {
1369 map: Option<&'a DefaultGenericMap<'gcx>>,
1371
1372 self_ty: Option<TermIn<'gcx>>,
1374}
1375
1376impl<'a, 'gcx> DefaultGenericCx<'a, 'gcx> {
1377 fn replace_self_type(&mut self, self_ty: TermIn<'gcx>) {
1378 self.self_ty = Some(self_ty);
1379 }
1380
1381 fn get_self_type(&self) -> Option<&TermIn<'gcx>> {
1382 self.self_ty.as_ref()
1383 }
1384
1385 fn get_generics_len<Q>(&self, name: &Q) -> Option<usize>
1387 where
1388 NameIn<'gcx>: borrow::Borrow<Q>,
1389 Q: Hash + Eq + ?Sized,
1390 {
1391 self.map?.get(name).map(|defaults| defaults.len())
1392 }
1393
1394 fn get_default_types<Q>(
1396 &self,
1397 name: &Q,
1398 ) -> Option<impl Iterator<Item = (usize, &TermIn<'gcx>)> + Clone>
1399 where
1400 NameIn<'gcx>: borrow::Borrow<Q>,
1401 Q: Hash + Eq + ?Sized,
1402 {
1403 let defaults = self.map?.get(name)?;
1404 let iter = defaults.iter().enumerate().filter_map(|(i, default)| {
1405 default.as_ref().map(|term| {
1406 if term.functor.as_ref() == "Self"
1408 || term.is_variable() && &term.functor[1..] == "Self"
1409 {
1410 let self_ty = self.self_ty.as_ref().unwrap_or_else(|| {
1411 panic!("self_ty is not given");
1412 });
1413 (i, self_ty)
1414 } else {
1415 (i, term)
1416 }
1417 })
1418 });
1419 Some(iter)
1420 }
1421}
1422
1423#[derive(Debug)]
1424pub(crate) struct DatabaseWrapper<'gcx> {
1425 db: Database<'gcx, GlobalCx<'gcx>>,
1426
1427 added_sized_known: Set<PredicateIn<'gcx>>,
1429
1430 gcx: &'gcx GlobalCx<'gcx>,
1431}
1432
1433impl<'gcx> DatabaseWrapper<'gcx> {
1434 fn new(gcx: &'gcx GlobalCx<'gcx>) -> Self {
1435 Self {
1436 db: Database::with_interner(gcx),
1437 added_sized_known: Set::default(),
1438 gcx,
1439 }
1440 }
1441
1442 fn insert_clause(&mut self, mut clause: ClauseIn<'gcx>) {
1443 self._insert_impl_sized_for_known_on_demand(&clause);
1447
1448 Self::_add_prefix_for_singleton_vars(&mut clause, self.gcx);
1451
1452 self.db.insert_clause(clause)
1453 }
1454
1455 fn commit(&mut self) {
1456 self.db.commit();
1457 }
1458
1459 fn query(&mut self, expr: ExprIn<'gcx>) -> ProveCx<'_, 'gcx, GlobalCx<'gcx>> {
1460 self.db.query(expr)
1461 }
1462
1463 pub(crate) fn to_prolog(&self) -> String {
1464 self.db.to_prolog(|name| {
1467 for custom_letter in CUSTOM_PREFIX_LETTERS {
1468 if let Some(stripped) = name.strip_prefix(custom_letter) {
1469 return stripped;
1470 }
1471 }
1472 name
1473 })
1474 }
1475
1476 fn _insert_impl_sized_for_known_on_demand(&mut self, clause: &ClauseIn<'gcx>) {
1477 term_helper(self, &clause.head);
1478 if let Some(body) = &clause.body {
1479 expr_helper(self, body);
1480 }
1481
1482 fn expr_helper<'gcx>(this: &mut DatabaseWrapper<'gcx>, expr: &ExprIn<'gcx>) {
1485 match expr {
1486 Expr::Term(term) => term_helper(this, term),
1487 Expr::Not(inner) => expr_helper(this, inner),
1488 Expr::And(args) | Expr::Or(args) => {
1489 for arg in args {
1490 expr_helper(this, arg);
1491 }
1492 }
1493 }
1494 }
1495
1496 fn term_helper<'gcx>(this: &mut DatabaseWrapper<'gcx>, term: &TermIn<'gcx>) {
1497 #[rustfmt::skip]
1498 const SORTED_KNOWN: [&str; 19] = [
1499 term::FUNCTOR_ARRAY,
1500 term::FUNCTOR_REF,
1501 term::FUNCTOR_TUPLE,
1502 "bool", "char",
1503 "f32", "f64",
1504 "i128", "i16", "i32", "i64", "i8", "isize",
1505 "u128", "u16", "u32", "u64", "u8", "usize",
1506 ];
1507 debug_assert!(SORTED_KNOWN.windows(2).all(|w| w[0] <= w[1]));
1508
1509 if SORTED_KNOWN.binary_search(&term.functor.as_ref()).is_err() {
1510 for arg in &term.args {
1511 term_helper(this, arg);
1512 }
1513 return;
1514 }
1515
1516 if !this.added_sized_known.insert(term.predicate()) {
1517 return;
1518 }
1519
1520 for arg in &term.args {
1521 term_helper(this, arg);
1522 }
1523
1524 let sized = Term {
1525 functor: Name::with_intern("Sized", this.gcx),
1526 args: [].into(),
1527 };
1528
1529 if term.functor.as_ref() == term::FUNCTOR_ARRAY {
1532 let var_elem = Term {
1533 functor: var_name("_E", this.gcx),
1534 args: [].into(),
1535 };
1536 let var_len = Term {
1537 functor: var_name("_L", this.gcx),
1538 args: [].into(),
1539 };
1540 let arr = term::array_2(var_elem, var_len, this.gcx);
1541 let head = term::impl_2(arr, sized, this.gcx);
1542 this.db.insert_clause(Clause { head, body: None });
1543 }
1544 else if term.functor.as_ref() == term::FUNCTOR_REF {
1547 let var = Term {
1548 functor: var_name("_", this.gcx), args: [].into(),
1550 };
1551 let ref_ = term::ref_1(var, this.gcx);
1552 let head = term::impl_2(ref_, sized, this.gcx);
1553 this.db.insert_clause(Clause { head, body: None });
1554 }
1555 else if term.functor.as_ref() == term::FUNCTOR_TUPLE {
1559 let arity = term.args.len();
1560 let mut elems = Vec::with_capacity(arity);
1561 let mut bounds = Vec::with_capacity(arity);
1562
1563 for i in 0..term.args.len() {
1564 let functor = if i < 26 {
1565 var_name(&((i as u8 + b'A') as char), this.gcx)
1566 } else {
1567 var_name(&(i - 26), this.gcx)
1568 };
1569 let var = Term {
1570 functor,
1571 args: [].into(),
1572 };
1573 let bound = term::impl_2(var.clone(), sized.clone(), this.gcx);
1574 elems.push(var);
1575 bounds.push(Expr::Term(bound));
1576 }
1577
1578 let tuple = term::tuple_n(elems, this.gcx);
1579 let head = term::impl_2(tuple, sized, this.gcx);
1580 this.db.insert_clause(Clause {
1581 head,
1582 body: Some(Expr::And(bounds)),
1583 });
1584 }
1585 else {
1588 debug_assert!(term.args.is_empty());
1589
1590 let term = try_make_int_or_float_term(&term.functor, this.gcx)
1592 .unwrap_or_else(|| term.clone());
1593
1594 let head = term::impl_2(term, sized, this.gcx);
1595 this.db.insert_clause(Clause { head, body: None });
1596 }
1597 }
1598 }
1599
1600 fn _add_prefix_for_singleton_vars(clause: &mut ClauseIn<'gcx>, gcx: &'gcx GlobalCx<'gcx>) {
1602 let ptr_term = &mut clause.head as *mut TermIn<'gcx>;
1603 let ptr_clause = (clause as *mut ClauseIn<'gcx>).cast_const();
1604 fix_term(ptr_term, ptr_clause, gcx);
1605
1606 if let Some(body) = &mut clause.body {
1607 let ptr_expr = body as *mut ExprIn<'gcx>;
1608 let ptr_clause = (clause as *mut ClauseIn<'gcx>).cast_const();
1609 fix_expr(ptr_expr, ptr_clause, gcx);
1610 }
1611
1612 fn fix_term<'gcx>(
1615 term: *mut TermIn<'gcx>,
1616 clause: *const ClauseIn<'gcx>,
1617 gcx: &'gcx GlobalCx<'gcx>,
1618 ) {
1619 let is_singleton = unsafe {
1620 let term = &*term;
1621 let clause = &*clause;
1622 is_singleton_var(term, clause)
1623 };
1624
1625 if is_singleton {
1626 unsafe {
1627 let term = &mut *term;
1628 if term.functor.starts_with(AUTO_VAR_PREFIX) {
1629 let functor = format!(
1630 "{}_{}",
1631 AUTO_VAR_PREFIX,
1632 &term.functor[AUTO_VAR_PREFIX.len()..]
1633 );
1634 term.functor = Name::with_intern(&functor, gcx);
1635 } else {
1636 let functor =
1637 format!("{}_{}", VAR_PREFIX, &term.functor[VAR_PREFIX.len_utf8()..]);
1638 term.functor = Name::with_intern(&functor, gcx);
1639 }
1640 }
1641 } else {
1642 let (args, num_args) = unsafe {
1643 let term = &mut *term;
1644 (term.args.as_mut_ptr(), term.args.len())
1645 };
1646
1647 for i in 0..num_args {
1648 unsafe { fix_term(args.add(i), clause, gcx) };
1649 }
1650 }
1651 }
1652
1653 fn fix_expr<'gcx>(
1654 expr: *mut ExprIn<'gcx>,
1655 clause: *const ClauseIn<'gcx>,
1656 gcx: &'gcx GlobalCx<'gcx>,
1657 ) {
1658 unsafe {
1659 let expr = &mut *expr;
1660 match expr {
1661 Expr::Term(term) => {
1662 fix_term(term as *mut _, clause, gcx);
1663 }
1664 Expr::Not(inner) => {
1665 let inner = &mut **inner;
1666 fix_expr(inner as *mut _, clause, gcx);
1667 }
1668 Expr::And(args) | Expr::Or(args) => {
1669 let num_args = args.len();
1670 let args = args.as_mut_ptr();
1671 for i in 0..num_args {
1672 fix_expr(args.add(i), clause, gcx);
1673 }
1674 }
1675 }
1676 }
1677 }
1678
1679 fn is_singleton_var<'gcx>(lhs: &TermIn<'gcx>, clause: &ClauseIn<'gcx>) -> bool {
1683 if !lhs.is_variable() {
1684 return false;
1685 }
1686
1687 let off = if lhs.functor.starts_with(AUTO_VAR_PREFIX) {
1688 AUTO_VAR_PREFIX.len()
1689 } else {
1690 VAR_PREFIX.len_utf8()
1691 };
1692 if lhs.functor[off..].starts_with('_') {
1693 return false;
1694 }
1695
1696 fn count_term<'gcx>(var: &TermIn<'gcx>, term: &TermIn<'gcx>, same_cnt: &mut u32) {
1697 if var == term {
1698 *same_cnt += 1;
1699 } else {
1700 for arg in &term.args {
1701 count_term(var, arg, same_cnt);
1702 }
1703 }
1704 }
1705
1706 fn count_expr<'gcx>(var: &TermIn<'gcx>, expr: &ExprIn<'gcx>, same_cnt: &mut u32) {
1707 match expr {
1708 Expr::Term(term) => count_term(var, term, same_cnt),
1709 Expr::Not(inner) => count_expr(var, inner, same_cnt),
1710 Expr::And(args) | Expr::Or(args) => {
1711 for arg in args {
1712 count_expr(var, arg, same_cnt);
1713 }
1714 }
1715 }
1716 }
1717
1718 let mut same_cnt = 0;
1719
1720 count_term(lhs, &clause.head, &mut same_cnt);
1721 if let Some(body) = &clause.body {
1722 count_expr(lhs, body, &mut same_cnt);
1723 }
1724
1725 same_cnt == 1
1726 }
1727 }
1728}
1729
1730impl<'gcx> ops::Deref for DatabaseWrapper<'gcx> {
1731 type Target = Database<'gcx, GlobalCx<'gcx>>;
1732
1733 fn deref(&self) -> &Self::Target {
1734 &self.db
1735 }
1736}
1737
1738fn generics_to_arg<'gcx>(generics: &syn::Generics, gcx: &'gcx GlobalCx<'gcx>) -> TermIn<'gcx> {
1741 let args = generics
1742 .params
1743 .iter()
1744 .map(|param| match param {
1745 syn::GenericParam::Type(ty_param) => Term {
1746 functor: var_name(&ty_param.ident, gcx),
1747 args: [].into(),
1748 },
1749 o => todo!("{o:#?}"),
1750 })
1751 .collect();
1752 term::arg_n(args, gcx)
1753}
1754
1755#[cfg(test)]
1756#[rustfmt::skip]
1757pub(crate) mod tests {
1758 use super::{
1759 ImplLogic,
1760 };
1761 use crate::{
1762 syntax::file::File,
1763 semantic::{
1764 logic::test_help::TestLogicHost,
1765 entry::GlobalCx,
1766 },
1767 };
1768 use pretty_assertions::assert_eq;
1769
1770 #[test]
1771 fn test_logic_construction() {
1772 test_impl();
1773 test_inherent_fn();
1774 test_trait_impl();
1775 test_trait_impl_assoc_ty();
1776 test_trait_assoc_fn();
1777 test_trait_complex_assoc_fn();
1778 test_sized_for_struct();
1779 test_default_generic_type();
1780 test_various_self();
1781 }
1782
1783 fn test_impl() {
1784 let clauses = load(r"
1785 impl<T: A + B> S<T> {}
1786 ");
1787 let expected = remove_whitespace(&[
1788 "#impl(S(#arg($T))) :-
1789 #impl($T, A(#arg)),
1790 #impl($T, B(#arg)),
1791 #impl($T, Sized)."
1792 ]);
1793 assert_eq!(clauses, expected);
1794 }
1795
1796 fn test_inherent_fn() {
1797 let clauses = load(r"
1798 impl<T: A> S<T> {
1799 fn f0() {}
1800 fn f1<U: B>() {}
1801 fn f2(u: U) -> T {}
1802 }
1803 ");
1804 let expected = remove_whitespace(&[
1805 "#impl(S(#arg($T))) :-
1806 #impl($T, A(#arg)),
1807 #impl($T, Sized).",
1808 "#inher_fn(S(#arg($T)), f0(#arg), #sig(#unit)) :-
1809 #impl(S(#arg($T))).",
1810 "#inher_fn(S(#arg($T)), f1(#arg($U)), #sig(#unit)) :-
1811 #impl($U, B(#arg)),
1812 #impl($U, Sized),
1813 #impl(S(#arg($T))).",
1814 "#inher_fn(S(#arg($T)), f2(#arg), #sig($T, U(#arg))) :-
1815 #impl(S(#arg($T))).",
1816 ]);
1817 assert_eq!(clauses, expected);
1818 }
1819
1820 fn test_trait_impl() {
1821 let clauses = load(r"
1822 impl<T, U: ?Sized> Trait<T> for S<U> {}
1823 ");
1824 let expected = remove_whitespace(&[
1825 "#impl(S(#arg($_U)), Trait(#arg($T))) :-
1826 #impl($T, Sized)."
1827 ]);
1828 assert_eq!(clauses, expected);
1829 }
1830
1831 fn test_trait_impl_assoc_ty() {
1832 let clauses = load(r"
1833 impl Trait for S {
1834 type AssocTy = T;
1835 }
1836 ");
1837 let expected = remove_whitespace(&[
1838 "#impl(S(#arg), Trait(#arg)).",
1839 "#assoc_ty(S(#arg), Trait(#arg), AssocTy(#arg), T(#arg)) :-
1840 #impl(S(#arg), Trait(#arg)).",
1841 ]);
1842 assert_eq!(clauses, expected);
1843 }
1844
1845 fn test_trait_assoc_fn() {
1846 let clauses = load(r"
1847 trait Trait<T: A> {
1848 fn f0();
1849 fn f1<U: B>();
1850 fn f2(u: U) -> T;
1851 }
1852 ");
1853 let expected = remove_whitespace(&[
1854 "#trait(Trait(#arg($T))) :-
1855 #impl($T, A(#arg)),
1856 #impl($T, Sized).",
1857 "#assoc_fn(Trait(#arg($T)), f0(#arg), #sig(#unit)) :-
1858 #trait(Trait(#arg($T))).",
1859 "#assoc_fn(Trait(#arg($T)), f1(#arg($U)), #sig(#unit)) :-
1860 #impl($U, B(#arg)),
1861 #impl($U, Sized),
1862 #trait(Trait(#arg($T))).",
1863 "#assoc_fn(Trait(#arg($T)), f2(#arg), #sig($T, U(#arg))) :-
1864 #trait(Trait(#arg($T))).",
1865 ]);
1866 assert_eq!(clauses, expected);
1867 }
1868
1869 fn test_trait_complex_assoc_fn() {
1870 let clauses = load(r"
1871 trait MyShl<Rhs = Self> {
1872 type Output;
1873 fn shl(self, rhs: Rhs) -> Self::Output;
1874 }
1875 ");
1876 let expected = remove_whitespace(&[
1877 "#trait(MyShl(#arg($Rhs))) :-
1878 #impl($Rhs, Sized).",
1879 "#assoc_fn(MyShl(#arg($Rhs)), shl(#arg), #sig($#A, $Self, $Rhs)) :-
1880 #trait(MyShl(#arg($Rhs))),
1881 #assoc_ty($Self, MyShl(#arg($Rhs)), Output(#arg), $#A).",
1882 ]);
1883 assert_eq!(clauses, expected);
1884 }
1885
1886 fn test_sized_for_struct() {
1887 let clauses = load(r"
1891 struct A { a: [i32; 1] }
1892 ");
1893 let expected = remove_whitespace(&[
1894 "#impl(#int(i32), Sized).",
1895 "#impl(#array($_E, $_L), Sized).",
1896 "#impl(A(#arg), Sized) :- #impl(#array(#int(i32), 1), Sized).",
1897 ]);
1898 assert_eq!(clauses, expected);
1899
1900 let clauses = load(r"
1902 struct A { a: (i32, f32) }
1903 ");
1904 let expected = remove_whitespace(&[
1905 "#impl(#int(i32), Sized).",
1906 "#impl(#float(f32), Sized).",
1907 "#impl(#tuple($A, $B), Sized) :- #impl($A, Sized), #impl($B, Sized).",
1908 "#impl(A(#arg), Sized) :- #impl(#tuple(#int(i32), #float(f32)), Sized).",
1909 ]);
1910 assert_eq!(clauses, expected);
1911
1912 let clauses = load(r"
1914 struct A { a: i32 }
1915 struct B { a1: A, a2: A, b: f32 }
1916 ");
1917 let expected = remove_whitespace(&[
1918 "#impl(#int(i32), Sized).",
1919 "#impl(A(#arg), Sized) :- #impl(#int(i32), Sized).",
1920 "#impl(#float(f32), Sized).",
1921 "#impl(B(#arg), Sized) :- #impl(A(#arg), Sized), #impl(#float(f32), Sized).",
1922 ]);
1923 assert_eq!(clauses, expected);
1924
1925 let clauses = load(r"
1927 struct A { a: &i32 }
1928 struct B { a: &mut i32 }
1929 ");
1930 let expected = remove_whitespace(&[
1931 "#impl(#int(i32), Sized).",
1932 "#impl(#ref($_), Sized).",
1933 "#impl(A(#arg), Sized) :- #impl(#ref(#int(i32)), Sized).",
1934 "#impl(B(#arg), Sized) :- #impl(#ref(#mut(#int(i32))), Sized).",
1935 ]);
1936 assert_eq!(clauses, expected);
1937
1938 let clauses = load(r"
1940 struct A { a: [i32] }
1941 ");
1942 let expected = remove_whitespace(&[
1943 "#impl(#int(i32), Sized).",
1944 "#impl(#array($_E, $_L), Sized).",
1945 "#impl(A(#arg), Sized) :- #impl(#array(#int(i32), #dyn), Sized).",
1946 ]);
1947 assert_eq!(clauses, expected);
1948 }
1949
1950 fn test_default_generic_type() {
1951 let clauses = load(r"
1953 trait Trait<A = Self, B = X> {}
1954 impl Trait for X {}
1955 impl Trait<W> for Y {}
1956 struct W;
1957 struct X;
1958 struct Y;
1959 ");
1960 let expected = remove_whitespace(&[
1961 "#trait(Trait(#arg($A, $B))) :- #impl($A, Sized), #impl($B, Sized).",
1962 "#impl(X(#arg), Trait(#arg(X(#arg), X(#arg)))).",
1963 "#impl(Y(#arg), Trait(#arg(W(#arg), X(#arg)))).",
1964 "#impl(W(#arg), Sized).",
1965 "#impl(X(#arg), Sized).",
1966 "#impl(Y(#arg), Sized).",
1967 ]);
1968 assert_eq!(clauses, expected);
1969
1970 let clauses = load(r"
1972 struct St<A = X, B = Y> { a: A, b: B }
1973 impl St {}
1974 impl St<W> {}
1975 struct W;
1976 struct X;
1977 struct Y;
1978 ");
1979 let expected = remove_whitespace(&[
1980 "#impl(St(#arg($A, $B)) ,Sized) :- #impl($A, Sized), #impl($B, Sized).",
1981 "#impl(W(#arg), Sized).",
1982 "#impl(X(#arg), Sized).",
1983 "#impl(Y(#arg), Sized).",
1984 "#impl(St(#arg(X(#arg), Y(#arg)))).",
1985 "#impl(St(#arg(W(#arg), Y(#arg)))).",
1986 ]);
1987 assert_eq!(clauses, expected);
1988
1989 let clauses = load(r"
1991 trait Trait<A = X> {
1992 type Assoc;
1993 }
1994 impl Trait for X {
1995 type Assoc = X;
1996 }
1997 impl Trait for Y {
1998 type Assoc = <X as Trait>::Assoc;
1999 }
2000 struct X;
2001 struct Y;
2002 ");
2003 let expected = remove_whitespace(&[
2004 "#trait(Trait(#arg($A))) :- #impl($A, Sized).",
2005 "#impl(X(#arg), Trait(#arg(X(#arg)))).",
2006 "#impl(Y(#arg), Trait(#arg(X(#arg)))).",
2007 "#impl(X(#arg), Sized).",
2008 "#impl(Y(#arg), Sized).",
2009 "#assoc_ty(X(#arg), Trait(#arg(X(#arg))), Assoc(#arg), X(#arg)) :-
2010 #impl(X(#arg), Trait(#arg(X(#arg)))).",
2011 "#assoc_ty(Y(#arg), Trait(#arg(X(#arg))), Assoc(#arg), $#A) :-
2012 #impl(Y(#arg), Trait(#arg(X(#arg)))),
2013 #assoc_ty(X(#arg), Trait(#arg(X(#arg))), Assoc(#arg), $#A).",
2014 ]);
2015 assert_eq!(clauses, expected);
2016 }
2017
2018 fn test_various_self() {
2019 let clauses = load(r"
2021 trait Trait<A = Self> {}
2022 impl Trait for X {}
2023 struct X;
2024 ");
2025 let expected = remove_whitespace(&[
2026 "#trait(Trait(#arg($A))) :- #impl($A, Sized).",
2027 "#impl(X(#arg), Trait(#arg(X(#arg)))).",
2028 "#impl(X(#arg), Sized).",
2029 ]);
2030 assert_eq!(clauses, expected);
2031
2032 let clauses = load(r"
2034 trait Trait {
2035 type Assoc;
2036 }
2037 impl Trait for X {
2038 type Assoc = Self;
2039 }
2040 struct X;
2041 ");
2042 let expected = remove_whitespace(&[
2043 "#trait(Trait(#arg)).",
2044 "#impl(X(#arg), Trait(#arg)).",
2045 "#impl(X(#arg), Sized).",
2046 "#assoc_ty(X(#arg), Trait(#arg), Assoc(#arg), X(#arg)) :-
2047 #impl(X(#arg), Trait(#arg)).",
2048 ]);
2049 assert_eq!(clauses, expected);
2050
2051 let clauses = load(r"
2053 struct X;
2054 impl X {
2055 fn f0(self) {}
2056 fn f1(&self) {}
2057 fn f2(&mut self) {}
2058 fn f3(self: Box<Self>) {}
2059 }
2060 ");
2061 let expected = remove_whitespace(&[
2062 "#impl(X(#arg), Sized).",
2063 "#impl(#ref($_), Sized).",
2064 "#impl(X(#arg)).",
2065 "#inher_fn(X(#arg), f0(#arg), #sig(#unit, X(#arg))) :-
2066 #impl(X(#arg)).",
2067 "#inher_fn(X(#arg), f1(#arg), #sig(#unit, #ref(X(#arg)))) :-
2068 #impl(X(#arg)).",
2069 "#inher_fn(X(#arg), f2(#arg), #sig(#unit, #ref(#mut(X(#arg))))) :-
2070 #impl(X(#arg)).",
2071 "#inher_fn(X(#arg), f3(#arg), #sig(#unit, Box(#arg(X(#arg))))) :-
2072 #impl(X(#arg)).",
2073 ]);
2074 assert_eq!(clauses, expected);
2075 }
2076
2077 fn load(code: &str) -> Vec<String> {
2078 let file = "test";
2079 let gcx = GlobalCx::default();
2080 let mut logic = ImplLogic::new(&gcx);
2081 let mut host = TestLogicHost::new();
2082 let file = File::new(file.into(), code).unwrap();
2083 logic.load_file(&mut host, &file.file).unwrap();
2084 logic
2085 .db
2086 .clauses()
2087 .map(|clause| {
2088 let mut clause = clause.to_string();
2089 clause.retain(|c| !c.is_whitespace());
2090 clause
2091 })
2092 .collect()
2093 }
2094
2095 fn remove_whitespace(clauses: &[&str]) -> Vec<String> {
2096 clauses
2097 .iter()
2098 .map(|clause| clause.chars().filter(|c| !c.is_whitespace()).collect())
2099 .collect()
2100 }
2101}