Skip to main content

syn_sem/semantic/logic/
construct.rs

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
19/// Auto-generated variables will be named in order of '$#A', '$#B', ..., '$#Z', '$#0', '$#1', ...
20const AUTO_VAR_PREFIX: &str = "$#";
21const CUSTOM_PREFIX_LETTERS: [char; 1] = ['#' /* used at AUTO_VAR_PREFIX */];
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    /// e.g.
60    /// * Input - ident: Z / arg: arg($T, $U)
61    /// * Output - list(x, y, Z($T, $U))
62    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        // e.g. i32 -> int(i32), w/o arg
70        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        // bool or char, w/o arg
76        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/// Logic DB about `impl` blocks. The DB also will include something associated with the impl
143/// blocks such as `trait` or `struct`.
144#[derive(Debug)]
145pub struct ImplLogic<'gcx> {
146    gcx: &'gcx GlobalCx<'gcx>,
147
148    db: DatabaseWrapper<'gcx>,
149
150    /// Stores already loaded items such as files, impl blocks, and so on in order to avoid
151    /// duplicate loading for the same item.
152    loaded: Set<*const ()>,
153
154    /// Default types of generic parameters of structs, traits, enums, and type aliases.
155    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    // TODO: Loading a huge file like "core" is taking a lot of time.
189    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    /// This method could generate clauses as follows.
256    /// * impl(SelfTy).
257    /// * impl(SelfTy, Trait).
258    /// * assoc_ty(SelfTy, Trait, AssocTy, AssignTy) :- impl(SelfTy, Trait).
259    /// * assoc_const_val(SelfTy, Trait, ConstName, ConstId) :-
260    ///   assoc_const_ty(Trait, ConstName, _).
261    /// * inher_fn(SelfTy, FnName, sig(..)) :- impl(SelfTy).
262    /// * inher_const(SelfTy, ConstName, ConstTy, ConstId) :- impl(SelfTy).
263    fn load_item_impl(&mut self, item_impl: &syn::ItemImpl) -> TriResult<(), ()> {
264        if self.has_loaded(item_impl) {
265            return Ok(());
266        }
267
268        // Generics
269        let mut bound = Bound::new(self.gcx);
270        bound.push_generics(&item_impl.generics, &mut self.host)?;
271
272        // Self type
273        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        // Trait
278        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        // e.g. `impl(SelfTy).` or `impl(SelfTy, Trait).`
290        self.logic.db.insert_clause(Clause {
291            head: impl_.clone(),
292            body: bound.take_bound_expr(),
293        });
294
295        // Now we go into inside 'impl' block, then make clauses for the associated items of the
296        // block.
297        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    /// This method could generate clauses as follows.
337    /// * impl(Struct, Sized) :- impl(Field, Sized).
338    fn load_item_struct(&mut self, item_struct: &syn::ItemStruct) -> TriResult<(), ()> {
339        // Generics
340        let mut bound = Bound::new(self.gcx);
341        bound.push_generics(&item_struct.generics, &mut self.host)?;
342
343        // Struct
344        let arg = generics_to_arg(&item_struct.generics, self.gcx);
345        let struct_ = self.host.ident_to_term(&item_struct.ident, arg)?;
346
347        // Adds default generics info.
348        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        // e.g. impl(Struct, Sized)
353        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        // e.g. impl(Field, Sized)
360        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    /// This method could generate clauses as follows.
381    /// * trait(Trait).
382    /// * assoc_fn(Trait, FnName, sig(..)) :- trait(Trait).
383    /// * assoc_const_ty(Trait, ConstName, ConstTy) :- trait(Trait).
384    /// * assoc_const_val(Trait, ConstName, ConstId) :- assoc_const_ty(Trait, ConstName, _).
385    fn load_item_trait(&mut self, item_trait: &syn::ItemTrait) -> TriResult<(), ()> {
386        // Generics
387        let mut bound = Bound::new(self.gcx);
388        bound.push_generics(&item_trait.generics, &mut self.host)?;
389
390        // Trait
391        let arg = generics_to_arg(&item_trait.generics, self.gcx);
392        let trait_ = self.host.ident_to_term(&item_trait.ident, arg)?;
393
394        // Adds default generics info.
395        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        // e.g. trait(Trait).
400        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        // Inside the trait definition block.
408        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    /// Returns true if the syn node has already been loaded. We don't need to load it again.
447    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    /// Records that the syn node has been fully loaded. [`has_loaded`](Self::has_loaded) will
453    /// return true for the syn node after call to this method.
454    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        // Confirms the change.
459        self.logic.db.commit();
460    }
461}
462
463// TODO: do we really need three lifetimes?
464/// For associated items in a trait impl block.
465struct 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(_) => { /* No corresponding term yet */ }
480                syn::ImplItem::Type(ty) => self._load_impl_item_type(ty)?,
481                _ => {}
482            }
483        }
484        Ok(())
485    }
486
487    /// This method could generate clauses as follows.
488    /// * assoc_const_val(SelfTy, Trait, ConstName, ConstId) :-
489    ///   assoc_const_ty(Trait, ConstName, _).
490    fn _load_impl_item_const(&mut self, item_const: &syn::ImplItemConst) -> TriResult<(), ()> {
491        // Note: `item_const.generics` is experimental at the time of writing, but just keep this
492        // for consistency.
493
494        debug_assert!(self.bound.bound_terms.is_empty());
495
496        // e.g. CONST<T, U> -> CONST(arg($T, $U))
497        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    /// This method could generate clauses as follows.
525    /// * assoc_ty(SelfTy, Trait, AssocTy, AssignTy) :- impl(SelfTy, Trait).
526    fn _load_impl_item_type(&mut self, item_ty: &syn::ImplItemType) -> TriResult<(), ()> {
527        // 'assoc_ty' should be implied(:-) by generic parameter's bounds.
528        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        // 'assoc_ty' should be implied(:-) by 'impl(SelfTy, Trait)'.
538        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
560// TODO: do we really need three lifetimes?
561/// For associated items in a trait definition block.
562struct 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    /// e.g. trait(Trait).
568    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    /// This method could generate clauses as follows.
585    /// * assoc_const_ty(Trait, ConstName, ConstTy) :- trait(Trait).
586    /// * assoc_const_val(Trait, ConstName, ConstId) :- assoc_const_ty(Trait, ConstName, _).
587    fn load_trait_item_const(&mut self, item_const: &syn::TraitItemConst) -> TriResult<(), ()> {
588        // Note: `item_const.generics` is experimental at the time of writing, but just keep this
589        // for consistency.
590
591        // `assoc_const_ty` should be implied(:-) by generic parameter's bounds.
592        debug_assert!(self.bound.bound_terms.is_empty());
593        self.bound.push_generics(&item_const.generics, self.host)?;
594
595        // `assoc_const_ty` should be implied(:-) by `trait(Trait)`.
596        self.bound.push_bound_term(self.trait_.clone());
597
598        // e.g. Takes `Trait` out of `trait(Trait)`.
599        let trait_ = self.trait_.args[0].clone();
600
601        // e.g. CONST<T, U> -> CONST(arg($T, $U))
602        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        // Inserts `assoc_const_ty(..)`.
611        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        // Inserts `assoc_const_val(..) :- assoc_const_ty(..)` if initialization expression exists.
618        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    /// This method could generate clauses as follows.
638    /// * assoc_fn(Trait, FnName, sig(..)) :- trait(Trait).
639    fn load_trait_item_fn(&mut self, item_fn: &syn::TraitItemFn) -> TriResult<(), ()> {
640        let sig = &item_fn.sig;
641
642        // `assoc_fn` should be implied(:-) by generic parameter's bounds.
643        debug_assert!(self.bound.bound_terms.is_empty());
644        self.bound.push_generics(&sig.generics, self.host)?;
645
646        // `assoc_fn` should be implied(:-) by `trait(Trait)`.
647        self.bound.push_bound_term(self.trait_.clone());
648
649        // e.g. Takes `Trait` out of `trait(Trait)`.
650        let trait_ = self.trait_.args[0].clone();
651
652        // e.g. foo<T, U> -> foo(arg($T, $U))
653        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
671// TODO: do we really need three lifetimes?
672/// For associated items in an inherent impl block.
673struct 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(_) => {} // Not supported by the language yet
689                _ => {}
690            }
691        }
692        Ok(())
693    }
694
695    /// This method could generate clauses as follows.
696    /// * inher_const(SelfTy, ConstName, ConstTy, ConstId) :- impl(SelfTy).
697    fn _load_impl_item_const(&mut self, item_const: &syn::ImplItemConst) -> TriResult<(), ()> {
698        // Note: `item_const.generics` is experimental at the time of writing, but just keep this
699        // for consistency.
700
701        // `inher_const` should be implied(:-) by generic parameter's bounds.
702        debug_assert!(self.bound.bound_terms.is_empty());
703        self.bound.push_generics(&item_const.generics, self.host)?;
704
705        // `inher_const` should be implied(:-) by `impl(SelfTy)`.
706        self.bound.push_bound_term(self.impl_.clone());
707
708        // e.g. CONST<T, U> -> CONST(arg($T, $U))
709        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        // const_id is the address of the init expression.
720        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    /// This method could generate clauses as follows.
740    /// * inher_fn(SelfTy, FnName, sig(..)) :- impl(SelfTy).
741    fn _load_impl_item_fn(&mut self, item_fn: &syn::ImplItemFn) -> TriResult<(), ()> {
742        let sig = &item_fn.sig;
743
744        // `inher_fn` should be implied(:-) by generic parameter's bounds.
745        debug_assert!(self.bound.bound_terms.is_empty());
746        self.bound.push_generics(&sig.generics, self.host)?;
747
748        // `inher_fn` should be implied(:-) by `impl(SelfTy)`.
749        self.bound.push_bound_term(self.impl_.clone());
750
751        // e.g. foo<T, U> -> foo(arg($T, $U))
752        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
771// TODO: do we really need three lifetimes?
772pub(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 generic type context.
778    default_cx: DefaultGenericCx<'b, 'gcx>,
779
780    /// If occupied, it means we're solving something related to the trait.
781    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    /// * trait_ - e.g. Add, not trait(Add).
818    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), // TODO: if len is complex expr?
864                        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    /// This method is meant to be called for a 'Fn' signature, not 'Closure'.
890    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                    // * If it's inherent method - We know the self type, so it will be a concrete
903                    // type.
904                    // * If it's trait associated function - We don't know self type, so it will be
905                    // something like ref($Self) or Box($Self) or ...
906                    let self_ty = self.type_to_term(&recv.ty)?;
907
908                    // If it's trait associated function, $Self needs a bound to impl($Self, Trait).
909                    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        // First segment -> canonical path segments
939        // e.g. Shl<i8> -> [core, ops, Shl(i8)]
940        let first = segments.clone().next().unwrap();
941
942        // If the path is something like `T::Assoc` and we're in a trait, then we turn it into
943        // `<T as Trait>::Assoc`.
944        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        // The rest of segments.
974        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    /// e.g.
994    /// If we have Trait, T::Assoc -> <T as Trait>::Assoc -> Term
995    /// If we don't have Trait, T::Assoc -> ConcreteTy::Assoc
996    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            // We're not inside a trait...
1021            todo!()
1022        }
1023    }
1024
1025    /// * Input - <qself_ty as trait_path>::trait_path
1026    /// * Output - A variable($X) with bounds
1027    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        // Replaces the self type of the defualt generic context.
1038        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    /// * Input - <self_ty as trait_>::assoc_item
1061    /// * Output - A variable($X) with bounds shown below
1062    /// * Bound - assoc_ty(self_ty, trait_, assoc_item, $X)
1063    /// * Bound - impl(self_ty, trait_)
1064    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            // 'assoc_ty' should be implied(:-) by 'impl(SelfTy, Trait)'.
1074            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    /// * path - e.g. `a::b::C`
1088    /// * args - e.g. `<X, Y>` in `a::b::C<X, Y>`
1089    /// * Output - arg(..)
1090    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 that will appear in a clause's body.
1140    ///
1141    /// e.g. some head :- impl(Foo, Clone), impl(Foo, Sized).
1142    bound_terms: Vec<TermIn<'gcx>>,
1143
1144    /// An integer for auto-generated variables.
1145    next_auto_var: u32,
1146
1147    /// Variable symbols.
1148    var_symbols: Vec<String>,
1149}
1150
1151impl<'gcx> Bound<'gcx> {
1152    pub(super) fn new(gcx: &'gcx GlobalCx<'gcx>) -> Self {
1153        // `Self` is a default variable symbol.
1154        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        // Rejects duplicate bound.
1166        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        // Removes redundant conditions. See detailed comments in the loop below.
1173        // - Preventing them from being inserted is quite complex. I think this is a little bit
1174        // inefficient, but looks better.
1175        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            // Case   : head :- assoc_ty(SelfTy, Trait), impl(SelfTy, Trait)
1183            // Reason : `assoc_ty` as a bound doesn't have to have `impl` bound. `assoc_ty` as the
1184            // head of a clause will have the `impl` bound.
1185            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    /// Don't forget to call [`Self::pop_generics`] after calling this method.
1210    fn push_generics<H: Host<'gcx>>(
1211        &mut self,
1212        generics: &syn::Generics,
1213        host: &mut HostWrapper<'_, 'gcx, H>,
1214    ) -> TriResult<(), ()> {
1215        // Stores idents of generic parameters. When we meet those idents later, we will make them
1216        // variables.
1217        self.var_symbols.push(String::new()); // Empty string is a seperator
1218        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                    // No terms related to this yet
1225                }
1226            }
1227        }
1228
1229        // Generic parameters that are not bound to ?Sized.
1230        let mut sized: Vec<TermIn<'gcx>> = Vec::new();
1231
1232        // Appends generic bound.
1233        //
1234        // NOTE: For now, we're considering type parameters only.
1235        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                    // For now, consider trait bounds only.
1245                    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            // e.g. $G implements Sized.
1280            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        // === Internal helper functions ===
1291
1292        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                // Bounds like `?Sized` will be added later at once.
1303                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            // e.g. `bounded_term` implements `trait_`.
1316            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                // Empty string is a seperator.
1326                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
1364/// * Key - The path of a struct, trait, enum or type alias.
1365/// * Value - Default generic types such as [None, Some(a::St), Some(Self)]
1366type DefaultGenericMap<'gcx> = Map<NameIn<'gcx>, BoxedSlice<Option<TermIn<'gcx>>>>;
1367
1368struct DefaultGenericCx<'a, 'gcx> {
1369    /// Optional default generic map.
1370    map: Option<&'a DefaultGenericMap<'gcx>>,
1371
1372    /// Optional self type for switching `Self` in the default generics.
1373    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    /// e.g. [None, Soem(A), Some(Self)] -> 3
1386    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    /// e.g. [None, Soem(A), Some(Self)] -> A, self_ty
1395    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                // Switches `Self` or `$Self` to `self_ty`
1407                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 well known 'Sized' types such as 'i32', 'u32', 'arr', and so on.
1428    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        // impl(X, Sized) plays kind of an important role in our logic. If we ask logic engine show
1444        // all possible types with a certain constraint, the engine will give us types that
1445        // appeared in impl(Ty, Sized).
1446        self._insert_impl_sized_for_known_on_demand(&clause);
1447
1448        // If the clause contains singleton variables(not being referred to), then puts prefix '_'
1449        // in front of them.
1450        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        // Removes custom prefix letters. `VAR_PREFIX`, on the other hand, would be removed by
1465        // logic_eval crate.
1466        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        // === Internal helper functions ===
1483
1484        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            // Inserts an additional clause shown below.
1530            // impl(array($_E, $_L), Sized).
1531            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            // Inserts an additional clause shown below.
1545            // impl(ref($_), Sized).
1546            else if term.functor.as_ref() == term::FUNCTOR_REF {
1547                let var = Term {
1548                    functor: var_name("_", this.gcx), // Anonymous variable in prolog
1549                    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            // Inserts additional clauses as follows.
1556            // e.g. impl(tuple($A, $B), Sized) :- impl($A, Sized), impl($B, Sized).
1557            // TODO: May cause neverend unifying in `logic-eval`.
1558            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            // Inserts additional clauses as follows.
1586            // e.g. impl(int(i32), Sized).
1587            else {
1588                debug_assert!(term.args.is_empty());
1589
1590                // e.g. i32 -> int(i32)
1591                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    /// e.g. foo($X, $Y) :- bar($X) => foo($X, $_Y) :- bar($X)
1601    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        // === Internal helper functions ===
1613
1614        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        /// Singleton variable here means a variable that appears only once in the clause. But,
1680        /// this method returns false even if it's singleton when it starts with '_' because we
1681        /// don't have things to do on that.
1682        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
1738/// * generics - e.g. <T, U>
1739/// * Output   - e.g. arg($T, $U)
1740fn 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        // impl(X, Sized) could automatically be generated on demand.
1888
1889        // Array (Sized)
1890        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        // Tuple (Sized)
1901        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        // User-defined structs (Sized)
1913        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        // Reference
1926        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        // Slice (Unsized)
1939        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        // Default generic types for a trait
1952        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        // Default generic types for a struct
1971        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        // Default generic types in a qself position.
1990        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        // Self in a generic parameter.
2020        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        // Self in a associated type.
2033        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        // Self in inherent methods.
2052        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}