1#[cfg(feature = "emit")]
2use core::mem::take;
3use core::ops::{Deref, DerefMut};
4
5use ::rust_alloc::rc::Rc;
6use ::rust_alloc::sync::Arc;
7
8use crate::alloc::borrow::Cow;
9use crate::alloc::prelude::*;
10use crate::alloc::{self, BTreeMap, HashSet, VecDeque};
11use crate::alloc::{hash_map, HashMap};
12use crate::ast;
13use crate::ast::{Span, Spanned};
14use crate::compile::context::ContextMeta;
15use crate::compile::{
16 self, ir, meta, CompileVisitor, Doc, DynLocation, ErrorKind, ImportStep, ItemId, ItemMeta,
17 Located, Location, MetaError, ModId, ModMeta, Names, Pool, Prelude, SourceLoader, SourceMeta,
18 UnitBuilder, Visibility, WithSpan,
19};
20use crate::grammar::{Ignore, Node, Stream};
21use crate::hir;
22use crate::indexing::{self, FunctionAst, Indexed, Items};
23use crate::item::ComponentRef;
24use crate::item::IntoComponent;
25use crate::macros::Storage;
26use crate::parse::{NonZeroId, Resolve};
27#[cfg(feature = "doc")]
28use crate::runtime::Call;
29use crate::runtime::ConstValue;
30use crate::shared::{Consts, Gen};
31use crate::{Context, Diagnostics, Hash, Item, ItemBuf, Options, SourceId, Sources};
32
33use super::{
34 Build, BuildEntry, BuiltInMacro, ConstFn, DeferEntry, ExpandedMacro, GenericsParameters, Named,
35 Named2, Named2Kind, Used,
36};
37
38enum ContextMatch<'this, 'm> {
39 Context(&'m ContextMeta, Hash),
40 Meta(&'this meta::Meta),
41 None,
42}
43
44const IMPORT_RECURSION_LIMIT: usize = 128;
46
47#[derive(Default)]
48pub(crate) struct QueryInner<'arena> {
49 meta: HashMap<(ItemId, Hash), meta::Meta>,
51 pub(crate) queue: VecDeque<BuildEntry>,
53 used: HashSet<ItemId>,
55 indexed: BTreeMap<ItemId, Vec<indexing::Entry>>,
58 const_fns: HashMap<ItemId, Rc<ConstFn<'arena>>>,
60 constants: HashMap<Hash, ConstValue>,
62 internal_macros: HashMap<NonZeroId, Arc<BuiltInMacro>>,
64 expanded_macros: HashMap<NonZeroId, ExpandedMacro>,
66 pub(crate) items: HashMap<ItemId, ItemMeta>,
72 names: Names,
74 pub(crate) defer_queue: VecDeque<DeferEntry>,
76}
77
78impl QueryInner<'_> {
79 pub(crate) fn get_const_value(&self, hash: Hash) -> Option<&ConstValue> {
81 self.constants.get(&hash)
82 }
83}
84
85pub(crate) struct QuerySource<'a, 'arena> {
86 query: Query<'a, 'arena>,
87 source_id: SourceId,
88}
89
90impl<'a, 'arena> Deref for QuerySource<'a, 'arena> {
91 type Target = Query<'a, 'arena>;
92
93 #[inline]
94 fn deref(&self) -> &Self::Target {
95 &self.query
96 }
97}
98
99impl DerefMut for QuerySource<'_, '_> {
100 #[inline]
101 fn deref_mut(&mut self) -> &mut Self::Target {
102 &mut self.query
103 }
104}
105
106impl<'a> Ignore<'a> for QuerySource<'_, '_> {
107 #[inline]
108 fn error(&mut self, error: compile::Error) -> alloc::Result<()> {
109 self.query.diagnostics.error(self.source_id, error)
110 }
111
112 #[inline]
113 fn ignore(&mut self, _: Node<'a>) -> compile::Result<()> {
114 Ok(())
115 }
116}
117
118pub(crate) struct Query<'a, 'arena> {
128 pub(crate) unit: &'a mut UnitBuilder,
130 prelude: &'a Prelude,
132 pub(crate) const_arena: &'arena hir::Arena,
134 pub(crate) consts: &'a mut Consts,
136 pub(crate) storage: &'a mut Storage,
138 pub(crate) sources: &'a mut Sources,
140 pub(crate) pool: &'a mut Pool,
142 pub(crate) visitor: &'a mut dyn CompileVisitor,
144 pub(crate) diagnostics: &'a mut Diagnostics,
146 pub(crate) source_loader: &'a mut dyn SourceLoader,
148 pub(crate) options: &'a Options,
150 pub(crate) gen: &'a Gen,
152 pub(crate) context: &'a Context,
154 pub(crate) inner: &'a mut QueryInner<'arena>,
156}
157
158impl<'a, 'arena> Query<'a, 'arena> {
159 pub(crate) fn new(
161 unit: &'a mut UnitBuilder,
162 prelude: &'a Prelude,
163 const_arena: &'arena hir::Arena,
164 consts: &'a mut Consts,
165 storage: &'a mut Storage,
166 sources: &'a mut Sources,
167 pool: &'a mut Pool,
168 visitor: &'a mut dyn CompileVisitor,
169 diagnostics: &'a mut Diagnostics,
170 source_loader: &'a mut dyn SourceLoader,
171 options: &'a Options,
172 gen: &'a Gen,
173 context: &'a Context,
174 inner: &'a mut QueryInner<'arena>,
175 ) -> Self {
176 Self {
177 unit,
178 prelude,
179 const_arena,
180 consts,
181 storage,
182 sources,
183 pool,
184 visitor,
185 diagnostics,
186 source_loader,
187 options,
188 gen,
189 context,
190 inner,
191 }
192 }
193
194 pub(crate) fn borrow(&mut self) -> Query<'_, 'arena> {
196 Query {
197 unit: self.unit,
198 prelude: self.prelude,
199 const_arena: self.const_arena,
200 consts: self.consts,
201 storage: self.storage,
202 pool: self.pool,
203 sources: self.sources,
204 visitor: self.visitor,
205 diagnostics: self.diagnostics,
206 source_loader: self.source_loader,
207 options: self.options,
208 gen: self.gen,
209 context: self.context,
210 inner: self.inner,
211 }
212 }
213
214 pub(crate) fn with_source_id(&mut self, source_id: SourceId) -> QuerySource<'_, 'arena> {
216 QuerySource {
217 query: self.borrow(),
218 source_id,
219 }
220 }
221
222 pub(crate) fn is_used(&self, item_meta: &ItemMeta) -> bool {
224 self.inner.used.contains(&item_meta.item)
225 }
226
227 pub(crate) fn set_used(&mut self, item_meta: &ItemMeta) -> alloc::Result<()> {
229 self.inner.used.try_insert(item_meta.item)?;
230 Ok(())
231 }
232
233 pub(crate) fn insert_new_macro(
235 &mut self,
236 expand_macro: impl FnOnce(NonZeroId) -> alloc::Result<DeferEntry>,
237 ) -> alloc::Result<NonZeroId> {
238 let id = self.gen.next();
239 self.inner.defer_queue.try_push_back(expand_macro(id)?)?;
240 Ok(id)
241 }
242
243 pub(crate) fn next_defer_entry(&mut self) -> Option<DeferEntry> {
245 self.inner.defer_queue.pop_front()
246 }
247
248 pub(crate) fn next_build_entry(&mut self) -> Option<BuildEntry> {
251 self.inner.queue.pop_front()
252 }
253
254 fn select_context_meta<'this, 'm>(
256 &'this self,
257 item: ItemId,
258 metas: impl Iterator<Item = &'m ContextMeta> + Clone,
259 parameters: &GenericsParameters,
260 ) -> Result<ContextMatch<'this, 'm>, rust_alloc::boxed::Box<ErrorKind>> {
261 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
262 enum Kind {
263 None,
264 Type,
265 Function,
266 AssociatedFunction,
267 }
268
269 fn determine_kind<'m>(metas: impl Iterator<Item = &'m ContextMeta>) -> Option<Kind> {
272 let mut kind = Kind::None;
273
274 for meta in metas {
275 let alt = match &meta.kind {
276 meta::Kind::Enum { .. }
277 | meta::Kind::Struct { .. }
278 | meta::Kind::Type { .. } => Kind::Type,
279 meta::Kind::Function {
280 associated: None, ..
281 } => Kind::Function,
282 meta::Kind::Function {
283 associated: Some(..),
284 ..
285 } => Kind::AssociatedFunction,
286 _ => {
287 continue;
288 }
289 };
290
291 if matches!(kind, Kind::None) {
292 kind = alt;
293 continue;
294 }
295
296 if kind != alt {
297 return None;
298 }
299 }
300
301 Some(kind)
302 }
303
304 fn build_parameters(kind: Kind, p: &GenericsParameters) -> Option<Hash> {
305 let hash = match (kind, p.trailing, p.parameters) {
306 (_, 0, _) => Hash::EMPTY,
307 (Kind::Type, 1, [Some(ty), None]) => Hash::EMPTY.with_type_parameters(ty),
308 (Kind::Function, 1, [Some(f), None]) => Hash::EMPTY.with_function_parameters(f),
309 (Kind::AssociatedFunction, 1, [Some(f), None]) => {
310 Hash::EMPTY.with_function_parameters(f)
311 }
312 (Kind::AssociatedFunction, 2, [Some(ty), f]) => Hash::EMPTY
313 .with_type_parameters(ty)
314 .with_function_parameters(f.unwrap_or(Hash::EMPTY)),
315 _ => {
316 return None;
317 }
318 };
319
320 Some(hash)
321 }
322
323 if let Some(parameters) =
324 determine_kind(metas.clone()).and_then(|kind| build_parameters(kind, parameters))
325 {
326 if let Some(meta) = self.get_meta(item, parameters) {
327 return Ok(ContextMatch::Meta(meta));
328 }
329
330 let mut it = metas
333 .clone()
334 .filter(|i| !matches!(i.kind, meta::Kind::Macro | meta::Kind::Module))
335 .filter(|i| i.kind.as_parameters() == parameters);
336
337 if let Some(meta) = it.next() {
338 if it.next().is_none() {
339 return Ok(ContextMatch::Context(meta, parameters));
340 }
341 } else {
342 return Ok(ContextMatch::None);
343 }
344 }
345
346 if metas.clone().next().is_none() {
347 return Ok(ContextMatch::None);
348 }
349
350 Err(rust_alloc::boxed::Box::new(
351 ErrorKind::AmbiguousContextItem {
352 item: self.pool.item(item).try_to_owned()?,
353 #[cfg(feature = "emit")]
354 infos: metas
355 .map(|i| i.info())
356 .try_collect::<alloc::Result<_>>()??,
357 },
358 ))
359 }
360
361 #[tracing::instrument(skip_all, fields(item = ?self.pool.item(item), parameters))]
363 pub(crate) fn try_lookup_meta(
364 &mut self,
365 location: &dyn Located,
366 item: ItemId,
367 parameters: &GenericsParameters,
368 ) -> compile::Result<Option<meta::Meta>> {
369 tracing::trace!("looking up meta");
370
371 if parameters.is_empty() {
372 if let Some(meta) = self.query_meta(location.as_spanned(), item, Default::default())? {
373 tracing::trace!(?meta, "found in query");
374
375 self.visitor
376 .visit_meta(location, meta.as_meta_ref(self.pool))
377 .with_span(location.as_spanned())?;
378 return Ok(Some(meta));
379 }
380 }
381
382 let Some(metas) = self.context.lookup_meta(self.pool.item(item)) else {
383 return Ok(None);
384 };
385
386 let (meta, parameters) = match self
387 .select_context_meta(item, metas, parameters)
388 .with_span(location.as_spanned())?
389 {
390 ContextMatch::None => return Ok(None),
391 ContextMatch::Meta(meta) => return Ok(Some(meta.try_clone()?)),
392 ContextMatch::Context(meta, parameters) => (meta, parameters),
393 };
394
395 let Some(item) = &meta.item else {
396 return Err(compile::Error::new(
397 location.as_spanned(),
398 ErrorKind::MissingItemHash { hash: meta.hash },
399 ));
400 };
401
402 let item = self.pool.alloc_item(item)?;
403
404 let meta = meta::Meta {
405 context: true,
406 hash: meta.hash,
407 item_meta: self.context_item_meta(item, None),
408 kind: meta.kind.try_clone()?,
409 source: None,
410 parameters,
411 };
412
413 self.insert_meta(meta.try_clone()?)
414 .with_span(location.as_spanned())?;
415
416 tracing::trace!(?meta, "Found in context");
417
418 self.visitor
419 .visit_meta(location, meta.as_meta_ref(self.pool))
420 .with_span(location.as_spanned())?;
421
422 Ok(Some(meta))
423 }
424
425 pub(crate) fn lookup_meta(
427 &mut self,
428 location: &dyn Located,
429 item: ItemId,
430 parameters: impl AsRef<GenericsParameters>,
431 ) -> compile::Result<meta::Meta> {
432 let parameters = parameters.as_ref();
433
434 if let Some(meta) = self.try_lookup_meta(location, item, parameters)? {
435 return Ok(meta);
436 }
437
438 let kind = if !parameters.parameters.is_empty() {
439 ErrorKind::MissingItemParameters {
440 item: self.pool.item(item).try_to_owned()?,
441 parameters: parameters.parameters,
442 }
443 } else {
444 ErrorKind::MissingItem {
445 item: self.pool.item(item).try_to_owned()?,
446 }
447 };
448
449 Err(compile::Error::new(location.as_spanned(), kind))
450 }
451
452 pub(crate) fn lookup_deprecation(&self, hash: Hash) -> Option<&str> {
453 self.context.lookup_deprecation(hash)
454 }
455
456 pub(crate) fn insert_mod(
458 &mut self,
459 items: &Items,
460 location: &dyn Located,
461 parent: ModId,
462 visibility: Visibility,
463 docs: &[Doc],
464 ) -> compile::Result<(ModId, ItemId)> {
465 let item = self.pool.alloc_item(items.item())?;
466
467 let module = self.pool.alloc_module(ModMeta {
468 #[cfg(feature = "emit")]
469 location: location.location(),
470 item,
471 visibility,
472 parent: Some(parent),
473 })?;
474
475 let item_meta =
476 self.insert_new_item_with(item, module, None, location, visibility, docs)?;
477
478 self.index_and_build(indexing::Entry {
479 item_meta,
480 indexed: Indexed::Module,
481 })?;
482
483 Ok((module, item))
484 }
485
486 pub(crate) fn insert_root_mod(
488 &mut self,
489 source_id: SourceId,
490 span: Span,
491 ) -> compile::Result<(ItemId, ModId)> {
492 let location = Location::new(source_id, span);
493
494 let module = self.pool.alloc_module(ModMeta {
495 #[cfg(feature = "emit")]
496 location,
497 item: ItemId::ROOT,
498 visibility: Visibility::Public,
499 parent: None,
500 })?;
501
502 self.inner.items.try_insert(
503 ItemId::ROOT,
504 ItemMeta {
505 location,
506 item: ItemId::ROOT,
507 visibility: Visibility::Public,
508 module,
509 impl_item: None,
510 },
511 )?;
512
513 self.insert_name(ItemId::ROOT).with_span(span)?;
514 Ok((ItemId::ROOT, module))
515 }
516
517 pub(crate) fn insert_new_item(
522 &mut self,
523 items: &Items,
524 module: ModId,
525 impl_item: Option<ItemId>,
526 location: &dyn Located,
527 visibility: Visibility,
528 docs: &[Doc],
529 ) -> compile::Result<ItemMeta> {
530 let item = self.pool.alloc_item(items.item())?;
531 self.insert_new_item_with(item, module, impl_item, location, visibility, docs)
532 }
533
534 pub(crate) fn insert_meta(&mut self, meta: meta::Meta) -> Result<&ItemMeta, MetaError> {
536 self.visitor.register_meta(meta.as_meta_ref(self.pool))?;
537
538 let meta = match self
539 .inner
540 .meta
541 .entry((meta.item_meta.item, meta.parameters))
542 {
543 hash_map::Entry::Occupied(e) => {
544 return Err(MetaError::new(
545 compile::error::MetaErrorKind::MetaConflict {
546 current: meta.info(self.pool)?,
547 existing: e.get().info(self.pool)?,
548 parameters: meta.parameters,
549 },
550 ));
551 }
552 hash_map::Entry::Vacant(e) => e.try_insert(meta)?,
553 };
554
555 Ok(&meta.item_meta)
556 }
557
558 fn insert_new_item_with(
561 &mut self,
562 item: ItemId,
563 module: ModId,
564 impl_item: Option<ItemId>,
565 location: &dyn Located,
566 visibility: Visibility,
567 docs: &[Doc],
568 ) -> compile::Result<ItemMeta> {
569 let location = location.location();
570
571 if !docs.is_empty() {
573 let cx = resolve_context!(self);
574
575 for doc in docs {
576 self.visitor
577 .visit_doc_comment(
578 &DynLocation::new(location.source_id, &doc.span),
579 self.pool.item(item),
580 self.pool.item_type_hash(item),
581 doc.doc_string.resolve(cx)?.as_ref(),
582 )
583 .with_span(location)?;
584 }
585 }
586
587 let item_meta = ItemMeta {
588 location,
589 item,
590 module,
591 visibility,
592 impl_item,
593 };
594
595 self.inner.items.try_insert(item, item_meta)?;
596 Ok(item_meta)
597 }
598
599 pub(crate) fn insert_new_builtin_macro(
601 &mut self,
602 internal_macro: BuiltInMacro,
603 ) -> compile::Result<NonZeroId> {
604 let id = self.gen.next();
605 self.inner
606 .internal_macros
607 .try_insert(id, Arc::new(internal_macro))?;
608 Ok(id)
609 }
610
611 pub(crate) fn insert_expanded_macro(
613 &mut self,
614 id: NonZeroId,
615 expanded: ExpandedMacro,
616 ) -> compile::Result<()> {
617 self.inner.expanded_macros.try_insert(id, expanded)?;
618 Ok(())
619 }
620
621 pub(crate) fn take_expanded_macro(&mut self, id: NonZeroId) -> Option<ExpandedMacro> {
623 self.inner.expanded_macros.remove(&id)
624 }
625
626 pub(crate) fn item_for(&self, what: &'static str, id: ItemId) -> anyhow::Result<ItemMeta> {
628 let Some(item_meta) = self.inner.items.get(&id) else {
629 let m = try_format!(
630 "missing item meta for `{what}` at {} with id {id}",
631 self.pool.item(id)
632 );
633 return Err(anyhow::Error::msg(m));
634 };
635
636 Ok(*item_meta)
637 }
638
639 pub(crate) fn builtin_macro_for(&self, id: NonZeroId) -> anyhow::Result<Arc<BuiltInMacro>> {
641 let Some(internal_macro) = self.inner.internal_macros.get(&id) else {
642 let m = try_format!("missing built-in macro for id {id}");
643 return Err(anyhow::Error::msg(m));
644 };
645
646 Ok(internal_macro.clone())
647 }
648
649 pub(crate) fn const_fn_for(&self, id: ItemId) -> anyhow::Result<Rc<ConstFn<'a>>> {
651 let Some(const_fn) = self.inner.const_fns.get(&id) else {
652 let m = try_format!(
653 "missing constant function {} for id {id}",
654 self.pool.item(id)
655 );
656 return Err(anyhow::Error::msg(m));
657 };
658
659 Ok(const_fn.clone())
660 }
661
662 #[tracing::instrument(skip_all)]
664 pub(crate) fn index(&mut self, entry: indexing::Entry) -> compile::Result<()> {
665 tracing::trace!(item = ?self.pool.item(entry.item_meta.item));
666
667 self.insert_name(entry.item_meta.item)
668 .with_span(entry.item_meta.location.span)?;
669
670 self.inner
671 .indexed
672 .entry(entry.item_meta.item)
673 .or_try_default()?
674 .try_push(entry)?;
675
676 Ok(())
677 }
678
679 #[tracing::instrument(skip_all)]
681 pub(crate) fn index_and_build(&mut self, entry: indexing::Entry) -> compile::Result<()> {
682 self.set_used(&entry.item_meta)?;
683
684 self.inner.queue.try_push_back(BuildEntry {
685 item_meta: entry.item_meta,
686 build: Build::Query,
687 })?;
688
689 self.index(entry)?;
690 Ok(())
691 }
692
693 #[tracing::instrument(skip_all)]
695 pub(crate) fn index_const_expr(
696 &mut self,
697 item_meta: ItemMeta,
698 const_expr: indexing::ConstExpr,
699 ) -> compile::Result<()> {
700 tracing::trace!(item = ?self.pool.item(item_meta.item));
701
702 self.index(indexing::Entry {
703 item_meta,
704 indexed: Indexed::ConstExpr(const_expr),
705 })?;
706
707 Ok(())
708 }
709
710 #[tracing::instrument(skip_all)]
712 pub(crate) fn index_const_block(
713 &mut self,
714 item_meta: ItemMeta,
715 block: indexing::ConstBlock,
716 ) -> compile::Result<()> {
717 tracing::trace!(item = ?self.pool.item(item_meta.item));
718
719 self.index(indexing::Entry {
720 item_meta,
721 indexed: Indexed::ConstBlock(block),
722 })?;
723
724 Ok(())
725 }
726
727 #[tracing::instrument(skip_all)]
729 pub(crate) fn index_const_fn(
730 &mut self,
731 item_meta: ItemMeta,
732 const_fn: indexing::ConstFn,
733 ) -> compile::Result<()> {
734 tracing::trace!(item = ?self.pool.item(item_meta.item));
735
736 self.index(indexing::Entry {
737 item_meta,
738 indexed: Indexed::ConstFn(const_fn),
739 })?;
740
741 Ok(())
742 }
743
744 #[tracing::instrument(skip_all)]
746 pub(crate) fn index_enum(&mut self, item_meta: ItemMeta) -> compile::Result<()> {
747 tracing::trace!(item = ?self.pool.item(item_meta.item));
748
749 self.index(indexing::Entry {
750 item_meta,
751 indexed: Indexed::Enum,
752 })?;
753
754 Ok(())
755 }
756
757 #[tracing::instrument(skip_all)]
759 pub(crate) fn index_struct(
760 &mut self,
761 item_meta: ItemMeta,
762 st: indexing::Struct,
763 ) -> compile::Result<()> {
764 tracing::trace!(item = ?self.pool.item(item_meta.item));
765
766 self.index(indexing::Entry {
767 item_meta,
768 indexed: Indexed::Struct(st),
769 })?;
770
771 Ok(())
772 }
773
774 #[tracing::instrument(skip_all)]
776 pub(crate) fn index_variant(
777 &mut self,
778 item_meta: ItemMeta,
779 variant: indexing::Variant,
780 ) -> compile::Result<()> {
781 tracing::trace!(item = ?self.pool.item(item_meta.item));
782
783 self.index(indexing::Entry {
784 item_meta,
785 indexed: Indexed::Variant(variant),
786 })?;
787
788 Ok(())
789 }
790
791 #[tracing::instrument(skip_all)]
793 pub(crate) fn index_meta(
794 &mut self,
795 span: &dyn Spanned,
796 item_meta: ItemMeta,
797 kind: meta::Kind,
798 ) -> compile::Result<()> {
799 tracing::trace!(item = ?self.pool.item(item_meta.item));
800
801 let source = SourceMeta {
802 location: item_meta.location,
803 path: self
804 .sources
805 .path(item_meta.location.source_id)
806 .map(|p| p.try_into())
807 .transpose()?,
808 };
809
810 let meta = meta::Meta {
811 context: false,
812 hash: self.pool.item_type_hash(item_meta.item),
813 item_meta,
814 kind,
815 source: Some(source),
816 parameters: Hash::EMPTY,
817 };
818
819 self.unit.insert_meta(span, &meta, self.pool, self.inner)?;
820 self.insert_meta(meta).with_span(span)?;
821 Ok(())
822 }
823
824 #[tracing::instrument(skip_all)]
828 pub(crate) fn queue_unused_entries(
829 &mut self,
830 errors: &mut Vec<(SourceId, compile::Error)>,
831 ) -> alloc::Result<bool> {
832 tracing::trace!("Queue unused");
833
834 let unused = self
835 .inner
836 .indexed
837 .values()
838 .flat_map(|entries| entries.iter())
839 .map(|e| (e.item_meta.location, e.item_meta.item))
840 .try_collect::<Vec<_>>()?;
841
842 if unused.is_empty() {
843 return Ok(true);
844 }
845
846 for (location, item) in unused {
847 if let Err(error) = self.query_indexed_meta(&location, item, Used::Unused) {
848 errors.try_push((location.source_id, error))?;
849 }
850 }
851
852 Ok(false)
853 }
854
855 pub(crate) fn get_meta(&self, item: ItemId, hash: Hash) -> Option<&meta::Meta> {
857 self.inner.meta.get(&(item, hash))
858 }
859
860 #[tracing::instrument(skip(self, span, item), fields(item = ?self.pool.item(item)))]
863 pub(crate) fn query_meta(
864 &mut self,
865 span: &dyn Spanned,
866 item: ItemId,
867 used: Used,
868 ) -> compile::Result<Option<meta::Meta>> {
869 if let Some(meta) = self.inner.meta.get(&(item, Hash::EMPTY)) {
870 tracing::trace!(item = ?item, meta = ?meta, "cached");
871 debug_assert!(!self.inner.indexed.contains_key(&item));
875 return Ok(Some(meta.try_clone()?));
876 }
877
878 self.query_indexed_meta(span, item, used)
879 }
880
881 #[tracing::instrument(skip_all, fields(item = ?self.pool.item(item)))]
883 fn query_indexed_meta(
884 &mut self,
885 span: &dyn Spanned,
886 item: ItemId,
887 used: Used,
888 ) -> compile::Result<Option<meta::Meta>> {
889 tracing::trace!("query indexed meta");
890
891 if let Some(entry) = self.remove_indexed(span, item)? {
892 let meta = self.build_indexed_entry(span, entry, used)?;
893 self.unit.insert_meta(span, &meta, self.pool, self.inner)?;
894 self.insert_meta(meta.try_clone()?).with_span(span)?;
895 tracing::trace!(item = ?item, meta = ?meta, "build");
896 return Ok(Some(meta));
897 }
898
899 Ok(None)
900 }
901
902 pub(crate) fn convert_path<'ast>(
904 &mut self,
905 path: &'ast ast::Path,
906 ) -> compile::Result<Named<'ast>> {
907 self.convert_path_with(path, false, Used::Used, Used::Used)
908 }
909
910 #[tracing::instrument(skip(self, path))]
912 pub(crate) fn convert_path_with<'ast>(
913 &mut self,
914 path: &'ast ast::Path,
915 deny_self_type: bool,
916 import_used: Used,
917 used: Used,
918 ) -> compile::Result<Named<'ast>> {
919 tracing::trace!("converting path");
920
921 let Some(&ItemMeta {
922 module,
923 item,
924 impl_item,
925 ..
926 }) = self.inner.items.get(&path.id)
927 else {
928 return Err(compile::Error::msg(
929 path,
930 try_format!("Missing query path for id {}", path.id),
931 ));
932 };
933
934 let mut in_self_type = false;
935
936 let item = match (&path.global, &path.first) {
937 (Some(..), ast::PathSegment::Ident(ident)) => self
938 .pool
939 .alloc_item(ItemBuf::with_crate(ident.resolve(resolve_context!(self))?)?)?,
940 (Some(span), _) => {
941 return Err(compile::Error::new(span, ErrorKind::UnsupportedGlobal));
942 }
943 (None, segment) => match segment {
944 ast::PathSegment::Ident(ident) => {
945 self.convert_initial_path(module, item, ident, used)?
946 }
947 ast::PathSegment::Super(..) => {
948 let Some(segment) = self
949 .pool
950 .try_map_alloc(self.pool.module(module).item, Item::parent)?
951 else {
952 return Err(compile::Error::new(segment, ErrorKind::UnsupportedSuper));
953 };
954
955 segment
956 }
957 ast::PathSegment::SelfType(..) => {
958 let impl_item = match impl_item {
959 Some(impl_item) if !deny_self_type => impl_item,
960 _ => {
961 return Err(compile::Error::new(
962 segment.span(),
963 ErrorKind::UnsupportedSelfType,
964 ));
965 }
966 };
967
968 let Some(impl_item) = self.inner.items.get(&impl_item) else {
969 return Err(compile::Error::msg(
970 segment.span(),
971 "Can't use `Self` due to unexpanded impl item",
972 ));
973 };
974
975 in_self_type = true;
976 impl_item.item
977 }
978 ast::PathSegment::SelfValue(..) => self.pool.module(module).item,
979 ast::PathSegment::Crate(..) => ItemId::ROOT,
980 ast::PathSegment::Generics(..) => {
981 return Err(compile::Error::new(
982 segment.span(),
983 ErrorKind::UnsupportedGenerics,
984 ));
985 }
986 },
987 };
988
989 let mut item = self.pool.item(item).try_to_owned()?;
990 let mut trailing = 0;
991 let mut parameters: [Option<(&dyn Spanned, _)>; 2] = [None, None];
992
993 let mut it = path.rest.iter();
994 let mut parameters_it = parameters.iter_mut();
995
996 for (_, segment) in it.by_ref() {
997 match segment {
998 ast::PathSegment::Ident(ident) => {
999 item.push(ident.resolve(resolve_context!(self))?)?;
1000 }
1001 ast::PathSegment::Super(span) => {
1002 if in_self_type {
1003 return Err(compile::Error::new(
1004 span,
1005 ErrorKind::UnsupportedSuperInSelfType,
1006 ));
1007 }
1008
1009 if !item.pop() {
1010 return Err(compile::Error::new(segment, ErrorKind::UnsupportedSuper));
1011 }
1012 }
1013 ast::PathSegment::Generics(arguments) => {
1014 let Some(p) = parameters_it.next() else {
1015 return Err(compile::Error::new(segment, ErrorKind::UnsupportedGenerics));
1016 };
1017
1018 trailing += 1;
1019 *p = Some((segment, arguments));
1020 break;
1021 }
1022 _ => {
1023 return Err(compile::Error::new(
1024 segment.span(),
1025 ErrorKind::ExpectedLeadingPathSegment,
1026 ));
1027 }
1028 }
1029 }
1030
1031 while let Some((_, segment)) = it.next() {
1033 let ast::PathSegment::Ident(ident) = segment else {
1034 return Err(compile::Error::new(
1035 segment.span(),
1036 ErrorKind::UnsupportedAfterGeneric,
1037 ));
1038 };
1039
1040 trailing += 1;
1041 item.push(ident.resolve(resolve_context!(self))?)?;
1042
1043 let Some(p) = parameters_it.next() else {
1044 return Err(compile::Error::new(segment, ErrorKind::UnsupportedGenerics));
1045 };
1046
1047 let Some(ast::PathSegment::Generics(arguments)) = it.clone().next().map(|(_, p)| p)
1048 else {
1049 continue;
1050 };
1051
1052 *p = Some((segment, arguments));
1053 it.next();
1054 }
1055
1056 let item = self.pool.alloc_item(item)?;
1057
1058 if let Some(new) = self.import(path, module, item, import_used, used)? {
1059 return Ok(Named {
1060 module,
1061 item: new,
1062 trailing,
1063 parameters,
1064 });
1065 }
1066
1067 Ok(Named {
1068 module,
1069 item,
1070 trailing,
1071 parameters,
1072 })
1073 }
1074
1075 pub(crate) fn convert_path2<'ast>(
1077 &mut self,
1078 p: &mut Stream<'ast>,
1079 ) -> compile::Result<Named2<'ast>> {
1080 self.convert_path2_with(p, false, Used::Used, Used::Used)
1081 }
1082
1083 #[tracing::instrument(skip(self, p))]
1085 pub(crate) fn convert_path2_with<'ast>(
1086 &mut self,
1087 p: &mut Stream<'ast>,
1088 deny_self_type: bool,
1089 import_used: Used,
1090 used: Used,
1091 ) -> compile::Result<Named2<'ast>> {
1092 use ast::Kind::*;
1093
1094 let IndexedPath(id) = p.kind() else {
1095 return Err(p.expected(Path));
1096 };
1097
1098 tracing::trace!("converting path");
1099
1100 let Some(&ItemMeta {
1101 module,
1102 item,
1103 impl_item,
1104 ..
1105 }) = self.inner.items.get(&id)
1106 else {
1107 return Err(compile::Error::msg(
1108 &*p,
1109 try_format!("missing query path for id {id}"),
1110 ));
1111 };
1112
1113 let mut trailing = 0;
1114 let mut parameters = [None, None];
1115
1116 let (item, kind) = 'out: {
1117 match p.kinds() {
1118 Some([K![ident]]) => {
1119 let ast = p.ast::<ast::Ident>()?;
1120 let item = self.convert_initial_path(module, item, &ast, used)?;
1121 let kind = Named2Kind::Ident(ast);
1122 break 'out (item, kind);
1123 }
1124 Some([K![self]]) => {
1125 let ast = p.ast::<ast::SelfValue>()?;
1126 let item = self.pool.module(module).item;
1127 let kind = Named2Kind::SelfValue(ast);
1128 break 'out (item, kind);
1129 }
1130 _ => {}
1131 }
1132
1133 let item = self.path_full(
1134 p,
1135 deny_self_type,
1136 used,
1137 module,
1138 item,
1139 impl_item,
1140 &mut trailing,
1141 &mut parameters,
1142 )?;
1143
1144 (item, Named2Kind::Full)
1145 };
1146
1147 let item = self
1148 .import(&*p, module, item, import_used, used)?
1149 .unwrap_or(item);
1150
1151 Ok(Named2 {
1152 module,
1153 kind,
1154 item,
1155 trailing,
1156 parameters,
1157 })
1158 }
1159
1160 fn path_full<'ast>(
1162 &mut self,
1163 p: &mut Stream<'ast>,
1164 deny_self_type: bool,
1165 used: Used,
1166 module: ModId,
1167 item: ItemId,
1168 impl_item: Option<ItemId>,
1169 trailing: &mut usize,
1170 parameters: &mut [Option<Node<'ast>>],
1171 ) -> compile::Result<ItemId> {
1172 use ast::Kind::*;
1173
1174 let mut in_self_type = false;
1175
1176 let is_global = p.eat(K![::]).span();
1177 let first = p.pump()?;
1178
1179 let (item, mut supports_generics) = match (is_global, first.kind()) {
1180 (Some(..), K![ident]) => {
1181 let first = first.ast::<ast::Ident>()?;
1182 let first = first.resolve(resolve_context!(self))?;
1183 let item = self.pool.alloc_item(ItemBuf::with_crate(first)?)?;
1184 (item, true)
1185 }
1186 (Some(node), _) => {
1187 return Err(compile::Error::new(node, ErrorKind::UnsupportedGlobal));
1188 }
1189 (None, K![ident]) => {
1190 let first = first.ast::<ast::Ident>()?;
1191 let item = self.convert_initial_path(module, item, &first, used)?;
1192 (item, true)
1193 }
1194 (None, K![super]) => {
1195 let Some(item) = self
1196 .pool
1197 .try_map_alloc(self.pool.module(module).item, crate::Item::parent)?
1198 else {
1199 return Err(compile::Error::new(first, ErrorKind::UnsupportedSuper));
1200 };
1201
1202 (item, false)
1203 }
1204 (None, K![Self]) => {
1205 let impl_item = match impl_item {
1206 Some(impl_item) if !deny_self_type => impl_item,
1207 _ => {
1208 return Err(compile::Error::new(first, ErrorKind::UnsupportedSelfType));
1209 }
1210 };
1211
1212 let Some(impl_item) = self.inner.items.get(&impl_item) else {
1213 return Err(compile::Error::msg(
1214 first,
1215 "Can't use `Self` due to unexpanded impl item",
1216 ));
1217 };
1218
1219 in_self_type = true;
1220 (impl_item.item, false)
1221 }
1222 (None, K![self]) => {
1223 let item = self.pool.module(module).item;
1224 (item, false)
1225 }
1226 (None, K![crate]) => (ItemId::ROOT, false),
1227 (_, PathGenerics) => {
1228 return Err(compile::Error::new(first, ErrorKind::UnsupportedGenerics));
1229 }
1230 _ => {
1231 return Err(first.expected(Path));
1232 }
1233 };
1234
1235 let mut item = self.pool.item(item).try_to_owned()?;
1236 let mut it = parameters.iter_mut();
1237
1238 while !p.is_eof() {
1239 p.expect(K![::])?;
1240 let node = p.pump()?;
1241
1242 match node.kind() {
1243 K![ident] => {
1244 let ident = node.ast::<ast::Ident>()?;
1245 item.push(ident.resolve(resolve_context!(self))?)?;
1246 supports_generics = true;
1247 }
1248 K![super] => {
1249 if in_self_type {
1250 return Err(compile::Error::new(
1251 node,
1252 ErrorKind::UnsupportedSuperInSelfType,
1253 ));
1254 }
1255
1256 if !item.pop() {
1257 return Err(compile::Error::new(node, ErrorKind::UnsupportedSuper));
1258 }
1259 }
1260 PathGenerics if supports_generics => {
1261 let Some(out) = it.next() else {
1262 return Err(compile::Error::new(node, ErrorKind::UnsupportedGenerics));
1263 };
1264
1265 *trailing += 1;
1266 *out = Some(node);
1267 break;
1268 }
1269 _ => {
1270 return Err(compile::Error::new(
1271 node,
1272 ErrorKind::ExpectedLeadingPathSegment,
1273 ));
1274 }
1275 }
1276 }
1277
1278 while !p.is_eof() {
1279 p.expect(K![::])?;
1280 let ident = p.pump()?.ast::<ast::Ident>()?;
1281 item.push(ident.resolve(resolve_context!(self))?)?;
1282 *trailing += 1;
1283
1284 let Some(node) = p.next() else {
1285 break;
1286 };
1287
1288 let Some(out) = it.next() else {
1289 return Err(compile::Error::new(node, ErrorKind::UnsupportedGenerics));
1290 };
1291
1292 *out = Some(p.expect(PathGenerics)?);
1293 }
1294
1295 let item = self.pool.alloc_item(item)?;
1296 Ok(item)
1297 }
1298
1299 #[tracing::instrument(skip_all)]
1301 pub(crate) fn insert_import(
1302 &mut self,
1303 location: &dyn Located,
1304 module: ModId,
1305 visibility: Visibility,
1306 at: &Item,
1307 target: &Item,
1308 alias: Option<ast::Ident>,
1309 wildcard: bool,
1310 ) -> compile::Result<()> {
1311 tracing::trace!(at = ?at, target = ?target);
1312
1313 let alias = match alias {
1314 Some(alias) => Some(alias.resolve(resolve_context!(self))?),
1315 None => None,
1316 };
1317
1318 let Some(last) = alias
1319 .as_ref()
1320 .map(IntoComponent::as_component_ref)
1321 .or_else(|| target.last())
1322 else {
1323 return Err(compile::Error::new(
1324 location.as_spanned(),
1325 ErrorKind::LastUseComponent,
1326 ));
1327 };
1328
1329 let item = self.pool.alloc_item(at.extended(last)?)?;
1330 let target = self.pool.alloc_item(target)?;
1331
1332 let entry = meta::Import {
1333 location: location.location(),
1334 target,
1335 module,
1336 };
1337
1338 let item_meta = self.insert_new_item_with(item, module, None, location, visibility, &[])?;
1339
1340 if item_meta.is_public(self.pool) {
1342 self.inner.used.try_insert(item_meta.item)?;
1343
1344 self.inner.queue.try_push_back(BuildEntry {
1345 item_meta,
1346 build: Build::ReExport,
1347 })?;
1348 }
1349
1350 self.index(indexing::Entry {
1351 item_meta,
1352 indexed: Indexed::Import(indexing::Import { wildcard, entry }),
1353 })?;
1354
1355 Ok(())
1356 }
1357
1358 pub(crate) fn contains_prefix(&self, item: &Item) -> alloc::Result<bool> {
1360 self.inner.names.contains_prefix(item)
1361 }
1362
1363 pub(crate) fn iter_components<'it, I>(
1365 &'it self,
1366 iter: I,
1367 ) -> alloc::Result<impl Iterator<Item = ComponentRef<'it>> + 'it>
1368 where
1369 I: 'it + IntoIterator,
1370 I::Item: IntoComponent,
1371 {
1372 self.inner.names.iter_components(iter)
1373 }
1374
1375 #[tracing::instrument(skip(self, span, module))]
1377 pub(crate) fn import(
1378 &mut self,
1379 span: &dyn Spanned,
1380 mut module: ModId,
1381 item: ItemId,
1382 import_used: Used,
1383 used: Used,
1384 ) -> compile::Result<Option<ItemId>> {
1385 let mut visited = HashSet::<ItemId>::new();
1386 let mut path = Vec::new();
1387 let mut item = self.pool.item(item).try_to_owned()?;
1388 let mut any_matched = false;
1389
1390 let mut count = 0usize;
1391
1392 'outer: loop {
1393 if count > IMPORT_RECURSION_LIMIT {
1394 return Err(compile::Error::new(
1395 span,
1396 ErrorKind::ImportRecursionLimit { count, path },
1397 ));
1398 }
1399
1400 count += 1;
1401
1402 let mut cur = ItemBuf::new();
1403 let mut it = item.iter();
1404
1405 while let Some(c) = it.next() {
1406 cur.push(c)?;
1407
1408 let cur = self.pool.alloc_item(&cur)?;
1409
1410 let update = self.import_step(
1411 span,
1412 module,
1413 cur,
1414 used,
1415 #[cfg(feature = "emit")]
1416 &mut path,
1417 )?;
1418
1419 let Some(FoundImportStep { item_meta, import }) = update else {
1420 continue;
1421 };
1422
1423 if let Used::Used = import_used {
1425 self.set_used(&item_meta)?;
1426 }
1427
1428 path.try_push(ImportStep {
1429 location: import.location,
1430 item: self.pool.item(import.target).try_to_owned()?,
1431 })?;
1432
1433 if !visited.try_insert(self.pool.alloc_item(&item)?)? {
1434 return Err(compile::Error::new(
1435 span,
1436 ErrorKind::ImportCycle {
1437 #[cfg(feature = "emit")]
1438 path,
1439 },
1440 ));
1441 }
1442
1443 module = import.module;
1444 item = self.pool.item(import.target).join(it)?;
1445 any_matched = true;
1446 continue 'outer;
1447 }
1448
1449 break;
1450 }
1451
1452 if any_matched {
1453 return Ok(Some(self.pool.alloc_item(item)?));
1454 }
1455
1456 Ok(None)
1457 }
1458
1459 #[tracing::instrument(skip(self, span, module, path))]
1461 fn import_step(
1462 &mut self,
1463 span: &dyn Spanned,
1464 module: ModId,
1465 item: ItemId,
1466 used: Used,
1467 #[cfg(feature = "emit")] path: &mut Vec<ImportStep>,
1468 ) -> compile::Result<Option<FoundImportStep>> {
1469 if let Some(meta) = self.inner.meta.get(&(item, Hash::EMPTY)) {
1471 return Ok(match meta.kind {
1472 meta::Kind::Import(import) => Some(FoundImportStep {
1473 item_meta: meta.item_meta,
1474 import,
1475 }),
1476 _ => None,
1477 });
1478 }
1479
1480 if let Some(metas) = self.context.lookup_meta(self.pool.item(item)) {
1481 for m in metas {
1482 if let meta::Kind::Alias(alias) = &m.kind {
1483 let target = self.pool.alloc_item(&alias.to)?;
1484
1485 let import = meta::Import {
1486 location: Default::default(),
1487 target,
1488 module,
1489 };
1490
1491 let meta = meta::Meta {
1492 context: true,
1493 hash: self.pool.item_type_hash(item),
1494 item_meta: self.context_item_meta(item, None),
1495 kind: meta::Kind::Import(import),
1496 source: None,
1497 parameters: Hash::EMPTY,
1498 };
1499
1500 let item_meta = self.insert_meta(meta).with_span(span)?;
1501
1502 return Ok(Some(FoundImportStep {
1503 item_meta: *item_meta,
1504 import,
1505 }));
1506 }
1507 }
1508 }
1509
1510 let Some(entry) = self.remove_indexed(span, item)? else {
1512 return Ok(None);
1513 };
1514
1515 self.check_access_to(
1516 span,
1517 module,
1518 item,
1519 entry.item_meta.module,
1520 #[cfg(feature = "emit")]
1521 entry.item_meta.location,
1522 entry.item_meta.visibility,
1523 #[cfg(feature = "emit")]
1524 path,
1525 )?;
1526
1527 let import = match entry.indexed {
1528 Indexed::Import(import) => import.entry,
1529 indexed => {
1530 self.import_indexed(span, entry.item_meta, indexed, used)?;
1531 return Ok(None);
1532 }
1533 };
1534
1535 let meta = meta::Meta {
1536 context: false,
1537 hash: self.pool.item_type_hash(entry.item_meta.item),
1538 item_meta: entry.item_meta,
1539 kind: meta::Kind::Import(import),
1540 source: None,
1541 parameters: Hash::EMPTY,
1542 };
1543
1544 let item_meta = self.insert_meta(meta).with_span(span)?;
1545
1546 Ok(Some(FoundImportStep {
1547 item_meta: *item_meta,
1548 import,
1549 }))
1550 }
1551
1552 fn context_item_meta(&self, item: ItemId, impl_item: Option<ItemId>) -> ItemMeta {
1553 ItemMeta {
1554 location: Default::default(),
1555 item,
1556 visibility: Default::default(),
1557 module: Default::default(),
1558 impl_item,
1559 }
1560 }
1561
1562 fn build_indexed_entry(
1564 &mut self,
1565 span: &dyn Spanned,
1566 entry: indexing::Entry,
1567 used: Used,
1568 ) -> compile::Result<meta::Meta> {
1569 #[cfg(feature = "doc")]
1570 fn to_doc_names(
1571 sources: &Sources,
1572 source_id: SourceId,
1573 args: &[Span],
1574 ) -> alloc::Result<Box<[meta::DocArgument]>> {
1575 let mut out = Vec::try_with_capacity(args.len())?;
1576
1577 for (n, span) in args.iter().enumerate() {
1578 let name = match sources.source(source_id, *span) {
1579 Some(name) => meta::DocName::Name(name.try_into()?),
1580 None => meta::DocName::Index(n),
1581 };
1582
1583 out.try_push(meta::DocArgument {
1584 name,
1585 base: Hash::EMPTY,
1586 generics: Box::default(),
1587 })?;
1588 }
1589
1590 Box::try_from(out)
1591 }
1592
1593 let indexing::Entry { item_meta, indexed } = entry;
1594
1595 if let Used::Used = used {
1596 self.inner.used.try_insert(item_meta.item)?;
1597 }
1598
1599 let kind = match indexed {
1600 Indexed::Enum => meta::Kind::Enum {
1601 parameters: Hash::EMPTY,
1602 },
1603 Indexed::Variant(variant) => {
1604 let enum_ = self.item_for("variant", variant.enum_id).with_span(span)?;
1605
1606 let Some(enum_meta) = self.query_meta(span, enum_.item, Default::default())? else {
1608 return Err(compile::Error::msg(
1609 span,
1610 try_format!("Missing enum by {:?}", variant.enum_id),
1611 ));
1612 };
1613
1614 meta::Kind::Struct {
1615 fields: variant.fields,
1616 constructor: None,
1617 parameters: Hash::EMPTY,
1618 enum_hash: enum_meta.hash,
1619 }
1620 }
1621 Indexed::Struct(st) => meta::Kind::Struct {
1622 fields: st.fields,
1623 constructor: None,
1624 parameters: Hash::EMPTY,
1625 enum_hash: Hash::EMPTY,
1626 },
1627 Indexed::Function(f) => {
1628 let kind = meta::Kind::Function {
1629 associated: match (f.is_instance, &f.ast) {
1630 (true, FunctionAst::Item(_, name)) => {
1631 let name: Cow<str> =
1632 Cow::Owned(name.resolve(resolve_context!(self))?.try_into()?);
1633 Some(meta::AssociatedKind::Instance(name))
1634 }
1635 (true, FunctionAst::Node(_, Some(name))) => {
1636 let name: Cow<str> =
1637 Cow::Owned(name.resolve(resolve_context!(self))?.try_into()?);
1638 Some(meta::AssociatedKind::Instance(name))
1639 }
1640 _ => None,
1641 },
1642 trait_hash: None,
1643 is_test: f.is_test,
1644 is_bench: f.is_bench,
1645 signature: meta::Signature {
1646 #[cfg(feature = "doc")]
1647 is_async: matches!(f.call, Call::Async | Call::Stream),
1648 #[cfg(feature = "doc")]
1649 arguments: Some(to_doc_names(
1650 self.sources,
1651 item_meta.location.source_id,
1652 &f.args,
1653 )?),
1654 #[cfg(feature = "doc")]
1655 return_type: meta::DocType::empty(),
1656 },
1657 parameters: Hash::EMPTY,
1658 #[cfg(feature = "doc")]
1659 container: {
1660 match f.impl_item {
1661 Some(item) => {
1662 let Some(impl_item) = self.inner.items.get(&item) else {
1663 return Err(compile::Error::msg(
1664 item_meta.location.span,
1665 "missing impl item",
1666 ));
1667 };
1668
1669 debug_assert_eq!(impl_item.item, item);
1670 Some(self.pool.item_type_hash(impl_item.item))
1671 }
1672 None => None,
1673 }
1674 },
1675 #[cfg(feature = "doc")]
1676 parameter_types: Vec::new(),
1677 };
1678
1679 self.inner.queue.try_push_back(BuildEntry {
1680 item_meta,
1681 build: Build::Function(f),
1682 })?;
1683
1684 kind
1685 }
1686 Indexed::ConstExpr(c) => {
1687 let ir = {
1688 let mut hir_ctx = crate::hir::Ctxt::with_const(
1689 self.const_arena,
1690 self.borrow(),
1691 item_meta.location.source_id,
1692 )?;
1693
1694 let hir = match c {
1695 indexing::ConstExpr::Ast(ast) => {
1696 crate::hir::lowering::expr(&mut hir_ctx, &ast)?
1697 }
1698 indexing::ConstExpr::Node(node) => {
1699 node.parse(|p| crate::hir::lowering2::expr(&mut hir_ctx, p))?
1700 }
1701 };
1702
1703 let mut cx = ir::Ctxt {
1704 source_id: item_meta.location.source_id,
1705 q: self.borrow(),
1706 };
1707 ir::compiler::expr(&hir, &mut cx)?
1708 };
1709
1710 let mut const_compiler = ir::Interpreter {
1711 budget: ir::Budget::new(1_000_000),
1712 scopes: ir::Scopes::new()?,
1713 module: item_meta.module,
1714 item: item_meta.item,
1715 q: self.borrow(),
1716 };
1717
1718 let const_value = const_compiler.eval_const(&ir, used)?;
1719
1720 let hash = self.pool.item_type_hash(item_meta.item);
1721 self.inner.constants.try_insert(hash, const_value)?;
1722
1723 if used.is_unused() {
1724 self.inner.queue.try_push_back(BuildEntry {
1725 item_meta,
1726 build: Build::Unused,
1727 })?;
1728 }
1729
1730 meta::Kind::Const
1731 }
1732 Indexed::ConstBlock(c) => {
1733 let ir = {
1734 let mut hir_ctx = crate::hir::Ctxt::with_const(
1735 self.const_arena,
1736 self.borrow(),
1737 item_meta.location.source_id,
1738 )?;
1739
1740 let hir = match &c {
1741 indexing::ConstBlock::Ast(ast) => {
1742 crate::hir::lowering::block(&mut hir_ctx, None, ast)?
1743 }
1744 indexing::ConstBlock::Node(node) => {
1745 node.parse(|p| crate::hir::lowering2::block(&mut hir_ctx, None, p))?
1746 }
1747 };
1748
1749 let mut cx = ir::Ctxt {
1750 source_id: item_meta.location.source_id,
1751 q: self.borrow(),
1752 };
1753 ir::Ir::new(item_meta.location.span, ir::compiler::block(&hir, &mut cx)?)
1754 };
1755
1756 let mut const_compiler = ir::Interpreter {
1757 budget: ir::Budget::new(1_000_000),
1758 scopes: ir::Scopes::new()?,
1759 module: item_meta.module,
1760 item: item_meta.item,
1761 q: self.borrow(),
1762 };
1763
1764 let const_value = const_compiler.eval_const(&ir, used)?;
1765
1766 let hash = self.pool.item_type_hash(item_meta.item);
1767 self.inner.constants.try_insert(hash, const_value)?;
1768
1769 if used.is_unused() {
1770 self.inner.queue.try_push_back(BuildEntry {
1771 item_meta,
1772 build: Build::Unused,
1773 })?;
1774 }
1775
1776 meta::Kind::Const
1777 }
1778 Indexed::ConstFn(c) => {
1779 let (ir_fn, hir) = {
1780 let mut cx = crate::hir::Ctxt::with_const(
1781 self.const_arena,
1782 self.borrow(),
1783 item_meta.location.source_id,
1784 )?;
1785
1786 let hir = match &c {
1787 indexing::ConstFn::Ast(ast) => crate::hir::lowering::item_fn(&mut cx, ast)?,
1788 indexing::ConstFn::Node(node) => {
1789 node.parse(|p| crate::hir::lowering2::item_fn(&mut cx, p, false))?
1790 }
1791 };
1792
1793 let mut cx = ir::Ctxt {
1794 source_id: item_meta.location.source_id,
1795 q: self.borrow(),
1796 };
1797 (ir::IrFn::compile_ast(&hir, &mut cx)?, hir)
1798 };
1799
1800 self.inner.const_fns.try_insert(
1801 item_meta.item,
1802 Rc::new(ConstFn {
1803 item_meta,
1804 ir_fn,
1805 hir,
1806 }),
1807 )?;
1808
1809 if used.is_unused() {
1810 self.inner.queue.try_push_back(BuildEntry {
1811 item_meta,
1812 build: Build::Unused,
1813 })?;
1814 }
1815
1816 meta::Kind::ConstFn
1817 }
1818 Indexed::Import(import) => {
1819 if !import.wildcard {
1820 self.inner.queue.try_push_back(BuildEntry {
1821 item_meta,
1822 build: Build::Import(import),
1823 })?;
1824 }
1825
1826 meta::Kind::Import(import.entry)
1827 }
1828 Indexed::Module => meta::Kind::Module,
1829 };
1830
1831 let source = SourceMeta {
1832 location: item_meta.location,
1833 path: self
1834 .sources
1835 .path(item_meta.location.source_id)
1836 .map(|p| p.try_into())
1837 .transpose()?,
1838 };
1839
1840 Ok(meta::Meta {
1841 context: false,
1842 hash: self.pool.item_type_hash(item_meta.item),
1843 item_meta,
1844 kind,
1845 source: Some(source),
1846 parameters: Hash::EMPTY,
1847 })
1848 }
1849
1850 fn insert_name(&mut self, item: ItemId) -> alloc::Result<()> {
1852 let item = self.pool.item(item);
1853 self.inner.names.insert(item)?;
1854 Ok(())
1855 }
1856
1857 fn import_indexed(
1859 &mut self,
1860 span: &dyn Spanned,
1861 item_meta: ItemMeta,
1862 indexed: Indexed,
1863 used: Used,
1864 ) -> compile::Result<()> {
1865 let entry = indexing::Entry { item_meta, indexed };
1869
1870 let meta = self.build_indexed_entry(span, entry, used)?;
1871 self.unit.insert_meta(span, &meta, self.pool, self.inner)?;
1872 self.insert_meta(meta).with_span(span)?;
1873 Ok(())
1874 }
1875
1876 fn remove_indexed(
1878 &mut self,
1879 span: &dyn Spanned,
1880 item: ItemId,
1881 ) -> compile::Result<Option<indexing::Entry>> {
1882 let Some(entries) = self.inner.indexed.remove(&item) else {
1884 return Ok(None);
1885 };
1886
1887 let mut it = entries.into_iter().peekable();
1888
1889 let Some(mut cur) = it.next() else {
1890 return Ok(None);
1891 };
1892
1893 if it.peek().is_none() {
1894 return Ok(Some(cur));
1895 }
1896
1897 let mut locations = try_vec![(cur.item_meta.location, cur.item())];
1898
1899 while let Some(oth) = it.next() {
1900 locations.try_push((oth.item_meta.location, oth.item()))?;
1901
1902 if let (Indexed::Import(a), Indexed::Import(b)) = (&cur.indexed, &oth.indexed) {
1903 if a.wildcard {
1904 cur = oth;
1905 continue;
1906 }
1907
1908 if b.wildcard {
1909 continue;
1910 }
1911 }
1912
1913 for oth in it {
1914 locations.try_push((oth.item_meta.location, oth.item()))?;
1915 }
1916
1917 return Err(compile::Error::new(
1918 span,
1919 ErrorKind::AmbiguousItem {
1920 item: self.pool.item(cur.item_meta.item).try_to_owned()?,
1921 #[cfg(feature = "emit")]
1922 locations: locations
1923 .into_iter()
1924 .map(|(loc, item)| Ok((loc, self.pool.item(item).try_to_owned()?)))
1925 .try_collect::<alloc::Result<_>>()??,
1926 },
1927 ));
1928 }
1929
1930 if let Indexed::Import(indexing::Import { wildcard: true, .. }) = &cur.indexed {
1931 return Err(compile::Error::new(
1932 span,
1933 ErrorKind::AmbiguousItem {
1934 item: self.pool.item(cur.item_meta.item).try_to_owned()?,
1935 #[cfg(feature = "emit")]
1936 locations: locations
1937 .into_iter()
1938 .map(|(loc, item)| Ok((loc, self.pool.item(item).try_to_owned()?)))
1939 .try_collect::<alloc::Result<_>>()??,
1940 },
1941 ));
1942 }
1943
1944 Ok(Some(cur))
1945 }
1946
1947 #[tracing::instrument(skip_all, fields(module = ?self.pool.module_item(module), base = ?self.pool.item(item)))]
1949 fn convert_initial_path(
1950 &mut self,
1951 module: ModId,
1952 item: ItemId,
1953 local: &ast::Ident,
1954 used: Used,
1955 ) -> compile::Result<ItemId> {
1956 let mut base = self.pool.item(item).try_to_owned()?;
1957 debug_assert!(base.starts_with(self.pool.module_item(module)));
1958
1959 let local_str = local.resolve(resolve_context!(self))?.try_to_owned()?;
1960
1961 while base.starts_with(self.pool.module_item(module)) {
1962 base.push(&local_str)?;
1963 tracing::trace!(?base, "testing");
1964
1965 if self.inner.names.contains(&base)? {
1966 let item = self.pool.alloc_item(&base)?;
1967
1968 if let Some(meta) = self.query_meta(local, item, used)? {
1971 tracing::trace!(?base, ?meta.kind, "testing found meta");
1972
1973 if !matches!(
1974 meta.kind,
1975 meta::Kind::Function {
1976 associated: Some(..),
1977 ..
1978 }
1979 ) {
1980 return Ok(self.pool.alloc_item(base)?);
1981 }
1982 }
1983 }
1984
1985 let c = base.pop();
1986 debug_assert!(c);
1987
1988 if !base.pop() {
1989 break;
1990 }
1991 }
1992
1993 if let Some(item) = self.prelude.get(&local_str) {
1994 return Ok(self.pool.alloc_item(item)?);
1995 }
1996
1997 if self.context.contains_crate(&local_str) {
1998 return Ok(self.pool.alloc_item(ItemBuf::with_crate(&local_str)?)?);
1999 }
2000
2001 let new_module = self.pool.module_item(module).extended(&local_str)?;
2002 Ok(self.pool.alloc_item(new_module)?)
2003 }
2004
2005 fn check_access_to(
2007 &mut self,
2008 span: &dyn Spanned,
2009 from: ModId,
2010 item: ItemId,
2011 module: ModId,
2012 #[cfg(feature = "emit")] location: Location,
2013 visibility: Visibility,
2014 #[cfg(feature = "emit")] chain: &mut Vec<ImportStep>,
2015 ) -> compile::Result<()> {
2016 #[cfg(feature = "emit")]
2017 fn into_chain(chain: Vec<ImportStep>) -> alloc::Result<Vec<Location>> {
2018 chain.into_iter().map(|c| c.location).try_collect()
2019 }
2020
2021 let (common, tree) = self
2022 .pool
2023 .module_item(from)
2024 .ancestry(self.pool.module_item(module))?;
2025
2026 let mut current_module = common.try_clone()?;
2027
2028 for c in &tree {
2030 current_module.push(c)?;
2031 let current_module_id = self.pool.alloc_item(¤t_module)?;
2032
2033 let Some(m) = self.pool.module_by_item(current_module_id) else {
2034 return Err(compile::Error::new(
2035 span,
2036 ErrorKind::MissingMod {
2037 item: current_module.try_clone()?,
2038 },
2039 ));
2040 };
2041
2042 if !m.visibility.is_visible(&common, ¤t_module) {
2043 return Err(compile::Error::new(
2044 span,
2045 ErrorKind::NotVisibleMod {
2046 #[cfg(feature = "emit")]
2047 chain: into_chain(take(chain))?,
2048 #[cfg(feature = "emit")]
2049 location: m.location,
2050 visibility: m.visibility,
2051 item: current_module,
2052 from: self.pool.module_item(from).try_to_owned()?,
2053 },
2054 ));
2055 }
2056 }
2057
2058 if !visibility.is_visible_inside(&common, self.pool.module_item(module)) {
2059 return Err(compile::Error::new(
2060 span,
2061 ErrorKind::NotVisible {
2062 #[cfg(feature = "emit")]
2063 chain: into_chain(take(chain))?,
2064 #[cfg(feature = "emit")]
2065 location,
2066 visibility,
2067 item: self.pool.item(item).try_to_owned()?,
2068 from: self.pool.module_item(from).try_to_owned()?,
2069 },
2070 ));
2071 }
2072
2073 Ok(())
2074 }
2075
2076 pub(crate) fn get_const_value(&self, hash: Hash) -> Option<&ConstValue> {
2078 if let Some(const_value) = self.inner.constants.get(&hash) {
2079 return Some(const_value);
2080 }
2081
2082 self.context.get_const_value(hash)
2083 }
2084}
2085
2086struct FoundImportStep {
2087 item_meta: ItemMeta,
2088 import: meta::Import,
2089}