1
Fork 0

Auto merge of #108138 - compiler-errors:malformed-fn-trait, r=TaKO8Ki

Move `Fn*` traits malformedness protections to typeck

I found it strange that we were doing a custom well-formedness check just for the `Fn*` traits' `call_*` fn items. My understanding from the git history is that this is just to avoid ICEs later on in typeck.

Well, that well-formedness check isn't even implemented correctly for `FnOnce::call_once`, or `FnMut::call_mut` for that matter. Instead, this PR just makes the typeck checks more robust, and leaves it up to the call-site to report errors when lang items are implemented in funny ways.

This coincidentally fixes another ICE where a the `Add` lang item is implemented with a `add` item that's a const instead of a method.
This commit is contained in:
bors 2023-02-21 12:59:11 +00:00
commit 3200982b76
16 changed files with 221 additions and 74 deletions

View file

@ -16,7 +16,7 @@ use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, ir::TypeVisitor, AdtKind, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
self, ir::TypeVisitor, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
TypeSuperVisitable,
};
use rustc_middle::ty::{GenericArgKind, InternalSubsts};
@ -277,56 +277,6 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
};
check_object_unsafe_self_trait_by_name(tcx, trait_item);
check_associated_item(tcx, def_id, span, method_sig);
let encl_trait_def_id = tcx.local_parent(def_id);
let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
let encl_trait_def_id = encl_trait.owner_id.to_def_id();
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
Some("fn")
} else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() {
Some("fn_mut")
} else {
None
};
if let (Some(fn_lang_item_name), "call") =
(fn_lang_item_name, trait_item.ident.name.to_ident_string().as_str())
{
// We are looking at the `call` function of the `fn` or `fn_mut` lang item.
// Do some rudimentary sanity checking to avoid an ICE later (issue #83471).
if let Some(hir::FnSig { decl, span, .. }) = method_sig {
if let [self_ty, _] = decl.inputs {
if !matches!(self_ty.kind, hir::TyKind::Ref(_, _)) {
tcx.sess
.struct_span_err(
self_ty.span,
&format!(
"first argument of `call` in `{fn_lang_item_name}` lang item must be a reference",
),
)
.emit();
}
} else {
tcx.sess
.struct_span_err(
*span,
&format!(
"`call` function in `{fn_lang_item_name}` lang item takes exactly two arguments",
),
)
.emit();
}
} else {
tcx.sess
.struct_span_err(
trait_item.span,
&format!(
"`call` trait item in `{fn_lang_item_name}` lang item must be a function",
),
)
.emit();
}
}
}
/// Require that the user writes where clauses on GATs for the implicit