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) { 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 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 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); self.collect_item(item_index, item_def_id);
// Now check whether the lang_item has the expected number of generic // Now check whether the lang_item has the expected number of generic
// arguments. Binary and indexing operations have one (for the RHS/index), // arguments if it is a trait. Generally speaking, binary and indexing
// unary operations have no generic arguments. // 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 { let expected_num = match lang_item {
// Binary operations
LangItem::Add LangItem::Add
| LangItem::Sub | LangItem::Sub
| LangItem::Mul | LangItem::Mul
@ -215,11 +222,48 @@ impl LanguageItemCollector<'tcx> {
| LangItem::ShlAssign | LangItem::ShlAssign
| LangItem::ShrAssign | LangItem::ShrAssign
| LangItem::Index | 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, _ => None,
}; };

View File

@ -1190,3 +1190,17 @@ fn fatally_break_rust(sess: &Session) {
fn potentially_plural_count(count: usize, word: &str) -> String { fn potentially_plural_count(count: usize, word: &str) -> String {
format!("{} {}{}", count, word, pluralize!(count)) 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. //! Code related to processing overloaded binary and unary operators.
use super::method::MethodCallee; use super::method::MethodCallee;
use super::FnCtxt; use super::{has_expected_num_generic_args, FnCtxt};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir; use rustc_hir as hir;
@ -800,18 +800,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// elsewhere by now, but we have to catch it here so that we do not // 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 // index `other_tys` out of bounds (if the lang item has too many
// generic arguments, `other_tys` is too short). // generic arguments, `other_tys` is too short).
if let Some(trait_did) = trait_did { if !has_expected_num_generic_args(
let generics = self.tcx.generics_of(trait_did); self.tcx,
let expected_num = match op { trait_did,
match op {
// Binary ops have a generic right-hand side, unary ops don't // Binary ops have a generic right-hand side, unary ops don't
Op::Binary(..) => 1, Op::Binary(..) => 1,
Op::Unary(..) => 0, 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| { let method = trait_did.and_then(|trait_did| {
let opname = Ident::with_dummy_span(opname); let opname = Ident::with_dummy_span(opname);

View File

@ -1,5 +1,5 @@
use crate::check::method::MethodCallee; 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_hir as hir;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk; use rustc_infer::infer::InferOk;
@ -157,17 +157,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the lang item was declared incorrectly, stop here so that we don't // 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 // run into an ICE (#83893). The error is reported where the lang item is
// declared. // declared.
if let Some(trait_did) = imm_tr { if !has_expected_num_generic_args(
let generics = self.tcx.generics_of(trait_did); self.tcx,
let expected_num = match op { imm_tr,
match op {
PlaceOp::Deref => 0, PlaceOp::Deref => 0,
PlaceOp::Index => 1, 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| { imm_tr.and_then(|trait_did| {
self.lookup_method_in_trait( self.lookup_method_in_trait(
@ -197,17 +196,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the lang item was declared incorrectly, stop here so that we don't // 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 // run into an ICE (#83893). The error is reported where the lang item is
// declared. // declared.
if let Some(trait_did) = mut_tr { if !has_expected_num_generic_args(
let generics = self.tcx.generics_of(trait_did); self.tcx,
let expected_num = match op { mut_tr,
match op {
PlaceOp::Deref => 0, PlaceOp::Deref => 0,
PlaceOp::Index => 1, 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| { mut_tr.and_then(|trait_did| {
self.lookup_method_in_trait( self.lookup_method_in_trait(