Use is_lang_item and as_lang_item instead of handrolling their logic

This commit is contained in:
Oli Scherer
2025-04-22 09:50:49 +00:00
parent 9bfa31f632
commit 5d2952100f
18 changed files with 194 additions and 220 deletions

View File

@@ -5,7 +5,7 @@ use rustc_hir as hir;
use rustc_hir::GenericArg;
use rustc_hir::def::{DefKind, PartialRes, Res};
use rustc_hir::def_id::DefId;
use rustc_middle::span_bug;
use rustc_middle::{span_bug, ty};
use rustc_session::parse::add_feature_diagnostics;
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
use smallvec::{SmallVec, smallvec};
@@ -590,14 +590,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`.
fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<DefId> {
let lang_items = self.tcx.lang_items();
if Some(def_id) == lang_items.fn_trait() {
lang_items.async_fn_trait()
} else if Some(def_id) == lang_items.fn_mut_trait() {
lang_items.async_fn_mut_trait()
} else if Some(def_id) == lang_items.fn_once_trait() {
lang_items.async_fn_once_trait()
} else {
None
match self.tcx.fn_trait_kind_from_def_id(def_id)? {
ty::ClosureKind::Fn => lang_items.async_fn_trait(),
ty::ClosureKind::FnMut => lang_items.async_fn_mut_trait(),
ty::ClosureKind::FnOnce => lang_items.async_fn_once_trait(),
}
}
}

View File

@@ -1265,12 +1265,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
&& let CallKind::FnCall { fn_trait_id, self_ty } = kind
&& let ty::Param(_) = self_ty.kind()
&& ty == self_ty
&& [
self.infcx.tcx.lang_items().fn_once_trait(),
self.infcx.tcx.lang_items().fn_mut_trait(),
self.infcx.tcx.lang_items().fn_trait(),
]
.contains(&Some(fn_trait_id))
&& self.infcx.tcx.fn_trait_kind_from_def_id(fn_trait_id).is_some()
{
// Do not suggest `F: FnOnce() + Clone`.
false

View File

@@ -2,8 +2,7 @@
use rustc_abi::ExternAbi;
use rustc_errors::DiagMessage;
use rustc_hir::{self as hir};
use rustc_middle::bug;
use rustc_hir::{self as hir, LangItem};
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefId;
@@ -173,23 +172,22 @@ pub(crate) fn check_intrinsic_type(
ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv),
]);
let mk_va_list_ty = |mutbl| {
tcx.lang_items().va_list().map(|did| {
let region = ty::Region::new_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon },
);
let env_region = ty::Region::new_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion {
var: ty::BoundVar::from_u32(2),
kind: ty::BoundRegionKind::ClosureEnv,
},
);
let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]);
(Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty)
})
let did = tcx.require_lang_item(LangItem::VaList, Some(span));
let region = ty::Region::new_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon },
);
let env_region = ty::Region::new_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion {
var: ty::BoundVar::from_u32(2),
kind: ty::BoundRegionKind::ClosureEnv,
},
);
let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]);
(Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty)
};
let (n_tps, n_lts, n_cts, inputs, output, safety) = if name_str.starts_with("atomic_") {
@@ -548,23 +546,17 @@ pub(crate) fn check_intrinsic_type(
)
}
sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) {
Some((va_list_ref_ty, _)) => (0, 0, vec![va_list_ref_ty], tcx.types.unit),
None => bug!("`va_list` lang item needed for C-variadic intrinsics"),
},
sym::va_start | sym::va_end => {
(0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit)
}
sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) {
Some((va_list_ref_ty, va_list_ty)) => {
let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty);
(0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit)
}
None => bug!("`va_list` lang item needed for C-variadic intrinsics"),
},
sym::va_copy => {
let (va_list_ref_ty, va_list_ty) = mk_va_list_ty(hir::Mutability::Not);
let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty);
(0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit)
}
sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) {
Some((va_list_ref_ty, _)) => (1, 0, vec![va_list_ref_ty], param(0)),
None => bug!("`va_list` lang item needed for C-variadic intrinsics"),
},
sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)),
sym::nontemporal_store => {
(1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit)

View File

@@ -750,7 +750,7 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
ObligationCause::misc(impl_span, checker.impl_def_id),
param_env,
nontrivial_field_ty,
tcx.lang_items().pointer_like().unwrap(),
tcx.require_lang_item(LangItem::PointerLike, Some(impl_span)),
);
// FIXME(dyn-star): We should regionck this implementation.
if ocx.select_all_or_error().is_empty() {

View File

@@ -37,7 +37,7 @@ pub(crate) fn check_legal_trait_for_method_call(
body_id: DefId,
) -> Result<(), ErrorGuaranteed> {
if tcx.is_lang_item(trait_id, LangItem::Drop)
&& tcx.lang_items().fallback_surface_drop_fn() != Some(body_id)
&& !tcx.is_lang_item(body_id, LangItem::FallbackSurfaceDrop)
{
let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) {
errors::ExplicitDestructorCallSugg::Snippet {

View File

@@ -925,7 +925,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let detect_dotdot = |err: &mut Diag<'_>, ty: Ty<'_>, expr: &hir::Expr<'_>| {
if let ty::Adt(adt, _) = ty.kind()
&& self.tcx().lang_items().get(hir::LangItem::RangeFull) == Some(adt.did())
&& self.tcx().is_lang_item(adt.did(), hir::LangItem::RangeFull)
&& let hir::ExprKind::Struct(
hir::QPath::LangItem(hir::LangItem::RangeFull, _),
[],

View File

@@ -1457,15 +1457,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => (None, None),
};
let ranges = &[
self.tcx.lang_items().range_struct(),
self.tcx.lang_items().range_from_struct(),
self.tcx.lang_items().range_to_struct(),
self.tcx.lang_items().range_full_struct(),
self.tcx.lang_items().range_inclusive_struct(),
self.tcx.lang_items().range_to_inclusive_struct(),
];
if type_def_id != None && ranges.contains(&type_def_id) {
let is_range = match type_def_id.and_then(|id| self.tcx.as_lang_item(id)) {
Some(
LangItem::Range
| LangItem::RangeFrom
| LangItem::RangeTo
| LangItem::RangeFull
| LangItem::RangeInclusiveStruct
| LangItem::RangeToInclusive,
) => true,
_ => false,
};
if is_range {
if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
let msg = "constants only support matching by type, \
if you meant to match against a range of values, \

View File

@@ -2,9 +2,8 @@ use std::cell::RefCell;
use std::ops::Deref;
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{HirId, HirIdMap};
use rustc_hir::{self as hir, HirId, HirIdMap, LangItem};
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_middle::span_bug;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode};
@@ -137,7 +136,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
obligation.predicate.kind().skip_binder()
&& let Some(ty) =
self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
&& self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id)
&& !self.tcx.is_lang_item(tpred.trait_ref.def_id, LangItem::Sized)
{
let new_self_ty = self.tcx.types.unit;

View File

@@ -1,4 +1,4 @@
use rustc_hir as hir;
use rustc_hir::{self as hir, LangItem};
use rustc_middle::ty::{self, Ty};
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_session::{declare_lint, impl_lint_pass};
@@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter {
let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
return;
};
if Some(method_def_id) != cx.tcx.lang_items().into_iter_fn() {
if !cx.tcx.is_lang_item(method_def_id, LangItem::IntoIterIntoIter) {
return;
}

View File

@@ -35,11 +35,10 @@ impl<'tcx> TyCtxt<'tcx> {
/// returns a corresponding [`ty::ClosureKind`].
/// For any other [`DefId`] return `None`.
pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
let items = self.lang_items();
match Some(id) {
x if x == items.fn_trait() => Some(ty::ClosureKind::Fn),
x if x == items.fn_mut_trait() => Some(ty::ClosureKind::FnMut),
x if x == items.fn_once_trait() => Some(ty::ClosureKind::FnOnce),
match self.as_lang_item(id)? {
LangItem::Fn => Some(ty::ClosureKind::Fn),
LangItem::FnMut => Some(ty::ClosureKind::FnMut),
LangItem::FnOnce => Some(ty::ClosureKind::FnOnce),
_ => None,
}
}
@@ -48,11 +47,10 @@ impl<'tcx> TyCtxt<'tcx> {
/// returns a corresponding [`ty::ClosureKind`].
/// For any other [`DefId`] return `None`.
pub fn async_fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
let items = self.lang_items();
match Some(id) {
x if x == items.async_fn_trait() => Some(ty::ClosureKind::Fn),
x if x == items.async_fn_mut_trait() => Some(ty::ClosureKind::FnMut),
x if x == items.async_fn_once_trait() => Some(ty::ClosureKind::FnOnce),
match self.as_lang_item(id)? {
LangItem::AsyncFn => Some(ty::ClosureKind::Fn),
LangItem::AsyncFnMut => Some(ty::ClosureKind::FnMut),
LangItem::AsyncFnOnce => Some(ty::ClosureKind::FnOnce),
_ => None,
}
}

View File

@@ -1774,9 +1774,7 @@ impl<'tcx> Ty<'tcx> {
match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) {
Ok(metadata_ty) => metadata_ty,
Err(tail_ty) => {
let Some(metadata_def_id) = tcx.lang_items().metadata_type() else {
bug!("No metadata_type lang item while looking at {self:?}")
};
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
Ty::new_projection(tcx, metadata_def_id, [tail_ty])
}
}

View File

@@ -3,6 +3,7 @@ use std::ops::ControlFlow;
use rustc_data_structures::graph::iterate::{
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
};
use rustc_hir::LangItem;
use rustc_hir::def::DefKind;
use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Terminator, TerminatorKind};
use rustc_middle::ty::{self, GenericArg, GenericArgs, Instance, Ty, TyCtxt};
@@ -44,8 +45,7 @@ impl<'tcx> MirLint<'tcx> for CheckDropRecursion {
if let DefKind::AssocFn = tcx.def_kind(def_id)
&& let Some(trait_ref) =
tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id))
&& let Some(drop_trait) = tcx.lang_items().drop_trait()
&& drop_trait == trait_ref.instantiate_identity().def_id
&& tcx.is_lang_item(trait_ref.instantiate_identity().def_id, LangItem::Drop)
// avoid erroneous `Drop` impls from causing ICEs below
&& let sig = tcx.fn_sig(def_id).instantiate_identity()
&& sig.inputs().skip_binder().len() == 1

View File

@@ -223,7 +223,7 @@ where
match mono_item.instantiation_mode(cx.tcx) {
InstantiationMode::GloballyShared { .. } => {}
InstantiationMode::LocalCopy => {
if Some(mono_item.def_id()) != cx.tcx.lang_items().start_fn() {
if !cx.tcx.is_lang_item(mono_item.def_id(), LangItem::Start) {
continue;
}
}

View File

@@ -81,9 +81,7 @@ pub fn call_kind<'tcx>(
}
});
let fn_call = parent.and_then(|p| {
lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
});
let fn_call = parent.filter(|&p| tcx.fn_trait_kind_from_def_id(p).is_some());
let operator = if !from_hir_call && let Some(p) = parent {
lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)

View File

@@ -146,7 +146,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&& leaf_trait_predicate.def_id() != root_pred.def_id()
// The root trait is not `Unsize`, as to avoid talking about it in
// `tests/ui/coercion/coerce-issue-49593-box-never.rs`.
&& Some(root_pred.def_id()) != self.tcx.lang_items().unsize_trait()
&& !self.tcx.is_lang_item(root_pred.def_id(), LangItem::Unsize)
{
(
self.resolve_vars_if_possible(
@@ -2274,10 +2274,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// auto-traits or fundamental traits that might not be exactly what
// the user might expect to be presented with. Instead this is
// useful for less general traits.
if peeled
&& !self.tcx.trait_is_auto(def_id)
&& !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
{
if peeled && !self.tcx.trait_is_auto(def_id) && self.tcx.as_lang_item(def_id).is_none() {
let impl_candidates = self.find_similar_impl_candidates(trait_pred);
self.report_similar_impl_candidates(
&impl_candidates,
@@ -3013,8 +3010,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// This shouldn't be common unless manually implementing one of the
// traits manually, but don't make it more confusing when it does
// happen.
if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait() && not_tupled
{
if !self.tcx.is_lang_item(expected_trait_ref.def_id, LangItem::Coroutine) && not_tupled {
return Ok(self.report_and_explain_type_error(
TypeTrace::trait_refs(&obligation.cause, expected_trait_ref, found_trait_ref),
obligation.param_env,

View File

@@ -3844,12 +3844,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
);
if let ty::PredicateKind::Clause(clause) = failed_pred.kind().skip_binder()
&& let ty::ClauseKind::Trait(pred) = clause
&& [
tcx.lang_items().fn_once_trait(),
tcx.lang_items().fn_mut_trait(),
tcx.lang_items().fn_trait(),
]
.contains(&Some(pred.def_id()))
&& tcx.fn_trait_kind_from_def_id(pred.def_id()).is_some()
{
if let [stmt, ..] = block.stmts
&& let hir::StmtKind::Semi(value) = stmt.kind

View File

@@ -1,5 +1,6 @@
use std::ops::ControlFlow;
use rustc_hir::LangItem;
use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
use rustc_infer::traits::{
@@ -452,9 +453,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
// We do this as a separate loop so that we do not choose to tell the user about some nested
// goal before we encounter a `T: FnPtr` nested goal.
for nested_goal in &nested_goals {
if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait()
&& let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
&& poly_trait_pred.def_id() == fn_ptr_trait
if let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
&& tcx.is_lang_item(poly_trait_pred.def_id(), LangItem::FnPtrTrait)
&& let Err(NoSolution) = nested_goal.result()
{
return ControlFlow::Break(self.obligation.clone());

View File

@@ -965,36 +965,38 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let tcx = selcx.tcx();
let lang_items = selcx.tcx().lang_items();
if [
lang_items.coroutine_trait(),
lang_items.future_trait(),
lang_items.iterator_trait(),
lang_items.async_iterator_trait(),
lang_items.fn_trait(),
lang_items.fn_mut_trait(),
lang_items.fn_once_trait(),
lang_items.async_fn_trait(),
lang_items.async_fn_mut_trait(),
lang_items.async_fn_once_trait(),
]
.contains(&Some(trait_ref.def_id))
{
true
} else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFnKindHelper) {
// FIXME(async_closures): Validity constraints here could be cleaned up.
if obligation.predicate.args.type_at(0).is_ty_var()
|| obligation.predicate.args.type_at(4).is_ty_var()
|| obligation.predicate.args.type_at(5).is_ty_var()
{
candidate_set.mark_ambiguous();
true
} else {
obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some()
&& obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some()
match selcx.tcx().as_lang_item(trait_ref.def_id) {
Some(
LangItem::Coroutine
| LangItem::Future
| LangItem::Iterator
| LangItem::AsyncIterator
| LangItem::Fn
| LangItem::FnMut
| LangItem::FnOnce
| LangItem::AsyncFn
| LangItem::AsyncFnMut
| LangItem::AsyncFnOnce,
) => true,
Some(LangItem::AsyncFnKindHelper) => {
// FIXME(async_closures): Validity constraints here could be cleaned up.
if obligation.predicate.args.type_at(0).is_ty_var()
|| obligation.predicate.args.type_at(4).is_ty_var()
|| obligation.predicate.args.type_at(5).is_ty_var()
{
candidate_set.mark_ambiguous();
true
} else {
obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some()
&& obligation
.predicate
.args
.type_at(1)
.to_opt_closure_kind()
.is_some()
}
}
} else if tcx.is_lang_item(trait_ref.def_id, LangItem::DiscriminantKind) {
match self_ty.kind() {
Some(LangItem::DiscriminantKind) => match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
@@ -1031,9 +1033,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Placeholder(..)
| ty::Infer(..)
| ty::Error(_) => false,
}
} else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncDestruct) {
match self_ty.kind() {
},
Some(LangItem::AsyncDestruct) => match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
@@ -1068,101 +1069,104 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Placeholder(..)
| ty::Infer(_)
| ty::Error(_) => false,
}
} else if tcx.is_lang_item(trait_ref.def_id, LangItem::PointeeTrait) {
let tail = selcx.tcx().struct_tail_raw(
self_ty,
|ty| {
// We throw away any obligations we get from this, since we normalize
// and confirm these obligations once again during confirmation
normalize_with_depth(
selcx,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
ty,
)
.value
},
|| {},
);
},
Some(LangItem::PointeeTrait) => {
let tail = selcx.tcx().struct_tail_raw(
self_ty,
|ty| {
// We throw away any obligations we get from this, since we normalize
// and confirm these obligations once again during confirmation
normalize_with_depth(
selcx,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
ty,
)
.value
},
|| {},
);
match tail.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Dynamic(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Never
// Extern types have unit metadata, according to RFC 2850
| ty::Foreign(_)
// If returned by `struct_tail` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
// If returned by `struct_tail` this is the empty tuple.
| ty::Tuple(..)
// Integers and floats are always Sized, and so have unit type metadata.
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..))
// This happens if we reach the recursion limit when finding the struct tail.
| ty::Error(..) => true,
match tail.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Dynamic(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Never
// Extern types have unit metadata, according to RFC 2850
| ty::Foreign(_)
// If returned by `struct_tail` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
// If returned by `struct_tail` this is the empty tuple.
| ty::Tuple(..)
// Integers and floats are always Sized, and so have unit type metadata.
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..))
// This happens if we reach the recursion limit when finding the struct tail.
| ty::Error(..) => true,
// We normalize from `Wrapper<Tail>::Metadata` to `Tail::Metadata` if able.
// Otherwise, type parameters, opaques, and unnormalized projections have
// unit metadata if they're known (e.g. by the param_env) to be sized.
ty::Param(_) | ty::Alias(..)
if self_ty != tail
|| selcx.infcx.predicate_must_hold_modulo_regions(
&obligation.with(
selcx.tcx(),
ty::TraitRef::new(
// We normalize from `Wrapper<Tail>::Metadata` to `Tail::Metadata` if able.
// Otherwise, type parameters, opaques, and unnormalized projections have
// unit metadata if they're known (e.g. by the param_env) to be sized.
ty::Param(_) | ty::Alias(..)
if self_ty != tail
|| selcx.infcx.predicate_must_hold_modulo_regions(
&obligation.with(
selcx.tcx(),
selcx.tcx().require_lang_item(
LangItem::Sized,
Some(obligation.cause.span),
ty::TraitRef::new(
selcx.tcx(),
selcx.tcx().require_lang_item(
LangItem::Sized,
Some(obligation.cause.span),
),
[self_ty],
),
[self_ty],
),
),
) =>
{
true
}
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
// FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
ty::Param(_)
| ty::Alias(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..) => {
if tail.has_infer_types() {
candidate_set.mark_ambiguous();
) =>
{
true
}
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
// FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
ty::Param(_)
| ty::Alias(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..) => {
if tail.has_infer_types() {
candidate_set.mark_ambiguous();
}
false
}
false
}
}
} else if tcx.trait_is_auto(trait_ref.def_id) {
tcx.dcx().span_delayed_bug(
tcx.def_span(obligation.predicate.def_id),
"associated types not allowed on auto traits",
);
false
} else {
bug!("unexpected builtin trait with associated type: {trait_ref:?}")
_ if tcx.trait_is_auto(trait_ref.def_id) => {
tcx.dcx().span_delayed_bug(
tcx.def_span(obligation.predicate.def_id),
"associated types not allowed on auto traits",
);
false
}
_ => {
bug!("unexpected builtin trait with associated type: {trait_ref:?}")
}
}
}
ImplSource::Param(..) => {