proc-macro-workshop:sorted-7

godme發表於2022-07-06
// The macro won't need to define what it means for other sorts of patterns to
// be sorted. It should be fine to trigger an error if any of the patterns is
// not something that can be compared by path.
//
// Be sure that the resulting error message is understandable and placed
// correctly underlining the unsupported pattern.

#[sorted::check]
fn f(bytes: &[u8]) -> Option<u8> {
    #[sorted]
    match bytes {
        [] => Some(0),
        [a] => Some(*a),
        [a, b] => Some(a + b),
        _other => None,
    }
}

fn main() {}

這裡主要說明的是,我們只能排序能排序的。
rustmatch功能十分強大,並非只是簡單的字元列舉匹配,還有很多的資料匹配。
對於這種,我們並不需要完全的支援。


impl syn::visit_mut::VisitMut for MatchVisitor {
    fn visit_expr_match_mut(&mut self, i: &mut syn::ExprMatch) {
        let mut target_idx: isize = -1;
        for (idx, attr) in i.attrs.iter().enumerate() {
            if path_to_string(&attr.path) == "sorted" {
                target_idx = idx as isize;
                break;
            }
        }
        if target_idx != -1 {
            i.attrs.remove(target_idx as usize);
            let mut match_arm_names: Vec<(String, &dyn quote::ToTokens)> = Vec::new();
            for arm in i.arms.iter() {
                match &arm.pat {
                    syn::Pat::Path(p) => {
                        match_arm_names.push((path_to_string(&p.path), &p.path));
                    }
                    syn::Pat::TupleStruct(p) => {
                        match_arm_names.push((path_to_string(&p.path), &p.path));
                    }
                    syn::Pat::Struct(p) => {
                        match_arm_names.push((path_to_string(&p.path), &p.path));
                    }
                    syn::Pat::Ident(p) => {
                        match_arm_names.push((p.ident.to_string(), &p.ident));
                    }
                    syn::Pat::Wild(p) => {
                        match_arm_names.push(("_".to_string(), &p.underscore_token));
                    }
                    _ => {
                        self.err = std::option::Option::Some(syn::Error::new_spanned(
                            &arm.pat,
                            "unsupported by #[sorted]",
                        ));
                        return;
                    }
                }
            }
            if let Some(e) = check_order(match_arm_names) {
                self.err = std::option::Option::Some(e);
                return;
            }
        }
        syn::visit_mut::visit_expr_match_mut(self, i)
    }
}

sorted-5中我們解析其他型別的時候,最後一個分支我們提示了一個錯誤。
其實就是這一關的提示錯誤

error: unsupported by #[sorted]
  --> tests/07-unrecognized-pattern.rs:12:9
   |
12 |         [] => Some(0),
   |  

雖然我是後續整理合二為一的,但是我相信,只要保持良好的編碼習慣,這種錯誤提示的相似性甚至一致性,是必然的結果。多多努力。

本作品採用《CC 協議》,轉載必須註明作者和本文連結