Implement changes suggested by varkor

This commit is contained in:
Fabian Wolff 2021-05-16 18:16:00 +02:00
parent 7217d767b2
commit 4efa4a5273
4 changed files with 86 additions and 31 deletions

View File

@ -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,
};

View File

@ -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
})
}

View File

@ -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| {

View File

@ -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| {