about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_passes/src/lang_items.rs54
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs14
-rw-r--r--compiler/rustc_typeck/src/check/op.rs17
-rw-r--r--compiler/rustc_typeck/src/check/place_op.rs32
4 files changed, 86 insertions, 31 deletions
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 111bdd1a117..9086e21579e 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -182,6 +182,8 @@ impl LanguageItemCollector<'tcx> {
         }
     }
 
+    // Like collect_item() above, but also checks whether the lang item is declared
+    // with the right number of generic arguments if it is a trait.
     fn collect_item_extended(&mut self, item_index: usize, hir_id: HirId, span: Span) {
         let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
         let lang_item = LangItem::from_u32(item_index as u32).unwrap();
@@ -190,10 +192,15 @@ impl LanguageItemCollector<'tcx> {
         self.collect_item(item_index, item_def_id);
 
         // Now check whether the lang_item has the expected number of generic
-        // arguments. Binary and indexing operations have one (for the RHS/index),
-        // unary operations have no generic arguments.
+        // arguments if it is a trait. Generally speaking, binary and indexing
+        // operations have one (for the RHS/index), unary operations have none,
+        // and the rest also have none except for the closure traits (one for
+        // the argument list), generators (one for the resume argument),
+        // ordering/equality relations (one for the RHS), and various conversion
+        // traits.
 
         let expected_num = match lang_item {
+            // Binary operations
             LangItem::Add
             | LangItem::Sub
             | LangItem::Mul
@@ -215,11 +222,48 @@ impl LanguageItemCollector<'tcx> {
             | LangItem::ShlAssign
             | LangItem::ShrAssign
             | LangItem::Index
-            | LangItem::IndexMut => Some(1),
+            | LangItem::IndexMut
 
-            LangItem::Neg | LangItem::Not | LangItem::Deref | LangItem::DerefMut => Some(0),
+            // Miscellaneous
+            | LangItem::Unsize
+            | LangItem::CoerceUnsized
+            | LangItem::DispatchFromDyn
+            | LangItem::Fn
+            | LangItem::FnMut
+            | LangItem::FnOnce
+            | LangItem::Generator
+            | LangItem::PartialEq
+            | LangItem::PartialOrd
+                => Some(1),
 
-            // FIXME: add more cases?
+            // Unary operations
+            LangItem::Neg
+            | LangItem::Not
+
+            // Miscellaneous
+            | LangItem::Deref
+            | LangItem::DerefMut
+            | LangItem::Sized
+            | LangItem::StructuralPeq
+            | LangItem::StructuralTeq
+            | LangItem::Copy
+            | LangItem::Clone
+            | LangItem::Sync
+            | LangItem::DiscriminantKind
+            | LangItem::PointeeTrait
+            | LangItem::Freeze
+            | LangItem::Drop
+            | LangItem::Receiver
+            | LangItem::Future
+            | LangItem::Unpin
+            | LangItem::Termination
+            | LangItem::Try
+            | LangItem::Send
+            | LangItem::UnwindSafe
+            | LangItem::RefUnwindSafe
+                => Some(0),
+
+            // Not a trait
             _ => None,
         };
 
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 994206bd419..6f96bd544c0 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -1190,3 +1190,17 @@ fn fatally_break_rust(sess: &Session) {
 fn potentially_plural_count(count: usize, word: &str) -> String {
     format!("{} {}{}", count, word, pluralize!(count))
 }
+
+fn has_expected_num_generic_args<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_did: Option<DefId>,
+    mut expected: usize,
+) -> bool {
+    trait_did.map_or(true, |trait_did| {
+        let generics = tcx.generics_of(trait_did);
+        if generics.has_self {
+            expected += 1;
+        }
+        generics.count() == expected
+    })
+}
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 87cb2d6d70c..963436d05d8 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -1,7 +1,7 @@
 //! Code related to processing overloaded binary and unary operators.
 
 use super::method::MethodCallee;
-use super::FnCtxt;
+use super::{has_expected_num_generic_args, FnCtxt};
 use rustc_ast as ast;
 use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -800,17 +800,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // elsewhere by now, but we have to catch it here so that we do not
         // index `other_tys` out of bounds (if the lang item has too many
         // generic arguments, `other_tys` is too short).
-        if let Some(trait_did) = trait_did {
-            let generics = self.tcx.generics_of(trait_did);
-            let expected_num = match op {
+        if !has_expected_num_generic_args(
+            self.tcx,
+            trait_did,
+            match op {
                 // Binary ops have a generic right-hand side, unary ops don't
                 Op::Binary(..) => 1,
                 Op::Unary(..) => 0,
-            } + if generics.has_self { 1 } else { 0 };
-            let num_generics = generics.count();
-            if num_generics != expected_num {
-                return Err(());
-            }
+            },
+        ) {
+            return Err(());
         }
 
         let method = trait_did.and_then(|trait_did| {
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs
index 23677d04d73..a63aec07ad1 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_typeck/src/check/place_op.rs
@@ -1,5 +1,5 @@
 use crate::check::method::MethodCallee;
-use crate::check::{FnCtxt, PlaceOp};
+use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
@@ -157,16 +157,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // If the lang item was declared incorrectly, stop here so that we don't
         // run into an ICE (#83893). The error is reported where the lang item is
         // declared.
-        if let Some(trait_did) = imm_tr {
-            let generics = self.tcx.generics_of(trait_did);
-            let expected_num = match op {
+        if !has_expected_num_generic_args(
+            self.tcx,
+            imm_tr,
+            match op {
                 PlaceOp::Deref => 0,
                 PlaceOp::Index => 1,
-            } + if generics.has_self { 1 } else { 0 };
-            let num_generics = generics.count();
-            if num_generics != expected_num {
-                return None;
-            }
+            },
+        ) {
+            return None;
         }
 
         imm_tr.and_then(|trait_did| {
@@ -197,16 +196,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // If the lang item was declared incorrectly, stop here so that we don't
         // run into an ICE (#83893). The error is reported where the lang item is
         // declared.
-        if let Some(trait_did) = mut_tr {
-            let generics = self.tcx.generics_of(trait_did);
-            let expected_num = match op {
+        if !has_expected_num_generic_args(
+            self.tcx,
+            mut_tr,
+            match op {
                 PlaceOp::Deref => 0,
                 PlaceOp::Index => 1,
-            } + if generics.has_self { 1 } else { 0 };
-            let num_generics = generics.count();
-            if num_generics != expected_num {
-                return None;
-            }
+            },
+        ) {
+            return None;
         }
 
         mut_tr.and_then(|trait_did| {