sway_parse/item/
item_impl.rs

1use crate::{Parse, ParseResult, Parser};
2
3use sway_ast::attribute::Annotated;
4use sway_ast::keywords::{
5    ConstToken, FnToken, OpenAngleBracketToken, SemicolonToken, TypeToken, WhereToken,
6};
7use sway_ast::{Braces, GenericParams, ItemImpl, ItemImplItem, PubToken, Ty};
8use sway_error::parser_error::ParseErrorKind;
9
10impl Parse for ItemImplItem {
11    fn parse(parser: &mut Parser) -> ParseResult<ItemImplItem> {
12        if parser.peek::<PubToken>().is_some() || parser.peek::<FnToken>().is_some() {
13            let fn_decl = parser.parse()?;
14            Ok(ItemImplItem::Fn(fn_decl))
15        } else if let Some(_const_keyword) = parser.peek::<ConstToken>() {
16            let const_decl = parser.parse()?;
17            parser.parse::<SemicolonToken>()?;
18            Ok(ItemImplItem::Const(const_decl))
19        } else if let Some(_type_keyword) = parser.peek::<TypeToken>() {
20            let type_decl = parser.parse()?;
21            parser.parse::<SemicolonToken>()?;
22            Ok(ItemImplItem::Type(type_decl))
23        } else {
24            Err(parser.emit_error(ParseErrorKind::ExpectedAnItem))
25        }
26    }
27}
28
29impl Parse for ItemImpl {
30    fn parse(parser: &mut Parser) -> ParseResult<ItemImpl> {
31        let impl_token = parser.parse()?;
32        let generic_params_opt = parser.guarded_parse::<OpenAngleBracketToken, GenericParams>()?;
33        let ty = parser.parse()?;
34        let (trait_opt, ty) = match parser.take() {
35            Some(for_token) => match ty {
36                Ty::Path(path_type) => (Some((path_type, for_token)), parser.parse()?),
37                _ => {
38                    return Err(parser.emit_error(ParseErrorKind::ExpectedPathType));
39                }
40            },
41            None => (None, ty),
42        };
43        let where_clause_opt = parser.guarded_parse::<WhereToken, _>()?;
44        let contents: Braces<Vec<Annotated<ItemImplItem>>> = parser.parse()?;
45        if trait_opt.is_some() {
46            for annotated in contents.get().iter() {
47                if let ItemImplItem::Fn(item_fn) = &annotated.value {
48                    parser.ban_visibility_qualifier(&item_fn.fn_signature.visibility)?;
49                }
50            }
51        }
52        Ok(ItemImpl {
53            impl_token,
54            generic_params_opt,
55            trait_opt,
56            ty,
57            where_clause_opt,
58            contents,
59        })
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use crate::test_utils::parse;
67    use assert_matches::*;
68
69    #[test]
70    fn parse_impl_ptr() {
71        let item = parse::<ItemImpl>(
72            r#"
73            impl __ptr[T] {}
74            "#,
75        );
76        assert_matches!(item.ty, Ty::Ptr { .. });
77    }
78
79    #[test]
80    fn parse_impl_for_ptr() {
81        let item = parse::<ItemImpl>(
82            r#"
83            impl Foo for __ptr[T] {}
84            "#,
85        );
86        assert_matches!(item.ty, Ty::Ptr { .. });
87    }
88
89    #[test]
90    fn parse_impl_slice() {
91        // deprecated syntax
92        let item = parse::<ItemImpl>("impl __slice[T] {}");
93        assert_matches!(
94            item.ty,
95            Ty::Slice {
96                slice_token: Some(..),
97                ty: _
98            }
99        );
100
101        // "new" syntax
102        let item = parse::<ItemImpl>("impl [T] {}");
103        assert_matches!(
104            item.ty,
105            Ty::Slice {
106                slice_token: None,
107                ty: _
108            }
109        );
110
111        let item = parse::<ItemImpl>("impl &[T] {}");
112        assert_matches!(item.ty, Ty::Ref { ty, .. } if matches!(&*ty, Ty::Slice { .. }));
113    }
114
115    #[test]
116    fn parse_impl_for_slice() {
117        let item = parse::<ItemImpl>(
118            r#"
119            impl Foo for __slice[T] {}
120            "#,
121        );
122        assert_matches!(item.ty, Ty::Slice { .. });
123    }
124
125    #[test]
126    fn parse_impl_ref() {
127        let item = parse::<ItemImpl>(
128            r#"
129            impl &T {}
130            "#,
131        );
132        assert_matches!(
133            item.ty,
134            Ty::Ref {
135                mut_token: None,
136                ..
137            }
138        );
139    }
140
141    #[test]
142    fn parse_impl_for_ref() {
143        let item = parse::<ItemImpl>(
144            r#"
145            impl Foo for &T {}
146            "#,
147        );
148        assert_matches!(
149            item.ty,
150            Ty::Ref {
151                mut_token: None,
152                ..
153            }
154        );
155    }
156
157    #[test]
158    fn parse_impl_mut_ref() {
159        let item = parse::<ItemImpl>(
160            r#"
161            impl &mut T {}
162            "#,
163        );
164        assert_matches!(
165            item.ty,
166            Ty::Ref {
167                mut_token: Some(_),
168                ..
169            }
170        );
171    }
172
173    #[test]
174    fn parse_impl_for_mut_ref() {
175        let item = parse::<ItemImpl>(
176            r#"
177            impl Foo for &mut T {}
178            "#,
179        );
180        assert_matches!(
181            item.ty,
182            Ty::Ref {
183                mut_token: Some(_),
184                ..
185            }
186        );
187    }
188}