snix_eval/
spans.rs

1//! Utilities for dealing with span tracking in the compiler and in
2//! error reporting.
3
4use codemap::{File, Span};
5use rnix::ast;
6use rowan::ast::AstNode;
7
8/// Trait implemented by all types from which we can retrieve a span.
9pub trait ToSpan {
10    fn span_for(&self, file: &File) -> Span;
11}
12
13impl ToSpan for Span {
14    fn span_for(&self, _: &File) -> Span {
15        *self
16    }
17}
18
19impl ToSpan for rnix::TextRange {
20    fn span_for(&self, file: &File) -> Span {
21        file.span
22            .subspan(u32::from(self.start()) as u64, u32::from(self.end()) as u64)
23    }
24}
25
26impl ToSpan for rnix::SyntaxToken {
27    fn span_for(&self, file: &File) -> Span {
28        self.text_range().span_for(file)
29    }
30}
31
32impl ToSpan for rnix::SyntaxNode {
33    fn span_for(&self, file: &File) -> Span {
34        self.text_range().span_for(file)
35    }
36}
37
38/// A placeholder [`ToSpan`] implementation covering the entire source file.
39#[derive(Debug, Clone, Copy)]
40pub struct EntireFile;
41
42impl ToSpan for EntireFile {
43    fn span_for(&self, file: &File) -> Span {
44        file.span
45    }
46}
47
48/// A placeholder [`ToSpan`] implementation which falls back to the entire file if its wrapped value
49/// is [`None`]
50#[derive(Debug, Clone, Copy)]
51pub struct OrEntireFile<T>(pub Option<T>);
52
53impl<T> ToSpan for OrEntireFile<T>
54where
55    T: ToSpan,
56{
57    fn span_for(&self, file: &File) -> Span {
58        match &self.0 {
59            Some(t) => t.span_for(file),
60            None => EntireFile.span_for(file),
61        }
62    }
63}
64
65/// Generates a `ToSpan` implementation for a type implementing
66/// `rowan::AstNode`. This is impossible to do as a blanket
67/// implementation because `rustc` forbids these implementations for
68/// traits from third-party crates due to a belief that semantic
69/// versioning truly could work (it doesn't).
70macro_rules! expr_to_span {
71    ( $type:path ) => {
72        impl ToSpan for $type {
73            fn span_for(&self, file: &File) -> Span {
74                self.syntax().span_for(file)
75            }
76        }
77    };
78}
79
80expr_to_span!(ast::Expr);
81expr_to_span!(ast::Apply);
82expr_to_span!(ast::Assert);
83expr_to_span!(ast::Attr);
84expr_to_span!(ast::AttrSet);
85expr_to_span!(ast::Attrpath);
86expr_to_span!(ast::AttrpathValue);
87expr_to_span!(ast::BinOp);
88expr_to_span!(ast::HasAttr);
89expr_to_span!(ast::Ident);
90expr_to_span!(ast::IdentParam);
91expr_to_span!(ast::IfElse);
92expr_to_span!(ast::Inherit);
93expr_to_span!(ast::Interpol);
94expr_to_span!(ast::Lambda);
95expr_to_span!(ast::LegacyLet);
96expr_to_span!(ast::LetIn);
97expr_to_span!(ast::List);
98expr_to_span!(ast::Literal);
99expr_to_span!(ast::PatBind);
100expr_to_span!(ast::Path);
101expr_to_span!(ast::Pattern);
102expr_to_span!(ast::Select);
103expr_to_span!(ast::Str);
104expr_to_span!(ast::UnaryOp);
105expr_to_span!(ast::With);