Skip to main content

cl_ast/desugar/
type_bubbler.rs

1//! Separates [Patterns](Pat) into their Value and Type components.
2
3use std::{convert::Infallible, mem::replace};
4
5use crate::{
6    At, Bind, BindOp, DefaultTypes, Pat, PatOp,
7    fold::{Fold, Foldable, impl_default_fold},
8};
9
10fn take(At(pat, span): &mut At<Pat>) -> At<Pat> {
11    At(replace(pat, Pat::Ignore), *span)
12}
13
14pub fn bubble_types(pat: At<Pat>, in_enum: bool) -> (At<Pat>, Option<At<Pat>>) {
15    //! Bubbles up type annotations from within a pattern to the top level.
16    let (op, mut pats, span) = match pat {
17        At(Pat::Op(op, pats), span) => (op, pats, span),
18        _ => return (pat, None),
19    };
20
21    match (op, &mut pats[..]) {
22        (PatOp::Typed, [pat, ty]) => {
23            let (value, _ty2) = bubble_types(take(pat), in_enum);
24            // TODO: unify ty, ty2
25            (value, Some(take(ty)))
26        }
27        (PatOp::TypePrefixed, [prefix, pat]) => {
28            let (pat, ty) = bubble_types(take(pat), in_enum);
29            let ty = match (ty, in_enum) {
30                (Some(At(ty, span)), false) => {
31                    Pat::Op(op, vec![prefix.clone(), ty.at(span)]).at(span)
32                }
33                (Some(At(ty, span)), true) => {
34                    Pat::Op(op, vec![Pat::Ignore.at(span), ty.at(span)]).at(span)
35                }
36                (None, _) => prefix.clone(),
37            };
38            let value = Pat::Op(op, vec![take(prefix), pat]).at(span);
39            (value, Some(ty))
40        }
41        (PatOp::MetaInner | PatOp::MetaOuter, [meta, pat]) => {
42            let (value, ty) = bubble_types(take(pat), in_enum);
43            (Pat::Op(op, vec![take(meta), value]).at(span), ty)
44        }
45        (PatOp::Pub | PatOp::Mut | PatOp::Ref | PatOp::Ptr, [pat]) => {
46            let (value, ty) = bubble_types(take(pat), in_enum);
47            (Pat::Op(op, vec![value]).at(span), ty)
48        }
49        (PatOp::Record, ..) => {
50            let (mut values, mut types) = (vec![], vec![]);
51            for At(pat, span) in pats {
52                // records use `Typed` nodes for value decomposition
53                let (name, body) = bubble_types(pat.at(span), false);
54
55                // but enums do not.
56                if in_enum {
57                    values.push(body.unwrap_or_else(|| name.clone()));
58                    types.push(name);
59                    continue;
60                }
61
62                // those `Typed` nodes must be further bubbled
63                let body = body.unwrap_or(Pat::Ignore.at(name.1));
64                let (body, ty) = bubble_types(body, false);
65                let ty = ty.unwrap_or(Pat::Ignore.at(body.1));
66
67                values.push(Pat::Op(PatOp::Typed, vec![name.clone(), body]).at(span));
68                types.push(Pat::Op(PatOp::Typed, vec![name, ty]).at(span));
69            }
70            let (value, ty) = (Pat::Op(op, values).at(span), Pat::Op(op, types).at(span));
71            (value, Some(ty))
72        }
73        (PatOp::ArRep, [pat, rep]) => {
74            let (pat, ty) = bubble_types(take(pat), in_enum);
75            let ty = ty.unwrap_or(Pat::Ignore.at(pat.1));
76            (
77                Pat::Op(op, vec![pat, Pat::Ignore.at(span)]).at(span),
78                Some(Pat::Op(op, vec![ty, take(rep)]).at(span)),
79            )
80        }
81        (PatOp::Generic, [pat, ..]) => {
82            let (pat, ty) = bubble_types(take(pat), in_enum);
83            pats[0] = ty.unwrap_or(Pat::Ignore.at(pat.1));
84            (pat, Some(Pat::Op(op, pats).at(span)))
85        }
86        (PatOp::Fn, [arg, ret]) => {
87            let (pat, ty) = bubble_types(take(arg), in_enum);
88            let ty = ty.unwrap_or(Pat::Ignore.at(pat.1));
89            (pat, Some(Pat::Op(op, vec![ty, take(ret)]).at(span)))
90        }
91        _ => {
92            let (mut values, mut tys) = (vec![], vec![]);
93            for pat in pats {
94                let (value, ty) = bubble_types(pat, in_enum);
95                tys.push(ty.unwrap_or(Pat::Ignore.at(value.1)));
96                values.push(value);
97            }
98            let (value, ty) = (Pat::Op(op, values).at(span), Pat::Op(op, tys).at(span));
99            (value, Some(ty))
100        }
101    }
102}
103
104/// The [Bubbler] separates [Patterns](Pat) into their value and type-annotation components,
105/// "bubbling" [PatOp::Typed] annotations up to the top of all pattern-expressions.
106///
107/// Its [`bool`] argument tracks whether or not it's inside of a [`BindOp::Enum`] expression,
108/// which gets different binding rules.
109#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
110pub struct Bubbler(pub bool);
111
112impl Fold<DefaultTypes, DefaultTypes> for Bubbler {
113    type Error = Infallible;
114    impl_default_fold!(DefaultTypes, DefaultTypes);
115
116    fn fold_at_pat(
117        &mut self,
118        pat: At<Pat<DefaultTypes>, DefaultTypes>,
119    ) -> Result<At<Pat<DefaultTypes>, DefaultTypes>, Self::Error> {
120        Ok(match bubble_types(pat, self.0) {
121            (value @ At(_, span), Some(ty)) => Pat::Op(PatOp::Typed, vec![value, ty]).at(span),
122            (value, None) => value,
123        })
124    }
125
126    fn fold_bind(&mut self, bind: Bind<DefaultTypes>) -> Result<Bind<DefaultTypes>, Self::Error> {
127        let mut bubbler = Bubbler(bind.0 == BindOp::Enum);
128        bind.children(&mut bubbler)
129    }
130}