This commit is contained in:
		
							parent
							
								
									bf907c3872
								
							
						
					
					
						commit
						59cef3f398
					
				
					 3 changed files with 255 additions and 22 deletions
				
			
		| 
						 | 
				
			
			@ -1273,6 +1273,130 @@ make_parsed_type_or_const! {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub(crate) struct ParsedTypePhantomData {
 | 
			
		||||
    pub(crate) phantom_data: known_items::PhantomData,
 | 
			
		||||
    pub(crate) lt_token: Token![<],
 | 
			
		||||
    pub(crate) ty: Box<ParsedType>,
 | 
			
		||||
    pub(crate) gt_token: Token![>],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl_fold! {
 | 
			
		||||
    struct ParsedTypePhantomData<> {
 | 
			
		||||
        phantom_data: known_items::PhantomData,
 | 
			
		||||
        lt_token: Token![<],
 | 
			
		||||
        ty: Box<ParsedType>,
 | 
			
		||||
        gt_token: Token![>],
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ParsedTypePhantomData {
 | 
			
		||||
    pub(crate) fn try_from_named(
 | 
			
		||||
        named: ParsedTypeNamed,
 | 
			
		||||
        parser: &mut TypesParser<'_>,
 | 
			
		||||
    ) -> Result<Result<Self, ParsedTypeNamed>, ParseFailed> {
 | 
			
		||||
        let ParsedTypeNamed { path, args } = named;
 | 
			
		||||
        let parsed_path = known_items::PhantomData::parse_path(path);
 | 
			
		||||
        let phantom_data = match parsed_path {
 | 
			
		||||
            Ok(phantom_data) => phantom_data,
 | 
			
		||||
            Err(path) => return Ok(Err(ParsedTypeNamed { path, args })),
 | 
			
		||||
        };
 | 
			
		||||
        let Some(ParsedGenericArguments {
 | 
			
		||||
            colon2_token: _,
 | 
			
		||||
            lt_token,
 | 
			
		||||
            args,
 | 
			
		||||
            gt_token,
 | 
			
		||||
        }) = args
 | 
			
		||||
        else {
 | 
			
		||||
            parser
 | 
			
		||||
                .errors()
 | 
			
		||||
                .error(phantom_data, "PhantomData requires generic arguments");
 | 
			
		||||
            return Err(ParseFailed);
 | 
			
		||||
        };
 | 
			
		||||
        let args_len = args.len();
 | 
			
		||||
        if args_len != 1 {
 | 
			
		||||
            parser.errors().error(
 | 
			
		||||
                phantom_data,
 | 
			
		||||
                format_args!(
 | 
			
		||||
                    "wrong number of generic arguments supplied: got {args_len}, expected 1"
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
            return Err(ParseFailed);
 | 
			
		||||
        }
 | 
			
		||||
        let ty = args.into_iter().next().unwrap();
 | 
			
		||||
        let ParsedGenericArgument::Type(ty) = ty else {
 | 
			
		||||
            parser.errors().error(ty, "expected a type");
 | 
			
		||||
            return Err(ParseFailed);
 | 
			
		||||
        };
 | 
			
		||||
        Ok(Ok(Self {
 | 
			
		||||
            phantom_data,
 | 
			
		||||
            lt_token,
 | 
			
		||||
            ty: Box::new(ty),
 | 
			
		||||
            gt_token,
 | 
			
		||||
        }))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ParsedTypePhantomData> for Type {
 | 
			
		||||
    fn from(value: ParsedTypePhantomData) -> Type {
 | 
			
		||||
        let ParsedTypePhantomData {
 | 
			
		||||
            phantom_data,
 | 
			
		||||
            lt_token,
 | 
			
		||||
            ty,
 | 
			
		||||
            gt_token,
 | 
			
		||||
        } = value;
 | 
			
		||||
        let path = phantom_data.path;
 | 
			
		||||
        let mut args = Punctuated::new();
 | 
			
		||||
        args.push(GenericArgument::Type(ty.into()));
 | 
			
		||||
        let args = AngleBracketedGenericArguments {
 | 
			
		||||
            colon2_token: Some(Token),
 | 
			
		||||
            lt_token,
 | 
			
		||||
            args,
 | 
			
		||||
            gt_token,
 | 
			
		||||
        };
 | 
			
		||||
        let mut segments = path.segments;
 | 
			
		||||
        segments.last_mut().unwrap().arguments = PathArguments::AngleBracketed(args);
 | 
			
		||||
        Type::Path(TypePath {
 | 
			
		||||
            qself: None,
 | 
			
		||||
            path: Path {
 | 
			
		||||
                leading_colon: path.leading_colon,
 | 
			
		||||
                segments,
 | 
			
		||||
            },
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl MakeHdlTypeExpr for ParsedTypePhantomData {
 | 
			
		||||
    fn make_hdl_type_expr(&self, _context: &MakeHdlTypeExprContext) -> Expr {
 | 
			
		||||
        let ParsedTypePhantomData {
 | 
			
		||||
            phantom_data,
 | 
			
		||||
            lt_token: _,
 | 
			
		||||
            ty: _,
 | 
			
		||||
            gt_token: _,
 | 
			
		||||
        } = self;
 | 
			
		||||
        Expr::Path(ExprPath {
 | 
			
		||||
            attrs: vec![],
 | 
			
		||||
            qself: None,
 | 
			
		||||
            path: phantom_data.path.clone(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ToTokens for ParsedTypePhantomData {
 | 
			
		||||
    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
			
		||||
        let Self {
 | 
			
		||||
            phantom_data,
 | 
			
		||||
            lt_token,
 | 
			
		||||
            ty,
 | 
			
		||||
            gt_token,
 | 
			
		||||
        } = self;
 | 
			
		||||
        phantom_data.to_tokens(tokens);
 | 
			
		||||
        lt_token.to_tokens(tokens);
 | 
			
		||||
        ty.to_tokens(tokens);
 | 
			
		||||
        gt_token.to_tokens(tokens);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub(crate) enum ParsedType {
 | 
			
		||||
    Delimited(ParsedTypeDelimited),
 | 
			
		||||
| 
						 | 
				
			
			@ -1280,6 +1404,7 @@ pub(crate) enum ParsedType {
 | 
			
		|||
    NamedParam(ParsedTypeNamedParam),
 | 
			
		||||
    Tuple(ParsedTypeTuple),
 | 
			
		||||
    ConstUsize(ParsedTypeConstUsize),
 | 
			
		||||
    PhantomData(ParsedTypePhantomData),
 | 
			
		||||
    Array(ParsedTypeArray),
 | 
			
		||||
    UInt(ParsedTypeUInt),
 | 
			
		||||
    SInt(ParsedTypeSInt),
 | 
			
		||||
| 
						 | 
				
			
			@ -1294,6 +1419,7 @@ impl_fold! {
 | 
			
		|||
        NamedParam(ParsedTypeNamedParam),
 | 
			
		||||
        Tuple(ParsedTypeTuple),
 | 
			
		||||
        ConstUsize(ParsedTypeConstUsize),
 | 
			
		||||
        PhantomData(ParsedTypePhantomData),
 | 
			
		||||
        Array(ParsedTypeArray),
 | 
			
		||||
        UInt(ParsedTypeUInt),
 | 
			
		||||
        SInt(ParsedTypeSInt),
 | 
			
		||||
| 
						 | 
				
			
			@ -1310,6 +1436,7 @@ impl From<ParsedType> for Type {
 | 
			
		|||
            ParsedType::NamedParam(v) => v.into(),
 | 
			
		||||
            ParsedType::Tuple(v) => v.into(),
 | 
			
		||||
            ParsedType::ConstUsize(v) => v.into(),
 | 
			
		||||
            ParsedType::PhantomData(v) => v.into(),
 | 
			
		||||
            ParsedType::Array(v) => v.into(),
 | 
			
		||||
            ParsedType::UInt(v) => v.into(),
 | 
			
		||||
            ParsedType::SInt(v) => v.into(),
 | 
			
		||||
| 
						 | 
				
			
			@ -1360,6 +1487,7 @@ impl ToTokens for ParsedType {
 | 
			
		|||
            ParsedType::Named(ty) => ty.to_tokens(tokens),
 | 
			
		||||
            ParsedType::Tuple(ty) => ty.to_tokens(tokens),
 | 
			
		||||
            ParsedType::ConstUsize(ty) => ty.to_tokens(tokens),
 | 
			
		||||
            ParsedType::PhantomData(ty) => ty.to_tokens(tokens),
 | 
			
		||||
            ParsedType::Array(ty) => ty.to_tokens(tokens),
 | 
			
		||||
            ParsedType::UInt(ty) => ty.to_tokens(tokens),
 | 
			
		||||
            ParsedType::SInt(ty) => ty.to_tokens(tokens),
 | 
			
		||||
| 
						 | 
				
			
			@ -1467,6 +1595,10 @@ impl ParseTypes<Path> for ParsedType {
 | 
			
		|||
            Ok(v) => return Ok(Self::ConstUsize(v)),
 | 
			
		||||
            Err(named) => named,
 | 
			
		||||
        };
 | 
			
		||||
        let named = match ParsedTypePhantomData::try_from_named(named, parser)? {
 | 
			
		||||
            Ok(v) => return Ok(Self::PhantomData(v)),
 | 
			
		||||
            Err(named) => named,
 | 
			
		||||
        };
 | 
			
		||||
        let named = match ParsedTypeUInt::try_from_named(named, parser)? {
 | 
			
		||||
            Ok(v) => return Ok(Self::UInt(v)),
 | 
			
		||||
            Err(named) => named,
 | 
			
		||||
| 
						 | 
				
			
			@ -1784,7 +1916,7 @@ pub(crate) mod known_items {
 | 
			
		|||
 | 
			
		||||
            #[allow(non_snake_case, dead_code)]
 | 
			
		||||
            pub(crate) fn $known_item(span: Span) -> $known_item {
 | 
			
		||||
                let segments = $known_item::PATH_SEGMENTS.iter()
 | 
			
		||||
                let segments = $known_item::PATH_SEGMENTS[0].iter()
 | 
			
		||||
                    .copied()
 | 
			
		||||
                    .map(|seg| PathSegment::from(Ident::new(seg, span)))
 | 
			
		||||
                    .collect();
 | 
			
		||||
| 
						 | 
				
			
			@ -1810,20 +1942,21 @@ pub(crate) mod known_items {
 | 
			
		|||
                            return Ok(Self { span: ident.span(), path });
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if path.segments.len() == Self::PATH_SEGMENTS.len()
 | 
			
		||||
                        && path
 | 
			
		||||
                            .segments
 | 
			
		||||
                            .iter()
 | 
			
		||||
                            .zip(Self::PATH_SEGMENTS)
 | 
			
		||||
                            .all(|(seg, expected)| {
 | 
			
		||||
                                matches!(seg.arguments, PathArguments::None)
 | 
			
		||||
                                && seg.ident == *expected
 | 
			
		||||
                            })
 | 
			
		||||
                    {
 | 
			
		||||
                        Ok(Self { span: path.segments.last().unwrap().ident.span(), path })
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Err(path)
 | 
			
		||||
                    for &path_segments in Self::PATH_SEGMENTS.iter() {
 | 
			
		||||
                        if path.segments.len() == path_segments.len()
 | 
			
		||||
                            && path
 | 
			
		||||
                                .segments
 | 
			
		||||
                                .iter()
 | 
			
		||||
                                .zip(path_segments)
 | 
			
		||||
                                .all(|(seg, expected)| {
 | 
			
		||||
                                    matches!(seg.arguments, PathArguments::None)
 | 
			
		||||
                                    && seg.ident == *expected
 | 
			
		||||
                                })
 | 
			
		||||
                        {
 | 
			
		||||
                            return Ok(Self { span: path.segments.last().unwrap().ident.span(), path });
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    Err(path)
 | 
			
		||||
                }
 | 
			
		||||
                #[allow(dead_code)]
 | 
			
		||||
                pub(crate) fn parse_path_with_arguments(mut path: Path) -> Result<(Self, PathArguments), Path> {
 | 
			
		||||
| 
						 | 
				
			
			@ -1878,19 +2011,24 @@ pub(crate) mod known_items {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    macro_rules! impl_known_item {
 | 
			
		||||
        ($([$(::$head:ident)*])? ::$next:ident $(::$tail:ident)+) => {
 | 
			
		||||
            impl_known_item!([$($(::$head)*)? ::$next] $(::$tail)+);
 | 
			
		||||
        };
 | 
			
		||||
        ([$(::$seg:ident)+] ::$known_item:ident) => {
 | 
			
		||||
        ($(#[alias = $(::$alias:ident)+])* [$(::$seg:ident)+] ::$known_item:ident) => {
 | 
			
		||||
            impl_known_item_body!($known_item);
 | 
			
		||||
 | 
			
		||||
            impl $known_item {
 | 
			
		||||
                pub(crate) const PATH_SEGMENTS: &'static [&'static str] = &[
 | 
			
		||||
                    $(stringify!($seg),)+
 | 
			
		||||
                    stringify!($known_item),
 | 
			
		||||
                pub(crate) const PATH_SEGMENTS: &'static [&'static [&'static str]] = &[
 | 
			
		||||
                    &[
 | 
			
		||||
                        $(stringify!($seg),)+
 | 
			
		||||
                        stringify!($known_item),
 | 
			
		||||
                    ],
 | 
			
		||||
                    $(&[
 | 
			
		||||
                        $(stringify!($alias),)+
 | 
			
		||||
                    ],)*
 | 
			
		||||
                ];
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        ($(#[alias = $(::$alias:ident)+])* $([$(::$head:ident)*])? ::$next:ident $(::$tail:ident)+) => {
 | 
			
		||||
            impl_known_item!($(#[alias = $(::$alias)+])* [$($(::$head)*)? ::$next] $(::$tail)+);
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl_known_item!(::fayalite::array::Array);
 | 
			
		||||
| 
						 | 
				
			
			@ -1911,7 +2049,16 @@ pub(crate) mod known_items {
 | 
			
		|||
    impl_known_item!(::fayalite::ty::Type);
 | 
			
		||||
    impl_known_item!(::fayalite::ty::Type::MaskType);
 | 
			
		||||
    impl_known_item!(::fayalite::util::ConstUsize);
 | 
			
		||||
    impl_known_item!(::fayalite::__std::primitive::usize);
 | 
			
		||||
    impl_known_item!(
 | 
			
		||||
        #[alias = ::std::primitive::usize]
 | 
			
		||||
        #[alias = ::core::primitive::usize]
 | 
			
		||||
        ::fayalite::__std::primitive::usize
 | 
			
		||||
    );
 | 
			
		||||
    impl_known_item!(
 | 
			
		||||
        #[alias = ::std::marker::PhantomData]
 | 
			
		||||
        #[alias = ::core::marker::PhantomData]
 | 
			
		||||
        ::fayalite::__std::marker::PhantomData
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
macro_rules! impl_bounds {
 | 
			
		||||
| 
						 | 
				
			
			@ -3969,6 +4116,7 @@ impl MakeHdlTypeExpr for ParsedType {
 | 
			
		|||
            Self::NamedParam(v) => v.make_hdl_type_expr(context),
 | 
			
		||||
            Self::Tuple(v) => v.make_hdl_type_expr(context),
 | 
			
		||||
            Self::ConstUsize(v) => v.make_hdl_type_expr(context),
 | 
			
		||||
            Self::PhantomData(v) => v.make_hdl_type_expr(context),
 | 
			
		||||
            Self::Array(v) => v.make_hdl_type_expr(context),
 | 
			
		||||
            Self::UInt(v) => v.make_hdl_type_expr(context),
 | 
			
		||||
            Self::SInt(v) => v.make_hdl_type_expr(context),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -446,3 +446,85 @@ impl_tuples! {
 | 
			
		|||
        {#[num = 11, field = field_11] v11: T11}
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + Send + Sync + 'static> Type for PhantomData<T> {
 | 
			
		||||
    type BaseType = Bundle;
 | 
			
		||||
    type MaskType = ();
 | 
			
		||||
    type MatchVariant = PhantomData<T>;
 | 
			
		||||
    type MatchActiveScope = ();
 | 
			
		||||
    type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Self::MatchVariant>;
 | 
			
		||||
    type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
 | 
			
		||||
    fn match_variants(
 | 
			
		||||
        this: Expr<Self>,
 | 
			
		||||
        source_location: SourceLocation,
 | 
			
		||||
    ) -> Self::MatchVariantsIter {
 | 
			
		||||
        let _ = this;
 | 
			
		||||
        let _ = source_location;
 | 
			
		||||
        std::iter::once(MatchVariantWithoutScope(PhantomData))
 | 
			
		||||
    }
 | 
			
		||||
    fn mask_type(&self) -> Self::MaskType {
 | 
			
		||||
        ()
 | 
			
		||||
    }
 | 
			
		||||
    fn canonical(&self) -> CanonicalType {
 | 
			
		||||
        Bundle::new(self.fields()).canonical()
 | 
			
		||||
    }
 | 
			
		||||
    #[track_caller]
 | 
			
		||||
    fn from_canonical(canonical_type: CanonicalType) -> Self {
 | 
			
		||||
        let CanonicalType::Bundle(bundle) = canonical_type else {
 | 
			
		||||
            panic!("expected bundle");
 | 
			
		||||
        };
 | 
			
		||||
        assert!(
 | 
			
		||||
            bundle.fields().is_empty(),
 | 
			
		||||
            "bundle has wrong number of fields"
 | 
			
		||||
        );
 | 
			
		||||
        PhantomData
 | 
			
		||||
    }
 | 
			
		||||
    fn source_location() -> SourceLocation {
 | 
			
		||||
        SourceLocation::builtin()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct PhantomDataBuilder<T: ?Sized + Send + Sync + 'static>(PhantomData<T>);
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + Send + Sync + 'static> Default for PhantomDataBuilder<T> {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self(PhantomData)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomDataBuilder<T> {
 | 
			
		||||
    type Type = PhantomData<T>;
 | 
			
		||||
 | 
			
		||||
    fn to_expr(&self) -> Expr<Self::Type> {
 | 
			
		||||
        PhantomData.to_expr()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + Send + Sync + 'static> BundleType for PhantomData<T> {
 | 
			
		||||
    type Builder = PhantomDataBuilder<T>;
 | 
			
		||||
    type FilledBuilder = PhantomDataBuilder<T>;
 | 
			
		||||
    fn fields(&self) -> Interned<[BundleField]> {
 | 
			
		||||
        Interned::default()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + Send + Sync + 'static> TypeWithDeref for PhantomData<T> {
 | 
			
		||||
    fn expr_deref(_this: &Expr<Self>) -> &Self::MatchVariant {
 | 
			
		||||
        &PhantomData
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + Send + Sync + 'static> StaticType for PhantomData<T> {
 | 
			
		||||
    const TYPE: Self = PhantomData;
 | 
			
		||||
    const MASK_TYPE: Self::MaskType = ();
 | 
			
		||||
    const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
 | 
			
		||||
    const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + Send + Sync + 'static> ToExpr for PhantomData<T> {
 | 
			
		||||
    type Type = PhantomData<T>;
 | 
			
		||||
 | 
			
		||||
    fn to_expr(&self) -> Expr<Self::Type> {
 | 
			
		||||
        BundleLiteral::new(PhantomData, Interned::default()).to_expr()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
			
		||||
// See Notices.txt for copyright information
 | 
			
		||||
use fayalite::prelude::*;
 | 
			
		||||
use std::marker::PhantomData;
 | 
			
		||||
 | 
			
		||||
#[hdl(outline_generated)]
 | 
			
		||||
pub struct S<T, Len: Size, T2> {
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +9,8 @@ pub struct S<T, Len: Size, T2> {
 | 
			
		|||
    b: UInt<3>,
 | 
			
		||||
    pub(crate) c: ArrayType<UInt<1>, Len>,
 | 
			
		||||
    pub d: T2,
 | 
			
		||||
    pub e: PhantomData<T>,
 | 
			
		||||
    pub f: PhantomData<Len>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[hdl(outline_generated)]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue