From 7217d767b2054ac98da4f1840934f35f8285890c Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sat, 15 May 2021 19:53:16 +0200 Subject: [PATCH 1/3] Report an error if a lang item has the wrong number of generic arguments --- compiler/rustc_passes/src/lang_items.rs | 88 +++++++++++++++++-- compiler/rustc_typeck/src/check/method/mod.rs | 4 +- compiler/rustc_typeck/src/check/op.rs | 18 ++++ compiler/rustc_typeck/src/check/place_op.rs | 32 +++++++ .../lang-item-missing-generator.rs | 0 .../lang-item-missing-generator.stderr | 0 .../ui/{ => lang-items}/lang-item-missing.rs | 0 .../{ => lang-items}/lang-item-missing.stderr | 0 .../wrong-number-generic-args-add.rs | 20 +++++ .../wrong-number-generic-args-add.stderr | 20 +++++ .../wrong-number-generic-args-index.rs | 19 ++++ .../wrong-number-generic-args-index.stderr | 18 ++++ 12 files changed, 212 insertions(+), 7 deletions(-) rename src/test/ui/{ => lang-items}/lang-item-missing-generator.rs (100%) rename src/test/ui/{ => lang-items}/lang-item-missing-generator.stderr (100%) rename src/test/ui/{ => lang-items}/lang-item-missing.rs (100%) rename src/test/ui/{ => lang-items}/lang-item-missing.stderr (100%) create mode 100644 src/test/ui/lang-items/wrong-number-generic-args-add.rs create mode 100644 src/test/ui/lang-items/wrong-number-generic-args-add.stderr create mode 100644 src/test/ui/lang-items/wrong-number-generic-args-index.rs create mode 100644 src/test/ui/lang-items/wrong-number-generic-args-index.stderr diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 7e6bb9779f077..111bdd1a117ea 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -13,12 +13,13 @@ use crate::weak_lang_items; use rustc_middle::middle::cstore::ExternCrate; use rustc_middle::ty::TyCtxt; -use rustc_errors::struct_span_err; +use rustc_errors::{pluralize, struct_span_err}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::{extract, ITEM_REFS}; use rustc_hir::{HirId, LangItem, LanguageItems, Target}; +use rustc_span::Span; use rustc_middle::ty::query::Providers; @@ -61,8 +62,7 @@ impl LanguageItemCollector<'tcx> { match ITEM_REFS.get(&value).cloned() { // Known lang item with attribute on correct target. Some((item_index, expected_target)) if actual_target == expected_target => { - let def_id = self.tcx.hir().local_def_id(hir_id); - self.collect_item(item_index, def_id.to_def_id()); + self.collect_item_extended(item_index, hir_id, span); } // Known lang item with attribute on incorrect target. Some((_, expected_target)) => { @@ -100,11 +100,12 @@ impl LanguageItemCollector<'tcx> { } fn collect_item(&mut self, item_index: usize, item_def_id: DefId) { + let lang_item = LangItem::from_u32(item_index as u32).unwrap(); + let name = lang_item.name(); + // Check for duplicates. if let Some(original_def_id) = self.items.items[item_index] { if original_def_id != item_def_id { - let lang_item = LangItem::from_u32(item_index as u32).unwrap(); - let name = lang_item.name(); let mut err = match self.tcx.hir().span_if_local(item_def_id) { Some(span) => struct_span_err!( self.tcx.sess, @@ -180,6 +181,83 @@ impl LanguageItemCollector<'tcx> { self.items.groups[group as usize].push(item_def_id); } } + + 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(); + let name = lang_item.name(); + + 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. + + let expected_num = match lang_item { + LangItem::Add + | LangItem::Sub + | LangItem::Mul + | LangItem::Div + | LangItem::Rem + | LangItem::BitXor + | LangItem::BitAnd + | LangItem::BitOr + | LangItem::Shl + | LangItem::Shr + | LangItem::AddAssign + | LangItem::SubAssign + | LangItem::MulAssign + | LangItem::DivAssign + | LangItem::RemAssign + | LangItem::BitXorAssign + | LangItem::BitAndAssign + | LangItem::BitOrAssign + | LangItem::ShlAssign + | LangItem::ShrAssign + | LangItem::Index + | LangItem::IndexMut => Some(1), + + LangItem::Neg | LangItem::Not | LangItem::Deref | LangItem::DerefMut => Some(0), + + // FIXME: add more cases? + _ => None, + }; + + if let Some(expected_num) = expected_num { + let (actual_num, generics_span) = match self.tcx.hir().get(hir_id) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, generics, ..), + .. + }) => (generics.params.len(), generics.span), + _ => bug!("op/index/deref lang item target is not a trait: {:?}", lang_item), + }; + + if expected_num != actual_num { + // We are issuing E0718 "incorrect target" here, because while the + // item kind of the target is correct, the target is still wrong + // because of the wrong number of generic arguments. + struct_span_err!( + self.tcx.sess, + span, + E0718, + "`{}` language item must be applied to a trait with {} generic argument{}", + name, + expected_num, + pluralize!(expected_num) + ) + .span_label( + generics_span, + format!( + "this trait has {} generic argument{}, not {}", + actual_num, + pluralize!(actual_num), + expected_num + ), + ) + .emit(); + } + } + } } /// Traverses and collects all the lang items in all crates. diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 0b1129a631249..427102afee103 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -303,8 +303,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_input_types: Option<&[Ty<'tcx>]>, ) -> Option>> { debug!( - "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?})", - self_ty, m_name, trait_def_id + "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})", + self_ty, m_name, trait_def_id, opt_input_types ); // Construct a trait-reference `self_ty : Trait` diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 567cb1a90d0d9..87cb2d6d70c57 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -795,6 +795,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, op, opname, trait_did ); + // Catches cases like #83893, where a lang item is declared with the + // wrong number of generic arguments. Should have yielded an error + // 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 { + // 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(()); + } + } + let method = trait_did.and_then(|trait_did| { let opname = Ident::with_dummy_span(opname); self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)) diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index 5bd385107ca39..23677d04d7301 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -153,6 +153,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref), PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index), }; + + // 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 { + 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; + } + } + imm_tr.and_then(|trait_did| { self.lookup_method_in_trait( span, @@ -177,6 +193,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut), PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut), }; + + // 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 { + 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; + } + } + mut_tr.and_then(|trait_did| { self.lookup_method_in_trait( span, diff --git a/src/test/ui/lang-item-missing-generator.rs b/src/test/ui/lang-items/lang-item-missing-generator.rs similarity index 100% rename from src/test/ui/lang-item-missing-generator.rs rename to src/test/ui/lang-items/lang-item-missing-generator.rs diff --git a/src/test/ui/lang-item-missing-generator.stderr b/src/test/ui/lang-items/lang-item-missing-generator.stderr similarity index 100% rename from src/test/ui/lang-item-missing-generator.stderr rename to src/test/ui/lang-items/lang-item-missing-generator.stderr diff --git a/src/test/ui/lang-item-missing.rs b/src/test/ui/lang-items/lang-item-missing.rs similarity index 100% rename from src/test/ui/lang-item-missing.rs rename to src/test/ui/lang-items/lang-item-missing.rs diff --git a/src/test/ui/lang-item-missing.stderr b/src/test/ui/lang-items/lang-item-missing.stderr similarity index 100% rename from src/test/ui/lang-item-missing.stderr rename to src/test/ui/lang-items/lang-item-missing.stderr diff --git a/src/test/ui/lang-items/wrong-number-generic-args-add.rs b/src/test/ui/lang-items/wrong-number-generic-args-add.rs new file mode 100644 index 0000000000000..9f4f2464a1e65 --- /dev/null +++ b/src/test/ui/lang-items/wrong-number-generic-args-add.rs @@ -0,0 +1,20 @@ +// Checks whether declaring a lang item with the wrong number +// of generic arguments crashes the compiler (issue #83893). + +#![feature(lang_items,no_core)] +#![no_core] +#![crate_type="lib"] + +#[lang = "sized"] +trait MySized {} + +#[lang = "add"] +trait MyAdd<'a, T> {} +//~^^ ERROR: `add` language item must be applied to a trait with 1 generic argument [E0718] + +fn ice() { + let r = 5; + let a = 6; + r + a + //~^ ERROR: cannot add `{integer}` to `{integer}` [E0369] +} diff --git a/src/test/ui/lang-items/wrong-number-generic-args-add.stderr b/src/test/ui/lang-items/wrong-number-generic-args-add.stderr new file mode 100644 index 0000000000000..6f89441fd285d --- /dev/null +++ b/src/test/ui/lang-items/wrong-number-generic-args-add.stderr @@ -0,0 +1,20 @@ +error[E0718]: `add` language item must be applied to a trait with 1 generic argument + --> $DIR/wrong-number-generic-args-add.rs:11:1 + | +LL | #[lang = "add"] + | ^^^^^^^^^^^^^^^ +LL | trait MyAdd<'a, T> {} + | ------- this trait has 2 generic arguments, not 1 + +error[E0369]: cannot add `{integer}` to `{integer}` + --> $DIR/wrong-number-generic-args-add.rs:18:7 + | +LL | r + a + | - ^ - {integer} + | | + | {integer} + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0369, E0718. +For more information about an error, try `rustc --explain E0369`. diff --git a/src/test/ui/lang-items/wrong-number-generic-args-index.rs b/src/test/ui/lang-items/wrong-number-generic-args-index.rs new file mode 100644 index 0000000000000..1d90e63dc5470 --- /dev/null +++ b/src/test/ui/lang-items/wrong-number-generic-args-index.rs @@ -0,0 +1,19 @@ +// Checks whether declaring a lang item with the wrong number +// of generic arguments crashes the compiler (issue #83893). + +#![feature(lang_items,no_core)] +#![no_core] +#![crate_type="lib"] + +#[lang = "sized"] +trait MySized {} + +#[lang = "index"] +trait MyIndex<'a, T> {} +//~^^ ERROR: `index` language item must be applied to a trait with 1 generic argument [E0718] + +fn ice() { + let arr = [0; 5]; + let _ = arr[2]; + //~^ ERROR: cannot index into a value of type `[{integer}; 5]` [E0608] +} diff --git a/src/test/ui/lang-items/wrong-number-generic-args-index.stderr b/src/test/ui/lang-items/wrong-number-generic-args-index.stderr new file mode 100644 index 0000000000000..bc3f19ff27623 --- /dev/null +++ b/src/test/ui/lang-items/wrong-number-generic-args-index.stderr @@ -0,0 +1,18 @@ +error[E0718]: `index` language item must be applied to a trait with 1 generic argument + --> $DIR/wrong-number-generic-args-index.rs:11:1 + | +LL | #[lang = "index"] + | ^^^^^^^^^^^^^^^^^ +LL | trait MyIndex<'a, T> {} + | ------- this trait has 2 generic arguments, not 1 + +error[E0608]: cannot index into a value of type `[{integer}; 5]` + --> $DIR/wrong-number-generic-args-index.rs:17:13 + | +LL | let _ = arr[2]; + | ^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0608, E0718. +For more information about an error, try `rustc --explain E0608`. From 4efa4a5273293354526801d8e3a3d05d005b2479 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sun, 16 May 2021 18:16:00 +0200 Subject: [PATCH 2/3] Implement changes suggested by varkor --- compiler/rustc_passes/src/lang_items.rs | 54 +++++++++++++++++++-- compiler/rustc_typeck/src/check/mod.rs | 14 ++++++ compiler/rustc_typeck/src/check/op.rs | 17 +++---- 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 111bdd1a117ea..9086e21579eda 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 994206bd41934..6f96bd544c06c 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, + 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 87cb2d6d70c57..963436d05d8ef 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 23677d04d7301..a63aec07ad1c0 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| { From 7b301985faa73b1404cbc21ffe7c7f859a293448 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Mon, 17 May 2021 13:56:11 +0200 Subject: [PATCH 3/3] Two minor changes for readability and efficiency --- compiler/rustc_passes/src/lang_items.rs | 5 ++--- compiler/rustc_typeck/src/check/mod.rs | 7 ++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 9086e21579eda..a6306ad923dab 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -100,12 +100,11 @@ impl LanguageItemCollector<'tcx> { } fn collect_item(&mut self, item_index: usize, item_def_id: DefId) { - let lang_item = LangItem::from_u32(item_index as u32).unwrap(); - let name = lang_item.name(); - // Check for duplicates. if let Some(original_def_id) = self.items.items[item_index] { if original_def_id != item_def_id { + let lang_item = LangItem::from_u32(item_index as u32).unwrap(); + let name = lang_item.name(); let mut err = match self.tcx.hir().span_if_local(item_def_id) { Some(span) => struct_span_err!( self.tcx.sess, diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 6f96bd544c06c..0b5387993c948 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -1194,13 +1194,10 @@ fn potentially_plural_count(count: usize, word: &str) -> String { fn has_expected_num_generic_args<'tcx>( tcx: TyCtxt<'tcx>, trait_did: Option, - mut expected: usize, + 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 + generics.count() == expected + if generics.has_self { 1 } else { 0 } }) }