vrl/compiler/expression/
return.rs

1use std::fmt;
2
3use crate::compiler::{
4    Context, Expression, Span, TypeDef,
5    expression::Resolved,
6    state::{TypeInfo, TypeState},
7};
8use crate::diagnostic::{DiagnosticMessage, Label, Note};
9use crate::parser::ast::Node;
10
11use super::{Expr, ExpressionError};
12
13#[derive(Debug, Clone, PartialEq)]
14pub struct Return {
15    span: Span,
16    expr: Box<Expr>,
17}
18
19impl Return {
20    /// # Errors
21    ///
22    /// * The returned value must not be fallible
23    pub fn new(span: Span, expr: Node<Expr>, state: &TypeState) -> Result<Self, Error> {
24        let (expr_span, expr) = expr.take();
25        let type_def = expr.type_info(state).result;
26
27        if type_def.is_fallible() {
28            return Err(Error {
29                variant: ErrorVariant::FallibleExpr,
30                expr_span,
31            });
32        }
33
34        Ok(Self {
35            span,
36            expr: Box::new(expr),
37        })
38    }
39}
40
41impl Expression for Return {
42    fn resolve(&self, ctx: &mut Context) -> Resolved {
43        Err(ExpressionError::Return {
44            span: self.span,
45            value: self.expr.resolve(ctx)?,
46        })
47    }
48
49    fn type_info(&self, state: &TypeState) -> TypeInfo {
50        let value = self.expr.type_info(state);
51        TypeInfo::new(
52            state,
53            TypeDef::never().with_returns(value.result.kind().clone()),
54        )
55    }
56}
57
58impl fmt::Display for Return {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        write!(f, "return")
61    }
62}
63
64// -----------------------------------------------------------------------------
65
66#[derive(Debug)]
67pub struct Error {
68    variant: ErrorVariant,
69    expr_span: Span,
70}
71
72#[derive(thiserror::Error, Debug)]
73pub(crate) enum ErrorVariant {
74    #[error("unhandled fallible expression")]
75    FallibleExpr,
76}
77
78impl fmt::Display for Error {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        write!(f, "{:#}", self.variant)
81    }
82}
83
84impl std::error::Error for Error {
85    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
86        Some(&self.variant)
87    }
88}
89
90impl DiagnosticMessage for Error {
91    fn code(&self) -> usize {
92        use ErrorVariant::FallibleExpr;
93
94        match self.variant {
95            FallibleExpr => 631,
96        }
97    }
98
99    fn labels(&self) -> Vec<Label> {
100        match &self.variant {
101            ErrorVariant::FallibleExpr => vec![
102                Label::primary(
103                    "return only accepts an infallible expression argument",
104                    self.expr_span,
105                ),
106                Label::context(
107                    "handle errors before using the expression as a return value",
108                    self.expr_span,
109                ),
110            ],
111        }
112    }
113
114    fn notes(&self) -> Vec<Note> {
115        match self.variant {
116            ErrorVariant::FallibleExpr => vec![Note::SeeErrorDocs],
117        }
118    }
119}