about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicholas Nethercote <n.nethercote@gmail.com>2022-07-01 16:32:20 +1000
committerNicholas Nethercote <n.nethercote@gmail.com>2022-07-04 18:36:39 +1000
commita7b1d31a9f358747221e8eb9986bb8303d5d6586 (patch)
tree800969fe38a3592be6582cc24567496b42a92a85
parent5762d2385ebdd735b110ab82e80eed6efa7d7c55 (diff)
downloadrust-a7b1d31a9f358747221e8eb9986bb8303d5d6586.tar.gz
rust-a7b1d31a9f358747221e8eb9986bb8303d5d6586.zip
Don't repeat `AssertParamIs{Clone,Eq}` assertions.
It's common to see repeated assertions like this in derived `clone` and
`eq` methods:
```
let _: ::core::clone::AssertParamIsClone<u32>;
let _: ::core::clone::AssertParamIsClone<u32>;
```
This commit avoids them.
-rw-r--r--compiler/rustc_ast/src/ast.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs26
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs25
-rw-r--r--src/test/ui/deriving/deriving-all-codegen.stdout13
4 files changed, 43 insertions, 29 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e5b61d7000a..bb0b8121cac 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2036,6 +2036,14 @@ impl TyKind {
     pub fn is_unit(&self) -> bool {
         matches!(self, TyKind::Tup(tys) if tys.is_empty())
     }
+
+    pub fn is_simple_path(&self) -> Option<Symbol> {
+        if let TyKind::Path(None, Path { segments, .. }) = &self && segments.len() == 1 {
+            Some(segments[0].ident.name)
+        } else {
+            None
+        }
+    }
 }
 
 /// Syntax used to declare a trait object.
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index b37b82dd089..0a55d4e0ce0 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -3,6 +3,7 @@ use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
 use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
@@ -99,20 +100,29 @@ fn cs_clone_simple(
     is_union: bool,
 ) -> BlockOrExpr {
     let mut stmts = Vec::new();
+    let mut seen_type_names = FxHashSet::default();
     let mut process_variant = |variant: &VariantData| {
         for field in variant.fields() {
-            // let _: AssertParamIsClone<FieldTy>;
-            super::assert_ty_bounds(
-                cx,
-                &mut stmts,
-                field.ty.clone(),
-                field.span,
-                &[sym::clone, sym::AssertParamIsClone],
-            );
+            // This basic redundancy checking only prevents duplication of
+            // assertions like `AssertParamIsClone<Foo>` where the type is a
+            // simple name. That's enough to get a lot of cases, though.
+            if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
+                // Already produced an assertion for this type.
+            } else {
+                // let _: AssertParamIsClone<FieldTy>;
+                super::assert_ty_bounds(
+                    cx,
+                    &mut stmts,
+                    field.ty.clone(),
+                    field.span,
+                    &[sym::clone, sym::AssertParamIsClone],
+                );
+            }
         }
     };
 
     if is_union {
+        // Just a single assertion for unions, that the union impls `Copy`.
         // let _: AssertParamIsCopy<Self>;
         let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper)));
         super::assert_ty_bounds(
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 59f8fbc4a08..c1a2ebcc146 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -3,6 +3,7 @@ use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
 use rustc_ast::{self as ast, MetaItem};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -53,16 +54,24 @@ fn cs_total_eq_assert(
     substr: &Substructure<'_>,
 ) -> BlockOrExpr {
     let mut stmts = Vec::new();
+    let mut seen_type_names = FxHashSet::default();
     let mut process_variant = |variant: &ast::VariantData| {
         for field in variant.fields() {
-            // let _: AssertParamIsEq<FieldTy>;
-            super::assert_ty_bounds(
-                cx,
-                &mut stmts,
-                field.ty.clone(),
-                field.span,
-                &[sym::cmp, sym::AssertParamIsEq],
-            );
+            // This basic redundancy checking only prevents duplication of
+            // assertions like `AssertParamIsEq<Foo>` where the type is a
+            // simple name. That's enough to get a lot of cases, though.
+            if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
+                // Already produced an assertion for this type.
+            } else {
+                // let _: AssertParamIsEq<FieldTy>;
+                super::assert_ty_bounds(
+                    cx,
+                    &mut stmts,
+                    field.ty.clone(),
+                    field.span,
+                    &[sym::cmp, sym::AssertParamIsEq],
+                );
+            }
         }
     };
 
diff --git a/src/test/ui/deriving/deriving-all-codegen.stdout b/src/test/ui/deriving/deriving-all-codegen.stdout
index fb5965858cc..7713627be5e 100644
--- a/src/test/ui/deriving/deriving-all-codegen.stdout
+++ b/src/test/ui/deriving/deriving-all-codegen.stdout
@@ -96,7 +96,6 @@ impl ::core::clone::Clone for Point {
     #[inline]
     fn clone(&self) -> Point {
         let _: ::core::clone::AssertParamIsClone<u32>;
-        let _: ::core::clone::AssertParamIsClone<u32>;
         *self
     }
 }
@@ -152,7 +151,6 @@ impl ::core::cmp::Eq for Point {
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
     }
 }
 #[automatically_derived]
@@ -291,13 +289,6 @@ impl ::core::cmp::Eq for Big {
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
     }
 }
 #[automatically_derived]
@@ -774,8 +765,6 @@ impl ::core::clone::Clone for Mixed {
     #[inline]
     fn clone(&self) -> Mixed {
         let _: ::core::clone::AssertParamIsClone<u32>;
-        let _: ::core::clone::AssertParamIsClone<u32>;
-        let _: ::core::clone::AssertParamIsClone<u32>;
         *self
     }
 }
@@ -871,8 +860,6 @@ impl ::core::cmp::Eq for Mixed {
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
         let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
-        let _: ::core::cmp::AssertParamIsEq<u32>;
     }
 }
 #[automatically_derived]