diff --git a/packages/yew-macro/src/html_tree/html_component.rs b/packages/yew-macro/src/html_tree/html_component.rs
index 9f8dd962cb8..751f255f751 100644
--- a/packages/yew-macro/src/html_tree/html_component.rs
+++ b/packages/yew-macro/src/html_tree/html_component.rs
@@ -1,5 +1,6 @@
use proc_macro2::Span;
use quote::{quote, quote_spanned, ToTokens};
+use syn::parse::discouraged::Speculative;
use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned;
use syn::{Token, Type};
@@ -45,7 +46,7 @@ impl Parse for HtmlComponent {
}
let mut children = HtmlChildrenTree::new();
- loop {
+ let close = loop {
if input.is_empty() {
return Err(syn::Error::new_spanned(
open.to_spanned(),
@@ -54,12 +55,46 @@ impl Parse for HtmlComponent {
}
if trying_to_close() {
- break;
+ let cursor = input.cursor();
+ let _ = cursor
+ .punct()
+ .and_then(|(_, cursor)| cursor.punct())
+ .and_then(|(_, cursor)| cursor.ident())
+ .ok_or_else(|| {
+ syn::Error::new(Span::call_site(), "expected a valid closing tag (e.g.: )")
+ })?;
+
+ let fork = input.fork();
+ let lt = fork.parse::()?;
+ let div = Some(fork.parse::()?);
+ let ty = fork.parse::()?;
+ if ty != open.ty {
+ fn format_token_stream(ts: impl ToTokens) -> String {
+ let string = ts.to_token_stream().to_string();
+ // remove unnecessary spaces
+ string.replace(' ', "")
+ }
+ let open_ty = open.ty;
+ return Err(syn::Error::new_spanned(
+ quote!(#open_ty #ty),
+ format!(
+ "mismatched closing tags: expected `{}`, found `{}`",
+ format_token_stream(open_ty),
+ format_token_stream(ty)
+ ),
+ ));
+ } else {
+ let gt = fork.parse::]>()?;
+ let close = HtmlComponentClose {
+ tag: TagTokens { lt, div, gt },
+ ty,
+ };
+ input.advance_to(&fork);
+ break close;
+ }
}
children.parse_child(input)?;
- }
-
- let close = input.parse::()?;
+ };
if !children.is_empty() {
if let Some(children_prop) = open.props.children() {
diff --git a/packages/yew-macro/tests/html_macro/component-fail.rs b/packages/yew-macro/tests/html_macro/component-fail.rs
index 5da187d2f5e..cdf9ccb34d2 100644
--- a/packages/yew-macro/tests/html_macro/component-fail.rs
+++ b/packages/yew-macro/tests/html_macro/component-fail.rs
@@ -148,4 +148,34 @@ fn not_expressions() {
html! { };
}
+fn mismatch_closing_tags() {
+ pub struct A;
+ impl Component for A {
+ type Message = ();
+ type Properties = ();
+
+ fn create(_ctx: &Context) -> Self {
+ unimplemented!()
+ }
+ fn view(&self, _ctx: &Context) -> Html {
+ unimplemented!()
+ }
+ }
+
+ pub struct B;
+ impl Component for B {
+ type Message = ();
+ type Properties = ();
+
+ fn create(_ctx: &Context) -> Self {
+ unimplemented!()
+ }
+ fn view(&self, _ctx: &Context) -> Html {
+ unimplemented!()
+ }
+ }
+ let _ = html! { };
+ let _ = html! { > };
+}
+
fn main() {}
diff --git a/packages/yew-macro/tests/html_macro/component-fail.stderr b/packages/yew-macro/tests/html_macro/component-fail.stderr
index 33f60e1a6a3..88716431599 100644
--- a/packages/yew-macro/tests/html_macro/component-fail.stderr
+++ b/packages/yew-macro/tests/html_macro/component-fail.stderr
@@ -386,6 +386,20 @@ error: only an expression may be assigned as a property. Consider removing this
148 | html! { };
| ^
+error: mismatched closing tags: expected `A`, found `B`
+ --> tests/html_macro/component-fail.rs:177:22
+ |
+177 | let _ = html! { };
+ | ^^^^^
+
+error: expected a valid closing tag (e.g.: )
+ --> tests/html_macro/component-fail.rs:178:13
+ |
+178 | let _ = html! { > };
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)
+
error[E0425]: cannot find value `blah` in this scope
--> tests/html_macro/component-fail.rs:82:22
|
diff --git a/packages/yew-macro/tests/html_macro/generic-component-fail.rs b/packages/yew-macro/tests/html_macro/generic-component-fail.rs
index ed2163bcfc5..7d06180caab 100644
--- a/packages/yew-macro/tests/html_macro/generic-component-fail.rs
+++ b/packages/yew-macro/tests/html_macro/generic-component-fail.rs
@@ -40,9 +40,15 @@ where
}}
fn compile_fail() {
+ #[allow(unused_imports)]
+ use std::path::Path;
+
html! { > };
html! { > };
html! { >>> };
+
+ html! { >> };
+ html! { >> };
}
fn main() {}
diff --git a/packages/yew-macro/tests/html_macro/generic-component-fail.stderr b/packages/yew-macro/tests/html_macro/generic-component-fail.stderr
index 7ce8f5a802d..aa7dbd2b589 100644
--- a/packages/yew-macro/tests/html_macro/generic-component-fail.stderr
+++ b/packages/yew-macro/tests/html_macro/generic-component-fail.stderr
@@ -1,21 +1,31 @@
error: this opening tag has no corresponding closing tag
- --> tests/html_macro/generic-component-fail.rs:43:13
+ --> tests/html_macro/generic-component-fail.rs:46:13
|
-43 | html! { > };
+46 | html! { > };
| ^^^^^^^^^^^^^^^^^
-error[E0107]: missing generics for struct `Generic`
- --> tests/html_macro/generic-component-fail.rs:44:32
+error: mismatched closing tags: expected `Generic`, found `Generic`
+ --> tests/html_macro/generic-component-fail.rs:47:14
|
-44 | html! { > };
- | ^^^^^^^ expected 1 generic argument
+47 | html! { > };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mismatched closing tags: expected `Generic`, found `Generic>`
+ --> tests/html_macro/generic-component-fail.rs:48:14
+ |
+48 | html! { >>> };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mismatched closing tags: expected `Generic`, found `Generic`
+ --> tests/html_macro/generic-component-fail.rs:50:14
|
-note: struct defined here, with 1 generic parameter: `T`
- --> tests/html_macro/generic-component-fail.rs:4:12
+50 | html! { >> };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected a valid closing tag (e.g.: )
+ --> tests/html_macro/generic-component-fail.rs:51:5
|
-4 | pub struct Generic {
- | ^^^^^^^ -
-help: add missing generic argument
+51 | html! { >> };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-44 | html! { >> };
- | ~~~~~~~~~~
+ = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)