diff --git a/src/item.rs b/src/item.rs index 917d4f1fed..5f3c8f4678 100644 --- a/src/item.rs +++ b/src/item.rs @@ -1177,14 +1177,25 @@ pub mod parsing { semi_token: Token![;], } - impl Parse for FlexibleItemType { - fn parse(input: ParseStream) -> Result { + enum WhereClauseLocation { + // type Ty where T: 'static = T; + BeforeEq, + // type Ty = T where T: 'static; + #[allow(dead_code)] + AfterEq, + // TODO: goes away once the migration period on rust-lang/rust#89122 is over + Both, + } + + impl FlexibleItemType { + fn parse(input: ParseStream, where_clause_location: WhereClauseLocation) -> Result { let vis: Visibility = input.parse()?; let defaultness: Option = input.parse()?; let type_token: Token![type] = input.parse()?; let ident: Ident = input.parse()?; let mut generics: Generics = input.parse()?; let colon_token: Option = input.parse()?; + let mut bounds = Punctuated::new(); if colon_token.is_some() { loop { @@ -1198,12 +1209,26 @@ pub mod parsing { bounds.push_punct(input.parse::()?); } } - generics.where_clause = input.parse()?; + + if let WhereClauseLocation::BeforeEq | WhereClauseLocation::Both = where_clause_location + { + generics.where_clause = input.parse()?; + } + let ty = if let Some(eq_token) = input.parse()? { Some((eq_token, input.parse::()?)) } else { None }; + + if generics.where_clause.is_none() { + if let WhereClauseLocation::AfterEq | WhereClauseLocation::Both = + where_clause_location + { + generics.where_clause = input.parse()?; + } + } + let semi_token: Token![;] = input.parse()?; Ok(FlexibleItemType { @@ -1868,7 +1893,7 @@ pub mod parsing { bounds: _, ty, semi_token, - } = input.parse()?; + } = FlexibleItemType::parse(input, WhereClauseLocation::BeforeEq)?; if defaultness.is_some() || generics.lt_token.is_some() @@ -1937,7 +1962,7 @@ pub mod parsing { bounds: _, ty, semi_token, - } = input.parse()?; + } = FlexibleItemType::parse(input, WhereClauseLocation::BeforeEq)?; if defaultness.is_some() || colon_token.is_some() || ty.is_none() { Ok(Item::Verbatim(verbatim::between(begin, input))) @@ -2328,7 +2353,6 @@ pub mod parsing { } } - generics.where_clause = input.parse()?; let default = if input.peek(Token![=]) { let eq_token: Token![=] = input.parse()?; let default: Type = input.parse()?; @@ -2336,6 +2360,8 @@ pub mod parsing { } else { None }; + + generics.where_clause = input.parse()?; let semi_token: Token![;] = input.parse()?; Ok(TraitItemType { @@ -2362,7 +2388,7 @@ pub mod parsing { bounds, ty, semi_token, - } = input.parse()?; + } = FlexibleItemType::parse(input, WhereClauseLocation::Both)?; if defaultness.is_some() || vis.is_some() { Ok(TraitItem::Verbatim(verbatim::between(begin, input))) @@ -2661,20 +2687,26 @@ pub mod parsing { #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for ImplItemType { fn parse(input: ParseStream) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let defaultness: Option = input.parse()?; + let type_token: Token![type] = input.parse()?; + let ident: Ident = input.parse()?; + let mut generics: Generics = input.parse()?; + let eq_token: Token![=] = input.parse()?; + let ty: Type = input.parse()?; + generics.where_clause = input.parse()?; + let semi_token: Token![;] = input.parse()?; Ok(ImplItemType { - attrs: input.call(Attribute::parse_outer)?, - vis: input.parse()?, - defaultness: input.parse()?, - type_token: input.parse()?, - ident: input.parse()?, - generics: { - let mut generics: Generics = input.parse()?; - generics.where_clause = input.parse()?; - generics - }, - eq_token: input.parse()?, - ty: input.parse()?, - semi_token: input.parse()?, + attrs, + vis, + defaultness, + type_token, + ident, + generics, + eq_token, + ty, + semi_token, }) } } @@ -2690,7 +2722,7 @@ pub mod parsing { bounds: _, ty, semi_token, - } = input.parse()?; + } = FlexibleItemType::parse(input, WhereClauseLocation::Both)?; if colon_token.is_some() || ty.is_none() { Ok(ImplItem::Verbatim(verbatim::between(begin, input))) @@ -3106,11 +3138,11 @@ mod printing { TokensOrDefault(&self.colon_token).to_tokens(tokens); self.bounds.to_tokens(tokens); } - self.generics.where_clause.to_tokens(tokens); if let Some((eq_token, default)) = &self.default { eq_token.to_tokens(tokens); default.to_tokens(tokens); } + self.generics.where_clause.to_tokens(tokens); self.semi_token.to_tokens(tokens); } } @@ -3171,9 +3203,9 @@ mod printing { self.type_token.to_tokens(tokens); self.ident.to_tokens(tokens); self.generics.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); self.eq_token.to_tokens(tokens); self.ty.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); self.semi_token.to_tokens(tokens); } } diff --git a/tests/common/eq.rs b/tests/common/eq.rs index d998f71948..69995334a6 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -339,8 +339,8 @@ spanless_eq_struct!(Token; kind span); spanless_eq_struct!(Trait; unsafety is_auto generics bounds items); spanless_eq_struct!(TraitRef; path ref_id); spanless_eq_struct!(Ty; id kind span tokens); -spanless_eq_struct!(TyAlias; defaultness generics where_clauses where_predicates_split bounds ty); -spanless_eq_struct!(TyAliasWhereClause; 0 1); +spanless_eq_struct!(TyAlias; defaultness generics where_clauses !where_predicates_split bounds ty); +spanless_eq_struct!(TyAliasWhereClause; !0 1); spanless_eq_struct!(UseTree; prefix kind span); spanless_eq_struct!(Variant; attrs id span !vis ident data disr_expr is_placeholder); spanless_eq_struct!(Visibility; kind span tokens); diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs index 37f6e018d4..cf748f85bf 100644 --- a/tests/repo/mod.rs +++ b/tests/repo/mod.rs @@ -14,19 +14,6 @@ const REVISION: &str = "e95b10ba4ac4564ed25f7eef143e3182c33b3902"; #[rustfmt::skip] static EXCLUDE: &[&str] = &[ - // TODO: trailing where-clause on impl associated type: - // impl Trait for Ty { type Assoc<'a> = T where T: 'a; } - // https://github.com/dtolnay/syn/issues/1071 - "src/test/ui/generic-associated-types/collections.rs", - "src/test/ui/generic-associated-types/construct_with_other_type.rs", - "src/test/ui/generic-associated-types/impl_bounds_ok.rs", - "src/test/ui/generic-associated-types/issue-76826.rs", - "src/test/ui/generic-associated-types/issue-88287.rs", - "src/test/ui/generic-associated-types/issue-91139.rs", - "src/test/ui/generic-associated-types/issue-92280.rs", - "src/test/ui/generic-associated-types/iterable.rs", - "src/test/ui/generic-associated-types/streaming_iterator.rs", - // TODO: impl ~const T {} // https://github.com/dtolnay/syn/issues/1051 "src/test/ui/rfc-2632-const-trait-impl/syntax.rs",