Skip to content

Commit

Permalink
Merge pull request #359 from kas-gui/work2
Browse files Browse the repository at this point in the history
impl_singleton: support _ and impl Trait in field types
  • Loading branch information
dhardy committed Oct 4, 2022
2 parents b6f2aa5 + 9d936c3 commit 935c7d1
Show file tree
Hide file tree
Showing 26 changed files with 188 additions and 216 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
- name: Test examples/mandlebrot
run: cargo test --manifest-path examples/mandlebrot/Cargo.toml --all-features
- name: Clippy
run: cargo clippy --all --features nightly
run: cargo clippy --all --features nightly -- -W clippy::all -A clippy::collapsible-if -A clippy::collapsible_else_if -A clippy::single_match -A clippy::comparison_chain -A clippy::unit_arg

test:
name: Test
Expand Down Expand Up @@ -100,4 +100,4 @@ jobs:
run: cargo test --manifest-path examples/mandlebrot/Cargo.toml
- name: Clippy (stable)
if: matrix.os == 'macos-latest'
run: cargo clippy --all -- -D warnings -A unknown_lints
run: cargo clippy --all -- -D warnings -W clippy::all -A clippy::collapsible-if -A clippy::collapsible_else_if -A clippy::single_match -A clippy::comparison_chain -A clippy::unit_arg
2 changes: 1 addition & 1 deletion clippy.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
single-char-binding-names-threshold = 7
type-complexity-threshold = 305
type-complexity-threshold = 400
2 changes: 0 additions & 2 deletions crates/kas-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
//! **Crate [`easy-cast`](https://crates.io/crates/easy-cast):** `Conv`, `Cast` traits and related functionality
//! (always included), available as [`kas::cast`](https://docs.rs/easy-cast/0.5/easy_cast).

// Use ``never_loop`` until: https://github.com/rust-lang/rust-clippy/issues/7397 is fixed
#![allow(clippy::identity_op, clippy::never_loop, clippy::enum_variant_names)]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(feature = "spec", feature(specialization))]

Expand Down
2 changes: 1 addition & 1 deletion crates/kas-core/src/model/filter/filter_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl<'b, K: Clone> Iterator for KeyIter<'b, K> {
}

fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.borrow().len() - self.index;
let len = self.borrow.len() - self.index;
(len, Some(len))
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/kas-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ version = "0.5.1" # version used in doc links
version = "1.0.14"
# We need 'extra-traits' for equality testing
# We need 'full' for parsing macros within macro arguments
features = ["extra-traits", "full", "visit-mut"]
features = ["extra-traits", "full", "visit", "visit-mut"]

[build-dependencies]
version_check = "0.9"
142 changes: 45 additions & 97 deletions crates/kas-macros/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::{Brace, Colon, Comma, Eq, Paren, Semi};
use syn::{braced, bracketed, parenthesized, parse_quote};
use syn::{
AttrStyle, Attribute, ConstParam, Expr, GenericParam, Generics, Ident, ItemImpl, Lifetime,
LifetimeDef, Member, Path, Token, Type, TypeParam, TypePath, TypeTraitObject, Visibility,
};
use syn::{Attribute, Expr, Generics, Ident, ItemImpl, Member, Path, Token, Type};

#[derive(Debug)]
pub struct Child {
Expand All @@ -31,7 +28,7 @@ fn parse_impl(in_ident: Option<&Ident>, input: ParseStream) -> Result<ItemImpl>
let has_generics = input.peek(Token![<])
&& (input.peek2(Token![>])
|| input.peek2(Token![#])
|| (input.peek2(Ident) || input.peek2(Lifetime))
|| (input.peek2(Ident) || input.peek2(syn::Lifetime))
&& (input.peek3(Token![:])
|| input.peek3(Token![,])
|| input.peek3(Token![>])
Expand All @@ -58,7 +55,7 @@ fn parse_impl(in_ident: Option<&Ident>, input: ParseStream) -> Result<ItemImpl>
while let Type::Group(ty) = first_ty {
first_ty = *ty.elem;
}
if let Type::Path(TypePath { qself: None, path }) = first_ty {
if let Type::Path(syn::TypePath { qself: None, path }) = first_ty {
trait_ = Some((None, path, for_token));
} else {
unreachable!();
Expand All @@ -76,7 +73,7 @@ fn parse_impl(in_ident: Option<&Ident>, input: ParseStream) -> Result<ItemImpl>

if self_ty != parse_quote! { Self } {
if let Some(ident) = in_ident {
if !matches!(self_ty, Type::Path(TypePath {
if !matches!(self_ty, Type::Path(syn::TypePath {
qself: None,
path: Path {
leading_colon: None,
Expand Down Expand Up @@ -122,7 +119,7 @@ fn parse_impl(in_ident: Option<&Ident>, input: ParseStream) -> Result<ItemImpl>
fn parse_attrs_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
while input.peek(Token![#]) && input.peek2(Token![!]) {
let pound_token = input.parse()?;
let style = AttrStyle::Inner(input.parse()?);
let style = syn::AttrStyle::Inner(input.parse()?);
let content;
let bracket_token = bracketed!(content in input);
let path = content.call(Path::parse_mod_style)?;
Expand Down Expand Up @@ -265,23 +262,14 @@ pub enum StructStyle {
Regular(Brace),
}

#[derive(Debug, PartialEq, Eq)]
pub enum ChildType {
Fixed(Type), // fixed type
// A given type using generics internally
InternGeneric(Punctuated<GenericParam, Comma>, Type),
// Generic, optionally with an additional trait bound.
Generic(Option<TypeTraitObject>),
}

#[derive(Debug)]
pub struct SingletonField {
pub attrs: Vec<Attribute>,
pub vis: Visibility,
pub vis: syn::Visibility,
pub ident: Option<Ident>,
pub colon_token: Option<Colon>,
pub ty: ChildType,
pub value: Option<Expr>,
pub ty: Type,
pub assignment: Option<(Eq, Expr)>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -354,64 +342,33 @@ impl Parse for ImplSingleton {
}

impl SingletonField {
fn parse_ty(input: ParseStream) -> Result<ChildType> {
if input.peek(Token![for]) {
// internal generic
let _: Token![for] = input.parse()?;

// copied from syn::Generic's Parse impl
let _: Token![<] = input.parse()?;

let mut params = Punctuated::new();
let mut allow_lifetime_param = true;
let mut allow_type_param = true;
loop {
if input.peek(Token![>]) {
break;
}

let attrs = input.call(Attribute::parse_outer)?;
let lookahead = input.lookahead1();
if allow_lifetime_param && lookahead.peek(Lifetime) {
params.push_value(GenericParam::Lifetime(LifetimeDef {
attrs,
..input.parse()?
}));
} else if allow_type_param && lookahead.peek(Ident) {
allow_lifetime_param = false;
params.push_value(GenericParam::Type(TypeParam {
attrs,
..input.parse()?
}));
} else if lookahead.peek(Token![const]) {
allow_lifetime_param = false;
allow_type_param = false;
params.push_value(GenericParam::Const(ConstParam {
attrs,
..input.parse()?
}));
} else {
return Err(lookahead.error());
fn check_is_fixed(ty: &Type, input_span: Span) -> Result<()> {
let is_fixed = match ty {
Type::ImplTrait(_) | Type::Infer(_) => false,
ty => {
struct IsFixed(bool);
let mut checker = IsFixed(true);

impl<'ast> syn::visit::Visit<'ast> for IsFixed {
fn visit_type(&mut self, node: &'ast Type) {
if matches!(node, Type::ImplTrait(_) | Type::Infer(_)) {
self.0 = false;
}
}
}
syn::visit::visit_type(&mut checker, ty);

if input.peek(Token![>]) {
break;
}
let punct = input.parse()?;
params.push_punct(punct);
checker.0
}
};

let _: Token![>] = input.parse()?;

let ty = input.parse()?;
Ok(ChildType::InternGeneric(params, ty))
} else if input.peek(Token![impl]) {
// generic with trait bound
let _: Token![impl] = input.parse()?;
let bound: TypeTraitObject = input.parse()?;
Ok(ChildType::Generic(Some(bound)))
if is_fixed {
Ok(())
} else {
Ok(ChildType::Fixed(input.parse()?))
Err(Error::new(
input_span,
"require either a fixed type or a value assignment",
))
}
}

Expand All @@ -431,19 +388,16 @@ impl SingletonField {
// Note: Colon matches `::` but that results in confusing error messages
let ty = if input.peek(Colon) && !input.peek2(Colon) {
colon_token = Some(input.parse()?);
Self::parse_ty(input)?
input.parse()?
} else {
ChildType::Generic(None)
parse_quote! { _ }
};

let mut value = None;
if let Ok(_) = input.parse::<Eq>() {
value = Some(input.parse()?);
} else if !matches!(&ty, ChildType::Fixed(_)) {
return Err(Error::new(
input.span(),
"require either a fixed type or a value assignment",
));
let mut assignment = None;
if let Ok(eq) = input.parse::<Eq>() {
assignment = Some((eq, input.parse()?));
} else {
Self::check_is_fixed(&ty, input.span())?;
}

Ok(SingletonField {
Expand All @@ -452,27 +406,21 @@ impl SingletonField {
ident,
colon_token,
ty,
value,
assignment,
})
}

fn parse_unnamed(input: ParseStream) -> Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let vis = input.parse()?;

let mut ty = Self::parse_ty(input)?;
if ty == ChildType::Fixed(parse_quote! { _ }) {
ty = ChildType::Generic(None);
}
let ty = input.parse()?;

let mut value = None;
if let Ok(_) = input.parse::<Eq>() {
value = Some(input.parse()?);
} else if !matches!(&ty, ChildType::Fixed(_)) {
return Err(Error::new(
input.span(),
"require either a fixed type or a value assignment",
));
let mut assignment = None;
if let Ok(eq) = input.parse::<Eq>() {
assignment = Some((eq, input.parse()?));
} else {
Self::check_is_fixed(&ty, input.span())?;
}

Ok(SingletonField {
Expand All @@ -481,7 +429,7 @@ impl SingletonField {
ident: None,
colon_token: None,
ty,
value,
assignment,
})
}
}
Loading

0 comments on commit 935c7d1

Please sign in to comment.