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