From 27f8be4d7ddb17c0679c590555f55f7e5dd42136 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 11 Jan 2022 14:28:06 -0800 Subject: [PATCH 1/5] Add `#![feature(let_else)]` to `rustc_builtin_macros` --- compiler/rustc_builtin_macros/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 8c3ef2864f485..3cbe9a07482a1 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -6,6 +6,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] +#![feature(let_else)] #![feature(nll)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] From e3b308ed5f1616adbc1e7087d8e1648162442af0 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 11 Jan 2022 13:20:36 -0800 Subject: [PATCH 2/5] Remove unnecessary block A remnant from the before times... --- .../src/deriving/generic/mod.rs | 76 +++++++++---------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 985c45e225388..ab9d7fb16f24c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -636,49 +636,45 @@ impl<'a> TraitDef<'a> { } })); - { - // Extra scope required here so ty_params goes out of scope before params is moved - - let mut ty_params = params - .iter() - .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) - .peekable(); - - if ty_params.peek().is_some() { - let ty_param_names: Vec = - ty_params.map(|ty_param| ty_param.ident.name).collect(); - - for field_ty in field_tys { - let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx); - - for field_ty_param in field_ty_params { - // if we have already handled this type, skip it - if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind { - if p.segments.len() == 1 - && ty_param_names.contains(&p.segments[0].ident.name) - { - continue; - }; - } - let mut bounds: Vec<_> = self - .additional_bounds - .iter() - .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) - .collect(); + let mut ty_params = params + .iter() + .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) + .peekable(); + + if ty_params.peek().is_some() { + let ty_param_names: Vec = + ty_params.map(|ty_param| ty_param.ident.name).collect(); + + for field_ty in field_tys { + let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx); + + for field_ty_param in field_ty_params { + // if we have already handled this type, skip it + if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind { + if p.segments.len() == 1 + && ty_param_names.contains(&p.segments[0].ident.name) + { + continue; + }; + } + let mut bounds: Vec<_> = self + .additional_bounds + .iter() + .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + .collect(); - // require the current trait - bounds.push(cx.trait_bound(trait_path.clone())); + // require the current trait + bounds.push(cx.trait_bound(trait_path.clone())); - let predicate = ast::WhereBoundPredicate { - span: self.span, - bound_generic_params: field_ty_param.bound_generic_params, - bounded_ty: field_ty_param.ty, - bounds, - }; + let predicate = ast::WhereBoundPredicate { + span: self.span, + bound_generic_params: field_ty_param.bound_generic_params, + bounded_ty: field_ty_param.ty, + bounds, + }; - let predicate = ast::WherePredicate::BoundPredicate(predicate); - where_clause.predicates.push(predicate); - } + let predicate = ast::WherePredicate::BoundPredicate(predicate); + where_clause.predicates.push(predicate); } } } From 0c392d802fe8dccd1777a648da8b7eeef82e55bf Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 11 Jan 2022 14:24:25 -0800 Subject: [PATCH 3/5] Add comment describing purpose of field traversal --- compiler/rustc_builtin_macros/src/deriving/generic/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index ab9d7fb16f24c..56efd859fd477 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -636,6 +636,10 @@ impl<'a> TraitDef<'a> { } })); + // If this type declaration has type parameters, look for any mention of types *derived* from + // those parameters in the declaration (e.g. `T::Item`). Those derived types need bounds as + // well. + let mut ty_params = params .iter() .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) From 794e50b7061cd30caa9e2ec556c59f2a267479f4 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 11 Jan 2022 14:25:26 -0800 Subject: [PATCH 4/5] Add helper for "simple" uses of type parameters "Simple" uses have no qualified self type or generic parameters. They're just a path (e.g. `T::Item`). --- .../src/deriving/generic/mod.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 56efd859fd477..83df9093e3a26 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -189,6 +189,7 @@ use rustc_data_structures::map_in_place::MapInPlace; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; +use smallvec::SmallVec; use ty::{Bounds, Path, Ptr, PtrTy, Self_, Ty}; @@ -337,6 +338,26 @@ struct TypeParameter { ty: P, } +impl TypeParameter { + /// Returns the `Ident`s that comprise the `Path` for this type parameter if it is unqualified + /// and has no bound generic params or segments with generic arguments. + fn to_simple_path(&self) -> Option> { + let TypeParameter { bound_generic_params, ty } = self; + if !bound_generic_params.is_empty() { + return None; + } + + let ast::TyKind::Path(None, path) = &ty.kind else { return None }; + + if path.segments.iter().any(|seg| seg.args.is_some()) { + return None; + } + + let path = path.segments.iter().map(|seg| seg.ident).collect(); + Some(path) + } +} + /// This method helps to extract all the type parameters referenced from a /// type. For a type parameter ``, it looks for either a `TyPath` that /// is not global and starts with `T`, or a `TyQPath`. From fd589e6d5e692893c241e8f45e6cde54c491fb2b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 11 Jan 2022 14:27:36 -0800 Subject: [PATCH 5/5] Deduplicate bounds on associated types when deriving --- .../src/deriving/generic/mod.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 83df9093e3a26..bc7c1aa3ea9e8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -185,11 +185,12 @@ use rustc_ast::ptr::P; use rustc_ast::{self as ast, BinOpKind, EnumDef, Expr, Generics, PatKind}; use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::map_in_place::MapInPlace; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use ty::{Bounds, Path, Ptr, PtrTy, Self_, Ty}; @@ -668,20 +669,23 @@ impl<'a> TraitDef<'a> { if ty_params.peek().is_some() { let ty_param_names: Vec = - ty_params.map(|ty_param| ty_param.ident.name).collect(); + ty_params.clone().map(|ty_param| ty_param.ident.name).collect(); + + let mut seen_simple_field_ty_params: FxHashSet<_> = + ty_params.map(|ty_param| smallvec![ty_param.ident]).collect(); for field_ty in field_tys { let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx); for field_ty_param in field_ty_params { // if we have already handled this type, skip it - if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind { - if p.segments.len() == 1 - && ty_param_names.contains(&p.segments[0].ident.name) - { + if let Some(field_ty_param_path) = field_ty_param.to_simple_path() { + let changed = seen_simple_field_ty_params.insert(field_ty_param_path); + if !changed { continue; - }; + } } + let mut bounds: Vec<_> = self .additional_bounds .iter()