Macro with unknown variants in match block compiles
gregorydemay opened this issue · comments
Summary
Macro with a match block behaves unexpectedly: when a variant is not recognized, it seems that the first variant in the enum definition is taken instead of failing compilation.
Environment
Observed with askama version 0.12.1
and rustc 1.73.0
(stable-aarch64-apple-darwin unchanged
)
Steps to reproduce
Based on the hello world starter template described here:
In templates/hello.html
: consider a macro which based on an enum variant displays one link or another:
{% macro etherscan_link -%}
{% match network %}
{%- when Sepolia -%}
<a href="https://sepolia.etherscan.io">Link</a>
{%- when Mainnet -%}
<a href="https://etherscan.io/address">Link</a>
{% endmatch %}
{%- endmacro %}
Here is the {% call etherscan_link() %}
In main.rs
, the file is adjusted to contain the enum definition with 2 variants and the template is instantiated with the second variant.
use askama::Template;
enum EthereumNetwork{
Sepolia,
Mainnet
}
#[derive(Template)]
#[template(path = "hello.html")]
struct HelloTemplate<'a> {
network: EthereumNetwork,
name: &'a str,
}
fn main() {
let hello = HelloTemplate { name: "world", network: EthereumNetwork::Mainnet };
println!("{}", hello.render().unwrap());
}
Expected Result
cargo runs
should return
Here is the <a href="https://etherscan.io/address">Link</a>
or compilation should fail if the match pattern in the macro is not recognized.
Actual Result
cargo run
wrongly returns
Here is the <a href="https://sepolia.etherscan.io">Link</a>
which would be the link for EthereumNetwork::Sepolia
, even though the template is instantiated with the other variant EthereumNetwork::Mainnet
.
The same behaviour can be observed if the match pattern in the macro is completely wrong
{% macro etherscan_link -%}
{% match network %}
{%- when Wrong1 -%}
<a href="https://sepolia.etherscan.io">Link</a>
{%- when Wrong2 -%}
<a href="https://etherscan.io/address">Link</a>
{% endmatch %}
{%- endmacro %}
Workaround
For the macro to function as expected it seems like the full path in each variant is required:
{% macro etherscan_link -%}
{% match network %}
{%- when EthereumNetwork::Sepolia -%}
<a href="https://sepolia.etherscan.io">Link</a>
{%- when EthereumNetwork::Mainnet -%}
<a href="https://etherscan.io/address">Link</a>
{% endmatch %}
{%- endmacro %}
In that case cargo run
returns the expected link
Here is the <a href="https://etherscan.io/address">Link</a>
This is basically what happens in Rust code, too. You should be able to write analogous Rust code, which will fail the same way.
This is basically what happens in Rust code, too. You should be able to write analogous Rust code, which will fail the same way.
I think here is depends exactly on how the match pattern is written. For example (see Rust playground):
#[derive(Debug)]
enum EthereumNetwork{
Sepolia,
Mainnet
}
fn main() {
let network = EthereumNetwork::Mainnet;
let url = match &network {
Sepolia => "https://sepolia.etherscan.io",
Mainnet => "https://etherscan.io/address"
};
println!("URL {} for network {:?}", url, network);
}
does not compile
Compiling playground v0.0.1 (/playground)
error[E0170]: pattern binding `Sepolia` is named the same as one of the variants of the type `EthereumNetwork`
--> src/main.rs:11:8
|
11 | Sepolia => "https://sepolia.etherscan.io",
| ^^^^^^^ help: to match on the variant, qualify the path: `EthereumNetwork::Sepolia`
|
= note: `#[deny(bindings_with_variant_name)]` on by default
It's true that if the match pattern is totally wrong like in here
let url = match &network {
Wrong1 => "https://sepolia.etherscan.io",
Wrong2 => "https://etherscan.io/address"
};
then it does compile, but with some useful warnings
Compiling playground v0.0.1 (/playground)
warning: unreachable pattern
--> src/main.rs:17:7
|
16 | Wrong1 => "https://sepolia.etherscan.io",
| ------ matches any value
17 | Wrong2 => "https://etherscan.io/address"
| ^^^^^^ unreachable pattern
|
= note: `#[warn(unreachable_patterns)]` on by default
Sure -- if you want to make a PR to improve on the current situation I'm open to that but I won't have time to work on this anytime soon.
Sure -- if you want to make a PR to improve on the current situation
I don't really know the internals of Askama, could you point me in the right direction? I can then try to come up with something when I have time.
Code generation for match
blocks is here:
https://github.com/djc/askama/blob/main/askama_derive/src/generator.rs#L544
Happy to answer other questions if you have them.
Duplicate of #711. Adding #[warn(unreachable_patterns)]
in generated code is suppressed.