diff options
| -rw-r--r-- | compiler/rustc_passes/src/lang_items.rs | 54 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/mod.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/op.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/place_op.rs | 32 |
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| { |
