diff options
| author | 2021-01-02 23:02:59 +0100 | |
|---|---|---|
| committer | 2021-01-05 16:17:14 +0100 | |
| commit | b76f7ef778dd37db08cb4dba2dc9329b15bbe984 (patch) | |
| tree | f12a3086ce2b5d5af9ed4ff6274c1fd44b3c2e1c /askama_shared/src/parser.rs | |
| parent | c2102d4d1f33fda499bccb09f77ea9cbd72f2018 (diff) | |
| download | askama-b76f7ef778dd37db08cb4dba2dc9329b15bbe984.tar.gz askama-b76f7ef778dd37db08cb4dba2dc9329b15bbe984.tar.bz2 askama-b76f7ef778dd37db08cb4dba2dc9329b15bbe984.zip  | |
Removed implicit borrowing of literals, calls, and more (fixes #404)
Diffstat (limited to 'askama_shared/src/parser.rs')
| -rw-r--r-- | askama_shared/src/parser.rs | 39 | 
1 files changed, 39 insertions, 0 deletions
diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs index 43377a6..3b3d4f4 100644 --- a/askama_shared/src/parser.rs +++ b/askama_shared/src/parser.rs @@ -51,6 +51,45 @@ pub enum Expr<'a> {      RustMacro(&'a str, &'a str),  } +impl Expr<'_> { +    /// Returns `true` if enough assumptions can be made, +    /// to determine that `self` is copyable. +    pub fn is_copyable(&self) -> bool { +        self.is_copyable_within_op(false) +    } + +    fn is_copyable_within_op(&self, within_op: bool) -> bool { +        use Expr::*; +        match self { +            BoolLit(_) | NumLit(_) | StrLit(_) | CharLit(_) => true, +            Unary(.., expr) => expr.is_copyable_within_op(true), +            BinOp(_, lhs, rhs) => { +                lhs.is_copyable_within_op(true) && rhs.is_copyable_within_op(true) +            } +            // The result of a call likely doesn't need to be borrowed, +            // as in that case the call is more likely to return a +            // reference in the first place then. +            VarCall(..) | PathCall(..) | MethodCall(..) => true, +            // If the `expr` is within a `Unary` or `BinOp` then +            // an assumption can be made that the operand is copy. +            // If not, then the value is moved and adding `.clone()` +            // will solve that issue. However, if the operand is +            // implicitly borrowed, then it's likely not even possible +            // to get the template to compile. +            _ => within_op && self.is_attr_self(), +        } +    } + +    /// Returns `true` if this is an `Attr` where the `obj` is `"self"`. +    pub fn is_attr_self(&self) -> bool { +        match self { +            Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Var("self")) => true, +            Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Attr(..)) => obj.is_attr_self(), +            _ => false, +        } +    } +} +  pub type When<'a> = (      WS,      Option<MatchVariant<'a>>,  | 
