Rollup merge of #152384 - enthropy7:fix-eii-root-resolution-clean, r=jdonszelmann

Restrict EII declarations to functions at lowering time

We tighten EII declaration resolution so that `lower_path_simple_eii` only accepts function‑like items (`Fn, AssocFn, Ctor(_, Fn)`) as valid EII targets. If name resolution points at something else (like a const with the same name), we now emit a direct error (“`externally implementable items must refer to a function`”) at the declaration site, which prevents bad `DefIds` from ever reaching `compare_eii_function_types` and turning into an ICE

this is more robust and root-cause oriented fix to rust-lang/rust#152337 issue and an alternate of my more simple PR rust-lang/rust#152365

test included
This commit is contained in:
Jonathan Brouwer
2026-04-10 15:33:11 +02:00
committed by GitHub
3 changed files with 59 additions and 6 deletions
+20 -6
View File
@@ -441,6 +441,8 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> {
TraitItem(Namespace, &'a PathSource<'a, 'ast, 'ra>),
/// Paths in delegation item
Delegation,
/// Paths in externally implementable item declarations.
ExternItemImpl,
/// An arg in a `use<'a, N>` precise-capturing bound.
PreciseCapturingArg(Namespace),
/// Paths that end with `(..)`, for return type notation.
@@ -465,6 +467,7 @@ fn namespace(self) -> Namespace {
| PathSource::Pat
| PathSource::TupleStruct(..)
| PathSource::Delegation
| PathSource::ExternItemImpl
| PathSource::ReturnTypeNotation => ValueNS,
PathSource::TraitItem(ns, _) => ns,
PathSource::PreciseCapturingArg(ns) => ns,
@@ -484,6 +487,7 @@ fn defer_to_typeck(self) -> bool {
| PathSource::TraitItem(..)
| PathSource::DefineOpaques
| PathSource::Delegation
| PathSource::ExternItemImpl
| PathSource::PreciseCapturingArg(..)
| PathSource::Macro
| PathSource::Module => false,
@@ -526,7 +530,9 @@ fn descr_expected(self) -> &'static str {
},
_ => "value",
},
PathSource::ReturnTypeNotation | PathSource::Delegation => "function",
PathSource::ReturnTypeNotation
| PathSource::Delegation
| PathSource::ExternItemImpl => "function",
PathSource::PreciseCapturingArg(..) => "type or const parameter",
PathSource::Macro => "macro",
PathSource::Module => "module",
@@ -618,6 +624,9 @@ pub(crate) fn is_expected(self, res: Res) -> bool {
_ => false,
},
PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)),
PathSource::ExternItemImpl => {
matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..), _))
}
PathSource::PreciseCapturingArg(ValueNS) => {
matches!(res, Res::Def(DefKind::ConstParam, _))
}
@@ -640,8 +649,12 @@ fn error_code(self, has_unexpected_resolution: bool) -> ErrCode {
(PathSource::Type | PathSource::DefineOpaques, false) => E0425,
(PathSource::Struct(_), true) => E0574,
(PathSource::Struct(_), false) => E0422,
(PathSource::Expr(..), true) | (PathSource::Delegation, true) => E0423,
(PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425,
(PathSource::Expr(..), true)
| (PathSource::Delegation, true)
| (PathSource::ExternItemImpl, true) => E0423,
(PathSource::Expr(..), false)
| (PathSource::Delegation, false)
| (PathSource::ExternItemImpl, false) => E0425,
(PathSource::Pat | PathSource::TupleStruct(..), true) => E0532,
(PathSource::Pat | PathSource::TupleStruct(..), false) => E0531,
(PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, true) => E0575,
@@ -1091,7 +1104,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, _: &AttrVec, sp: Span, fn_id: Node
*node_id,
&None,
&target.foreign_item,
PathSource::Expr(None),
PathSource::ExternItemImpl,
);
} else {
self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro);
@@ -2198,7 +2211,8 @@ fn resolve_elided_lifetimes_in_path(
| PathSource::Struct(_)
| PathSource::TupleStruct(..)
| PathSource::DefineOpaques
| PathSource::Delegation => true,
| PathSource::Delegation
| PathSource::ExternItemImpl => true,
};
if inferred {
// Do not create a parameter for patterns and expressions: type checking can infer
@@ -3004,7 +3018,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
item.id,
&None,
extern_item_path,
PathSource::Expr(None),
PathSource::ExternItemImpl,
);
}
}
@@ -0,0 +1,12 @@
// Regression test for ICE "unexpected sort of node in fn_sig()" (issue #152337).
// When the same name is used for a const and an #[eii] function, the declaration
// was incorrectly resolved to the const, causing fn_sig() to be called on a non-function.
#![feature(extern_item_impls)]
const A: () = ();
#[eii]
fn A() {} //~ ERROR the name `A` is defined multiple times
//~^ ERROR expected function, found constant
//~| ERROR expected function, found constant
fn main() {}
@@ -0,0 +1,27 @@
error[E0428]: the name `A` is defined multiple times
--> $DIR/eii-declaration-not-fn-issue-152337.rs:8:1
|
LL | const A: () = ();
| ----------------- previous definition of the value `A` here
LL | #[eii]
LL | fn A() {}
| ^^^^^^ `A` redefined here
|
= note: `A` must be defined only once in the value namespace of this module
error[E0423]: expected function, found constant `self::A`
--> $DIR/eii-declaration-not-fn-issue-152337.rs:8:4
|
LL | fn A() {}
| ^ not a function
error[E0423]: expected function, found constant `A`
--> $DIR/eii-declaration-not-fn-issue-152337.rs:8:4
|
LL | fn A() {}
| ^ not a function
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0423, E0428.
For more information about an error, try `rustc --explain E0423`.