Skip to content

Commit

Permalink
Span hygene and editor UX (#2702)
Browse files Browse the repository at this point in the history
* add span for closing tag to macro expansion

* decouple name resolution from locations

* commit to new macro errors
  • Loading branch information
WorldSEnder committed May 25, 2022
1 parent 9d00e0e commit e68060a
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 48 deletions.
4 changes: 2 additions & 2 deletions examples/counter_functional/src/main.rs
@@ -1,7 +1,7 @@
use yew::prelude::*;

#[function_component(App)]
fn app() -> Html {
#[function_component]
fn App() -> Html {
let state = use_state(|| 0);

let incr_counter = {
Expand Down
28 changes: 21 additions & 7 deletions packages/yew-macro/src/html_tree/html_component.rs
Expand Up @@ -18,6 +18,7 @@ pub struct HtmlComponent {
ty: Type,
props: ComponentProps,
children: HtmlChildrenTree,
close: Option<HtmlComponentClose>,
}

impl PeekValue<()> for HtmlComponent {
Expand Down Expand Up @@ -47,6 +48,7 @@ impl Parse for HtmlComponent {
ty: open.ty,
props: open.props,
children: HtmlChildrenTree::new(),
close: None,
});
}

Expand All @@ -67,7 +69,7 @@ impl Parse for HtmlComponent {
children.parse_child(input)?;
}

input.parse::<HtmlComponentClose>()?;
let close = input.parse::<HtmlComponentClose>()?;

if !children.is_empty() {
if let Some(children_prop) = open.props.children() {
Expand All @@ -82,6 +84,7 @@ impl Parse for HtmlComponent {
ty: open.ty,
props: open.props,
children,
close: Some(close),
})
}
}
Expand All @@ -92,9 +95,11 @@ impl ToTokens for HtmlComponent {
ty,
props,
children,
close,
} = self;

let props_ty = quote_spanned!(ty.span()=> <#ty as ::yew::html::BaseComponent>::Properties);
let ty_span = ty.span().resolved_at(Span::call_site());
let props_ty = quote_spanned!(ty_span=> <#ty as ::yew::html::BaseComponent>::Properties);
let children_renderer = if children.is_empty() {
None
} else {
Expand All @@ -105,23 +110,32 @@ impl ToTokens for HtmlComponent {
let special_props = props.special();
let node_ref = if let Some(node_ref) = &special_props.node_ref {
let value = &node_ref.value;
quote_spanned! {value.span()=> #value }
quote! { #value }
} else {
quote! { <::yew::html::NodeRef as ::std::default::Default>::default() }
};

let key = if let Some(key) = &special_props.key {
let value = &key.value;
quote_spanned! {value.span()=>
quote_spanned! {value.span().resolved_at(Span::call_site())=>
#[allow(clippy::useless_conversion)]
Some(::std::convert::Into::<::yew::virtual_dom::Key>::into(#value))
}
} else {
quote! { ::std::option::Option::None }
};
let use_close_tag = if let Some(close) = close {
let close_ty = &close.ty;
quote_spanned! {close_ty.span()=>
let _ = |_:#close_ty| {};
}
} else {
Default::default()
};

tokens.extend(quote_spanned! {ty.span()=>
tokens.extend(quote_spanned! {ty_span=>
{
#use_close_tag
let __yew_props = #build_props;
::yew::virtual_dom::VChild::<#ty>::new(__yew_props, #node_ref, #key)
}
Expand Down Expand Up @@ -268,7 +282,7 @@ impl Parse for HtmlComponentOpen {

struct HtmlComponentClose {
tag: TagTokens,
_ty: Type,
ty: Type,
}
impl HtmlComponentClose {
fn to_spanned(&self) -> impl ToTokens {
Expand Down Expand Up @@ -296,7 +310,7 @@ impl Parse for HtmlComponentClose {
fn parse(input: ParseStream) -> syn::Result<Self> {
TagTokens::parse_end_content(input, |input, tag| {
let ty = input.parse()?;
Ok(Self { tag, _ty: ty })
Ok(Self { tag, ty })
})
}
}
26 changes: 14 additions & 12 deletions packages/yew-macro/src/html_tree/html_element.rs
@@ -1,5 +1,5 @@
use boolinator::Boolinator;
use proc_macro2::{Delimiter, TokenStream};
use proc_macro2::{Delimiter, Span, TokenStream};
use proc_macro_error::emit_warning;
use quote::{quote, quote_spanned, ToTokens};
use syn::buffer::Cursor;
Expand Down Expand Up @@ -123,7 +123,7 @@ impl ToTokens for HtmlElement {
.as_ref()
.map(|attr| {
let value = &attr.value;
quote_spanned! {value.span()=>
quote_spanned! {value.span().resolved_at(Span::call_site())=>
::yew::html::IntoPropValue::<::yew::html::NodeRef>
::into_prop_value(#value)
}
Expand All @@ -133,7 +133,7 @@ impl ToTokens for HtmlElement {
.as_ref()
.map(|attr| {
let value = attr.value.optimize_literals();
quote_spanned! {value.span()=>
quote_spanned! {value.span().resolved_at(Span::call_site())=>
::std::option::Option::Some(
::std::convert::Into::<::yew::virtual_dom::Key>::into(#value)
)
Expand Down Expand Up @@ -174,15 +174,17 @@ impl ToTokens for HtmlElement {
#key
}}),
},
expr => Value::Dynamic(quote_spanned! {expr.span()=>
if #expr {
::std::option::Option::Some(
::yew::virtual_dom::AttrValue::Static(#key)
)
} else {
::std::option::Option::None
}
}),
expr => Value::Dynamic(
quote_spanned! {expr.span().resolved_at(Span::call_site())=>
if #expr {
::std::option::Option::Some(
::yew::virtual_dom::AttrValue::Static(#key)
)
} else {
::std::option::Option::None
}
},
),
},
))
});
Expand Down
12 changes: 6 additions & 6 deletions packages/yew-macro/src/html_tree/html_node.rs
@@ -1,5 +1,5 @@
use proc_macro2::TokenStream;
use quote::{quote_spanned, ToTokens};
use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned, ToTokens};
use syn::buffer::Cursor;
use syn::parse::{Parse, ParseStream, Result};
use syn::spanned::Spanned;
Expand Down Expand Up @@ -49,7 +49,7 @@ impl ToTokens for HtmlNode {
let sr = lit.stringify();
quote_spanned! {lit.span()=> ::yew::virtual_dom::VText::new(#sr) }
}
HtmlNode::Expression(expr) => quote_spanned! {expr.span()=> #expr},
HtmlNode::Expression(expr) => quote! {#expr},
});
}
}
Expand All @@ -60,9 +60,9 @@ impl ToNodeIterator for HtmlNode {
HtmlNode::Literal(_) => None,
HtmlNode::Expression(expr) => {
// NodeSeq turns both Into<T> and Vec<Into<T>> into IntoIterator<Item = T>
Some(
quote_spanned! {expr.span()=> ::std::convert::Into::<::yew::utils::NodeSeq<_, _>>::into(#expr)},
)
Some(quote_spanned! {expr.span().resolved_at(Span::call_site())=>
::std::convert::Into::<::yew::utils::NodeSeq<_, _>>::into(#expr)
})
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions packages/yew-macro/src/html_tree/mod.rs
Expand Up @@ -181,10 +181,12 @@ impl Parse for HtmlRootVNode {
impl ToTokens for HtmlRootVNode {
fn to_tokens(&self, tokens: &mut TokenStream) {
let new_tokens = self.0.to_token_stream();
tokens.extend(quote! {{
#[allow(clippy::useless_conversion)]
<::yew::virtual_dom::VNode as ::std::convert::From<_>>::from(#new_tokens)
}});
tokens.extend(
quote_spanned! {self.0.span().resolved_at(Span::mixed_site())=> {
#[allow(clippy::useless_conversion)]
<::yew::virtual_dom::VNode as ::std::convert::From<_>>::from(#new_tokens)
}},
);
}
}

Expand Down
17 changes: 11 additions & 6 deletions packages/yew-macro/src/props/component.rs
@@ -1,6 +1,6 @@
use std::convert::TryFrom;

use proc_macro2::{Ident, TokenStream};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, quote_spanned, ToTokens};
use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned;
Expand Down Expand Up @@ -50,16 +50,21 @@ impl ComponentProps {
}

fn prop_validation_tokens(&self, props_ty: impl ToTokens, has_children: bool) -> TokenStream {
let props_ident = Ident::new("__yew_props", props_ty.span());
let check_children = if has_children {
Some(quote_spanned! {props_ty.span()=> __yew_props.children; })
Some(quote_spanned! {props_ty.span()=> #props_ident.children; })
} else {
None
};

let check_props: TokenStream = self
.props
.iter()
.map(|Prop { label, .. }| quote_spanned! ( label.span()=> __yew_props.#label; ))
.map(|Prop { label, .. }| {
quote_spanned! {
Span::call_site().located_at(label.span())=> #props_ident.#label;
}
})
.chain(self.base_expr.iter().map(|expr| {
quote_spanned! {props_ty.span()=>
let _: #props_ty = #expr;
Expand All @@ -70,7 +75,7 @@ impl ComponentProps {
quote_spanned! {props_ty.span()=>
#[allow(clippy::no_effect)]
if false {
let _ = |__yew_props: #props_ty| {
let _ = |#props_ident: #props_ty| {
#check_children
#check_props
};
Expand Down Expand Up @@ -110,7 +115,7 @@ impl ComponentProps {
Some(expr) => {
let ident = Ident::new("__yew_props", props_ty.span());
let set_props = self.props.iter().map(|Prop { label, value, .. }| {
quote_spanned! {value.span()=>
quote_spanned! {value.span().resolved_at(Span::call_site())=>
#ident.#label = ::yew::html::IntoPropValue::into_prop_value(#value);
}
});
Expand All @@ -121,7 +126,7 @@ impl ComponentProps {
});

quote! {
let mut #ident = #expr;
let mut #ident: #props_ty = #expr;
#(#set_props)*
#set_children
#ident
Expand Down
4 changes: 2 additions & 2 deletions packages/yew-macro/src/stringify.rs
@@ -1,11 +1,11 @@
use proc_macro2::TokenStream;
use proc_macro2::{Span, TokenStream};
use quote::{quote_spanned, ToTokens};
use syn::spanned::Spanned;
use syn::{Expr, Lit, LitStr};

/// Stringify a value at runtime.
fn stringify_at_runtime(src: impl ToTokens) -> TokenStream {
quote_spanned! {src.span()=>
quote_spanned! {src.span().resolved_at(Span::call_site())=>
::std::convert::Into::<::yew::virtual_dom::AttrValue>::into(#src)
}
}
Expand Down
Expand Up @@ -18,6 +18,7 @@ error[E0599]: no method named `build` found for struct `PropsBuilder<PropsBuilde
|
= note: the method was found for
- `PropsBuilder<PropsBuilderStepPropsBuilder>`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Comp<MissingTypeBounds>: yew::BaseComponent` is not satisfied
--> tests/function_component_attr/generic-props-fail.rs:27:14
Expand All @@ -27,6 +28,7 @@ error[E0277]: the trait bound `Comp<MissingTypeBounds>: yew::BaseComponent` is n
|
= help: the following implementations were found:
<Comp<P> as yew::BaseComponent>
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: the function or associated item `new` exists for struct `VChild<Comp<MissingTypeBounds>>`, but its trait bounds were not satisfied
--> tests/function_component_attr/generic-props-fail.rs:27:14
Expand All @@ -39,6 +41,7 @@ error[E0599]: the function or associated item `new` exists for struct `VChild<Co
|
= note: the following trait bounds were not satisfied:
`Comp<MissingTypeBounds>: yew::BaseComponent`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `MissingTypeBounds: yew::Properties` is not satisfied
--> tests/function_component_attr/generic-props-fail.rs:27:14
Expand All @@ -54,6 +57,7 @@ note: required by a bound in `Comp`
...
11 | P: Properties + PartialEq,
| ^^^^^^^^^^ required by this bound in `Comp`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0107]: missing generics for struct `Comp`
--> tests/function_component_attr/generic-props-fail.rs:30:14
Expand Down
2 changes: 2 additions & 0 deletions packages/yew-macro/tests/html_macro/block-fail.stderr
Expand Up @@ -12,6 +12,7 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
= note: 2 redundant requirements hidden
= note: required because of the requirements on the impl of `Into<NodeSeq<(), VNode>>` for `()`
note: required by `into`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: `()` doesn't implement `std::fmt::Display`
--> tests/html_macro/block-fail.rs:12:16
Expand All @@ -27,6 +28,7 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
= note: 2 redundant requirements hidden
= note: required because of the requirements on the impl of `Into<NodeSeq<(), VNode>>` for `()`
note: required by `into`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: `()` doesn't implement `std::fmt::Display`
--> tests/html_macro/block-fail.rs:15:17
Expand Down
15 changes: 6 additions & 9 deletions packages/yew-macro/tests/html_macro/component-fail.stderr
Expand Up @@ -290,15 +290,6 @@ error[E0308]: mismatched types
= note: expected struct `ChildProperties`
found struct `std::ops::Range<_>`

error[E0308]: mismatched types
--> tests/html_macro/component-fail.rs:53:14
|
53 | html! { <Child ..p1 ..p2 /> };
| ^^^^^ expected struct `ChildProperties`, found struct `std::ops::Range`
|
= note: expected struct `ChildProperties`
found struct `std::ops::Range<_>`

error[E0609]: no field `value` on type `ChildProperties`
--> tests/html_macro/component-fail.rs:69:20
|
Expand Down Expand Up @@ -404,6 +395,7 @@ error[E0609]: no field `children` on type `ChildProperties`
| ^^^^^ unknown field
|
= note: available fields are: `string`, `int`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: no method named `children` found for struct `ChildPropertiesBuilder` in the current scope
--> tests/html_macro/component-fail.rs:87:14
Expand All @@ -413,6 +405,8 @@ error[E0599]: no method named `children` found for struct `ChildPropertiesBuilde
...
87 | html! { <Child>{ "Not allowed" }</Child> };
| ^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
|
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0609]: no field `children` on type `ChildProperties`
--> tests/html_macro/component-fail.rs:94:10
Expand All @@ -421,6 +415,7 @@ error[E0609]: no field `children` on type `ChildProperties`
| ^^^^^ unknown field
|
= note: available fields are: `string`, `int`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: no method named `build` found for struct `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>` in the current scope
--> tests/html_macro/component-fail.rs:99:14
Expand All @@ -433,6 +428,7 @@ error[E0599]: no method named `build` found for struct `ChildContainerProperties
|
= note: the method was found for
- `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStepPropsBuilder>`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: no method named `build` found for struct `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStep_missing_required_prop_children>` in the current scope
--> tests/html_macro/component-fail.rs:100:14
Expand All @@ -445,6 +441,7 @@ error[E0599]: no method named `build` found for struct `ChildContainerProperties
|
= note: the method was found for
- `ChildContainerPropertiesBuilder<ChildContainerPropertiesBuilderStepPropsBuilder>`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `VChild<Child>: From<yew::virtual_dom::VText>` is not satisfied
--> tests/html_macro/component-fail.rs:101:31
Expand Down
Expand Up @@ -5,6 +5,7 @@ error[E0277]: the trait bound `Unimplemented: yew::Component` is not satisfied
| ^^^^^^^^^^^^^ the trait `yew::Component` is not implemented for `Unimplemented`
|
= note: required because of the requirements on the impl of `BaseComponent` for `Unimplemented`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: the function or associated item `new` exists for struct `VChild<Unimplemented>`, but its trait bounds were not satisfied
--> tests/html_macro/component-unimplemented-fail.rs:6:14
Expand All @@ -17,3 +18,4 @@ error[E0599]: the function or associated item `new` exists for struct `VChild<Un
|
= note: the following trait bounds were not satisfied:
`Unimplemented: BaseComponent`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)

1 comment on commit e68060a

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yew master branch benchmarks (Lower is better)

Benchmark suite Current: e68060a Previous: b90c99a Ratio
yew-struct-keyed 01_run1k 158.3265 209.8605 0.75
yew-struct-keyed 02_replace1k 162.347 221.566 0.73
yew-struct-keyed 03_update10th1k_x16 194.863 324.3225 0.60
yew-struct-keyed 04_select1k 35.4435 52.919 0.67
yew-struct-keyed 05_swap1k 53.5115 76.3895 0.70
yew-struct-keyed 06_remove-one-1k 21.867 29.3365 0.75
yew-struct-keyed 07_create10k 2572.289 3471.836 0.74
yew-struct-keyed 08_create1k-after1k_x2 342.75649999999996 511.691 0.67
yew-struct-keyed 09_clear1k_x8 139.92149999999998 218.93 0.64
yew-struct-keyed 21_ready-memory 1.4598236083984375 1.4553260803222656 1.00
yew-struct-keyed 22_run-memory 1.6740837097167969 1.6948776245117188 0.99
yew-struct-keyed 23_update5-memory 1.6741104125976562 1.6992073059082031 0.99
yew-struct-keyed 24_run5-memory 1.7175254821777344 1.7175521850585938 1.00
yew-struct-keyed 25_run-clear-memory 1.3330841064453125 1.3328704833984375 1.00
yew-struct-keyed 31_startup-ci 1736.004 1883.725 0.92
yew-struct-keyed 32_startup-bt 24.659999999999997 31.98 0.77
yew-struct-keyed 33_startup-mainthreadcost 201.00399999999996 309.65600000000006 0.65
yew-struct-keyed 34_startup-totalbytes 331.59765625 331.59765625 1

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.