Remove QPath::LangItem

This commit is contained in:
Cameron Steffen 2025-09-01 14:54:03 -05:00
parent a96e21b199
commit ead5e120a5
35 changed files with 19 additions and 144 deletions

View file

@ -2171,7 +2171,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
lang_item: hir::LangItem,
fields: &'hir [hir::Expr<'hir>],
) -> hir::Expr<'hir> {
let path = self.arena.alloc(self.lang_item_qpath(span, lang_item));
let path = self.arena.alloc(self.make_lang_item_qpath(lang_item, span, None));
self.expr_enum_variant(span, path, fields)
}
@ -2203,43 +2203,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args))
}
// TEMPORARY - will be replaced with expr_call_lang_item_fn_mut
pub(super) fn expr_call_lang_item_qpath_fn_mut(
pub(super) fn expr_lang_item_path(
&mut self,
span: Span,
lang_item: hir::LangItem,
args: &'hir [hir::Expr<'hir>],
) -> hir::Expr<'hir> {
let path = self.arena.alloc(self.expr_lang_item_qpath(span, lang_item));
self.expr_call_mut(span, path, args)
}
// TEMPORARY - will be replaced with expr_call_lang_item_fn
pub(super) fn expr_call_lang_item_qpath_fn(
&mut self,
span: Span,
lang_item: hir::LangItem,
args: &'hir [hir::Expr<'hir>],
) -> &'hir hir::Expr<'hir> {
self.arena.alloc(self.expr_call_lang_item_qpath_fn_mut(span, lang_item, args))
}
fn expr_lang_item_path(&mut self, span: Span, lang_item: hir::LangItem) -> hir::Expr<'hir> {
let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span), None);
self.expr(span, hir::ExprKind::Path(qpath))
}
// TEMPORARY - will be replaced with expr_lang_item_path
fn expr_lang_item_qpath(&mut self, span: Span, lang_item: hir::LangItem) -> hir::Expr<'hir> {
let qpath = self.lang_item_qpath(span, lang_item);
self.expr(span, hir::ExprKind::Path(qpath))
}
// TEMPORARY - will be replaced with expr_lang_item_path
fn lang_item_qpath(&mut self, span: Span, lang_item: hir::LangItem) -> hir::QPath<'hir> {
hir::QPath::LangItem(lang_item, self.lower_span(span))
}
/// `<LangItem>::name`
pub(super) fn expr_lang_item_type_relative(
&mut self,

View file

@ -2535,8 +2535,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lang_item: hir::LangItem,
fields: &'hir [hir::PatField<'hir>],
) -> &'hir hir::Pat<'hir> {
let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span));
self.pat(span, hir::PatKind::Struct(qpath, fields, None))
let path = self.make_lang_item_qpath(lang_item, self.lower_span(span), None);
self.pat(span, hir::PatKind::Struct(path, fields, None))
}
fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, HirId) {

View file

@ -503,8 +503,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
&& let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
call_expr.kind
&& let hir::ExprKind::Path(qpath) = call_expr.kind
&& tcx.qpath_is_lang_item(qpath, LangItem::IntoIterIntoIter)
{
// Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
} else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans

View file

@ -31,7 +31,6 @@ use smallvec::SmallVec;
use thin_vec::ThinVec;
use tracing::debug;
use crate::LangItem;
use crate::attrs::AttributeKind;
use crate::def::{CtorKind, DefKind, MacroKinds, PerNS, Res};
use crate::def_id::{DefId, LocalDefIdMap};
@ -2420,9 +2419,6 @@ impl Expr<'_> {
allow_projections_from(base) || base.is_place_expr(allow_projections_from)
}
// Lang item paths cannot currently be local variables or statics.
ExprKind::Path(QPath::LangItem(..)) => false,
// Suppress errors for bad expressions.
ExprKind::Err(_guar)
| ExprKind::Let(&LetExpr { recovered: ast::Recovered::Yes(_guar), .. }) => true,
@ -2592,10 +2588,6 @@ impl Expr<'_> {
pub fn equivalent_for_indexing(&self, other: &Expr<'_>) -> bool {
match (self.kind, other.kind) {
(ExprKind::Lit(lit1), ExprKind::Lit(lit2)) => lit1.node == lit2.node,
(
ExprKind::Path(QPath::LangItem(item1, _)),
ExprKind::Path(QPath::LangItem(item2, _)),
) => item1 == item2,
(
ExprKind::Path(QPath::Resolved(None, path1)),
ExprKind::Path(QPath::Resolved(None, path2)),
@ -2850,9 +2842,6 @@ pub enum QPath<'hir> {
/// `<Vec>::new`, and `T::X::Y::method` into `<<<T>::X>::Y>::method`,
/// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`.
TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>),
/// Reference to a `#[lang = "foo"]` item.
LangItem(LangItem, Span),
}
impl<'hir> QPath<'hir> {
@ -2861,7 +2850,6 @@ impl<'hir> QPath<'hir> {
match *self {
QPath::Resolved(_, path) => path.span,
QPath::TypeRelative(qself, ps) => qself.span.to(ps.ident.span),
QPath::LangItem(_, span) => span,
}
}
@ -2871,7 +2859,6 @@ impl<'hir> QPath<'hir> {
match *self {
QPath::Resolved(_, path) => path.span,
QPath::TypeRelative(qself, _) => qself.span,
QPath::LangItem(_, span) => span,
}
}
}

View file

@ -1416,7 +1416,6 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_ty_unambig(qself));
visitor.visit_path_segment(segment)
}
QPath::LangItem(..) => V::Result::output(),
}
}

View file

@ -2240,13 +2240,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
}
hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => {
ty::Const::new_error_with_message(
tcx,
qpath.span(),
format!("Const::lower_const_arg: invalid qpath {qpath:?}"),
)
}
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
}
@ -2561,17 +2554,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|(ty, _, _)| ty)
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
}
&hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
let def_id = tcx.require_lang_item(lang_item, span);
let (args, _) = self.lower_generic_args_of_path(
span,
def_id,
&[],
&hir::PathSegment::invalid(),
None,
);
tcx.at(span).type_of(def_id).instantiate(tcx, args)
}
hir::TyKind::Array(ty, length) => {
let length = self.lower_const_arg(length, FeedConstTy::No);
Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length)

View file

@ -1774,11 +1774,6 @@ impl<'a> State<'a> {
self.print_ident(item_segment.ident);
self.print_generic_args(item_segment.args(), colons_before_params)
}
hir::QPath::LangItem(lang_item, span) => {
self.word("#[lang = \"");
self.print_ident(Ident::new(lang_item.name(), span));
self.word("\"]");
}
}
}

View file

@ -545,7 +545,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ExprKind::AddrOf(kind, mutbl, oprnd) => {
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
}
ExprKind::Path(QPath::LangItem(..)) => unreachable!(),
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None),
ExprKind::InlineAsm(asm) => {
// We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).

View file

@ -671,9 +671,6 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
path.segments.last().expect("paths should have a segment")
}
hir::QPath::TypeRelative(_, segment) => segment,
hir::QPath::LangItem(..) => {
return hir::intravisit::walk_qpath(self, qpath, id);
}
};
// Alternatively, try to turbofish `::<_, (), _>`.
if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id()

View file

@ -721,9 +721,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.lowerer().lower_ty(qself);
(LoweredTy::from_raw(self, span, ty), qself, segment)
}
QPath::LangItem(..) => {
bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
}
};
self.register_wf_obligation(

View file

@ -419,7 +419,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return true;
}
}
_ => {}
}
false

View file

@ -1291,7 +1291,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
}
QPath::LangItem(..) => unreachable!(),
}
}

View file

@ -718,7 +718,7 @@ impl<'tcx> LateContext<'tcx> {
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
match *qpath {
hir::QPath::Resolved(_, path) => path.res,
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
hir::QPath::TypeRelative(..) => self
.maybe_typeck_results()
.filter(|typeck_results| typeck_results.hir_owner == id.owner)
.or_else(|| {

View file

@ -2586,8 +2586,6 @@ pub fn rendered_const<'tcx>(tcx: TyCtxt<'tcx>, body: &hir::Body<'_>, def_id: Loc
// FIXME: Claiming that those kinds of QPaths are simple is probably not true if the Ty
// contains const arguments. Is there a *concise* way to check for this?
hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => Simple,
// FIXME: Can they contain const arguments and thus leak private struct fields?
hir::ExprKind::Path(hir::QPath::LangItem(..)) => Simple,
_ => Complex,
}
}

View file

@ -266,7 +266,7 @@ impl<'tcx> TypeckResults<'tcx> {
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: HirId) -> Res {
match *qpath {
hir::QPath::Resolved(_, path) => path.res,
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
hir::QPath::TypeRelative(..) => self
.type_dependent_def(id)
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
}

View file

@ -425,7 +425,6 @@ impl<'tcx> ThirBuildCx<'tcx> {
None
}
}
_ => None,
}
} else {
None

View file

@ -1268,7 +1268,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
Res::Def(kind, def_id) => Some((kind, def_id)),
_ => None,
},
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
hir::QPath::TypeRelative(..) => {
match self.maybe_typeck_results {
Some(typeck_results) => typeck_results.type_dependent_def(id),
// FIXME: Check type-relative associated types in signatures.
@ -1287,9 +1287,6 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
if let DefKind::Static { .. } = kind { def_id.is_local() } else { false };
if !self.item_is_accessible(def_id) && !is_local_static {
let name = match *qpath {
hir::QPath::LangItem(it, ..) => {
self.tcx.lang_items().get(it).map(|did| self.tcx.def_path_str(did))
}
hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
};

View file

@ -1147,7 +1147,6 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
Box::new(segment.into_iter())
}
hir::QPath::LangItem(_, _) => Box::new(iter::empty()),
}
}
}

View file

@ -1703,7 +1703,6 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
trait_,
}))
}
hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
}
}

View file

@ -253,7 +253,6 @@ pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String {
let segments = match *p {
hir::QPath::Resolved(_, path) => &path.segments,
hir::QPath::TypeRelative(_, segment) => return segment.ident.to_string(),
hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(),
};
join_path_idents(segments.iter().map(|seg| seg.ident))

View file

@ -300,7 +300,6 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
intravisit::walk_path(self, path);
}
}
_ => {}
}
}

View file

@ -550,7 +550,6 @@ fn get_item_name(item: &Item<'_>) -> Option<String> {
// This case doesn't exist in the clippy tests codebase.
None
},
QPath::LangItem(_, _) => None,
}
} else {
// Impls for anything that isn't a named type can be skipped.

View file

@ -4,7 +4,7 @@ use clippy_utils::msrvs::Msrv;
use clippy_utils::{is_in_const_context, is_in_test};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, QPath, RustcVersion, StabilityLevel, StableSince};
use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, RustcVersion, StabilityLevel, StableSince};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::TyCtxt;
use rustc_session::impl_lint_pass;
@ -193,10 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv {
self.emit_lint_if_under_msrv(cx, method_did, expr.hir_id, span);
}
},
// Desugaring into function calls by the compiler will use `QPath::LangItem` variants. Those should
// not be linted as they will not be generated in older compilers if the function is not available,
// and the compiler is allowed to call unstable functions.
ExprKind::Path(qpath @ (QPath::Resolved(..) | QPath::TypeRelative(..))) => {
ExprKind::Path(qpath) => {
if let Some(path_def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id() {
self.emit_lint_if_under_msrv(cx, path_def_id, expr.hir_id, expr.span);
}
@ -206,7 +203,7 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv {
}
fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
if let hir::TyKind::Path(qpath @ (QPath::Resolved(..) | QPath::TypeRelative(..))) = hir_ty.kind
if let hir::TyKind::Path(qpath) = hir_ty.kind
&& let Some(ty_def_id) = cx.qpath_res(&qpath, hir_ty.hir_id).opt_def_id()
// `CStr` and `CString` have been moved around but have been available since Rust 1.0.0
&& !matches!(cx.tcx.get_diagnostic_name(ty_def_id), Some(sym::cstr_type | sym::cstring_type))

View file

@ -181,7 +181,6 @@ pub(super) fn check_function(cx: &LateContext<'_>, expr: &Expr<'_>, callee: &Exp
QPath::TypeRelative(_, seg) => Some(SpansKind::Fn {
fn_span: seg.ident.span,
}),
QPath::LangItem(_, _) => unreachable!("`TryFrom` and `TryInto` are not lang items"),
};
check(

View file

@ -97,7 +97,6 @@ fn extract_fn_ty<'tcx>(
// let a: String = String::new();
// let a: String = String::get_string();
hir::QPath::TypeRelative(..) => func_hir_id_to_func_ty(cx, call.hir_id),
hir::QPath::LangItem(..) => None,
}
}

View file

@ -655,7 +655,6 @@ impl Types {
}
}
},
QPath::LangItem(..) => {},
}
},
TyKind::Path(ref qpath) => {

View file

@ -106,7 +106,6 @@ fn get_hir_ty_def_id<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: rustc_hir::Ty<'tcx>) -> Op
_ => None,
}
},
QPath::LangItem(..) => None,
}
}
@ -291,7 +290,6 @@ fn is_default_method_on_current_ty<'tcx>(tcx: TyCtxt<'tcx>, qpath: QPath<'tcx>,
}
get_hir_ty_def_id(tcx, *ty) == Some(implemented_ty_id)
},
QPath::LangItem(..) => false,
}
}

View file

@ -60,7 +60,6 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
}
},
hir::QPath::TypeRelative(_, path) => path.ident.name,
hir::QPath::LangItem(..) => return,
};
match constructor_symbol {
sym::Some | sym::Ok if path.ident.name == sym::map => (),

View file

@ -270,9 +270,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
}
fn qpath(&self, qpath: &Binding<&QPath<'_>>, hir_id_binding: &str, hir_id: HirId) {
if let QPath::LangItem(lang_item, ..) = *qpath.value {
chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))");
} else if let Some(def_id) = self.cx.qpath_res(qpath.value, hir_id).opt_def_id()
if let Some(def_id) = self.cx.qpath_res(qpath.value, hir_id).opt_def_id()
&& !def_id.is_local()
{
bind!(self, def_id);

View file

@ -121,7 +121,6 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
(start, end)
},
QPath::TypeRelative(_, name) => (Pat::Str(""), Pat::Sym(name.ident.name)),
QPath::LangItem(..) => (Pat::Str(""), Pat::Str("")),
}
}

View file

@ -167,7 +167,6 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
QPath::TypeRelative(_, name) => {
self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty());
},
QPath::LangItem(..) => self.eagerness = Lazy,
},
_ => self.eagerness = Lazy,
},

View file

@ -555,7 +555,6 @@ impl HirEqInterExpr<'_, '_, '_> {
(QPath::TypeRelative(lty, lseg), QPath::TypeRelative(rty, rseg)) => {
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
},
(QPath::LangItem(llang_item, ..), QPath::LangItem(rlang_item, ..)) => llang_item == rlang_item,
_ => false,
}
}
@ -1092,9 +1091,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
QPath::TypeRelative(_, path) => {
self.hash_name(path.ident.name);
},
QPath::LangItem(lang_item, ..) => {
std::mem::discriminant(lang_item).hash(&mut self.s);
},
}
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
}

View file

@ -361,7 +361,6 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
match *path {
QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
QPath::TypeRelative(_, seg) => seg,
QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
}
}

View file

@ -99,15 +99,6 @@ pub trait MaybeQPath<'a>: Copy {
/// use for type dependant lookup.
fn opt_qpath(self) -> Option<QPathId<'a>>;
/// If this node is a `QPath::LangItem` gets the item it resolves to.
#[inline]
fn opt_lang_path(self) -> Option<LangItem> {
match self.opt_qpath() {
Some((&QPath::LangItem(item, _), _)) => Some(item),
_ => None,
}
}
/// If this is a path gets its resolution. Returns `Res::Err` otherwise.
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
@ -116,10 +107,10 @@ pub trait MaybeQPath<'a>: Copy {
fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>) -> Res {
match *qpath {
QPath::Resolved(_, p) => p.res,
QPath::TypeRelative(..) | QPath::LangItem(..) if let Some((kind, id)) = typeck.ty_based_def(id) => {
QPath::TypeRelative(..) if let Some((kind, id)) = typeck.ty_based_def(id) => {
Res::Def(kind, id)
},
QPath::TypeRelative(..) | QPath::LangItem(..) => Res::Err,
QPath::TypeRelative(..) => Res::Err,
}
}
match self.opt_qpath() {
@ -148,7 +139,7 @@ pub trait MaybeQPath<'a>: Copy {
{
Res::Def(kind, id)
},
QPath::Resolved(..) | QPath::TypeRelative(..) | QPath::LangItem(..) => Res::Err,
QPath::Resolved(..) | QPath::TypeRelative(..) => Res::Err,
}
}
match self.opt_qpath() {
@ -168,7 +159,7 @@ pub trait MaybeQPath<'a>: Copy {
QPath::TypeRelative(_, seg) if let Some((kind, id)) = typeck.ty_based_def(id) => {
(Res::Def(kind, id), Some(seg))
},
QPath::Resolved(..) | QPath::TypeRelative(..) | QPath::LangItem(..) => (Res::Err, None),
QPath::Resolved(..) | QPath::TypeRelative(..) => (Res::Err, None),
}
}
match self.opt_qpath() {
@ -202,7 +193,7 @@ pub trait MaybeQPath<'a>: Copy {
},
_,
) if let Some((kind, id)) = typeck.ty_based_def(id) => Res::Def(kind, id),
QPath::Resolved(..) | QPath::TypeRelative(..) | QPath::LangItem(..) => Res::Err,
QPath::Resolved(..) | QPath::TypeRelative(..) => Res::Err,
}
}
match self.opt_qpath() {
@ -244,7 +235,7 @@ pub trait MaybeQPath<'a>: Copy {
{
Res::Def(kind, id)
},
QPath::Resolved(..) | QPath::TypeRelative(..) | QPath::LangItem(..) => Res::Err,
QPath::Resolved(..) | QPath::TypeRelative(..) => Res::Err,
}
}
match self.opt_qpath() {

View file

@ -197,19 +197,6 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo
QPath::TypeRelative(ty, path_segment) => {
path_segment_certainty(cx, type_certainty(cx, ty), path_segment, resolves_to_type)
},
QPath::LangItem(lang_item, ..) => cx
.tcx
.lang_items()
.get(*lang_item)
.map_or(Certainty::Uncertain, |def_id| {
let generics = cx.tcx.generics_of(def_id);
if generics.is_empty() {
Certainty::Certain(if resolves_to_type { Some(def_id) } else { None })
} else {
Certainty::Uncertain
}
}),
};
debug_assert!(resolves_to_type || certainty.to_def_id().is_none());
certainty