Revert "Improve nested html! expansion by unwrapping VNodes (#820)" (#842)

This reverts commit a900fbee496d1140b424bcb2f1c91402d20eca2b.
This commit is contained in:
Justin Starry 2020-01-04 13:35:50 -05:00 committed by GitHub
parent f7313348f6
commit 70862a46a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 104 additions and 197 deletions

View File

@ -23,7 +23,7 @@ lazy_static = "1.3.0"
proc-macro-hack = "0.5"
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", features = ["full", "extra-traits", "visit-mut"] }
syn = { version = "1.0", features = ["full", "extra-traits"] }
[dev-dependencies]
yew = { path = "../.." }

View File

@ -26,7 +26,7 @@ impl PeekValue<()> for HtmlBlock {
impl Parse for HtmlBlock {
fn parse(input: ParseStream) -> ParseResult<Self> {
let content: syn::parse::ParseBuffer<'_>;
let content;
let brace = braced!(content in input);
let content = if HtmlIterable::peek(content.cursor()).is_some() {
BlockContent::Iterable(content.parse()?)

View File

@ -12,8 +12,8 @@ use syn::parse::{Parse, ParseStream, Result as ParseResult};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{
AngleBracketedGenericArguments, Expr, GenericArgument, Ident, Index, Path, PathArguments,
PathSegment, Token, Type, TypePath,
AngleBracketedGenericArguments, Expr, GenericArgument, Ident, Path, PathArguments, PathSegment,
Token, Type, TypePath,
};
pub struct HtmlComponent {
@ -126,17 +126,10 @@ impl ToTokens for HtmlComponent {
};
let set_children = if !children.is_empty() {
let i = (0..children.len())
.map(|x| Index::from(x))
.collect::<Vec<_>>();
quote! {
.children(::yew::html::ChildrenRenderer::new({
let mut v = Vec::new();
let comps = (#(#children,)*);
#(::yew::utils::NodeSeq::from(comps.#i).into_iter()
.for_each(|x| v.push(x.into()));)*
v
}))
.children(::yew::html::ChildrenRenderer::new(
vec![#(#children.into(),)*]
))
}
} else {
quote! {}

View File

@ -7,10 +7,6 @@ use syn::parse::{Parse, ParseStream, Result as ParseResult};
use syn::spanned::Spanned;
use syn::{Expr, Token};
use proc_macro2::{Ident, Span};
use syn::visit_mut::{self, VisitMut};
use syn::Macro;
pub struct HtmlIterable(Expr);
impl PeekValue<()> for HtmlIterable {
@ -20,28 +16,12 @@ impl PeekValue<()> for HtmlIterable {
}
}
struct HtmlInnerModifier;
impl VisitMut for HtmlInnerModifier {
fn visit_macro_mut(&mut self, node: &mut Macro) {
if node.path.is_ident("html") {
let ident = &mut node.path.segments.last_mut().unwrap().ident;
*ident = Ident::new("html_nested", Span::call_site());
}
// Delegate to the default impl to visit any nested functions.
visit_mut::visit_macro_mut(self, node);
}
}
impl Parse for HtmlIterable {
fn parse(input: ParseStream) -> ParseResult<Self> {
let for_token = input.parse::<Token![for]>()?;
match input.parse() {
Ok(mut expr) => {
HtmlInnerModifier.visit_expr_mut(&mut expr);
Ok(HtmlIterable(expr))
}
Ok(expr) => Ok(HtmlIterable(expr)),
Err(err) => {
if err.to_string().starts_with("unexpected end of input") {
Err(syn::Error::new_spanned(

View File

@ -4,26 +4,8 @@ use quote::{quote, quote_spanned, ToTokens};
use syn::buffer::Cursor;
use syn::parse::{Parse, ParseStream, Result};
use syn::spanned::Spanned;
use syn::Expr;
use syn::Lit;
use proc_macro2::{Ident, Span};
use syn::visit_mut::{self, VisitMut};
use syn::Macro;
struct HtmlInnerModifier;
impl VisitMut for HtmlInnerModifier {
fn visit_macro_mut(&mut self, node: &mut Macro) {
if node.path.is_ident("html") {
let ident = &mut node.path.segments.last_mut().unwrap().ident;
*ident = Ident::new("html_nested", Span::call_site());
}
// Delegate to the default impl to visit any nested functions.
visit_mut::visit_macro_mut(self, node);
}
}
pub struct HtmlNode(Node);
impl Parse for HtmlNode {
@ -36,9 +18,7 @@ impl Parse for HtmlNode {
}
Node::Literal(lit)
} else {
let mut expr: Expr = input.parse()?;
HtmlInnerModifier.visit_expr_mut(&mut expr);
Node::Expression(expr)
Node::Raw(input.parse()?)
};
Ok(HtmlNode(node))
@ -66,8 +46,12 @@ impl ToTokens for HtmlNode {
impl ToTokens for Node {
fn to_tokens(&self, tokens: &mut TokenStream) {
let node_token = match &self {
Node::Literal(lit) => quote! {#lit},
Node::Expression(expr) => quote_spanned! {expr.span()=> {#expr} },
Node::Literal(lit) => quote! {
::yew::virtual_dom::VNode::from(#lit)
},
Node::Raw(stream) => quote_spanned! {stream.span()=>
::yew::virtual_dom::VNode::from({#stream})
},
};
tokens.extend(node_token);
@ -76,5 +60,5 @@ impl ToTokens for Node {
enum Node {
Literal(Lit),
Expression(Expr),
Raw(TokenStream),
}

View File

@ -126,19 +126,6 @@ impl HtmlTree {
}
}
pub struct HtmlRootNested(HtmlTreeNested);
impl Parse for HtmlRootNested {
fn parse(input: ParseStream) -> Result<Self> {
Ok(HtmlRootNested(HtmlTreeNested::parse(input)?))
}
}
impl ToTokens for HtmlRootNested {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
self.0.to_tokens(tokens);
}
}
pub struct HtmlTreeNested(HtmlTree);
impl Parse for HtmlTreeNested {
fn parse(input: ParseStream) -> Result<Self> {

View File

@ -63,7 +63,7 @@ mod derive_props;
mod html_tree;
use derive_props::DerivePropsInput;
use html_tree::{HtmlRoot, HtmlRootNested};
use html_tree::HtmlRoot;
use proc_macro::TokenStream;
use proc_macro_hack::proc_macro_hack;
use quote::{quote, ToTokens};
@ -94,12 +94,6 @@ pub fn derive_props(input: TokenStream) -> TokenStream {
TokenStream::from(input.into_token_stream())
}
#[proc_macro_hack]
pub fn html_nested(input: TokenStream) -> TokenStream {
let root = parse_macro_input!(input as HtmlRootNested);
TokenStream::from(quote! {#root})
}
#[proc_macro_hack]
pub fn html(input: TokenStream) -> TokenStream {
let root = parse_macro_input!(input as HtmlRoot);

View File

@ -72,14 +72,9 @@ use proc_macro_hack::proc_macro_hack;
#[proc_macro_hack(support_nested)]
pub use yew_macro::html;
#[doc(hidden)]
#[proc_macro_hack(support_nested)]
pub use yew_macro::html_nested;
/// This module contains macros which implements html! macro and JSX-like templates
pub mod macros {
pub use crate::html;
pub use crate::html_nested;
pub use yew_macro::Properties;
}
@ -163,7 +158,6 @@ pub mod prelude {
Renderable, ShouldRender,
};
pub use crate::macros::*;
pub use crate::utils::NodeSeq;
pub use crate::virtual_dom::Classes;
/// Prelude module for creating worker.

View File

@ -3,8 +3,6 @@
use failure::{err_msg, Error};
use stdweb::web::document;
use crate::virtual_dom::VNode;
/// Returns `host` for the current document. Useful to connect to a server that server the app.
pub fn host() -> Result<String, Error> {
document()
@ -12,30 +10,3 @@ pub fn host() -> Result<String, Error> {
.ok_or_else(|| err_msg("can't get location"))
.and_then(|l| l.host().map_err(Error::from))
}
/// Specialty type necessary for helping flattening components returned from nested html macros.
#[derive(Debug)]
pub struct NodeSeq<T>(Vec<T>)
where
T: Into<VNode>;
impl<T: Into<VNode>> From<T> for NodeSeq<T> {
fn from(val: T) -> Self {
NodeSeq(vec![val])
}
}
impl<T: Into<VNode>> From<Vec<T>> for NodeSeq<T> {
fn from(val: Vec<T>) -> Self {
NodeSeq(val)
}
}
impl<T: Into<VNode>> IntoIterator for NodeSeq<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}

View File

@ -2,6 +2,7 @@
use std::marker::PhantomData;
use yew::prelude::*;
use yew::virtual_dom::{VChild, VComp, VNode};
#[derive(Clone, Properties, PartialEq)]
pub struct ChildProperties {
@ -20,6 +21,18 @@ impl Component for Child {
fn view(&self) -> Html { unimplemented!() }
}
impl From<VChild<Child>> for ChildProperties {
fn from(comp: VChild<Child>) -> Self {
comp.props
}
}
impl Into<VNode> for ChildProperties {
fn into(self) -> VNode {
VComp::new::<Child>(self, NodeRef::default()).into()
}
}
#[derive(Clone, Properties)]
pub struct ChildContainerProperties {
#[props(required)]

View File

@ -1,145 +1,145 @@
error: this open tag has no corresponding close tag
--> $DIR/html-component-fail.rs:53:13
--> $DIR/html-component-fail.rs:66:13
|
53 | html! { <Child> };
66 | html! { <Child> };
| ^^^^^^^
error: expected identifier
--> $DIR/html-component-fail.rs:54:22
--> $DIR/html-component-fail.rs:67:22
|
54 | html! { <Child:: /> };
67 | html! { <Child:: /> };
| ^
error: unexpected end of input, expected identifier
--> $DIR/html-component-fail.rs:55:5
--> $DIR/html-component-fail.rs:68:5
|
55 | html! { <Child with /> };
68 | html! { <Child with /> };
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: unexpected token
--> $DIR/html-component-fail.rs:56:20
--> $DIR/html-component-fail.rs:69:20
|
56 | html! { <Child props /> };
69 | html! { <Child props /> };
| ^^^^^
error: this open tag has no corresponding close tag
--> $DIR/html-component-fail.rs:57:13
--> $DIR/html-component-fail.rs:70:13
|
57 | html! { <Child with props > };
70 | html! { <Child with props > };
| ^^^^^^^^^^^^^^^^^^^
error: unexpected token
--> $DIR/html-component-fail.rs:58:38
--> $DIR/html-component-fail.rs:71:38
|
58 | html! { <Child with props ref=() ref=() /> };
71 | html! { <Child with props ref=() ref=() /> };
| ^^^
error: unexpected token
--> $DIR/html-component-fail.rs:59:27
--> $DIR/html-component-fail.rs:72:27
|
59 | html! { <Child ref=() with props /> };
72 | html! { <Child ref=() with props /> };
| ^^^^
error: unexpected token
--> $DIR/html-component-fail.rs:61:31
--> $DIR/html-component-fail.rs:74:31
|
61 | html! { <Child with props () /> };
74 | html! { <Child with props () /> };
| ^^
error: expected identifier
--> $DIR/html-component-fail.rs:62:20
--> $DIR/html-component-fail.rs:75:20
|
62 | html! { <Child type=0 /> };
75 | html! { <Child type=0 /> };
| ^^^^
error: expected identifier
--> $DIR/html-component-fail.rs:63:20
--> $DIR/html-component-fail.rs:76:20
|
63 | html! { <Child invalid-prop-name=0 /> };
76 | html! { <Child invalid-prop-name=0 /> };
| ^^^^^^^^^^^^^^^^^
error: unexpected end of input, expected expression
--> $DIR/html-component-fail.rs:65:5
--> $DIR/html-component-fail.rs:78:5
|
65 | html! { <Child string= /> };
78 | html! { <Child string= /> };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: too many refs set
--> $DIR/html-component-fail.rs:70:33
--> $DIR/html-component-fail.rs:83:33
|
70 | html! { <Child int=1 ref=() ref=() /> };
83 | html! { <Child int=1 ref=() ref=() /> };
| ^^^
error: this close tag has no corresponding open tag
--> $DIR/html-component-fail.rs:73:13
--> $DIR/html-component-fail.rs:86:13
|
73 | html! { </Child> };
86 | html! { </Child> };
| ^^^^^^^^
error: this open tag has no corresponding close tag
--> $DIR/html-component-fail.rs:74:13
--> $DIR/html-component-fail.rs:87:13
|
74 | html! { <Child><Child></Child> };
87 | html! { <Child><Child></Child> };
| ^^^^^^^
error: only one root html element allowed
--> $DIR/html-component-fail.rs:75:28
--> $DIR/html-component-fail.rs:88:28
|
75 | html! { <Child></Child><Child></Child> };
88 | html! { <Child></Child><Child></Child> };
| ^^^^^^^^^^^^^^^
error: this close tag has no corresponding open tag
--> $DIR/html-component-fail.rs:84:30
--> $DIR/html-component-fail.rs:97:30
|
84 | html! { <Generic<String>></Generic> };
97 | html! { <Generic<String>></Generic> };
| ^^^^^^^^^^
error: this close tag has no corresponding open tag
--> $DIR/html-component-fail.rs:85:30
--> $DIR/html-component-fail.rs:98:30
|
85 | html! { <Generic<String>></Generic<Vec<String>>> };
98 | html! { <Generic<String>></Generic<Vec<String>>> };
| ^^^^^^^^^^^^^^^^^^^^^^^
error[E0425]: cannot find value `blah` in this scope
--> $DIR/html-component-fail.rs:60:25
--> $DIR/html-component-fail.rs:73:25
|
60 | html! { <Child with blah /> };
73 | html! { <Child with blah /> };
| ^^^^ not found in this scope
error[E0609]: no field `unknown` on type `ChildProperties`
--> $DIR/html-component-fail.rs:64:20
--> $DIR/html-component-fail.rs:77:20
|
64 | html! { <Child unknown="unknown" /> };
77 | html! { <Child unknown="unknown" /> };
| ^^^^^^^ unknown field
|
= note: available fields are: `string`, `int`
error[E0599]: no method named `unknown` found for type `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope
--> $DIR/html-component-fail.rs:64:20
--> $DIR/html-component-fail.rs:77:20
|
6 | #[derive(Clone, Properties, PartialEq)]
7 | #[derive(Clone, Properties, PartialEq)]
| - method `unknown` not found for this
...
64 | html! { <Child unknown="unknown" /> };
77 | html! { <Child unknown="unknown" /> };
| ^^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
error[E0308]: mismatched types
--> $DIR/html-component-fail.rs:66:33
--> $DIR/html-component-fail.rs:79:33
|
66 | html! { <Child int=1 string={} /> };
79 | html! { <Child int=1 string={} /> };
| ^^ expected struct `std::string::String`, found ()
|
= note: expected type `std::string::String`
found type `()`
error[E0308]: mismatched types
--> $DIR/html-component-fail.rs:67:33
--> $DIR/html-component-fail.rs:80:33
|
67 | html! { <Child int=1 string=3 /> };
80 | html! { <Child int=1 string=3 /> };
| ^
| |
| expected struct `std::string::String`, found integer
@ -149,9 +149,9 @@ error[E0308]: mismatched types
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/html-component-fail.rs:68:33
--> $DIR/html-component-fail.rs:81:33
|
68 | html! { <Child int=1 string={3} /> };
81 | html! { <Child int=1 string={3} /> };
| ^^^
| |
| expected struct `std::string::String`, found integer
@ -161,89 +161,89 @@ error[E0308]: mismatched types
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/html-component-fail.rs:69:30
--> $DIR/html-component-fail.rs:82:30
|
69 | html! { <Child int=1 ref=() /> };
82 | html! { <Child int=1 ref=() /> };
| ^^ expected struct `yew::html::NodeRef`, found ()
|
= note: expected type `yew::html::NodeRef`
found type `()`
error[E0308]: mismatched types
--> $DIR/html-component-fail.rs:71:24
--> $DIR/html-component-fail.rs:84:24
|
71 | html! { <Child int=0u32 /> };
84 | html! { <Child int=0u32 /> };
| ^^^^ expected i32, found u32
|
help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit
|
71 | html! { <Child int=0u32.try_into().unwrap() /> };
84 | html! { <Child int=0u32.try_into().unwrap() /> };
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0599]: no method named `string` found for type `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope
--> $DIR/html-component-fail.rs:72:20
--> $DIR/html-component-fail.rs:85:20
|
6 | #[derive(Clone, Properties, PartialEq)]
7 | #[derive(Clone, Properties, PartialEq)]
| - method `string` not found for this
...
72 | html! { <Child string="abc" /> };
85 | html! { <Child string="abc" /> };
| ^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
error[E0599]: no method named `children` found for type `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope
--> $DIR/html-component-fail.rs:76:5
--> $DIR/html-component-fail.rs:89:5
|
6 | #[derive(Clone, Properties, PartialEq)]
7 | #[derive(Clone, Properties, PartialEq)]
| - method `children` not found for this
...
76 | html! { <Child>{ "Not allowed" }</Child> };
89 | html! { <Child>{ "Not allowed" }</Child> };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error[E0599]: no method named `build` found for type `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>` in the current scope
--> $DIR/html-component-fail.rs:78:5
--> $DIR/html-component-fail.rs:91:5
|
23 | #[derive(Clone, Properties)]
36 | #[derive(Clone, Properties)]
| - method `build` not found for this
...
78 | html! { <ChildContainer /> };
91 | html! { <ChildContainer /> };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>`
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error[E0599]: no method named `build` found for type `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>` in the current scope
--> $DIR/html-component-fail.rs:79:5
--> $DIR/html-component-fail.rs:92:5
|
23 | #[derive(Clone, Properties)]
36 | #[derive(Clone, Properties)]
| - method `build` not found for this
...
79 | html! { <ChildContainer></ChildContainer> };
92 | html! { <ChildContainer></ChildContainer> };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>`
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<&str>` is not satisfied
--> $DIR/html-component-fail.rs:80:5
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vnode::VNode>` is not satisfied
--> $DIR/html-component-fail.rs:93:5
|
80 | html! { <ChildContainer>{ "Not allowed" }</ChildContainer> };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<&str>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`
93 | html! { <ChildContainer>{ "Not allowed" }</ChildContainer> };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`
|
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `&str`
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vnode::VNode`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vnode::VNode>` is not satisfied
--> $DIR/html-component-fail.rs:81:5
--> $DIR/html-component-fail.rs:94:5
|
81 | html! { <ChildContainer><></></ChildContainer> };
94 | html! { <ChildContainer><></></ChildContainer> };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`
|
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vnode::VNode`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vnode::VNode>` is not satisfied
--> $DIR/html-component-fail.rs:82:5
--> $DIR/html-component-fail.rs:95:5
|
82 | html! { <ChildContainer><Child int=1 /><other /></ChildContainer> };
95 | html! { <ChildContainer><Child int=1 /><other /></ChildContainer> };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`
|
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vnode::VNode`

View File

@ -229,16 +229,7 @@ fn compile_pass() {
html! {
<ChildContainer int=1>
<AltChild />
{
html! {
<Child int=1 />
}
}
{(0..2).map(|_| {
return html! {
<Child int=1 />
}
}).collect::<Vec<VChild<Child>>>()}
<Child int=1 />
</ChildContainer>
};