Skip to main content

pliron/
attribute.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) The pliron contributors
3
4//! Attributes are non-SSA data stored in [Operation](crate::operation::Operation)s.
5//!
6//! See [MLIR Attributes](https://mlir.llvm.org/docs/LangRef/#attributes).
7//! Unlike in MLIR, we do not unique attributes, and hence they are mutable.
8//! These are similar in concept to [Properties](https://discourse.llvm.org/t/rfc-introducing-mlir-operation-properties/67846).
9//! Attribute objects are boxed and not wrapped with [Ptr](crate::context::Ptr).
10//! They are heavy (i.e., not just a pointer, handle or reference),
11//! making clones potentially expensive.
12//!
13//! The [pliron_attr](pliron::derive::pliron_attr) proc macro from the
14//! pliron-derive create can be used to implement [Attribute] for a rust type.
15//!
16//! Common semantics, API and behaviour of [Attribute]s are
17//! abstracted into interfaces. Interfaces in pliron capture MLIR
18//! functionality of both [Traits](https://mlir.llvm.org/docs/Traits/)
19//! and [Interfaces](https://mlir.llvm.org/docs/Interfaces/).
20//! Interfaces must all implement an associated function named `verify` with
21//! the type [AttrInterfaceVerifier].
22//!
23//! Interfaces are rust Trait definitions annotated with the attribute macro
24//! [attr_interface](pliron::derive::attr_interface). The attribute ensures that any
25//! verifiers of super-interfaces are run prior to the verifier of this interface.
26//! Note: Super-interface verifiers *may* run multiple times for the same attribute.
27//!
28//! [Attribute]s that implement an interface must annotate the implementation with
29//! [attr_interface_impl](pliron::derive::attr_interface_impl) macro to ensure that
30//! the interface verifier is automatically called during verification
31//! and that a `&dyn Attribute` object can be [cast](attr_cast) into an interface object,
32//! (or that it can be checked if the interface is [implemented](attr_impls))
33//! with ease.
34//!
35//! Use [verify_attr] to verify an [Attribute] object.
36//! This function verifies all interfaces implemented by the attribute, and then the attribute itself.
37//! The attribute's verifier must explicitly invoke verifiers on any sub-objects it contains.
38//!
39//! [AttrObj]s can be downcasted to their concrete types using
40//! [downcast_rs](https://docs.rs/downcast-rs/latest/downcast_rs/#example-without-generics).
41
42use crate::{
43    builtin::attr_interfaces::{OutlinedAttr, TypedAttrInterface},
44    combine::{Parser, parser, token},
45    common_traits::Verify,
46    context::{Context, collect_deduped_interface_verifiers},
47    dialect::{Dialect, DialectName},
48    dyn_clone::DynClone,
49    identifier::Identifier,
50    impl_printable_for_display, input_err, input_error,
51    irfmt::{
52        parsers::{attr_parser, delimited_list_parser, spaced},
53        printers::iter_with_sep,
54    },
55    parsable::{IntoParseResult, Parsable, ParseResult, StateStream, StreamLocation},
56    printable::{self, Printable},
57    result::Result,
58    std_deps::sync::LazyLock,
59    storage_uniquer::TypeValueHash,
60    r#type::TypeHandle,
61    utils::{
62        table::{HMap, SmallMap},
63        trait_cast::impls_trait_static,
64    },
65};
66use alloc::{
67    boxed::Box,
68    string::{String, ToString},
69    vec::Vec,
70};
71use core::{
72    fmt::{Debug, Display},
73    hash::{Hash, Hasher},
74    ops::Deref,
75};
76use downcast_rs::{Downcast, impl_downcast};
77use thiserror::Error;
78
79/// Convenience type to easily print and parse key-value pairs in an [AttributeDict].
80#[derive(Clone)]
81struct AttributeDictKeyVal<'a> {
82    key: &'a Identifier,
83    val: &'a AttrObj,
84}
85
86impl<'a> Printable for AttributeDictKeyVal<'a> {
87    fn fmt(
88        &self,
89        ctx: &Context,
90        state: &printable::State,
91        f: &mut core::fmt::Formatter<'_>,
92    ) -> core::fmt::Result {
93        write!(f, "{}: {}", self.key, self.val.print(ctx, state))
94    }
95}
96
97impl<'b> Parsable for AttributeDictKeyVal<'b> {
98    type Arg = ();
99
100    type Parsed = (Identifier, AttrObj);
101
102    fn parse<'a>(
103        state_stream: &mut StateStream<'a>,
104        _arg: Self::Arg,
105    ) -> ParseResult<'a, Self::Parsed> {
106        (Identifier::parser(()), spaced(token(':')), attr_parser())
107            .map(|(key, _, val)| (key, val))
108            .parse_stream(state_stream)
109            .into_result()
110    }
111}
112
113impl Printable for AttributeDict {
114    fn fmt(
115        &self,
116        ctx: &Context,
117        state: &printable::State,
118        f: &mut core::fmt::Formatter<'_>,
119    ) -> core::fmt::Result {
120        write!(
121            f,
122            "[{}]",
123            iter_with_sep(
124                self.0
125                    .iter()
126                    .map(|(key, val)| AttributeDictKeyVal { key, val }),
127                printable::ListSeparator::CharSpace(','),
128            )
129            .print(ctx, state)
130        )
131    }
132}
133
134impl Parsable for AttributeDict {
135    type Arg = ();
136    type Parsed = Self;
137
138    fn parse<'a>(
139        state_stream: &mut StateStream<'a>,
140        _arg: Self::Arg,
141    ) -> ParseResult<'a, Self::Parsed> {
142        delimited_list_parser('[', ']', ',', AttributeDictKeyVal::parser(()))
143            .map(|key_vals| AttributeDict(key_vals.into_iter().collect()))
144            .parse_stream(state_stream)
145            .into_result()
146    }
147}
148
149pub type AttributeDictContainer = SmallMap<Identifier, AttrObj, 1>;
150
151/// A dictionary of attributes, mapping keys to attribute objects.
152#[derive(Default, Debug, Clone, PartialEq, Eq)]
153pub struct AttributeDict(pub AttributeDictContainer);
154
155impl Hash for AttributeDict {
156    fn hash<H: Hasher>(&self, state: &mut H) {
157        // Sort by key so that the hash doesn't depend on insertion order.
158        let mut entries: Vec<_> = self.0.iter().collect();
159        entries.sort_by_key(|(k, _)| *k);
160        entries.hash(state);
161    }
162}
163
164impl AttributeDict {
165    /// Get reference to attribute value that is mapped to key `k`.
166    pub fn get<T: Attribute>(&self, k: &Identifier) -> Option<&T> {
167        self.0.get(k).and_then(|ao| ao.downcast_ref::<T>())
168    }
169
170    /// Get mutable reference to attribute value that is mapped to key `k`.
171    pub fn get_mut<T: Attribute>(&mut self, k: &Identifier) -> Option<&mut T> {
172        self.0.get_mut(k).and_then(|ao| ao.downcast_mut::<T>())
173    }
174
175    /// Reference to the attribute value (that is mapped to key `k`) as an interface reference.
176    pub fn get_as<T: ?Sized + AttrInterfaceMarker + 'static>(&self, k: &Identifier) -> Option<&T> {
177        self.0.get(k).and_then(|ao| attr_cast::<T>(&**ao))
178    }
179
180    /// Set the attribute value for key `k`.
181    pub fn set<T: Attribute>(&mut self, k: Identifier, v: T) {
182        self.0.insert(k, Box::new(v));
183    }
184
185    /// Clone, but skip [Outlined](OutlinedAttr) attributes.
186    pub fn clone_skip_outlined(&self, ctx: &Context) -> Self {
187        self.0
188            .iter()
189            .filter_map(|(k, v)| {
190                if attr_should_outline(&**v, ctx) {
191                    None
192                } else {
193                    Some((k.clone(), dyn_clone::clone_box(&**v)))
194                }
195            })
196            .collect::<AttributeDictContainer>()
197            .into()
198    }
199}
200
201impl From<AttributeDictContainer> for AttributeDict {
202    fn from(value: AttributeDictContainer) -> Self {
203        AttributeDict(value)
204    }
205}
206
207/// Basic functionality that every attribute in the IR must implement.
208///
209/// See [module](crate::attribute) documentation for more information.
210pub trait Attribute: Printable + Verify + Downcast + Sync + Send + DynClone + Debug {
211    /// Compute and get the hash for this instance of Self.
212    /// Hash collisions can be a possibility.
213    fn hash_attr(&self) -> TypeValueHash;
214
215    /// Is self equal to an other Attribute?
216    fn eq_attr(&self, other: &dyn Attribute) -> bool;
217
218    /// Get an [Attribute]'s static name. This is *not* per instantnce.
219    /// It is mostly useful for printing and parsing the attribute.
220    fn get_attr_id(&self) -> AttrId;
221
222    /// Same as [get_attr_id](Self::get_attr_id), but without the self reference.
223    fn get_attr_id_static() -> AttrId
224    where
225        Self: Sized;
226
227    #[doc(hidden)]
228    /// Verify all interfaces implemented by this attribute.
229    fn verify_interfaces(&self, ctx: &Context) -> Result<()>;
230
231    /// Register this attribute's [AttrId] in the dialect it belongs to.
232    fn register<A: Attribute>(ctx: &mut Context)
233    where
234        Self: Sized + Parsable<Arg = (), Parsed = A>,
235    {
236        let attr_parser: AttrParserFn = |parsable_state, &()| {
237            Self::parse(parsable_state, ()).map(|(attr, r)| -> (AttrObj, _) { (Box::new(attr), r) })
238        };
239        let attrid = Self::get_attr_id_static();
240        Dialect::register(ctx, &attrid.dialect).add_attr(attrid.clone(), attr_parser);
241    }
242}
243impl_downcast!(Attribute);
244dyn_clone::clone_trait_object!(Attribute);
245
246/// [Attribute] objects are boxed and stored in the IR.
247pub type AttrObj = Box<dyn Attribute>;
248
249/// A storable function pointer to parse a specific [Attribute].
250/// The [Attribute]'s [Dialect] maps an [AttrId] to such a parser.
251pub(crate) type AttrParserFn = for<'a> fn(&mut StateStream<'a>, &'a ()) -> ParseResult<'a, AttrObj>;
252
253impl PartialEq for AttrObj {
254    fn eq(&self, other: &Self) -> bool {
255        (**self).eq_attr(&**other)
256    }
257}
258
259impl<T: Attribute> From<T> for AttrObj {
260    fn from(value: T) -> Self {
261        Box::new(value)
262    }
263}
264
265impl Eq for AttrObj {}
266
267impl Hash for AttrObj {
268    fn hash<H: Hasher>(&self, state: &mut H) {
269        state.write_u64(self.hash_attr().into());
270    }
271}
272
273/// Print [AttrId] followed by the attribute itself.
274///
275/// This is generally used through `AttrObj as Printable`,
276/// or `Box<dyn I> as Printable`.
277/// ```
278/// use pliron::{
279///     attribute::AttrObj, builtin::attributes::StringAttr, context::Context,
280///     printable::Printable,
281/// };
282/// let ctx = &Context::new();
283///
284/// let attr: AttrObj = Box::new(StringAttr::new("hello".to_string()));
285/// assert_eq!(attr.disp(ctx).to_string(), r#"builtin.string "hello""#);
286/// ```
287pub fn fmt_attr_obj(
288    attr: &dyn Attribute,
289    ctx: &Context,
290    state: &printable::State,
291    f: &mut core::fmt::Formatter<'_>,
292) -> core::fmt::Result {
293    write!(f, "{} ", attr.get_attr_id())?;
294    Printable::fmt(attr, ctx, state, f)
295}
296
297impl Printable for AttrObj {
298    fn fmt(
299        &self,
300        ctx: &Context,
301        state: &printable::State,
302        f: &mut core::fmt::Formatter<'_>,
303    ) -> core::fmt::Result {
304        fmt_attr_obj(self.deref(), ctx, state, f)
305    }
306}
307
308#[derive(Debug, Error)]
309#[error("{provided} does not implement the attribute interface {interface}")]
310pub struct AttrInterfaceCastErr {
311    pub interface: String,
312    pub provided: String,
313}
314
315/// Parse `Box<dyn I>`.
316///
317/// This is generally used through `<Box<dyn I>>::parser` and not directly.
318/// ```
319/// use pliron::{
320///     builtin::{
321///         attr_interfaces::TypedAttrInterface,
322///         types::{IntegerType, Signedness},
323///     },
324///     context::Context,
325///     parsable::{Parsable, parse_from_str},
326/// };
327/// let ctx = &mut Context::new();
328///
329/// // `Box<dyn TypedAttrInterface>` parses through this.
330/// let parser = <Box<dyn TypedAttrInterface>>::parser(());
331/// let attr = parse_from_str(parser, ctx, "builtin.integer <42: si64>")
332///     .expect("An IntegerAttr has a type");
333/// assert_eq!(attr.get_type(ctx), IntegerType::get(ctx, 64, Signedness::Signed).into());
334///
335/// // A string carries no type, so it isn't a `TypedAttrInterface`.
336/// let parser = <Box<dyn TypedAttrInterface>>::parser(());
337/// assert!(parse_from_str(parser, ctx, r#"builtin.string "hello""#).is_err());
338/// ```
339pub fn parse_attr_interface_obj<'a, I: ?Sized + AttrInterfaceMarker + 'static>(
340    state_stream: &mut StateStream<'a>,
341) -> ParseResult<'a, Box<I>> {
342    let loc = state_stream.loc();
343    let (attr, _) = attr_parser().parse_stream(state_stream).into_result()?;
344
345    // The cast consumes the attribute, so name it for the error before casting.
346    let provided = attr.get_attr_id();
347    boxed_attr_cast::<I>(attr)
348        .ok_or_else(|| {
349            input_error!(
350                loc,
351                AttrInterfaceCastErr {
352                    interface: core::any::type_name::<I>().to_string(),
353                    provided: provided.to_string(),
354                }
355            )
356        })
357        .into_parse_result()
358}
359
360impl Parsable for AttrObj {
361    type Arg = ();
362    type Parsed = AttrObj;
363
364    fn parse<'a>(
365        state_stream: &mut StateStream<'a>,
366        _arg: Self::Arg,
367    ) -> ParseResult<'a, Self::Parsed> {
368        let loc = state_stream.loc();
369        let attr_id_parser = spaced(AttrId::parser(()));
370
371        let mut attr_parser = attr_id_parser.then(move |attr_id: AttrId| {
372            let loc = loc.clone();
373            combine::parser(move |parsable_state: &mut StateStream<'a>| {
374                let state = &parsable_state.state;
375                let dialect = state
376                    .ctx
377                    .dialects
378                    .get(&attr_id.dialect)
379                    .expect("Dialect name parsed but dialect isn't registered");
380                let Some(attr_parser) = dialect.attributes.get(&attr_id) else {
381                    input_err!(
382                        loc.clone(),
383                        "Unregistered attribute {}",
384                        attr_id.disp(state.ctx)
385                    )?
386                };
387                attr_parser(parsable_state, &())
388            })
389        });
390
391        attr_parser.parse_stream(state_stream).into_result()
392    }
393}
394
395/// Verify an [Attribute] object.
396/// 1. Verify all interfaces implemented by this attribute.
397/// 2. Verify the attribute itself.
398pub fn verify_attr(attr: &dyn Attribute, ctx: &Context) -> Result<()> {
399    // Verify all interfaces implemented by this attribute.
400    attr.verify_interfaces(ctx)?;
401
402    // Verify the attribute itself.
403    Verify::verify(attr, ctx)
404}
405
406impl Verify for AttrObj {
407    fn verify(&self, ctx: &Context) -> Result<()> {
408        verify_attr(self.as_ref(), ctx)
409    }
410}
411
412/// Marker trait for attribute interface trait objects.
413///
414/// This is auto-implemented by the `#[attr_interface]` macro for `dyn Interface`
415/// objects and is used to restrict [attr_cast] and [attr_impls] to interface casts.
416#[diagnostic::on_unimplemented(
417    message = "`{Self}` not an attribute interface.",
418    label = "If `{Self}` is a trait, annotate it with #[attr_interface] to be able to cast to it from a `&dyn Attribute`",
419    note = "If you want to cast to a concrete `Attribute`, use `downcast_ref` instead."
420)]
421pub trait AttrInterfaceMarker {}
422
423/// Cast reference to an [Attribute] object to an interface reference.
424///
425/// Right usage: cast to an interface trait object.
426/// ```
427/// use pliron::attribute::{Attribute, attr_cast};
428/// use pliron::builtin::attr_interfaces::TypedAttrInterface;
429///
430/// fn right_cast(attr: &dyn Attribute) {
431///     let _ = attr_cast::<dyn TypedAttrInterface>(attr);
432/// }
433/// ```
434///
435/// Casting to concrete [Attribute] types are intentionally rejected.
436/// ```compile_fail
437/// use pliron::attribute::{Attribute, attr_cast};
438/// use pliron::builtin::attributes::IntegerAttr;
439///
440/// fn wrong_cast(attr: &dyn Attribute) {
441///     let _ = attr_cast::<IntegerAttr>(attr);
442/// }
443/// ```
444/// Use [downcast_rs](https://docs.rs/downcast-rs/latest/downcast_rs/#example-without-generics)
445/// to cast to concrete [Attribute] types.
446pub fn attr_cast<T: ?Sized + AttrInterfaceMarker + 'static>(attr: &dyn Attribute) -> Option<&T> {
447    crate::utils::trait_cast::any_to_trait::<T>(attr.as_any())
448}
449
450/// Does this [Attribute] object implement interface `T`?
451///
452/// Right usage: query using an interface trait object.
453/// ```
454/// use pliron::attribute::{Attribute, attr_impls};
455/// use pliron::builtin::attr_interfaces::TypedAttrInterface;
456///
457/// fn right_query(attr: &dyn Attribute) {
458///     let _ = attr_impls::<dyn TypedAttrInterface>(attr);
459/// }
460/// ```
461///
462/// Querying with a concrete [Attribute] type is intentionally rejected.
463/// ```compile_fail
464/// use pliron::attribute::{Attribute, attr_impls};
465/// use pliron::builtin::attributes::IntegerAttr;
466///
467/// fn wrong_query(attr: &dyn Attribute) {
468///     let _ = attr_impls::<IntegerAttr>(attr);
469/// }
470/// ```
471pub fn attr_impls<T: ?Sized + AttrInterfaceMarker + 'static>(attr: &dyn Attribute) -> bool {
472    attr_cast::<T>(attr).is_some()
473}
474
475/// Should `attr` be printed outlined?
476pub fn attr_should_outline(attr: &dyn Attribute, ctx: &Context) -> bool {
477    attr_cast::<dyn OutlinedAttr>(attr).is_some_and(|attr| OutlinedAttr::outline(attr, ctx))
478}
479
480/// Does [Attribute] `A` implement interface `I`?
481/// See also: [`attr_impls`].
482///
483/// Example:
484/// ```
485/// use pliron::attribute::{Attribute, attr_impls_static};
486/// use pliron::builtin::attr_interfaces::{FloatAttr, TypedAttrInterface};
487/// use pliron::builtin::attributes::IntegerAttr;
488/// assert!(attr_impls_static::<IntegerAttr, dyn TypedAttrInterface>());
489/// assert!(!attr_impls_static::<IntegerAttr, dyn FloatAttr>());
490/// ```
491pub fn attr_impls_static<A: Attribute, I: ?Sized + AttrInterfaceMarker + 'static>() -> bool {
492    impls_trait_static::<A, I>()
493}
494
495/// Cast a boxed [Attribute] object to a boxed interface object.
496///
497/// Usage:
498///
499/// ```
500/// use pliron::{
501///     attribute::{Attribute, boxed_attr_cast},
502///     builtin::{
503///         attr_interfaces::{FloatAttr, TypedAttrInterface},
504///         attributes::IntegerAttr,
505///         types::{IntegerType, Signedness},
506///     },
507///     context::Context,
508///     utils::apint::{APInt, bw},
509/// };
510/// let ctx = &Context::new();
511///
512/// let i64_ty = IntegerType::get(ctx, 64, Signedness::Signed);
513/// let int_attr = || -> Box<dyn Attribute> {
514///     Box::new(IntegerAttr::new(i64_ty, APInt::from_i64(42, bw(64))))
515/// };
516///
517/// let typed = boxed_attr_cast::<dyn TypedAttrInterface>(int_attr())
518///     .expect("IntegerAttr implements TypedAttrInterface");
519/// assert_eq!(typed.get_type(ctx), i64_ty.into());
520///
521/// // IntegerAttr isn't a float attribute, so the cast fails.
522/// assert!(boxed_attr_cast::<dyn FloatAttr>(int_attr()).is_none());
523/// ```
524///
525/// Casting to concrete [Attribute] types are intentionally rejected.
526/// ```compile_fail
527/// use pliron::attribute::{Attribute, boxed_attr_cast};
528/// use pliron::builtin::attributes::IntegerAttr;
529///
530/// fn wrong_cast(attr: Box<dyn Attribute>) {
531///     let _ = boxed_attr_cast::<IntegerAttr>(attr);
532/// }
533/// ```
534/// Use [downcast_rs](https://docs.rs/downcast-rs/latest/downcast_rs/#example-without-generics)
535/// to cast to concrete [Attribute] types.
536pub fn boxed_attr_cast<T: ?Sized + AttrInterfaceMarker + 'static>(
537    attr: Box<dyn Attribute>,
538) -> Option<Box<T>> {
539    crate::utils::trait_cast::boxed_any_to_trait::<T>(attr as Box<dyn core::any::Any>)
540}
541
542/// If an [Attribute] impls [TypedAttrInterface], get its [Type](crate::type::Type).
543///
544/// ```
545/// use pliron::{
546///     attribute::attr_type,
547///     builtin::{
548///         attributes::{IntegerAttr, StringAttr},
549///         types::{IntegerType, Signedness},
550///     },
551///     context::Context,
552///     utils::apint::{APInt, bw},
553/// };
554/// let ctx = &Context::new();
555///
556/// let i64_ty = IntegerType::get(ctx, 64, Signedness::Signed);
557/// let int_attr = IntegerAttr::new(i64_ty, APInt::from_i64(42, bw(64)));
558/// assert_eq!(attr_type(&int_attr, ctx), Some(i64_ty.into()));
559///
560/// // A string carries no type.
561/// assert!(attr_type(&StringAttr::new("hello".to_string()), ctx).is_none());
562/// ```
563pub fn attr_type(attr: &dyn Attribute, ctx: &Context) -> Option<TypeHandle> {
564    attr_cast::<dyn TypedAttrInterface>(attr).map(|typed| typed.get_type(ctx))
565}
566
567#[derive(Clone, Hash, PartialEq, Eq)]
568/// An [Attribute]'s name (not including it's dialect).
569pub struct AttrName(Identifier);
570
571impl AttrName {
572    /// Create a new AttrName.
573    pub fn try_new(name: &str) -> Result<AttrName> {
574        Identifier::try_from(name).map(AttrName)
575    }
576}
577
578impl_printable_for_display!(AttrName);
579
580impl Display for AttrName {
581    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
582        write!(f, "{}", self.0)
583    }
584}
585
586impl Parsable for AttrName {
587    type Arg = ();
588    type Parsed = AttrName;
589
590    fn parse<'a>(
591        state_stream: &mut crate::parsable::StateStream<'a>,
592        _arg: Self::Arg,
593    ) -> ParseResult<'a, Self::Parsed>
594    where
595        Self: Sized,
596    {
597        Identifier::parser(())
598            .map(AttrName)
599            .parse_stream(state_stream)
600            .into()
601    }
602}
603
604impl AsRef<str> for AttrName {
605    fn as_ref(&self) -> &str {
606        self.0.as_ref()
607    }
608}
609
610impl AsRef<Identifier> for AttrName {
611    fn as_ref(&self) -> &Identifier {
612        &self.0
613    }
614}
615
616impl From<Identifier> for AttrName {
617    fn from(value: Identifier) -> Self {
618        AttrName(value)
619    }
620}
621
622impl From<AttrName> for Identifier {
623    fn from(value: AttrName) -> Self {
624        value.0
625    }
626}
627
628impl TryFrom<&str> for AttrName {
629    type Error = crate::result::Error;
630
631    fn try_from(value: &str) -> Result<Self> {
632        Identifier::try_from(value).map(AttrName)
633    }
634}
635
636impl TryFrom<String> for AttrName {
637    type Error = crate::result::Error;
638
639    fn try_from(value: String) -> Result<Self> {
640        Identifier::try_from(value).map(AttrName)
641    }
642}
643
644/// A combination of a Attr's name and its dialect.
645#[derive(Clone, Hash, PartialEq, Eq)]
646pub struct AttrId {
647    pub dialect: DialectName,
648    pub name: AttrName,
649}
650
651impl_printable_for_display!(AttrId);
652
653impl Display for AttrId {
654    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
655        write!(f, "{}.{}", self.dialect, self.name)
656    }
657}
658
659impl Parsable for AttrId {
660    type Arg = ();
661    type Parsed = AttrId;
662
663    // Parses (but does not validate) a TypeId.
664    fn parse<'a>(
665        state_stream: &mut StateStream<'a>,
666        _arg: Self::Arg,
667    ) -> ParseResult<'a, Self::Parsed>
668    where
669        Self: Sized,
670    {
671        let mut parser = DialectName::parser(())
672            .skip(parser::char::char('.'))
673            .and(AttrName::parser(()))
674            .map(|(dialect, name)| AttrId { dialect, name });
675        parser.parse_stream(state_stream).into()
676    }
677}
678
679/// Every attribute interface must have a function named `verify` with this type.
680pub type AttrInterfaceVerifier = fn(&dyn Attribute, &Context) -> Result<()>;
681/// Function returns the list of super verifiers, followed by a self verifier, for an interface.
682pub type AttrInterfaceAllVerifiers = fn() -> Vec<AttrInterfaceVerifier>;
683
684#[doc(hidden)]
685/// An [Attribute] paired with an interface it implements
686/// (specifically the verifiers (including super verifiers) for that interface).
687type AttrInterfaceVerifierInfo = &'static [(core::any::TypeId, AttrInterfaceAllVerifiers)];
688
689#[doc(hidden)]
690#[cfg(not(target_family = "wasm"))]
691pub mod statics {
692    use super::*;
693
694    #[::pliron::linkme::distributed_slice]
695    pub static ATTR_INTERFACE_VERIFIERS: [AttrInterfaceVerifierInfo] = [..];
696
697    pub(super) fn get_attr_interface_verifiers()
698    -> impl Iterator<Item = &'static AttrInterfaceVerifierInfo> {
699        ATTR_INTERFACE_VERIFIERS.iter()
700    }
701}
702#[doc(hidden)]
703#[cfg(not(target_family = "wasm"))]
704pub use statics::ATTR_INTERFACE_VERIFIERS;
705
706#[doc(hidden)]
707#[cfg(target_family = "wasm")]
708pub mod statics {
709    use super::*;
710    use crate::InventoryWrapper;
711
712    ::pliron::inventory::collect!(InventoryWrapper<AttrInterfaceVerifierInfo>);
713
714    pub(super) fn get_attr_interface_verifiers()
715    -> impl Iterator<Item = &'static AttrInterfaceVerifierInfo> {
716        ::pliron::inventory::iter::<InventoryWrapper<AttrInterfaceVerifierInfo>>().map(|llw| llw.0)
717    }
718}
719
720#[doc(hidden)]
721/// A map from every [Attribute] to its ordered (as per interface deps) list of interface verifiers.
722/// An interface's super-interfaces are to be verified before it itself is.
723pub static ATTR_INTERFACE_VERIFIERS_MAP: LazyLock<
724    HMap<core::any::TypeId, Vec<AttrInterfaceVerifier>>,
725> = LazyLock::new(|| collect_deduped_interface_verifiers(statics::get_attr_interface_verifiers()));