Auto merge of #139845 - Zalathar:rollup-u5u5y1v, r=Zalathar

Rollup of 17 pull requests

Successful merges:

 - #138374 (Enable contracts for const functions)
 - #138380 (ci: add runners for vanilla LLVM 20)
 - #138393 (Allow const patterns of matches to contain pattern types)
 - #139517 (std: sys: process: uefi: Use NULL stdin by default)
 - #139554 (std: add Output::exit_ok)
 - #139660 (compiletest: Add an experimental new executor to replace libtest)
 - #139669 (Overhaul `AssocItem`)
 - #139671 (Proc macro span API redesign: Replace proc_macro::SourceFile by Span::{file, local_file})
 - #139750 (std/thread: Use default stack size from menuconfig for NuttX)
 - #139772 (Remove `hir::Map`)
 - #139785 (Let CStrings be either 1 or 2 byte aligned.)
 - #139789 (do not unnecessarily leak auto traits in item bounds)
 - #139791 (drop global where-bounds before merging candidates)
 - #139798 (normalize: prefer `ParamEnv` over `AliasBound` candidates)
 - #139822 (Fix: Map EOPNOTSUPP to ErrorKind::Unsupported on Unix)
 - #139833 (Fix some HIR pretty-printing problems)
 - #139836 (Basic tests of MPMC receiver cloning)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-04-15 08:02:23 +00:00
commit f433fa46b0
173 changed files with 2499 additions and 994 deletions

View File

@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.delegation_fn_sigs
.get(&local_def_id)
.is_some_and(|sig| sig.has_self),
None => self.tcx.associated_item(def_id).fn_has_self_parameter,
None => self.tcx.associated_item(def_id).is_method(),
},
_ => span_bug!(span, "unexpected DefKind for delegation item"),
}

View File

@ -399,12 +399,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
expr: &'hir hir::Expr<'hir>,
span: Span,
check_ident: Ident,
check_hir_id: HirId,
cond_ident: Ident,
cond_hir_id: HirId,
) -> &'hir hir::Expr<'hir> {
let checker_fn = self.expr_ident(span, check_ident, check_hir_id);
let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
self.expr_call(span, checker_fn, std::slice::from_ref(expr))
let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
let call_expr = self.expr_call_lang_item_fn_mut(
span,
hir::LangItem::ContractCheckEnsures,
arena_vec![self; *cond_fn, *expr],
);
self.arena.alloc(call_expr)
}
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {

View File

@ -1206,8 +1206,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
let precond = if let Some(req) = &contract.requires {
// Lower the precondition check intrinsic.
let lowered_req = this.lower_expr_mut(&req);
let req_span = this.mark_span_with_reason(
DesugaringKind::Contract,
lowered_req.span,
None,
);
let precond = this.expr_call_lang_item_fn_mut(
req.span,
req_span,
hir::LangItem::ContractCheckRequires,
&*arena_vec![this; lowered_req],
);
@ -1217,6 +1222,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
};
let (postcond, body) = if let Some(ens) = &contract.ensures {
let ens_span = this.lower_span(ens.span);
let ens_span =
this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None);
// Set up the postcondition `let` statement.
let check_ident: Ident =
Ident::from_str_and_span("__ensures_checker", ens_span);

View File

@ -647,7 +647,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
&& tc.polarity() == ty::PredicatePolarity::Positive
&& supertrait_def_ids(tcx, tc.def_id())
.flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
.any(|item| item.fn_has_self_parameter)
.any(|item| item.is_method())
})
}) {
return None;

View File

@ -1557,11 +1557,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
CastKind::Transmute => {
span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
);
let ty_from = op.ty(self.body, tcx);
match ty_from.kind() {
ty::Pat(base, _) if base == ty => {}
_ => span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
),
}
}
}
}

View File

@ -1,6 +1,6 @@
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use rustc_hir::LangItem;
use rustc_middle::ty::{AssocKind, GenericArg};
use rustc_middle::ty::{AssocTag, GenericArg};
use rustc_session::config::EntryFnType;
use rustc_span::{DUMMY_SP, Ident};
@ -107,7 +107,7 @@ pub(crate) fn maybe_create_entry_wrapper(
.find_by_ident_and_kind(
tcx,
Ident::from_str("report"),
AssocKind::Fn,
AssocTag::Fn,
termination_trait,
)
.unwrap();

View File

@ -1,5 +1,4 @@
use std::ops::{Bound, Range};
use std::sync::Arc;
use ast::token::IdentIsRaw;
use pm::bridge::{
@ -18,7 +17,7 @@ use rustc_parse::parser::Parser;
use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
use rustc_session::parse::ParseSess;
use rustc_span::def_id::CrateNum;
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span, Symbol, sym};
use rustc_span::{BytePos, FileName, Pos, Span, Symbol, sym};
use smallvec::{SmallVec, smallvec};
use crate::base::ExtCtxt;
@ -458,7 +457,6 @@ impl<'a, 'b> Rustc<'a, 'b> {
impl server::Types for Rustc<'_, '_> {
type FreeFunctions = FreeFunctions;
type TokenStream = TokenStream;
type SourceFile = Arc<SourceFile>;
type Span = Span;
type Symbol = Symbol;
}
@ -664,28 +662,6 @@ impl server::TokenStream for Rustc<'_, '_> {
}
}
impl server::SourceFile for Rustc<'_, '_> {
fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
Arc::ptr_eq(file1, file2)
}
fn path(&mut self, file: &Self::SourceFile) -> String {
match &file.name {
FileName::Real(name) => name
.local_path()
.expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
.to_str()
.expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
.to_string(),
_ => file.name.prefer_local().to_string(),
}
}
fn is_real(&mut self, file: &Self::SourceFile) -> bool {
file.is_real_file()
}
}
impl server::Span for Rustc<'_, '_> {
fn debug(&mut self, span: Self::Span) -> String {
if self.ecx.ecfg.span_debug {
@ -695,8 +671,29 @@ impl server::Span for Rustc<'_, '_> {
}
}
fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
self.psess().source_map().lookup_char_pos(span.lo()).file
fn file(&mut self, span: Self::Span) -> String {
self.psess()
.source_map()
.lookup_char_pos(span.lo())
.file
.name
.prefer_remapped_unconditionaly()
.to_string()
}
fn local_file(&mut self, span: Self::Span) -> Option<String> {
self.psess()
.source_map()
.lookup_char_pos(span.lo())
.file
.name
.clone()
.into_local_path()
.map(|p| {
p.to_str()
.expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
.to_string()
})
}
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {

View File

@ -25,7 +25,10 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf {
path.to_path_buf()
} else {
// `/a/b/c/foo/bar.rs` contains the current macro invocation
#[cfg(bootstrap)]
let mut source_file_path = span.source_file().path();
#[cfg(not(bootstrap))]
let mut source_file_path = span.local_file().unwrap();
// `/a/b/c/foo/`
source_file_path.pop();
// `/a/b/c/foo/../locales/en-US/example.ftl`

View File

@ -6,7 +6,7 @@
//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
//! - Example: find all items with a `#[foo]` attribute on them.
//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir_item*(id)` to filter and
//! access actual item-like thing, respectively.
//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
//! the hir_owners themselves or not.

View File

@ -442,6 +442,8 @@ language_item_table! {
DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None;
DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None;
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None;
}
/// The requirement imposed on the generics of a lang item

View File

@ -443,13 +443,13 @@ fn best_definition_site_of_opaque<'tcx>(
let impl_def_id = tcx.local_parent(parent);
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
match assoc.kind {
ty::AssocKind::Const | ty::AssocKind::Fn => {
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
{
return Some(span);
}
}
ty::AssocKind::Type => {}
ty::AssocKind::Type { .. } => {}
}
}
@ -740,7 +740,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
for &assoc_item in assoc_items.in_definition_order() {
match assoc_item.kind {
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => {
let trait_args = GenericArgs::identity_for_item(tcx, def_id);
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx,
@ -942,7 +942,7 @@ fn check_impl_items_against_trait<'tcx>(
if res.is_ok() {
match ty_impl_item.kind {
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
tcx,
ty_impl_item,
@ -952,8 +952,8 @@ fn check_impl_items_against_trait<'tcx>(
.instantiate_identity(),
);
}
ty::AssocKind::Const => {}
ty::AssocKind::Type => {}
ty::AssocKind::Const { .. } => {}
ty::AssocKind::Type { .. } => {}
}
}

View File

@ -43,9 +43,11 @@ pub(super) fn compare_impl_item(
debug!(?impl_trait_ref);
match impl_item.kind {
ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Const { .. } => {
compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref)
}
}
}
@ -651,7 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
cause.span,
E0053,
"method `{}` has an incompatible return type for trait",
trait_m.name
trait_m.name()
);
infcx.err_ctxt().note_type_err(
&mut diag,
@ -1029,11 +1031,11 @@ fn report_trait_method_mismatch<'tcx>(
impl_err_span,
E0053,
"method `{}` has an incompatible type for trait",
trait_m.name
trait_m.name()
);
match &terr {
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
if trait_m.fn_has_self_parameter =>
if trait_m.is_method() =>
{
let ty = trait_sig.inputs()[0];
let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty());
@ -1252,7 +1254,7 @@ fn compare_self_type<'tcx>(
get_self_string(self_arg_ty, can_eq_self)
};
match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
match (trait_m.is_method(), impl_m.is_method()) {
(false, false) | (true, true) => {}
(false, true) => {
@ -1263,14 +1265,14 @@ fn compare_self_type<'tcx>(
impl_m_span,
E0185,
"method `{}` has a `{}` declaration in the impl, but not in the trait",
trait_m.name,
trait_m.name(),
self_descr
);
err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
err.span_label(span, format!("trait method declared without `{self_descr}`"));
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
}
return Err(err.emit_unless(delay));
}
@ -1283,14 +1285,14 @@ fn compare_self_type<'tcx>(
impl_m_span,
E0186,
"method `{}` has a `{}` declaration in the trait, but not in the impl",
trait_m.name,
trait_m.name(),
self_descr
);
err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
err.span_label(span, format!("`{self_descr}` used in trait"));
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
}
return Err(err.emit_unless(delay));
@ -1360,7 +1362,7 @@ fn compare_number_of_generics<'tcx>(
let mut err_occurred = None;
for (kind, trait_count, impl_count) in matchings {
if impl_count != trait_count {
let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| {
let mut spans = generics
.params
.iter()
@ -1370,7 +1372,7 @@ fn compare_number_of_generics<'tcx>(
} => {
// A fn can have an arbitrary number of extra elided lifetimes for the
// same signature.
!matches!(kind, ty::AssocKind::Fn)
!item.is_fn()
}
_ => true,
})
@ -1383,7 +1385,7 @@ fn compare_number_of_generics<'tcx>(
};
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
let trait_item = tcx.hir_expect_trait_item(def_id);
let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
let arg_spans: Vec<Span> = arg_spans(&trait_, trait_item.generics);
let impl_trait_spans: Vec<Span> = trait_item
.generics
.params
@ -1409,7 +1411,7 @@ fn compare_number_of_generics<'tcx>(
_ => None,
})
.collect();
let spans = arg_spans(impl_.kind, impl_item.generics);
let spans = arg_spans(&impl_, impl_item.generics);
let span = spans.first().copied();
let mut err = tcx.dcx().struct_span_err(
@ -1418,7 +1420,7 @@ fn compare_number_of_generics<'tcx>(
"{} `{}` has {} {kind} parameter{} but its trait \
declaration has {} {kind} parameter{}",
item_kind,
trait_.name,
trait_.name(),
impl_count,
pluralize!(impl_count),
trait_count,
@ -1509,7 +1511,7 @@ fn compare_number_of_method_arguments<'tcx>(
impl_span,
E0050,
"method `{}` has {} but the declaration in trait `{}` has {}",
trait_m.name,
trait_m.name(),
potentially_plural_count(impl_number_args, "parameter"),
tcx.def_path_str(trait_m.def_id),
trait_number_args
@ -1524,7 +1526,7 @@ fn compare_number_of_method_arguments<'tcx>(
),
);
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
}
err.span_label(
@ -1578,7 +1580,7 @@ fn compare_synthetic_generics<'tcx>(
impl_span,
E0643,
"method `{}` has incompatible signature for trait",
trait_m.name
trait_m.name()
);
err.span_label(trait_span, "declaration in trait here");
if impl_synthetic {
@ -1700,7 +1702,7 @@ fn compare_generic_param_kinds<'tcx>(
trait_item: ty::AssocItem,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
assert_eq!(impl_item.kind, trait_item.kind);
assert_eq!(impl_item.as_tag(), trait_item.as_tag());
let ty_const_params_of = |def_id| {
tcx.generics_of(def_id).own_params.iter().filter(|param| {
@ -1738,7 +1740,7 @@ fn compare_generic_param_kinds<'tcx>(
E0053,
"{} `{}` has an incompatible generic parameter for trait `{}`",
impl_item.descr(),
trait_item.name,
trait_item.name(),
&tcx.def_path_str(tcx.parent(trait_item.def_id))
);
@ -1874,7 +1876,7 @@ fn compare_const_predicate_entailment<'tcx>(
cause.span,
E0326,
"implemented const `{}` has an incompatible type for trait",
trait_ct.name
trait_ct.name()
);
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
@ -2232,16 +2234,19 @@ fn param_env_with_gat_bounds<'tcx>(
// of the RPITITs associated with the same body. This is because checking
// the item bounds of RPITITs often involves nested RPITITs having to prove
// bounds about themselves.
let impl_tys_to_install = match impl_ty.opt_rpitit_info {
None => vec![impl_ty],
Some(
ty::ImplTraitInTraitData::Impl { fn_def_id }
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
) => tcx
let impl_tys_to_install = match impl_ty.kind {
ty::AssocKind::Type {
data:
ty::AssocTypeData::Rpitit(
ty::ImplTraitInTraitData::Impl { fn_def_id }
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
),
} => tcx
.associated_types_for_impl_traits_in_associated_fn(fn_def_id)
.iter()
.map(|def_id| tcx.associated_item(*def_id))
.collect(),
_ => vec![impl_ty],
};
for impl_ty in impl_tys_to_install {

View File

@ -217,15 +217,11 @@ pub(crate) fn check_intrinsic_type(
};
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
} else if intrinsic_name == sym::contract_check_ensures {
// contract_check_ensures::<'a, Ret, C>(&'a Ret, C)
// where C: impl Fn(&'a Ret) -> bool,
// contract_check_ensures::<Ret, C>(Ret, C) -> Ret
// where C: for<'a> Fn(&'a Ret) -> bool,
//
// so: two type params, one lifetime param, 0 const params, two inputs, no return
let p = generics.param_at(0, tcx);
let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data());
let ref_ret = Ty::new_imm_ref(tcx, r, param(1));
(2, 1, 0, vec![ref_ret, param(2)], tcx.types.unit, hir::Safety::Safe)
// so: two type params, 0 lifetime param, 0 const params, two inputs, no return
(2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe)
} else {
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
let (n_tps, n_cts, inputs, output) = match intrinsic_name {

View File

@ -205,7 +205,7 @@ fn missing_items_err(
let missing_items_msg = missing_items
.clone()
.map(|trait_item| trait_item.name.to_string())
.map(|trait_item| trait_item.name().to_string())
.collect::<Vec<_>>()
.join("`, `");
@ -236,7 +236,7 @@ fn missing_items_err(
let code = format!("{padding}{snippet}\n{padding}");
if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
missing_trait_item_label
.push(errors::MissingTraitItemLabel { span, item: trait_item.name });
.push(errors::MissingTraitItemLabel { span, item: trait_item.name() });
missing_trait_item.push(errors::MissingTraitItemSuggestion {
span: sugg_sp,
code,
@ -407,14 +407,14 @@ fn fn_sig_suggestion<'tcx>(
.enumerate()
.map(|(i, ty)| {
Some(match ty.kind() {
ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
ty::Ref(reg, ref_ty, mutability) if i == 0 => {
let reg = format!("{reg} ");
let reg = match &reg[..] {
"'_ " | " " => "",
reg => reg,
};
if assoc.fn_has_self_parameter {
if assoc.is_method() {
match ref_ty.kind() {
ty::Param(param) if param.name == kw::SelfUpper => {
format!("&{}{}self", reg, mutability.prefix_str())
@ -427,7 +427,7 @@ fn fn_sig_suggestion<'tcx>(
}
}
_ => {
if assoc.fn_has_self_parameter && i == 0 {
if assoc.is_method() && i == 0 {
format!("self: {ty}")
} else {
format!("_: {ty}")
@ -489,7 +489,7 @@ fn suggestion_signature<'tcx>(
);
match assoc.kind {
ty::AssocKind::Fn => fn_sig_suggestion(
ty::AssocKind::Fn { .. } => fn_sig_suggestion(
tcx,
tcx.liberate_late_bound_regions(
assoc.def_id,
@ -499,14 +499,14 @@ fn suggestion_signature<'tcx>(
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
assoc,
),
ty::AssocKind::Type => {
ty::AssocKind::Type { .. } => {
let (generics, where_clauses) = bounds_from_generic_predicates(
tcx,
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
);
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name)
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
}
ty::AssocKind::Const => {
ty::AssocKind::Const { name } => {
let ty = tcx.type_of(assoc.def_id).instantiate_identity();
let val = tcx
.infer_ctxt()
@ -514,7 +514,7 @@ fn suggestion_signature<'tcx>(
.err_ctxt()
.ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
.unwrap_or_else(|| "value".to_string());
format!("const {}: {} = {};", assoc.name, ty, val)
format!("const {}: {} = {};", name, ty, val)
}
}
}

View File

@ -408,7 +408,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
let gat_def_id = gat_item.def_id.expect_local();
let gat_item = tcx.associated_item(gat_def_id);
// If this item is not an assoc ty, or has no args, then it's not a GAT
if gat_item.kind != ty::AssocKind::Type {
if !gat_item.is_type() {
continue;
}
let gat_generics = tcx.generics_of(gat_def_id);
@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
let item_required_bounds = match tcx.associated_item(item_def_id).kind {
// In our example, this corresponds to `into_iter` method
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
// For methods, we check the function signature's return type for any GATs
// to constrain. In the `into_iter` case, we see that the return type
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
@ -453,7 +453,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
)
}
// In our example, this corresponds to the `Iter` and `Item` associated types
ty::AssocKind::Type => {
ty::AssocKind::Type { .. } => {
// If our associated item is a GAT with missing bounds, add them to
// the param-env here. This allows this GAT to propagate missing bounds
// to other GATs.
@ -474,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
gat_generics,
)
}
ty::AssocKind::Const => None,
ty::AssocKind::Const { .. } => None,
};
if let Some(item_required_bounds) = item_required_bounds {
@ -1076,7 +1076,7 @@ fn check_associated_item(
};
match item.kind {
ty::AssocKind::Const => {
ty::AssocKind::Const { .. } => {
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
@ -1089,7 +1089,7 @@ fn check_associated_item(
);
Ok(())
}
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
let hir_sig = sig_if_method.expect("bad signature for method");
check_fn_or_method(
@ -1101,7 +1101,7 @@ fn check_associated_item(
);
check_method_receiver(wfcx, hir_sig, item, self_ty)
}
ty::AssocKind::Type => {
ty::AssocKind::Type { .. } => {
if let ty::AssocItemContainer::Trait = item.container {
check_associated_type_bounds(wfcx, item, span)
}
@ -1716,7 +1716,7 @@ fn check_method_receiver<'tcx>(
) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx();
if !method.fn_has_self_parameter {
if !method.is_method() {
return Ok(());
}

View File

@ -51,7 +51,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
for &item1 in impl_items1.in_definition_order() {
let collision = impl_items2
.filter_by_name_unhygienic(item1.name)
.filter_by_name_unhygienic(item1.name())
.any(|&item2| self.compare_hygienically(item1, item2));
if collision {
@ -64,7 +64,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool {
// Symbols and namespace match, compare hygienically.
item1.kind.namespace() == item2.kind.namespace()
item1.namespace() == item2.namespace()
&& item1.ident(self.tcx).normalize_to_macros_2_0()
== item2.ident(self.tcx).normalize_to_macros_2_0()
}
@ -113,7 +113,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
let mut res = Ok(());
for &item1 in impl_items1.in_definition_order() {
let collision = impl_items2
.filter_by_name_unhygienic(item1.name)
.filter_by_name_unhygienic(item1.name())
.find(|&&item2| self.compare_hygienically(item1, item2));
if let Some(item2) = collision {
@ -230,11 +230,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
let mut ids = impl_items
.in_definition_order()
.filter_map(|item| {
let entry = connected_region_ids.entry(item.name);
let entry = connected_region_ids.entry(item.name());
if let IndexEntry::Occupied(e) = &entry {
Some(*e.get())
} else {
idents_to_add.push(item.name);
idents_to_add.push(item.name());
None
}
})

View File

@ -44,7 +44,7 @@ use rustc_trait_selection::traits::ObligationCtxt;
use tracing::{debug, instrument};
use crate::errors;
use crate::hir_ty_lowering::errors::assoc_kind_str;
use crate::hir_ty_lowering::errors::assoc_tag_str;
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
pub(crate) mod dump;
@ -450,7 +450,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
item_def_id: DefId,
item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
@ -525,7 +525,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
inferred_sugg,
bound,
mpart_sugg,
what: assoc_kind_str(kind),
what: assoc_tag_str(assoc_tag),
}))
}
}

View File

@ -1811,7 +1811,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
type_def_id,
constraint.ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
) {
bound_vars.extend(
self.tcx
@ -1843,7 +1843,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
type_def_id,
constraint.ident,
ty::AssocKind::Type,
ty::AssocTag::Type,
)
.map(|(bound_vars, _)| bound_vars);
self.with(scope, |this| {
@ -1875,13 +1875,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
def_id: DefId,
assoc_ident: Ident,
assoc_kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
let trait_defines_associated_item_named = |trait_def_id: DefId| {
tcx.associated_items(trait_def_id).find_by_ident_and_kind(
tcx,
assoc_ident,
assoc_kind,
assoc_tag,
trait_def_id,
)
};
@ -1894,8 +1894,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let Some((def_id, bound_vars)) = stack.pop() else {
break None;
};
// See issue #83753. If someone writes an associated type on a non-trait, just treat it as
// there being no supertrait HRTBs.
// See issue #83753. If someone writes an associated type on a non-trait, just treat it
// as there being no supertrait HRTBs.
match tcx.def_kind(def_id) {
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
_ => break None,
@ -2067,7 +2067,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
trait_def_id,
item_segment.ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
)
});
@ -2112,7 +2112,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
trait_def_id,
item_segment.ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
) else {
return;
};

View File

@ -32,9 +32,11 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
let assoc = tcx.associated_item(assoc_id);
match assoc.kind {
ty::AssocKind::Const | ty::AssocKind::Fn => locator.check(assoc_id.expect_local()),
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
locator.check(assoc_id.expect_local())
}
// Associated types don't have bodies, so they can't constrain hidden types
ty::AssocKind::Type => {}
ty::AssocKind::Type { .. } => {}
}
}

View File

@ -4,7 +4,7 @@ use GenericArgsInfo::*;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize};
use rustc_hir as hir;
use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
use rustc_middle::ty::{self as ty, AssocItems, TyCtxt};
use rustc_span::def_id::DefId;
use tracing::debug;
@ -486,13 +486,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
let items: &AssocItems = self.tcx.associated_items(self.def_id);
items
.in_definition_order()
.filter(|item| item.kind == AssocKind::Type)
.filter(|item| item.is_type())
.filter(|item| {
!self
.gen_args
.constraints
.iter()
.any(|constraint| constraint.ident.name == item.name)
.any(|constraint| constraint.ident.name == item.name())
})
.filter(|item| !item.is_impl_trait_in_trait())
.map(|item| self.tcx.item_ident(item.def_id).to_string())

View File

@ -431,16 +431,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) -> Result<(), ErrorGuaranteed> {
let tcx = self.tcx();
let assoc_kind = if constraint.gen_args.parenthesized
let assoc_tag = if constraint.gen_args.parenthesized
== hir::GenericArgsParentheses::ReturnTypeNotation
{
ty::AssocKind::Fn
ty::AssocTag::Fn
} else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } =
constraint.kind
{
ty::AssocKind::Const
ty::AssocTag::Const
} else {
ty::AssocKind::Type
ty::AssocTag::Type
};
// Given something like `U: Trait<T = X>`, we want to produce a predicate like
@ -453,7 +453,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// trait SuperTrait<A> { type T; }
let candidate = if self.probe_trait_that_defines_assoc_item(
trait_ref.def_id(),
assoc_kind,
assoc_tag,
constraint.ident,
) {
// Simple case: The assoc item is defined in the current trait.
@ -464,7 +464,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.probe_single_bound_for_assoc_item(
|| traits::supertraits(tcx, trait_ref),
AssocItemQSelf::Trait(trait_ref.def_id()),
assoc_kind,
assoc_tag,
constraint.ident,
path_span,
Some(constraint),
@ -474,7 +474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc_item = self
.probe_assoc_item(
constraint.ident,
assoc_kind,
assoc_tag,
hir_ref_id,
constraint.span,
candidate.def_id(),
@ -493,7 +493,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
})
.or_insert(constraint.span);
let projection_term = if let ty::AssocKind::Fn = assoc_kind {
let projection_term = if let ty::AssocTag::Fn = assoc_tag {
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
ty::Binder::bind_with_vars(
self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(),
@ -542,7 +542,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
match constraint.kind {
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocTag::Fn = assoc_tag => {
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
span: constraint.span,
}));
@ -679,7 +679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_def_id,
hir_ty.span,
item_segment,
ty::AssocKind::Type,
ty::AssocTag::Type,
);
return Ty::new_error(tcx, guar);
};
@ -771,7 +771,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
},
AssocItemQSelf::SelfTyAlias,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
assoc_ident,
span,
None,
@ -783,7 +783,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(),
qself.span,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
assoc_ident,
span,
)?,
@ -823,7 +823,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_def_id = bound.def_id();
let assoc_ty = self
.probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id)
.probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
.expect("failed to find associated type");
Ok((bound, assoc_ty.def_id))

View File

@ -201,7 +201,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.associated_items(pred.trait_ref.def_id)
.in_definition_order()
// We only care about associated types.
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| item.is_type())
// No RPITITs -- they're not dyn-compatible for now.
.filter(|item| !item.is_impl_trait_in_trait())
// If the associated type has a `where Self: Sized` bound,

View File

@ -116,7 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
all_candidates: impl Fn() -> I,
qself: AssocItemQSelf,
assoc_kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
assoc_ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@ -134,14 +134,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}) {
return self.complain_about_assoc_kind_mismatch(
assoc_item,
assoc_kind,
assoc_tag,
assoc_ident,
span,
constraint,
);
}
let assoc_kind_str = assoc_kind_str(assoc_kind);
let assoc_kind_str = assoc_tag_str(assoc_tag);
let qself_str = qself.to_string(tcx);
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
@ -168,7 +168,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
.filter_map(|item| {
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag {
item.opt_name()
} else {
None
}
})
.collect();
@ -200,7 +204,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.iter()
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
.filter_map(|item| {
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
(!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag)
.then_some(item.name())
})
.collect();
@ -213,7 +218,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.filter(|trait_def_id| {
tcx.associated_items(trait_def_id)
.filter_by_name_unhygienic(suggested_name)
.any(|item| item.kind == assoc_kind)
.any(|item| item.as_tag() == assoc_tag)
})
.collect::<Vec<_>>()[..]
{
@ -330,14 +335,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn complain_about_assoc_kind_mismatch(
&self,
assoc_item: &ty::AssocItem,
assoc_kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind
&& let Some(constraint) = constraint
&& let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
{
@ -375,17 +380,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(ct) => ct.span(),
};
(span, Some(ident.span), assoc_item.kind, assoc_kind)
(span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
} else {
(ident.span, None, assoc_kind, assoc_item.kind)
(ident.span, None, assoc_tag, assoc_item.as_tag())
};
self.dcx().emit_err(errors::AssocKindMismatch {
span,
expected: assoc_kind_str(expected),
got: assoc_kind_str(got),
expected: assoc_tag_str(expected),
got: assoc_tag_str(got),
expected_because_label,
assoc_kind: assoc_kind_str(assoc_item.kind),
assoc_kind: assoc_tag_str(assoc_item.as_tag()),
def_span: tcx.def_span(assoc_item.def_id),
bound_on_assoc_const_label,
wrap_in_braces_sugg,
@ -398,9 +403,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
types: &[String],
traits: &[String],
name: Symbol,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
let kind_str = assoc_kind_str(kind);
let kind_str = assoc_tag_str(assoc_tag);
let mut err =
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
if self
@ -569,7 +574,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
candidates: Vec<(DefId, (DefId, DefId))>,
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
span: Span,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
// Either
@ -579,14 +584,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();
let kind_str = assoc_kind_str(kind);
let assoc_tag_str = assoc_tag_str(assoc_tag);
let adt_did = self_ty.ty_adt_def().map(|def| def.did());
let add_def_label = |err: &mut Diag<'_>| {
if let Some(did) = adt_did {
err.span_label(
tcx.def_span(did),
format!(
"associated {kind_str} `{name}` not found for this {}",
"associated {assoc_tag_str} `{name}` not found for this {}",
tcx.def_descr(did)
),
);
@ -615,11 +620,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.dcx(),
name.span,
E0220,
"associated {kind_str} `{name}` not found for `{self_ty}` in the current scope"
"associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope"
);
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
err.note(format!(
"the associated {kind_str} was found for\n{type_candidates}{additional_types}",
"the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}",
));
add_def_label(&mut err);
return err.emit();
@ -700,7 +705,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut err = self.dcx().struct_span_err(
name.span,
format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
);
if !bounds.is_empty() {
err.note(format!(
@ -710,7 +715,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
err.span_label(
name.span,
format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
);
for (span, mut bounds) in bound_spans {
@ -761,7 +766,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// `issue-22560.rs`.
let mut dyn_compatibility_violations = Ok(());
for (assoc_item, trait_ref) in &missing_assoc_types {
names.entry(trait_ref).or_default().push(assoc_item.name);
names.entry(trait_ref).or_default().push(assoc_item.name());
names_len += 1;
let violations =
@ -812,7 +817,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
tcx,
ident,
ty::AssocKind::Type,
ty::AssocTag::Type,
trait_def,
);
@ -852,16 +857,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut names: UnordMap<_, usize> = Default::default();
for (item, _) in &missing_assoc_types {
types_count += 1;
*names.entry(item.name).or_insert(0) += 1;
*names.entry(item.name()).or_insert(0) += 1;
}
let mut dupes = false;
let mut shadows = false;
for (item, trait_ref) in &missing_assoc_types {
let prefix = if names[&item.name] > 1 {
let name = item.name();
let prefix = if names[&name] > 1 {
let trait_def_id = trait_ref.def_id();
dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id))
} else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
} else if bound_names.get(&name).is_some_and(|x| *x != item) {
let trait_def_id = trait_ref.def_id();
shadows = true;
format!("{}::", tcx.def_path_str(trait_def_id))
@ -871,7 +877,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut is_shadowed = false;
if let Some(assoc_item) = bound_names.get(&item.name)
if let Some(assoc_item) = bound_names.get(&name)
&& *assoc_item != item
{
is_shadowed = true;
@ -880,17 +886,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
err.span_label(
tcx.def_span(assoc_item.def_id),
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
format!("`{}{}` shadowed here{}", prefix, name, rename_message),
);
}
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
err.span_label(
sp,
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
);
err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message));
}
}
if potential_assoc_types.len() == missing_assoc_types.len() {
@ -903,7 +906,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
{
let types: Vec<_> = missing_assoc_types
.iter()
.map(|(item, _)| format!("{} = Type", item.name))
.map(|(item, _)| format!("{} = Type", item.name()))
.collect();
let code = if let Some(snippet) = snippet.strip_suffix('>') {
// The user wrote `Trait<'a>` or similar and we don't have a type we can
@ -938,16 +941,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
for (item, _) in &missing_assoc_types {
types_count += 1;
*names.entry(item.name).or_insert(0) += 1;
*names.entry(item.name()).or_insert(0) += 1;
}
let mut label = vec![];
for (item, trait_ref) in &missing_assoc_types {
let postfix = if names[&item.name] > 1 {
let name = item.name();
let postfix = if names[&name] > 1 {
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
} else {
String::new()
};
label.push(format!("`{}`{}", item.name, postfix));
label.push(format!("`{}`{}", name, postfix));
}
if !label.is_empty() {
err.span_label(
@ -1022,12 +1026,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|simple_ty| tcx.incoherent_impls(simple_ty))
})
&& let name = Symbol::intern(&format!("{ident2}_{ident3}"))
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls
&& let Some(item) = inherent_impls
.iter()
.flat_map(|inherent_impl| {
tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
})
.next()
&& item.is_fn()
{
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
.with_span_suggestion_verbose(
@ -1629,10 +1634,10 @@ fn generics_args_err_extend<'a>(
}
}
pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
match kind {
ty::AssocKind::Fn => "function",
ty::AssocKind::Const => "constant",
ty::AssocKind::Type => "type",
pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
match assoc_tag {
ty::AssocTag::Fn => "function",
ty::AssocTag::Const => "constant",
ty::AssocTag::Type => "type",
}
}

View File

@ -501,8 +501,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let names: Vec<_> = tcx
.associated_items(trait_def_id)
.in_definition_order()
.filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS)
.map(|cand| cand.name)
.filter(|assoc| assoc.namespace() == Namespace::ValueNS)
.map(|cand| cand.name())
.collect();
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
diag.span_suggestion_verbose(

View File

@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
TypeVisitableExt, TypingMode, Upcast, fold_regions,
self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, ObligationCtxt};
use tracing::{debug, instrument};
use self::errors::assoc_kind_str;
use self::errors::assoc_tag_str;
use crate::check::check_abi_fn_ptr;
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
@ -168,7 +168,7 @@ pub trait HirTyLowerer<'tcx> {
item_def_id: DefId,
item_segment: &hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
fn lower_fn_sig(
@ -251,10 +251,10 @@ enum LowerAssocMode {
}
impl LowerAssocMode {
fn kind(self) -> ty::AssocKind {
fn assoc_tag(self) -> ty::AssocTag {
match self {
LowerAssocMode::Type { .. } => ty::AssocKind::Type,
LowerAssocMode::Const => ty::AssocKind::Const,
LowerAssocMode::Type { .. } => ty::AssocTag::Type,
LowerAssocMode::Const => ty::AssocTag::Const,
}
}
@ -268,7 +268,8 @@ impl LowerAssocMode {
fn permit_variants(self) -> bool {
match self {
LowerAssocMode::Type { permit_variants } => permit_variants,
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which resolve to const ctors/fn items respectively
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which
// resolve to const ctors/fn items respectively.
LowerAssocMode::Const => false,
}
}
@ -932,12 +933,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_trait_that_defines_assoc_item(
&self,
trait_def_id: DefId,
assoc_kind: ty::AssocKind,
assoc_tag: AssocTag,
assoc_ident: Ident,
) -> bool {
self.tcx()
.associated_items(trait_def_id)
.find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_kind, trait_def_id)
.find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_tag, trait_def_id)
.is_some()
}
@ -975,7 +976,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
ty_param_def_id: LocalDefId,
ty_param_span: Span,
kind: ty::AssocKind,
assoc_tag: AssocTag,
assoc_ident: Ident,
span: Span,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
@ -993,7 +994,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident)
},
AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span),
kind,
assoc_tag,
assoc_ident,
span,
None,
@ -1010,7 +1011,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
all_candidates: impl Fn() -> I,
qself: AssocItemQSelf,
assoc_kind: ty::AssocKind,
assoc_tag: AssocTag,
assoc_ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@ -1021,14 +1022,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();
let mut matching_candidates = all_candidates().filter(|r| {
self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_kind, assoc_ident)
self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_tag, assoc_ident)
});
let Some(bound) = matching_candidates.next() else {
let reported = self.complain_about_assoc_item_not_found(
all_candidates,
qself,
assoc_kind,
assoc_tag,
assoc_ident,
span,
constraint,
@ -1040,7 +1041,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if let Some(bound2) = matching_candidates.next() {
debug!(?bound2);
let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
let assoc_kind_str = errors::assoc_tag_str(assoc_tag);
let qself_str = qself.to_string(tcx);
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
span,
@ -1059,14 +1060,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
},
);
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!).
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality
// predicates!).
// FIXME: Turn this into a structured, translateable & more actionable suggestion.
let mut where_bounds = vec![];
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
let bound_id = bound.def_id();
let bound_span = tcx
.associated_items(bound_id)
.find_by_ident_and_kind(tcx, assoc_ident, assoc_kind, bound_id)
.find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id)
.and_then(|item| tcx.hir_span_if_local(item.def_id));
if let Some(bound_span) = bound_span {
@ -1265,7 +1267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
qself_ty,
hir_ref_id,
span,
mode.kind(),
mode.assoc_tag(),
)? {
return Ok(LoweredAssoc::Term(did, args));
}
@ -1296,7 +1298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
},
AssocItemQSelf::SelfTyAlias,
mode.kind(),
mode.assoc_tag(),
assoc_ident,
span,
None,
@ -1308,12 +1310,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(),
qself.span,
mode.kind(),
mode.assoc_tag(),
assoc_ident,
span,
)?,
_ => {
let kind_str = assoc_kind_str(mode.kind());
let kind_str = assoc_tag_str(mode.assoc_tag());
let reported = if variant_resolution.is_some() {
// Variant in type position
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
@ -1420,7 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&[qself_ty.to_string()],
&traits,
assoc_ident.name,
mode.kind(),
mode.assoc_tag(),
)
};
return Err(reported);
@ -1429,10 +1431,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_did = bound.def_id();
let assoc_item = self
.probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did)
.probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
.expect("failed to find associated item");
let (def_id, args) =
self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?;
let (def_id, args) = self.lower_assoc_shared(
span,
assoc_item.def_id,
assoc_segment,
bound,
mode.assoc_tag(),
)?;
let result = LoweredAssoc::Term(def_id, args);
if let Some(variant_def_id) = variant_resolution {
@ -1469,20 +1476,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>,
block: HirId,
span: Span,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> {
let tcx = self.tcx();
if !tcx.features().inherent_associated_types() {
match kind {
// Don't attempt to look up inherent associated types when the feature is not enabled.
// Theoretically it'd be fine to do so since we feature-gate their definition site.
// However, due to current limitations of the implementation (caused by us performing
// selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
// errors (#108491) which mask the feature-gate error, needlessly confusing users
// who use IATs by accident (#113265).
ty::AssocKind::Type => return Ok(None),
ty::AssocKind::Const => {
match assoc_tag {
// Don't attempt to look up inherent associated types when the feature is not
// enabled. Theoretically it'd be fine to do so since we feature-gate their
// definition site. However, due to current limitations of the implementation
// (caused by us performing selection during HIR ty lowering instead of in the
// trait solver), IATs can lead to cycle errors (#108491) which mask the
// feature-gate error, needlessly confusing users who use IATs by accident
// (#113265).
ty::AssocTag::Type => return Ok(None),
ty::AssocTag::Const => {
// We also gate the mgca codepath for type-level uses of inherent consts
// with the inherent_associated_types feature gate since it relies on the
// same machinery and has similar rough edges.
@ -1494,7 +1502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
.emit());
}
ty::AssocKind::Fn => unreachable!(),
ty::AssocTag::Fn => unreachable!(),
}
}
@ -1503,7 +1511,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.inherent_impls(adt_did)
.iter()
.filter_map(|&impl_| {
let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?;
let (item, scope) =
self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
Some((impl_, (item.def_id, scope)))
})
.collect();
@ -1542,7 +1551,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty,
|self_ty| {
self.select_inherent_assoc_candidates(
infcx, name, span, self_ty, param_env, candidates, kind,
infcx, name, span, self_ty, param_env, candidates, assoc_tag,
)
},
)?;
@ -1570,7 +1579,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>,
param_env: ParamEnv<'tcx>,
candidates: Vec<(DefId, (DefId, DefId))>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
let tcx = self.tcx();
let mut fulfillment_errors = Vec::new();
@ -1621,7 +1630,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
candidates,
fulfillment_errors,
span,
kind,
assoc_tag,
)),
&[applicable_candidate] => Ok(applicable_candidate),
@ -1640,12 +1649,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_assoc_item(
&self,
ident: Ident,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
block: HirId,
span: Span,
scope: DefId,
) -> Option<ty::AssocItem> {
let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?;
let (item, scope) = self.probe_assoc_item_unchecked(ident, assoc_tag, block, scope)?;
self.check_assoc_item(item.def_id, ident, scope, block, span);
Some(item)
}
@ -1657,7 +1666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_assoc_item_unchecked(
&self,
ident: Ident,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
block: HirId,
scope: DefId,
) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
@ -1670,7 +1679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let item = tcx
.associated_items(scope)
.filter_by_name_unhygienic(ident.name)
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
.find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
Some((*item, def_scope))
}
@ -1722,9 +1731,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.associated_items(*trait_def_id)
.in_definition_order()
.any(|i| {
i.kind.namespace() == Namespace::TypeNS
i.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
&& matches!(i.kind, ty::AssocKind::Type)
&& i.is_type()
})
// Consider only accessible traits
&& tcx.visibility(*trait_def_id)
@ -1770,7 +1779,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id,
trait_segment,
item_segment,
ty::AssocKind::Type,
ty::AssocTag::Type,
) {
Ok((item_def_id, item_args)) => {
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
@ -1795,7 +1804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id,
trait_segment,
item_segment,
ty::AssocKind::Const,
ty::AssocTag::Const,
) {
Ok((item_def_id, item_args)) => {
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
@ -1813,7 +1822,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
let tcx = self.tcx();
@ -1821,7 +1830,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
debug!(?trait_def_id);
let Some(self_ty) = opt_self_ty else {
return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind));
return Err(self.error_missing_qpath_self_ty(
trait_def_id,
span,
item_segment,
assoc_tag,
));
};
debug!(?self_ty);
@ -1840,7 +1854,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_def_id: DefId,
span: Span,
item_segment: &hir::PathSegment<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let path_str = tcx.def_path_str(trait_def_id);
@ -1877,7 +1891,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
// references the trait. Relevant for the first case in
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind)
self.report_ambiguous_assoc(
span,
&type_names,
&[path_str],
item_segment.ident.name,
assoc_tag,
)
}
pub fn prohibit_generic_args<'a>(
@ -2862,7 +2882,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
tcx,
*ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
trait_ref.def_id,
)?;

View File

@ -112,14 +112,14 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
.flat_map(|def_id| {
let item = tcx.associated_item(def_id);
match item.kind {
ty::AssocKind::Type => {
ty::AssocKind::Type { .. } => {
if item.defaultness(tcx).has_value() {
cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
} else {
vec![]
}
}
ty::AssocKind::Fn | ty::AssocKind::Const => vec![],
ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => vec![],
}
})
.collect();

View File

@ -1871,10 +1871,11 @@ impl<'a> State<'a> {
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
self.maybe_print_comment(pat.span.lo());
self.ann.pre(self, AnnNode::Pat(pat));
// Pat isn't normalized, but the beauty of it
// is that it doesn't matter
// Pat isn't normalized, but the beauty of it is that it doesn't matter.
match pat.kind {
PatKind::Missing => unreachable!(),
// Printing `_` isn't ideal for a missing pattern, but it's easy and good enough.
// E.g. `fn(u32)` gets printed as `fn(_: u32)`.
PatKind::Missing => self.word("_"),
PatKind::Wild => self.word("_"),
PatKind::Never => self.word("!"),
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
@ -2164,7 +2165,9 @@ impl<'a> State<'a> {
s.end();
});
if decl.c_variadic {
self.word(", ");
if !decl.inputs.is_empty() {
self.word(", ");
}
print_arg(self, None);
self.word("...");
}

View File

@ -1089,14 +1089,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// This function checks whether the method is not static and does not accept other parameters than `self`.
fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
match method.kind {
ty::AssocKind::Fn => {
method.fn_has_self_parameter
&& self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len()
== 1
}
_ => false,
}
method.is_method()
&& self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1
}
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression

View File

@ -2588,9 +2588,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.into_iter()
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
// Only assoc fn with no receivers.
.filter(|item| {
matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter
})
.filter(|item| item.is_fn() && !item.is_method())
.filter_map(|item| {
// Only assoc fns that return `Self`
let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder();
@ -2603,8 +2601,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
}
let input_len = fn_sig.inputs().skip_binder().len();
let order = !item.name.as_str().starts_with("new");
Some((order, item.name, input_len))
let name = item.name();
let order = !name.as_str().starts_with("new");
Some((order, name, input_len))
})
.collect::<Vec<_>>();
items.sort_by_key(|(order, _, _)| *order);

View File

@ -616,7 +616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some((DefKind::AssocFn, def_id)) =
self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
&& let Some(assoc) = tcx.opt_associated_item(def_id)
&& assoc.fn_has_self_parameter
&& assoc.is_method()
{
Some(*receiver)
} else {
@ -642,8 +642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
TraitsInScope,
|mut ctxt| ctxt.probe_for_similar_candidate(),
)
&& let ty::AssocKind::Fn = assoc.kind
&& assoc.fn_has_self_parameter
&& assoc.is_method()
{
let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id);
let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args);
@ -684,10 +683,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.all(|(expected, found)| self.may_coerce(*expected, *found))
&& fn_sig.inputs()[1..].len() == input_types.len()
{
let assoc_name = assoc.name();
err.span_suggestion_verbose(
call_name.span,
format!("you might have meant to use `{}`", assoc.name),
assoc.name,
format!("you might have meant to use `{}`", assoc_name),
assoc_name,
Applicability::MaybeIncorrect,
);
return;
@ -707,7 +707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tcx.def_span(assoc.def_id),
format!(
"there's is a method with similar name `{}`, but the arguments don't match",
assoc.name,
assoc.name(),
),
);
return;
@ -719,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!(
"there's is a method with similar name `{}`, but their argument count \
doesn't match",
assoc.name,
assoc.name(),
),
);
return;

View File

@ -314,7 +314,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
item_def_id: DefId,
item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
_kind: ty::AssocKind,
_assoc_tag: ty::AssocTag,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
let trait_ref = self.instantiate_binder_with_fresh_vars(
span,

View File

@ -381,9 +381,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut suggestions = methods
.iter()
.filter_map(|conversion_method| {
let conversion_method_name = conversion_method.name();
let receiver_method_ident = expr.method_ident();
if let Some(method_ident) = receiver_method_ident
&& method_ident.name == conversion_method.name
&& method_ident.name == conversion_method_name
{
return None; // do not suggest code that is already there (#53348)
}
@ -391,20 +392,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let method_call_list = [sym::to_vec, sym::to_string];
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
&& receiver_method.ident.name == sym::clone
&& method_call_list.contains(&conversion_method.name)
&& method_call_list.contains(&conversion_method_name)
// If receiver is `.clone()` and found type has one of those methods,
// we guess that the user wants to convert from a slice type (`&[]` or `&str`)
// to an owned type (`Vec` or `String`). These conversions clone internally,
// so we remove the user's `clone` call.
{
vec![(receiver_method.ident.span, conversion_method.name.to_string())]
vec![(receiver_method.ident.span, conversion_method_name.to_string())]
} else if expr.precedence() < ExprPrecedence::Unambiguous {
vec![
(expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)),
]
} else {
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method_name))]
};
let struct_pat_shorthand_field =
self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr);

View File

@ -265,7 +265,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty()
{
if let Some(item) = tcx.opt_associated_item(def_id.into())
&& let ty::AssocKind::Const = item.kind
&& let ty::AssocKind::Const { .. } = item.kind
&& let ty::AssocItemContainer::Impl = item.container
&& let Some(trait_item_def_id) = item.trait_item_def_id
{

View File

@ -379,7 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let def_id = method_item.def_id;
if method_item.kind != ty::AssocKind::Fn {
if !method_item.is_fn() {
span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function");
}
@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
let def_kind = pick.item.kind.as_def_kind();
let def_kind = pick.item.as_def_kind();
tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span));
Ok((def_kind, pick.item.def_id))
}

View File

@ -992,7 +992,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool {
match method.kind {
ty::AssocKind::Fn => self.probe(|_| {
ty::AssocKind::Fn { .. } => self.probe(|_| {
let args = self.fresh_args_for_item(self.span, method.def_id);
let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
@ -1583,7 +1583,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
},
None,
) {
self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
self.private_candidate.set(Some((pick.item.as_def_kind(), pick.item.def_id)));
}
}
None
@ -1671,16 +1671,7 @@ impl<'tcx> Pick<'tcx> {
/// Do not use for type checking.
pub(crate) fn differs_from(&self, other: &Self) -> bool {
let Self {
item:
AssocItem {
def_id,
name: _,
kind: _,
container: _,
trait_item_def_id: _,
fn_has_self_parameter: _,
opt_rpitit_info: _,
},
item: AssocItem { def_id, kind: _, container: _, trait_item_def_id: _ },
kind: _,
import_ids: _,
autoderefs: _,
@ -1703,7 +1694,7 @@ impl<'tcx> Pick<'tcx> {
if self.unstable_candidates.is_empty() {
return;
}
let def_kind = self.item.kind.as_def_kind();
let def_kind = self.item.as_def_kind();
tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| {
lint.primary_message(format!(
"{} {} with this name may be added to the standard library in the future",
@ -1712,7 +1703,7 @@ impl<'tcx> Pick<'tcx> {
));
match (self.item.kind, self.item.container) {
(ty::AssocKind::Fn, _) => {
(ty::AssocKind::Fn { .. }, _) => {
// FIXME: This should be a `span_suggestion` instead of `help`
// However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing
@ -1723,17 +1714,12 @@ impl<'tcx> Pick<'tcx> {
tcx.def_path_str(self.item.def_id),
));
}
(ty::AssocKind::Const, ty::AssocItemContainer::Trait) => {
(ty::AssocKind::Const { name }, ty::AssocItemContainer::Trait) => {
let def_id = self.item.container_id(tcx);
lint.span_suggestion(
span,
"use the fully qualified path to the associated const",
format!(
"<{} as {}>::{}",
self.self_ty,
tcx.def_path_str(def_id),
self.item.name
),
format!("<{} as {}>::{}", self.self_ty, tcx.def_path_str(def_id), name),
Applicability::MachineApplicable,
);
}
@ -2222,7 +2208,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let best_name = {
let names = applicable_close_candidates
.iter()
.map(|cand| cand.name)
.map(|cand| cand.name())
.collect::<Vec<Symbol>>();
find_best_match_for_name_with_substrings(
&names,
@ -2234,10 +2220,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
applicable_close_candidates
.iter()
.find(|cand| self.matches_by_doc_alias(cand.def_id))
.map(|cand| cand.name)
.map(|cand| cand.name())
});
Ok(best_name.and_then(|best_name| {
applicable_close_candidates.into_iter().find(|method| method.name == best_name)
applicable_close_candidates
.into_iter()
.find(|method| method.name() == best_name)
}))
}
})
@ -2252,10 +2240,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// In Path mode (i.e., resolving a value like `T::next`), consider any
// associated value (i.e., methods, constants) but not types.
match self.mode {
Mode::MethodCall => item.fn_has_self_parameter,
Mode::MethodCall => item.is_method(),
Mode::Path => match item.kind {
ty::AssocKind::Type => false,
ty::AssocKind::Fn | ty::AssocKind::Const => true,
ty::AssocKind::Type { .. } => false,
ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => true,
},
}
// FIXME -- check for types that deref to `Self`,
@ -2277,7 +2265,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
impl_ty: Ty<'tcx>,
args: GenericArgsRef<'tcx>,
) -> (Ty<'tcx>, Option<Ty<'tcx>>) {
if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall {
if item.is_fn() && self.mode == Mode::MethodCall {
let sig = self.xform_method_sig(item.def_id, args);
(sig.inputs()[0], Some(sig.output()))
} else {
@ -2328,8 +2316,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// Determine if the given associated item type is relevant in the current context.
fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
match (self.mode, kind) {
(Mode::MethodCall, ty::AssocKind::Fn) => true,
(Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true,
(Mode::MethodCall, ty::AssocKind::Fn { .. }) => true,
(Mode::Path, ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. }) => true,
_ => false,
}
}
@ -2411,7 +2399,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
match edit_distance_with_substrings(
name.as_str(),
x.name.as_str(),
x.name().as_str(),
max_dist,
) {
Some(d) => d > 0,

View File

@ -713,7 +713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let Some(candidate) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
self.tcx,
item_ident,
ty::AssocKind::Type,
ty::AssocTag::Type,
impl_def_id,
)
&& let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def()
@ -1442,7 +1442,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(assoc) = self.associated_value(*def_id, item_ident) {
// Check for both mode is the same so we avoid suggesting
// incorrect associated item.
match (mode, assoc.fn_has_self_parameter, source) {
match (mode, assoc.is_method(), source) {
(Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
// We check that the suggest type is actually
// different from the received one
@ -1722,7 +1722,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// that had unsatisfied trait bounds
if unsatisfied_predicates.is_empty()
// ...or if we already suggested that name because of `rustc_confusable` annotation.
&& Some(similar_candidate.name) != confusable_suggested
&& Some(similar_candidate.name()) != confusable_suggested
{
self.find_likely_intended_associated_item(
&mut err,
@ -1819,12 +1819,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mode: Mode,
) {
let tcx = self.tcx;
let def_kind = similar_candidate.kind.as_def_kind();
let def_kind = similar_candidate.as_def_kind();
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
let similar_candidate_name = similar_candidate.name();
let msg = format!(
"there is {an} {} `{}` with a similar name",
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
similar_candidate.name,
similar_candidate_name,
);
// Methods are defined within the context of a struct and their first parameter
// is always `self`, which represents the instance of the struct the method is
@ -1834,7 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
if similar_candidate.fn_has_self_parameter {
if similar_candidate.is_method() {
if let Some(args) = args
&& fn_sig.inputs()[1..].len() == args.len()
{
@ -1843,7 +1844,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
span,
msg,
similar_candidate.name,
similar_candidate_name,
Applicability::MaybeIncorrect,
);
} else {
@ -1865,7 +1866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
span,
msg,
similar_candidate.name,
similar_candidate_name,
Applicability::MaybeIncorrect,
);
} else {
@ -1878,7 +1879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
span,
msg,
similar_candidate.name,
similar_candidate_name,
Applicability::MaybeIncorrect,
);
} else {
@ -1902,7 +1903,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols)
&& candidates.contains(&item_name.name)
&& let ty::AssocKind::Fn = inherent_method.kind
&& inherent_method.is_fn()
{
let args =
ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id)
@ -1918,6 +1919,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
infer::FnCall,
fn_sig,
);
let name = inherent_method.name();
if let Some(ref args) = call_args
&& fn_sig.inputs()[1..]
.iter()
@ -1927,20 +1929,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
err.span_suggestion_verbose(
item_name.span,
format!("you might have meant to use `{}`", inherent_method.name),
inherent_method.name,
format!("you might have meant to use `{}`", name),
name,
Applicability::MaybeIncorrect,
);
return Some(inherent_method.name);
return Some(name);
} else if let None = call_args {
err.span_note(
self.tcx.def_span(inherent_method.def_id),
format!(
"you might have meant to use method `{}`",
inherent_method.name,
),
format!("you might have meant to use method `{}`", name),
);
return Some(inherent_method.name);
return Some(name);
}
}
}
@ -2116,8 +2115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Only assoc fn with no receivers and only if
// they are resolvable
.filter(|item| {
matches!(item.kind, ty::AssocKind::Fn)
&& !item.fn_has_self_parameter
matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. })
&& self
.probe_for_name(
Mode::Path,
@ -2261,7 +2259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let assoc = self.associated_value(assoc_did, item_name)?;
if assoc.kind != ty::AssocKind::Fn {
if !assoc.is_fn() {
return None;
}
@ -3208,7 +3206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If this method receives `&self`, then the provided
// argument _should_ coerce, so it's valid to suggest
// just changing the path.
&& pick.item.fn_has_self_parameter
&& pick.item.is_method()
&& let Some(self_ty) =
self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0)
&& self_ty.is_ref()
@ -3560,7 +3558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| (("Pin::new" == *pre)
&& ((sym::as_ref == item_name.name) || !unpin))
|| inputs_len.is_some_and(|inputs_len| {
pick.item.kind == ty::AssocKind::Fn
pick.item.is_fn()
&& self
.tcx
.fn_sig(pick.item.def_id)
@ -3618,7 +3616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& pick.autoderefs == 0
// Check that the method of the same name that was found on the new `Pin<T>`
// receiver has the same number of arguments that appear in the user's code.
&& inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
&& inputs_len.is_some_and(|inputs_len| pick.item.is_fn() && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
{
let indent = self
.tcx
@ -3756,7 +3754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& self
.associated_value(info.def_id, item_name)
.filter(|item| {
if let ty::AssocKind::Fn = item.kind {
if item.is_fn() {
let id = item
.def_id
.as_local()
@ -4279,17 +4277,17 @@ fn print_disambiguation_help<'tcx>(
item: ty::AssocItem,
) -> Option<String> {
let trait_impl_type = trait_ref.self_ty().peel_refs();
let trait_ref = if item.fn_has_self_parameter {
let trait_ref = if item.is_method() {
trait_ref.print_only_trait_name().to_string()
} else {
format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name())
};
Some(
if matches!(item.kind, ty::AssocKind::Fn)
if item.is_fn()
&& let SelfSource::MethodCall(receiver) = source
&& let Some(args) = args
{
let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id);
let def_kind_descr = tcx.def_kind_descr(item.as_def_kind(), item.def_id);
let item_name = item.ident(tcx);
let first_input =
tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0);
@ -4304,7 +4302,7 @@ fn print_disambiguation_help<'tcx>(
let args = if let Some(first_arg_type) = first_arg_type
&& (first_arg_type == tcx.types.self_param
|| first_arg_type == trait_impl_type
|| item.fn_has_self_parameter)
|| item.is_method())
{
Some(receiver)
} else {

View File

@ -372,7 +372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.associated_item_def_ids(def_id)
.iter()
.find(|item_def_id| {
self.tcx.associated_item(*item_def_id).name == sym::Output
self.tcx.associated_item(*item_def_id).name() == sym::Output
})
.cloned()
});

View File

@ -855,11 +855,11 @@ impl<'tcx> LateContext<'tcx> {
&self,
self_ty: Ty<'tcx>,
trait_id: DefId,
name: &str,
name: Symbol,
) -> Option<Ty<'tcx>> {
let tcx = self.tcx;
tcx.associated_items(trait_id)
.find_by_ident_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
.find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
.and_then(|assoc| {
let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()

View File

@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
&& let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
&& let Some(self_principal) = data.principal()
// `<T as Deref>::Target` is `dyn target_principal`
&& let Some(target) = cx.get_associated_type(self_ty, did, "Target")
&& let Some(target) = cx.get_associated_type(self_ty, did, sym::Target)
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
&& let Some(target_principal) = data.principal()
// `target_principal` is a supertrait of `t_principal`

View File

@ -1332,29 +1332,30 @@ impl<'a> CrateMetadataRef<'a> {
}
fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() {
kw::Empty
} else {
self.item_name(id)
};
let (kind, has_self) = match self.def_kind(id) {
DefKind::AssocConst => (ty::AssocKind::Const, false),
DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)),
DefKind::AssocTy => (ty::AssocKind::Type, false),
let kind = match self.def_kind(id) {
DefKind::AssocConst => ty::AssocKind::Const { name: self.item_name(id) },
DefKind::AssocFn => ty::AssocKind::Fn {
name: self.item_name(id),
has_self: self.get_fn_has_self_parameter(id, sess),
},
DefKind::AssocTy => {
let data = if let Some(rpitit_info) = self.root.tables.opt_rpitit_info.get(self, id)
{
ty::AssocTypeData::Rpitit(rpitit_info.decode(self))
} else {
ty::AssocTypeData::Normal(self.item_name(id))
};
ty::AssocKind::Type { data }
}
_ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
};
let container = self.root.tables.assoc_container.get(self, id).unwrap();
let opt_rpitit_info =
self.root.tables.opt_rpitit_info.get(self, id).map(|d| d.decode(self));
ty::AssocItem {
name,
kind,
def_id: self.local_def_id(id),
trait_item_def_id: self.get_trait_item_def_id(id),
container,
fn_has_self_parameter: has_self,
opt_rpitit_info,
}
}

View File

@ -1338,7 +1338,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
if let Some(assoc_item) = tcx.opt_associated_item(def_id)
&& assoc_item.container == ty::AssocItemContainer::Trait
&& assoc_item.kind == ty::AssocKind::Fn
&& assoc_item.is_fn()
{
true
} else {
@ -1691,7 +1691,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
match item.container {
AssocItemContainer::Trait => {
if let ty::AssocKind::Type = item.kind {
if item.is_type() {
self.encode_explicit_item_bounds(def_id);
self.encode_explicit_item_self_bounds(def_id);
if tcx.is_conditionally_const(def_id) {
@ -1706,7 +1706,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
}
}
if let Some(rpitit_info) = item.opt_rpitit_info {
if let ty::AssocKind::Type { data: ty::AssocTypeData::Rpitit(rpitit_info) } = item.kind {
record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) {
record_array!(

View File

@ -1,3 +1,7 @@
//! This module used to contain a type called `Map`. That type has since been
//! eliminated, and all its methods are now on `TyCtxt`. But the module name
//! stays as `map` because there isn't an obviously better name for it.
use rustc_abi::ExternAbi;
use rustc_ast::visit::{VisitorResult, walk_list};
use rustc_data_structures::fingerprint::Fingerprint;
@ -18,16 +22,6 @@ use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
use crate::query::LocalCrate;
use crate::ty::TyCtxt;
// FIXME: the structure was necessary in the past but now it
// only serves as "namespace" for HIR-related methods, and can be
// removed if all the methods are reasonably renamed and moved to tcx
// (https://github.com/rust-lang/rust/pull/118256#issuecomment-1826442834).
#[allow(unused)] // FIXME: temporary
#[derive(Copy, Clone)]
pub struct Map<'hir> {
pub(super) tcx: TyCtxt<'hir>,
}
/// An iterator that walks up the ancestor tree of a given `HirId`.
/// Constructed using `tcx.hir_parent_iter(hir_id)`.
struct ParentHirIterator<'tcx> {
@ -335,7 +329,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Returns an iterator of the `DefId`s for all body-owners in this
/// crate. If you would prefer to iterate over the bodies
/// themselves, you can do `self.hir().krate().body_ids.iter()`.
/// themselves, you can do `self.hir_crate(()).body_ids.iter()`.
#[inline]
pub fn hir_body_owners(self) -> impl Iterator<Item = LocalDefId> {
self.hir_crate_items(()).body_owners.iter().copied()

View File

@ -116,11 +116,6 @@ impl ModuleItems {
}
impl<'tcx> TyCtxt<'tcx> {
#[inline(always)]
pub fn hir(self) -> map::Map<'tcx> {
map::Map { tcx: self }
}
pub fn parent_module(self, id: HirId) -> LocalModDefId {
if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
LocalModDefId::new_unchecked(id.owner.def_id)

View File

@ -1636,8 +1636,8 @@ pub fn find_self_call<'tcx>(
&body[block].terminator
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
&& let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
tcx.opt_associated_item(def_id)
&& let Some(item) = tcx.opt_associated_item(def_id)
&& item.is_method()
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
**args
{

View File

@ -161,11 +161,11 @@ rustc_queries! {
/// Represents crate as a whole (as distinct from the top-level crate module).
///
/// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir_crate()`),
/// we will have to assume that any change means that you need to be recompiled.
/// This is because the `hir_crate` query gives you access to all other items.
/// To avoid this fate, do not call `tcx.hir_crate()`; instead,
/// prefer wrappers like [`TyCtxt::hir_visit_all_item_likes_in_crate`].
/// If you call `tcx.hir_crate(())` we will have to assume that any change
/// means that you need to be recompiled. This is because the `hir_crate`
/// query gives you access to all other items. To avoid this fate, do not
/// call `tcx.hir_crate(())`; instead, prefer wrappers like
/// [`TyCtxt::hir_visit_all_item_likes_in_crate`].
query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
arena_cache
eval_always
@ -197,7 +197,7 @@ rustc_queries! {
/// Gives access to the HIR node's parent for the HIR owner `key`.
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// This can be conveniently accessed by `tcx.hir_*` methods.
/// Avoid calling this query directly.
query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) }
@ -205,7 +205,7 @@ rustc_queries! {
/// Gives access to the HIR nodes and bodies inside `key` if it's a HIR owner.
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// This can be conveniently accessed by `tcx.hir_*` methods.
/// Avoid calling this query directly.
query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) }
@ -214,7 +214,7 @@ rustc_queries! {
/// Gives access to the HIR attributes inside the HIR owner `key`.
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// This can be conveniently accessed by `tcx.hir_*` methods.
/// Avoid calling this query directly.
query hir_attr_map(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) }

View File

@ -5,7 +5,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_span::Span;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{Ty, TyCtxt};
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum PointerCoercion {
@ -133,7 +133,7 @@ impl OverloadedDeref {
};
tcx.associated_items(trait_def_id)
.in_definition_order()
.find(|m| m.kind == ty::AssocKind::Fn)
.find(|item| item.is_fn())
.unwrap()
.def_id
}

View File

@ -18,27 +18,33 @@ pub enum AssocItemContainer {
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
pub struct AssocItem {
pub def_id: DefId,
pub name: Symbol,
pub kind: AssocKind,
pub container: AssocItemContainer,
/// If this is an item in an impl of a trait then this is the `DefId` of
/// the associated item on the trait that this implements.
pub trait_item_def_id: Option<DefId>,
/// Whether this is a method with an explicit self
/// as its first parameter, allowing method calls.
pub fn_has_self_parameter: bool,
/// `Some` if the associated item (an associated type) comes from the
/// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
/// provides additional information about its source.
pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>,
}
impl AssocItem {
// Gets the identifier, if it has one.
pub fn opt_name(&self) -> Option<Symbol> {
match self.kind {
ty::AssocKind::Type { data: AssocTypeData::Normal(name) } => Some(name),
ty::AssocKind::Type { data: AssocTypeData::Rpitit(_) } => None,
ty::AssocKind::Const { name } => Some(name),
ty::AssocKind::Fn { name, .. } => Some(name),
}
}
// Gets the identifier name. Aborts if it lacks one, i.e. is an RPITIT
// associated type.
pub fn name(&self) -> Symbol {
self.opt_name().expect("name of non-Rpitit assoc item")
}
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
Ident::new(self.name(), tcx.def_ident_span(self.def_id).unwrap())
}
/// Gets the defaultness of the associated item.
@ -78,35 +84,65 @@ impl AssocItem {
pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
match self.kind {
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
// We skip the binder here because the binder would deanonymize all
// late-bound regions, and we don't want method signatures to show up
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
// regions just fine, showing `fn(&MyType)`.
tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
}
ty::AssocKind::Type => format!("type {};", self.name),
ty::AssocKind::Const => {
format!(
"const {}: {:?};",
self.name,
tcx.type_of(self.def_id).instantiate_identity()
)
ty::AssocKind::Type { .. } => format!("type {};", self.name()),
ty::AssocKind::Const { name } => {
format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity())
}
}
}
pub fn descr(&self) -> &'static str {
match self.kind {
ty::AssocKind::Const => "associated const",
ty::AssocKind::Fn if self.fn_has_self_parameter => "method",
ty::AssocKind::Fn => "associated function",
ty::AssocKind::Type => "associated type",
ty::AssocKind::Const { .. } => "associated const",
ty::AssocKind::Fn { has_self: true, .. } => "method",
ty::AssocKind::Fn { has_self: false, .. } => "associated function",
ty::AssocKind::Type { .. } => "associated type",
}
}
pub fn namespace(&self) -> Namespace {
match self.kind {
ty::AssocKind::Type { .. } => Namespace::TypeNS,
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
}
}
pub fn as_def_kind(&self) -> DefKind {
match self.kind {
AssocKind::Const { .. } => DefKind::AssocConst,
AssocKind::Fn { .. } => DefKind::AssocFn,
AssocKind::Type { .. } => DefKind::AssocTy,
}
}
pub fn is_type(&self) -> bool {
matches!(self.kind, ty::AssocKind::Type { .. })
}
pub fn is_fn(&self) -> bool {
matches!(self.kind, ty::AssocKind::Fn { .. })
}
pub fn is_method(&self) -> bool {
matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
}
pub fn as_tag(&self) -> AssocTag {
match self.kind {
AssocKind::Const { .. } => AssocTag::Const,
AssocKind::Fn { .. } => AssocTag::Fn,
AssocKind::Type { .. } => AssocTag::Type,
}
}
pub fn is_impl_trait_in_trait(&self) -> bool {
self.opt_rpitit_info.is_some()
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
}
/// Returns true if:
@ -114,7 +150,7 @@ impl AssocItem {
/// - If it is in a trait impl, the item from the original trait has this attribute, or
/// - It is an inherent assoc const.
pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
if self.kind != ty::AssocKind::Const {
if !matches!(self.kind, ty::AssocKind::Const { .. }) {
return false;
}
@ -128,26 +164,35 @@ impl AssocItem {
}
}
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
pub enum AssocTypeData {
Normal(Symbol),
/// The associated type comes from an RPITIT. It has no name, and the
/// `ImplTraitInTraitData` provides additional information about its
/// source.
Rpitit(ty::ImplTraitInTraitData),
}
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
pub enum AssocKind {
Const,
Fn,
Type,
Const { name: Symbol },
Fn { name: Symbol, has_self: bool },
Type { data: AssocTypeData },
}
impl AssocKind {
pub fn namespace(&self) -> Namespace {
match *self {
ty::AssocKind::Type => Namespace::TypeNS,
ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS,
ty::AssocKind::Type { .. } => Namespace::TypeNS,
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
}
}
pub fn as_def_kind(&self) -> DefKind {
match self {
AssocKind::Const => DefKind::AssocConst,
AssocKind::Fn => DefKind::AssocFn,
AssocKind::Type => DefKind::AssocTy,
AssocKind::Const { .. } => DefKind::AssocConst,
AssocKind::Fn { .. } => DefKind::AssocFn,
AssocKind::Type { .. } => DefKind::AssocTy,
}
}
}
@ -155,15 +200,22 @@ impl AssocKind {
impl std::fmt::Display for AssocKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
// FIXME: fails to distinguish between "associated function" and
// "method" because `has_self` isn't known here.
AssocKind::Fn => write!(f, "method"),
AssocKind::Const => write!(f, "associated const"),
AssocKind::Type => write!(f, "associated type"),
AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
AssocKind::Const { .. } => write!(f, "associated const"),
AssocKind::Type { .. } => write!(f, "associated type"),
}
}
}
// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AssocTag {
Const,
Fn,
Type,
}
/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
///
/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
@ -171,17 +223,17 @@ impl std::fmt::Display for AssocKind {
/// done only on items with the same name.
#[derive(Debug, Clone, PartialEq, HashStable)]
pub struct AssocItems {
items: SortedIndexMultiMap<u32, Symbol, ty::AssocItem>,
items: SortedIndexMultiMap<u32, Option<Symbol>, ty::AssocItem>,
}
impl AssocItems {
/// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect();
AssocItems { items }
}
/// Returns a slice of associated items in the order they were defined.
/// Returns an iterator over associated items in the order they were defined.
///
/// New code should avoid relying on definition order. If you need a particular associated item
/// for a known trait, make that trait a lang item instead of indexing this array.
@ -198,7 +250,8 @@ impl AssocItems {
&self,
name: Symbol,
) -> impl '_ + Iterator<Item = &ty::AssocItem> {
self.items.get_by_key(name)
assert!(!name.is_empty());
self.items.get_by_key(Some(name))
}
/// Returns the associated item with the given identifier and `AssocKind`, if one exists.
@ -207,27 +260,14 @@ impl AssocItems {
&self,
tcx: TyCtxt<'_>,
ident: Ident,
kind: AssocKind,
assoc_tag: AssocTag,
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name)
.filter(|item| item.kind == kind)
.filter(|item| item.as_tag() == assoc_tag)
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
}
/// Returns the associated item with the given identifier and any of `AssocKind`, if one
/// exists. The identifier is matched hygienically.
pub fn find_by_ident_and_kinds(
&self,
tcx: TyCtxt<'_>,
ident: Ident,
// Sorted in order of what kinds to look at
kinds: &[AssocKind],
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
kinds.iter().find_map(|kind| self.find_by_ident_and_kind(tcx, ident, *kind, parent_def_id))
}
/// Returns the associated item with the given identifier in the given `Namespace`, if one
/// exists. The identifier is matched hygienically.
pub fn find_by_ident_and_namespace(
@ -238,7 +278,7 @@ impl AssocItems {
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name)
.filter(|item| item.kind.namespace() == ns)
.filter(|item| item.namespace() == ns)
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
}
}

View File

@ -464,7 +464,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
self.associated_items(def_id)
.in_definition_order()
.filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type))
.filter(|assoc_item| assoc_item.is_type())
.map(|assoc_item| assoc_item.def_id)
}
@ -2147,7 +2147,7 @@ impl<'tcx> TyCtxt<'tcx> {
return vec![];
};
let mut v = TraitObjectVisitor(vec![], self.hir());
let mut v = TraitObjectVisitor(vec![]);
v.visit_ty_unambig(hir_output);
v.0
}
@ -2160,7 +2160,7 @@ impl<'tcx> TyCtxt<'tcx> {
scope_def_id: LocalDefId,
) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option<Span>)> {
let hir_id = self.local_def_id_to_hir_id(scope_def_id);
let mut v = TraitObjectVisitor(vec![], self.hir());
let mut v = TraitObjectVisitor(vec![]);
// when the return type is a type alias
if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir_fn_decl_by_hir_id(hir_id)
&& let hir::TyKind::Path(hir::QPath::Resolved(

View File

@ -571,7 +571,7 @@ pub fn suggest_constraining_type_params<'a>(
}
/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
pub(crate) struct TraitObjectVisitor<'tcx>(pub(crate) Vec<&'tcx hir::Ty<'tcx>>);
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
@ -592,18 +592,6 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
}
}
/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = lt.res
{
self.0.push(lt.ident.span);
}
}
}
pub struct IsSuggestableVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
infer_suggestable: bool,

View File

@ -746,7 +746,7 @@ impl<'tcx> Instance<'tcx> {
let call_once = tcx
.associated_items(fn_once)
.in_definition_order()
.find(|it| it.kind == ty::AssocKind::Fn)
.find(|it| it.is_fn())
.unwrap()
.def_id;
let track_caller =

View File

@ -1462,7 +1462,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
self.associated_items(id)
.in_definition_order()
.filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
.filter(move |item| item.is_fn() && item.defaultness(self).has_value())
}
pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
@ -1608,8 +1608,11 @@ impl<'tcx> TyCtxt<'tcx> {
/// return-position `impl Trait` from a trait, then provide the source info
/// about where that RPITIT came from.
pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> {
if let DefKind::AssocTy = self.def_kind(def_id) {
self.associated_item(def_id).opt_rpitit_info
if let DefKind::AssocTy = self.def_kind(def_id)
&& let AssocKind::Type { data: AssocTypeData::Rpitit(rpitit_info) } =
self.associated_item(def_id).kind
{
Some(rpitit_info)
} else {
None
}

View File

@ -1214,7 +1214,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
&& assoc
.trait_container(tcx)
.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine))
&& assoc.name == rustc_span::sym::Return
&& assoc.opt_name() == Some(rustc_span::sym::Return)
{
if let ty::Coroutine(_, args) = args.type_at(0).kind() {
let return_ty = args.as_coroutine().return_ty();
@ -1237,7 +1237,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
p!(", ");
}
p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name()));
match term.unpack() {
TermKind::Ty(ty) => p!(print(ty)),
@ -3291,7 +3291,7 @@ define_print! {
}
ty::ExistentialProjection<'tcx> {
let name = cx.tcx().associated_item(self.def_id).name;
let name = cx.tcx().associated_item(self.def_id).name();
// The args don't contain the self ty (as it has been erased) but the corresp.
// generics do as the trait always has a self ty param. We need to offset.
let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..];

View File

@ -735,7 +735,7 @@ impl<'tcx> Ty<'tcx> {
.map(|principal| {
tcx.associated_items(principal.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| item.is_type())
.filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.count()

View File

@ -819,7 +819,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Get an English description for the item's kind.
pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str {
match def_kind {
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method",
DefKind::AssocFn if self.associated_item(def_id).is_method() => "method",
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
match coroutine_kind {
hir::CoroutineKind::Desugared(
@ -873,7 +873,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Gets an English article for the [`TyCtxt::def_kind_descr`].
pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str {
match def_kind {
DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a",
DefKind::AssocFn if self.associated_item(def_id).is_method() => "a",
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
match coroutine_kind {
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an",

View File

@ -140,8 +140,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let success_block = target_block(TestBranch::Success);
let fail_block = target_block(TestBranch::Failure);
let expect_ty = value.ty();
let expect = self.literal_operand(test.span, value);
let mut expect_ty = value.ty();
let mut expect = self.literal_operand(test.span, value);
let mut place = place;
let mut block = block;
@ -174,6 +174,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place = ref_str;
ty = ref_str_ty;
}
&ty::Pat(base, _) => {
assert_eq!(ty, value.ty());
assert!(base.is_trivially_pure_clone_copy());
let transmuted_place = self.temp(base, test.span);
self.cfg.push_assign(
block,
self.source_info(scrutinee_span),
transmuted_place,
Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base),
);
let transmuted_expect = self.temp(base, test.span);
self.cfg.push_assign(
block,
self.source_info(test.span),
transmuted_expect,
Rvalue::Cast(CastKind::Transmute, expect, base),
);
place = transmuted_place;
expect = Operand::Copy(transmuted_expect);
ty = base;
expect_ty = base;
}
_ => {}
}
@ -715,7 +740,7 @@ fn trait_method<'tcx>(
let item = tcx
.associated_items(trait_def_id)
.filter_by_name_unhygienic(method_name)
.find(|item| item.kind == ty::AssocKind::Fn)
.find(|item| item.is_fn())
.expect("trait method not found");
let method_ty = Ty::new_fn_def(tcx, item.def_id, args);

View File

@ -42,7 +42,7 @@ impl<'a, 'tcx> UndefinedTransmutesChecker<'a, 'tcx> {
if self.tcx.is_const_fn(def_id)
|| matches!(
self.tcx.opt_associated_item(def_id),
Some(AssocItem { kind: AssocKind::Const, .. })
Some(AssocItem { kind: AssocKind::Const { .. }, .. })
)
{
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();

View File

@ -66,7 +66,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
let call_mut = tcx
.associated_items(fn_mut)
.in_definition_order()
.find(|it| it.kind == ty::AssocKind::Fn)
.find(|it| it.is_fn())
.unwrap()
.def_id;

View File

@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::visit::Visitor as MirVisitor;
use rustc_middle::mir::{self, Location, traversal};
use rustc_middle::ty::{self, AssocKind, Instance, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{self, AssocTag, Instance, Ty, TyCtxt, TypeFoldable};
use rustc_session::Limit;
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
use rustc_span::source_map::Spanned;
@ -194,7 +194,7 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
if let Some(new) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
tcx,
fn_ident,
AssocKind::Fn,
AssocTag::Fn,
def_id,
) {
return Some(new.def_id);

View File

@ -792,37 +792,46 @@ where
};
match proven_via {
// Even when a trait bound has been proven using a where-bound, we
// still need to consider alias-bounds for normalization, see
// tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
//
// FIXME(const_trait_impl): should this behavior also be used by
// constness checking. Doing so is *at least theoretically* breaking,
// see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
let mut candidates_from_env_and_bounds: Vec<_> = candidates
.iter()
.filter(|c| {
matches!(
c.source,
CandidateSource::AliasBound | CandidateSource::ParamEnv(_)
)
})
.map(|c| c.result)
.collect();
let mut considered_candidates = Vec::new();
considered_candidates.extend(
candidates
.iter()
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
.map(|c| c.result),
);
// Even when a trait bound has been proven using a where-bound, we
// still need to consider alias-bounds for normalization, see
// tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
//
// We still need to prefer where-bounds over alias-bounds however.
// See tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs.
//
// FIXME(const_trait_impl): should this behavior also be used by
// constness checking. Doing so is *at least theoretically* breaking,
// see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
if considered_candidates.is_empty() {
considered_candidates.extend(
candidates
.iter()
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
.map(|c| c.result),
);
}
// If the trait goal has been proven by using the environment, we want to treat
// aliases as rigid if there are no applicable projection bounds in the environment.
if candidates_from_env_and_bounds.is_empty() {
if considered_candidates.is_empty() {
if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
candidates_from_env_and_bounds.push(response);
considered_candidates.push(response);
}
}
if let Some(response) = self.try_merge_responses(&candidates_from_env_and_bounds) {
if let Some(response) = self.try_merge_responses(&considered_candidates) {
Ok(response)
} else {
self.flounder(&candidates_from_env_and_bounds)
self.flounder(&considered_candidates)
}
}
TraitGoalProvenVia::Misc => {

View File

@ -164,6 +164,7 @@ where
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let cx = ecx.cx();
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -174,20 +175,37 @@ where
// Only consider auto impls of unsafe traits when there are no unsafe
// fields.
if ecx.cx().trait_is_unsafe(goal.predicate.def_id())
if cx.trait_is_unsafe(goal.predicate.def_id())
&& goal.predicate.self_ty().has_unsafe_fields()
{
return Err(NoSolution);
}
// We only look into opaque types during analysis for opaque types
// outside of their defining scope. Doing so for opaques in the
// defining scope may require calling `typeck` on the same item we're
// currently type checking, which will result in a fatal cycle that
// ideally we want to avoid, since we can make progress on this goal
// via an alias bound or a locally-inferred hidden type instead.
// We leak the implemented auto traits of opaques outside of their defining scope.
// This depends on `typeck` of the defining scope of that opaque, which may result in
// fatal query cycles.
//
// We only get to this point if we're outside of the defining scope as we'd otherwise
// be able to normalize the opaque type. We may also cycle in case `typeck` of a defining
// scope relies on the current context, e.g. either because it also leaks auto trait
// bounds of opaques defined in the current context or by evaluating the current item.
//
// To avoid this we don't try to leak auto trait bounds if they can also be proven via
// item bounds of the opaque. These bounds are always applicable as auto traits must not
// have any generic parameters. They would also get preferred over the impl candidate
// when merging candidates anyways.
//
// See tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs.
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
if item_bound
.as_trait_clause()
.is_some_and(|b| b.def_id() == goal.predicate.def_id())
{
return Err(NoSolution);
}
}
}
ecx.probe_and_evaluate_goal_for_constituent_tys(
@ -1238,10 +1256,11 @@ where
D: SolverDelegate<Interner = I>,
I: Interner,
{
#[instrument(level = "debug", skip(self, goal), ret)]
pub(super) fn merge_trait_candidates(
&mut self,
goal: Goal<I, TraitPredicate<I>>,
candidates: Vec<Candidate<I>>,
mut candidates: Vec<Candidate<I>>,
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
if let TypingMode::Coherence = self.typing_mode() {
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
@ -1323,13 +1342,16 @@ where
// If there are *only* global where bounds, then make sure to return that this
// is still reported as being proven-via the param-env so that rigid projections
// operate correctly.
// operate correctly. Otherwise, drop all global where-bounds before merging the
// remaining candidates.
let proven_via =
if candidates.iter().all(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
TraitGoalProvenVia::ParamEnv
} else {
candidates.retain(|c| !matches!(c.source, CandidateSource::ParamEnv(_)));
TraitGoalProvenVia::Misc
};
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
if let Some(response) = self.try_merge_responses(&all_candidates) {
Ok((response, Some(proven_via)))

View File

@ -1994,7 +1994,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
.iter()
.flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
// Only assoc fn with no receivers.
.filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
.filter(|item| item.is_fn() && !item.is_method())
.filter_map(|item| {
// Only assoc fns that return `Self`
let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
@ -2007,8 +2007,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
if def.did() != def_id {
return None;
}
let order = !item.name.as_str().starts_with("new");
Some((order, item.name, input_len))
let name = item.name();
let order = !name.as_str().starts_with("new");
Some((order, name, input_len))
})
.collect::<Vec<_>>();
items.sort_by_key(|(order, _, _)| *order);

View File

@ -240,7 +240,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
.flat_map(|super_poly_trait_ref| {
tcx.associated_items(super_poly_trait_ref.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| item.is_type())
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.map(move |assoc_ty| {
super_poly_trait_ref.map_bound(|super_trait_ref| {
@ -446,7 +446,7 @@ pub(crate) fn transform_instance<'tcx>(
let call = tcx
.associated_items(trait_id)
.in_definition_order()
.find(|it| it.kind == ty::AssocKind::Fn)
.find(|it| it.is_fn())
.expect("No call-family function on closure-like Fn trait?")
.def_id;

View File

@ -894,12 +894,21 @@ impl<'tcx> Stable<'tcx> for rustc_session::cstore::ForeignModule {
impl<'tcx> Stable<'tcx> for ty::AssocKind {
type T = stable_mir::ty::AssocKind;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
use stable_mir::ty::AssocKind;
match self {
ty::AssocKind::Const => AssocKind::Const,
ty::AssocKind::Fn => AssocKind::Fn,
ty::AssocKind::Type => AssocKind::Type,
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
use stable_mir::ty::{AssocKind, AssocTypeData};
match *self {
ty::AssocKind::Const { name } => AssocKind::Const { name: name.to_string() },
ty::AssocKind::Fn { name, has_self } => {
AssocKind::Fn { name: name.to_string(), has_self }
}
ty::AssocKind::Type { data } => AssocKind::Type {
data: match data {
ty::AssocTypeData::Normal(name) => AssocTypeData::Normal(name.to_string()),
ty::AssocTypeData::Rpitit(rpitit) => {
AssocTypeData::Rpitit(rpitit.stable(tables))
}
},
},
}
}
}
@ -922,12 +931,9 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem {
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
stable_mir::ty::AssocItem {
def_id: tables.assoc_def(self.def_id),
name: self.name.to_string(),
kind: self.kind.stable(tables),
container: self.container.stable(tables),
trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)),
fn_has_self_parameter: self.fn_has_self_parameter,
opt_rpitit_info: self.opt_rpitit_info.map(|rpitit| rpitit.stable(tables)),
}
}
}

View File

@ -22,9 +22,10 @@ impl Display for Ty {
impl Display for AssocKind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
AssocKind::Fn => write!(f, "method"),
AssocKind::Const => write!(f, "associated const"),
AssocKind::Type => write!(f, "associated type"),
AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
AssocKind::Const { .. } => write!(f, "associated const"),
AssocKind::Type { .. } => write!(f, "associated type"),
}
}
}

View File

@ -1578,29 +1578,28 @@ crate_def! {
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct AssocItem {
pub def_id: AssocDef,
pub name: Symbol,
pub kind: AssocKind,
pub container: AssocItemContainer,
/// If this is an item in an impl of a trait then this is the `DefId` of
/// the associated item on the trait that this implements.
pub trait_item_def_id: Option<AssocDef>,
}
/// Whether this is a method with an explicit self
/// as its first parameter, allowing method calls.
pub fn_has_self_parameter: bool,
/// `Some` if the associated item (an associated type) comes from the
/// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
/// provides additional information about its source.
pub opt_rpitit_info: Option<ImplTraitInTraitData>,
#[derive(Clone, PartialEq, Debug, Eq, Serialize)]
pub enum AssocTypeData {
Normal(Symbol),
/// The associated type comes from an RPITIT. It has no name, and the
/// `ImplTraitInTraitData` provides additional information about its
/// source.
Rpitit(ImplTraitInTraitData),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum AssocKind {
Const,
Fn,
Type,
Const { name: Symbol },
Fn { name: Symbol, has_self: bool },
Type { data: AssocTypeData },
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
@ -1617,6 +1616,6 @@ pub enum ImplTraitInTraitData {
impl AssocItem {
pub fn is_impl_trait_in_trait(&self) -> bool {
self.opt_rpitit_info.is_some()
matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
}
}

View File

@ -615,7 +615,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
cx.print_def_path(trait_ref.def_id, trait_ref.args)?;
}
ty::ExistentialPredicate::Projection(projection) => {
let name = cx.tcx.associated_item(projection.def_id).name;
let name = cx.tcx.associated_item(projection.def_id).name();
cx.push("p");
cx.push_ident(name.as_str());
match projection.term.unpack() {

View File

@ -2334,13 +2334,13 @@ impl<'tcx> ObligationCause<'tcx> {
subdiags: Vec<TypeErrorAdditionalDiags>,
) -> ObligationCauseFailureCode {
match self.code() {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
ObligationCauseFailureCode::MethodCompat { span, subdiags }
}
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
ObligationCauseFailureCode::TypeCompat { span, subdiags }
}
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
ObligationCauseFailureCode::ConstCompat { span, subdiags }
}
ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
@ -2398,13 +2398,13 @@ impl<'tcx> ObligationCause<'tcx> {
fn as_requirement_str(&self) -> &'static str {
match self.code() {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
"method type is compatible with trait"
}
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
"associated type is compatible with trait"
}
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
"const is compatible with trait"
}
ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
@ -2422,9 +2422,13 @@ pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
let kind = match self.0.code() {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat",
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat",
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
"method_compat"
}
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
"type_compat"
}
ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
"const_compat"
}
ObligationCauseCode::MainFunctionType => "fn_main_correct_type",

View File

@ -98,7 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let assoc_item = self.tcx().associated_item(trait_item_def_id);
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
match assoc_item.kind {
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
if let Some(hir_id) =
assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id))
{

View File

@ -158,6 +158,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
&& self
.tcx()
.opt_associated_item(scope_def_id.to_def_id())
.is_some_and(|i| i.fn_has_self_parameter)
.is_some_and(|i| i.is_method())
}
}

View File

@ -782,8 +782,8 @@ fn foo(&self) -> Self::T { String::new() }
let methods: Vec<(Span, String)> = items
.in_definition_order()
.filter(|item| {
ty::AssocKind::Fn == item.kind
&& Some(item.name) != current_method_ident
item.is_fn()
&& Some(item.name()) != current_method_ident
&& !tcx.is_doc_hidden(item.def_id)
})
.filter_map(|item| {

View File

@ -1017,7 +1017,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
" for lifetime parameter {}in trait containing associated type `{}`",
br_string(br),
self.tcx.associated_item(def_id).name
self.tcx.associated_item(def_id).name()
),
infer::RegionParameterDefinition(_, name) => {
format!(" for lifetime parameter `{name}`")

View File

@ -348,11 +348,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
&& let None = self.tainted_by_errors()
{
let (verb, noun) = match self.tcx.associated_item(item_id).kind {
ty::AssocKind::Const => ("refer to the", "constant"),
ty::AssocKind::Fn => ("call", "function"),
ty::AssocKind::Const { .. } => ("refer to the", "constant"),
ty::AssocKind::Fn { .. } => ("call", "function"),
// This is already covered by E0223, but this following single match
// arm doesn't hurt here.
ty::AssocKind::Type => ("refer to the", "type"),
ty::AssocKind::Type { .. } => ("refer to the", "type"),
};
// Replace the more general E0283 with a more specific error

View File

@ -2112,16 +2112,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_ref: DefId,
) {
if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) {
if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind {
if let ty::AssocKind::Const { .. } | ty::AssocKind::Type { .. } = assoc_item.kind {
err.note(format!(
"{}s cannot be accessed directly on a `trait`, they can only be \
accessed through a specific `impl`",
self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id)
self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id)
));
err.span_suggestion(
span,
"use the fully qualified path to an implementation",
format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.name),
format!(
"<Type as {}>::{}",
self.tcx.def_path_str(trait_ref),
assoc_item.name()
),
Applicability::HasPlaceholders,
);
}
@ -5411,7 +5415,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind(
tcx,
Ident::with_dummy_span(name),
ty::AssocKind::Type,
ty::AssocTag::Type,
data.impl_or_alias_def_id,
)
{

View File

@ -188,7 +188,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
tcx.associated_items(trait_def_id)
.in_definition_order()
// We're only looking at associated type bounds
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| item.is_type())
// Ignore GATs with `Self: Sized`
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
@ -298,31 +298,33 @@ pub fn dyn_compatibility_violations_for_assoc_item(
match item.kind {
// Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all,
// and associated const bounds in trait objects aren't a thing yet either.
ty::AssocKind::Const => {
vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)]
ty::AssocKind::Const { name } => {
vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)]
}
ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
.into_iter()
.map(|v| {
let node = tcx.hir_get_if_local(item.def_id);
// Get an accurate span depending on the violation.
let span = match (&v, node) {
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
}
_ => item.ident(tcx).span,
};
ty::AssocKind::Fn { name, .. } => {
virtual_call_violations_for_method(tcx, trait_def_id, item)
.into_iter()
.map(|v| {
let node = tcx.hir_get_if_local(item.def_id);
// Get an accurate span depending on the violation.
let span = match (&v, node) {
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
}
_ => item.ident(tcx).span,
};
DynCompatibilityViolation::Method(item.name, v, span)
})
.collect(),
DynCompatibilityViolation::Method(name, v, span)
})
.collect()
}
// Associated types can only be dyn-compatible if they have `Self: Sized` bounds.
ty::AssocKind::Type => {
ty::AssocKind::Type { .. } => {
if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() {
vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)]
vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)]
} else {
// We will permit associated types if they are explicitly mentioned in the trait object.
// We can't check this here, as here we only check if it is guaranteed to not be possible.
@ -344,7 +346,7 @@ fn virtual_call_violations_for_method<'tcx>(
let sig = tcx.fn_sig(method.def_id).instantiate_identity();
// The method's first parameter must be named `self`
if !method.fn_has_self_parameter {
if !method.is_method() {
let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
generics,
kind: hir::TraitItemKind::Fn(sig, _),

View File

@ -1393,7 +1393,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
coroutine_sig,
);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Output);
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
@ -1439,7 +1439,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
gen_sig,
);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
@ -1485,7 +1485,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
gen_sig,
);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
let ty::Adt(_poll_adt, args) = *yield_ty.kind() else {
bug!();
@ -2005,7 +2005,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
if !assoc_ty.item.defaultness(tcx).has_value() {
debug!(
"confirm_impl_candidate: no associated type {:?} for {:?}",
assoc_ty.item.name, obligation.predicate
assoc_ty.item.name(),
obligation.predicate
);
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
// We treat this projection as rigid here, which is represented via

View File

@ -594,9 +594,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Associated types that require `Self: Sized` do not show up in the built-in
// implementation of `Trait for dyn Trait`, and can be dropped here.
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.filter_map(
|item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
)
.filter_map(|item| if item.is_type() { Some(item.def_id) } else { None })
.collect();
for assoc_type in assoc_types {

View File

@ -197,10 +197,8 @@ fn own_existential_vtable_entries_iter(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
) -> impl Iterator<Item = DefId> {
let trait_methods = tcx
.associated_items(trait_def_id)
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Fn);
let trait_methods =
tcx.associated_items(trait_def_id).in_definition_order().filter(|item| item.is_fn());
// Now list each method's DefId (for within its trait).
let own_entries = trait_methods.filter_map(move |&trait_method| {

View File

@ -6,7 +6,6 @@ use rustc_hir::{self as hir, AmbigArg};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::kw;
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
@ -129,39 +128,35 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
let owner_id = trait_item_ref.id.owner_id;
let (kind, has_self) = match trait_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
let name = trait_item_ref.ident.name;
let kind = match trait_item_ref.kind {
hir::AssocItemKind::Const => ty::AssocKind::Const { name },
hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
};
ty::AssocItem {
name: trait_item_ref.ident.name,
kind,
def_id: owner_id.to_def_id(),
trait_item_def_id: Some(owner_id.to_def_id()),
container: ty::AssocItemContainer::Trait,
fn_has_self_parameter: has_self,
opt_rpitit_info: None,
}
}
fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
let def_id = impl_item_ref.id.owner_id;
let (kind, has_self) = match impl_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
let name = impl_item_ref.ident.name;
let kind = match impl_item_ref.kind {
hir::AssocItemKind::Const => ty::AssocKind::Const { name },
hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
};
ty::AssocItem {
name: impl_item_ref.ident.name,
kind,
def_id: def_id.to_def_id(),
trait_item_def_id: impl_item_ref.trait_item_def_id,
container: ty::AssocItemContainer::Impl,
fn_has_self_parameter: has_self,
opt_rpitit_info: None,
}
}
@ -264,16 +259,15 @@ fn associated_type_for_impl_trait_in_trait(
trait_assoc_ty.def_ident_span(Some(span));
trait_assoc_ty.associated_item(ty::AssocItem {
name: kw::Empty,
kind: ty::AssocKind::Type,
kind: ty::AssocKind::Type {
data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
fn_def_id: fn_def_id.to_def_id(),
opaque_def_id: opaque_ty_def_id.to_def_id(),
}),
},
def_id,
trait_item_def_id: None,
container: ty::AssocItemContainer::Trait,
fn_has_self_parameter: false,
opt_rpitit_info: Some(ImplTraitInTraitData::Trait {
fn_def_id: fn_def_id.to_def_id(),
opaque_def_id: opaque_ty_def_id.to_def_id(),
}),
});
// Copy visility of the containing function.
@ -317,13 +311,14 @@ fn associated_type_for_impl_trait_in_impl(
impl_assoc_ty.def_ident_span(Some(span));
impl_assoc_ty.associated_item(ty::AssocItem {
name: kw::Empty,
kind: ty::AssocKind::Type,
kind: ty::AssocKind::Type {
data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
fn_def_id: impl_fn_def_id.to_def_id(),
}),
},
def_id,
trait_item_def_id: Some(trait_assoc_def_id),
container: ty::AssocItemContainer::Impl,
fn_has_self_parameter: false,
opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }),
});
// Copy visility of the containing function.

View File

@ -2,19 +2,23 @@
pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires};
/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }`
/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }`
/// (including the implicit return of the tail expression, if any).
/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute.
///
/// This is an existing hack to allow users to omit the type of the return value in their ensures
/// attribute.
///
/// Ideally, rustc should be able to generate the type annotation.
/// The existing lowering logic makes it rather hard to add the explicit type annotation,
/// while the function call is fairly straight forward.
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
// Similar to `contract_check_requires`, we need to use the user-facing
// `contracts` feature rather than the perma-unstable `contracts_internals`.
// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
#[lang = "contract_build_check_ensures"]
#[track_caller]
pub fn build_check_ensures<Ret, C>(cond: C) -> impl (Fn(Ret) -> Ret) + Copy
pub const fn build_check_ensures<Ret, C>(cond: C) -> C
where
C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static,
C: Fn(&Ret) -> bool + Copy + 'static,
{
#[track_caller]
move |ret| {
crate::intrinsics::contract_check_ensures(&ret, cond);
ret
}
cond
}

View File

@ -3402,20 +3402,62 @@ pub const fn contract_checks() -> bool {
///
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
/// returns false.
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
///
/// Note that this function is a no-op during constant evaluation.
#[unstable(feature = "contracts_internals", issue = "128044")]
// Calls to this function get inserted by an AST expansion pass, which uses the equivalent of
// `#[allow_internal_unstable]` to allow using `contracts_internals` functions. Const-checking
// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing
// `contracts` feature rather than the perma-unstable `contracts_internals`
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
#[lang = "contract_check_requires"]
#[rustc_intrinsic]
pub fn contract_check_requires<C: Fn() -> bool>(cond: C) {
if contract_checks() && !cond() {
// Emit no unwind panic in case this was a safety requirement.
crate::panicking::panic_nounwind("failed requires check");
}
pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
const_eval_select!(
@capture[C: Fn() -> bool + Copy] { cond: C } :
if const {
// Do nothing
} else {
if contract_checks() && !cond() {
// Emit no unwind panic in case this was a safety requirement.
crate::panicking::panic_nounwind("failed requires check");
}
}
)
}
/// Check if the post-condition `cond` has been met.
///
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
/// returns false.
///
/// Note that this function is a no-op during constant evaluation.
#[cfg(not(bootstrap))]
#[unstable(feature = "contracts_internals", issue = "128044")]
// Similar to `contract_check_requires`, we need to use the user-facing
// `contracts` feature rather than the perma-unstable `contracts_internals`.
// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
#[lang = "contract_check_ensures"]
#[rustc_intrinsic]
pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, ret: Ret) -> Ret {
const_eval_select!(
@capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret :
if const {
// Do nothing
ret
} else {
if contract_checks() && !cond(&ret) {
// Emit no unwind panic in case this was a safety requirement.
crate::panicking::panic_nounwind("failed ensures check");
}
ret
}
)
}
/// This is the old version of contract_check_ensures kept here for bootstrap only.
#[cfg(bootstrap)]
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
#[rustc_intrinsic]
pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) {

View File

@ -101,7 +101,6 @@
#![feature(bstr)]
#![feature(bstr_internals)]
#![feature(cfg_match)]
#![feature(closure_track_caller)]
#![feature(const_carrying_mul_add)]
#![feature(const_eval_select)]
#![feature(core_intrinsics)]

View File

@ -111,12 +111,6 @@ impl Clone for TokenStream {
}
}
impl Clone for SourceFile {
fn clone(&self) -> Self {
self.clone()
}
}
impl Span {
pub(crate) fn def_site() -> Span {
Bridge::with(|bridge| bridge.globals.def_site)

View File

@ -81,16 +81,8 @@ macro_rules! with_api {
$self: $S::TokenStream
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
},
SourceFile {
fn drop($self: $S::SourceFile);
fn clone($self: &$S::SourceFile) -> $S::SourceFile;
fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool;
fn path($self: &$S::SourceFile) -> String;
fn is_real($self: &$S::SourceFile) -> bool;
},
Span {
fn debug($self: $S::Span) -> String;
fn source_file($self: $S::Span) -> $S::SourceFile;
fn parent($self: $S::Span) -> Option<$S::Span>;
fn source($self: $S::Span) -> $S::Span;
fn byte_range($self: $S::Span) -> Range<usize>;
@ -98,6 +90,8 @@ macro_rules! with_api {
fn end($self: $S::Span) -> $S::Span;
fn line($self: $S::Span) -> usize;
fn column($self: $S::Span) -> usize;
fn file($self: $S::Span) -> String;
fn local_file($self: $S::Span) -> Option<String>;
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
fn subspan($self: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
@ -120,7 +114,6 @@ macro_rules! with_api_handle_types {
'owned:
FreeFunctions,
TokenStream,
SourceFile,
'interned:
Span,

View File

@ -82,7 +82,6 @@ with_api_handle_types!(define_server_handles);
pub trait Types {
type FreeFunctions: 'static;
type TokenStream: 'static + Clone;
type SourceFile: 'static + Clone;
type Span: 'static + Copy + Eq + Hash;
type Symbol: 'static;
}

View File

@ -491,12 +491,6 @@ impl Span {
Span(bridge::client::Span::mixed_site())
}
/// The original source file into which this span points.
#[unstable(feature = "proc_macro_span", issue = "54725")]
pub fn source_file(&self) -> SourceFile {
SourceFile(self.0.source_file())
}
/// The `Span` for the tokens in the previous macro expansion from which
/// `self` was generated from, if any.
#[unstable(feature = "proc_macro_span", issue = "54725")]
@ -546,6 +540,25 @@ impl Span {
self.0.column()
}
/// The path to the source file in which this span occurs, for display purposes.
///
/// This might not correspond to a valid file system path.
/// It might be remapped, or might be an artificial path such as `"<macro expansion>"`.
#[unstable(feature = "proc_macro_span", issue = "54725")]
pub fn file(&self) -> String {
self.0.file()
}
/// The path to the source file in which this span occurs on disk.
///
/// This is the actual path on disk. It is unaffected by path remapping.
///
/// This path should not be embedded in the output of the macro; prefer `file()` instead.
#[unstable(feature = "proc_macro_span", issue = "54725")]
pub fn local_file(&self) -> Option<PathBuf> {
self.0.local_file().map(|s| PathBuf::from(s))
}
/// Creates a new span encompassing `self` and `other`.
///
/// Returns `None` if `self` and `other` are from different files.
@ -614,58 +627,6 @@ impl fmt::Debug for Span {
}
}
/// The source file of a given `Span`.
#[unstable(feature = "proc_macro_span", issue = "54725")]
#[derive(Clone)]
pub struct SourceFile(bridge::client::SourceFile);
impl SourceFile {
/// Gets the path to this source file.
///
/// ### Note
/// If the code span associated with this `SourceFile` was generated by an external macro, this
/// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check.
///
/// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on
/// the command line, the path as given might not actually be valid.
///
/// [`is_real`]: Self::is_real
#[unstable(feature = "proc_macro_span", issue = "54725")]
pub fn path(&self) -> PathBuf {
PathBuf::from(self.0.path())
}
/// Returns `true` if this source file is a real source file, and not generated by an external
/// macro's expansion.
#[unstable(feature = "proc_macro_span", issue = "54725")]
pub fn is_real(&self) -> bool {
// This is a hack until intercrate spans are implemented and we can have real source files
// for spans generated in external macros.
// https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368
self.0.is_real()
}
}
#[unstable(feature = "proc_macro_span", issue = "54725")]
impl fmt::Debug for SourceFile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SourceFile")
.field("path", &self.path())
.field("is_real", &self.is_real())
.finish()
}
}
#[unstable(feature = "proc_macro_span", issue = "54725")]
impl PartialEq for SourceFile {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
#[unstable(feature = "proc_macro_span", issue = "54725")]
impl Eq for SourceFile {}
/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`).
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
#[derive(Clone)]

View File

@ -1286,6 +1286,40 @@ pub struct Output {
pub stderr: Vec<u8>,
}
impl Output {
/// Returns an error if a nonzero exit status was received.
///
/// If the [`Command`] exited successfully,
/// `self` is returned.
///
/// This is equivalent to calling [`exit_ok`](ExitStatus::exit_ok)
/// on [`Output.status`](Output::status).
///
/// Note that this will throw away the [`Output::stderr`] field in the error case.
/// If the child process outputs useful informantion to stderr, you can:
/// * Use `cmd.stderr(Stdio::inherit())` to forward the
/// stderr child process to the parent's stderr,
/// usually printing it to console where the user can see it.
/// This is usually correct for command-line applications.
/// * Capture `stderr` using a custom error type.
/// This is usually correct for libraries.
///
/// # Examples
///
/// ```
/// #![feature(exit_status_error)]
/// # #[cfg(unix)] {
/// use std::process::Command;
/// assert!(Command::new("false").output().unwrap().exit_ok().is_err());
/// # }
/// ```
#[unstable(feature = "exit_status_error", issue = "84908")]
pub fn exit_ok(self) -> Result<Self, ExitStatusError> {
self.status.exit_ok()?;
Ok(self)
}
}
// If either stderr or stdout are valid utf8 strings it prints the valid
// strings, otherwise it prints the byte sequence instead
#[stable(feature = "process_output_debug", since = "1.7.0")]

View File

@ -274,6 +274,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
libc::ETXTBSY => ExecutableFileBusy,
libc::EXDEV => CrossesDevices,
libc::EINPROGRESS => InProgress,
libc::EOPNOTSUPP => Unsupported,
libc::EACCES | libc::EPERM => PermissionDenied,

View File

@ -8,14 +8,19 @@ use crate::sys::weak::weak;
use crate::sys::{os, stack_overflow};
use crate::time::Duration;
use crate::{cmp, io, ptr};
#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
#[cfg(not(any(
target_os = "l4re",
target_os = "vxworks",
target_os = "espidf",
target_os = "nuttx"
)))]
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
#[cfg(target_os = "l4re")]
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
#[cfg(target_os = "vxworks")]
pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
#[cfg(target_os = "espidf")]
pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF menuconfig system should be used
#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used
#[cfg(target_os = "fuchsia")]
mod zircon {
@ -52,10 +57,10 @@ impl Thread {
let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
#[cfg(target_os = "espidf")]
#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
if stack > 0 {
// Only set the stack if a non-zero value is passed
// 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used
// 0 is used as an indication that the default stack size configured in the ESP-IDF/NuttX menuconfig system should be used
assert_eq!(
libc::pthread_attr_setstacksize(
attr.as_mut_ptr(),
@ -65,7 +70,7 @@ impl Thread {
);
}
#[cfg(not(target_os = "espidf"))]
#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
{
let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr()));

View File

@ -1,4 +1,4 @@
use r_efi::protocols::simple_text_output;
use r_efi::protocols::{simple_text_input, simple_text_output};
use crate::collections::BTreeMap;
pub use crate::ffi::OsString as EnvKey;
@ -23,6 +23,7 @@ pub struct Command {
args: Vec<OsString>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
stdin: Option<Stdio>,
env: CommandEnv,
}
@ -48,6 +49,7 @@ impl Command {
args: Vec::new(),
stdout: None,
stderr: None,
stdin: None,
env: Default::default(),
}
}
@ -64,8 +66,8 @@ impl Command {
panic!("unsupported")
}
pub fn stdin(&mut self, _stdin: Stdio) {
panic!("unsupported")
pub fn stdin(&mut self, stdin: Stdio) {
self.stdin = Some(stdin);
}
pub fn stdout(&mut self, stdout: Stdio) {
@ -122,6 +124,22 @@ impl Command {
}
}
fn create_stdin(
s: Stdio,
) -> io::Result<Option<helpers::OwnedProtocol<uefi_command_internal::InputProtocol>>> {
match s {
Stdio::Null => unsafe {
helpers::OwnedProtocol::create(
uefi_command_internal::InputProtocol::null(),
simple_text_input::PROTOCOL_GUID,
)
}
.map(Some),
Stdio::Inherit => Ok(None),
Stdio::MakePipe => unsupported(),
}
}
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
@ -149,6 +167,15 @@ impl Command {
cmd.stderr_inherit()
};
// Setup Stdin
let stdin = self.stdin.unwrap_or(Stdio::Null);
let stdin = Self::create_stdin(stdin)?;
if let Some(con) = stdin {
cmd.stdin_init(con)
} else {
cmd.stdin_inherit()
};
let env = env_changes(&self.env);
// Set any new vars
@ -334,7 +361,7 @@ impl<'a> fmt::Debug for CommandArgs<'a> {
#[allow(dead_code)]
mod uefi_command_internal {
use r_efi::protocols::{loaded_image, simple_text_output};
use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output};
use crate::ffi::{OsStr, OsString};
use crate::io::{self, const_error};
@ -350,6 +377,7 @@ mod uefi_command_internal {
handle: NonNull<crate::ffi::c_void>,
stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
stdin: Option<helpers::OwnedProtocol<InputProtocol>>,
st: OwnedTable<r_efi::efi::SystemTable>,
args: Option<(*mut u16, usize)>,
}
@ -384,7 +412,14 @@ mod uefi_command_internal {
helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });
Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None })
Ok(Self {
handle: child_handle,
stdout: None,
stderr: None,
stdin: None,
st,
args: None,
})
}
}
@ -445,6 +480,17 @@ mod uefi_command_internal {
}
}
fn set_stdin(
&mut self,
handle: r_efi::efi::Handle,
protocol: *mut simple_text_input::Protocol,
) {
unsafe {
(*self.st.as_mut_ptr()).console_in_handle = handle;
(*self.st.as_mut_ptr()).con_in = protocol;
}
}
pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
self.set_stdout(
protocol.handle().as_ptr(),
@ -471,6 +517,19 @@ mod uefi_command_internal {
unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
}
pub(crate) fn stdin_init(&mut self, protocol: helpers::OwnedProtocol<InputProtocol>) {
self.set_stdin(
protocol.handle().as_ptr(),
protocol.as_ref() as *const InputProtocol as *mut simple_text_input::Protocol,
);
self.stdin = Some(protocol);
}
pub(crate) fn stdin_inherit(&mut self) {
let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) }
}
pub fn stderr(&self) -> io::Result<Vec<u8>> {
match &self.stderr {
Some(stderr) => stderr.as_ref().utf8(),
@ -722,6 +781,56 @@ mod uefi_command_internal {
}
}
#[repr(C)]
pub(crate) struct InputProtocol {
reset: simple_text_input::ProtocolReset,
read_key_stroke: simple_text_input::ProtocolReadKeyStroke,
wait_for_key: r_efi::efi::Event,
}
impl InputProtocol {
pub(crate) fn null() -> Self {
let evt = helpers::OwnedEvent::new(
r_efi::efi::EVT_NOTIFY_WAIT,
r_efi::efi::TPL_CALLBACK,
Some(Self::empty_notify),
None,
)
.unwrap();
Self {
reset: Self::null_reset,
read_key_stroke: Self::null_read_key,
wait_for_key: evt.into_raw(),
}
}
extern "efiapi" fn null_reset(
_: *mut simple_text_input::Protocol,
_: r_efi::efi::Boolean,
) -> r_efi::efi::Status {
r_efi::efi::Status::SUCCESS
}
extern "efiapi" fn null_read_key(
_: *mut simple_text_input::Protocol,
_: *mut simple_text_input::InputKey,
) -> r_efi::efi::Status {
r_efi::efi::Status::UNSUPPORTED
}
extern "efiapi" fn empty_notify(_: r_efi::efi::Event, _: *mut crate::ffi::c_void) {}
}
impl Drop for InputProtocol {
fn drop(&mut self) {
// Close wait_for_key
unsafe {
let _ = helpers::OwnedEvent::from_raw(self.wait_for_key);
}
}
}
pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
const QUOTE: u16 = 0x0022;
const SPACE: u16 = 0x0020;

View File

@ -142,8 +142,12 @@ impl io::Write for Stderr {
// UTF-16 character should occupy 4 bytes at most in UTF-8
pub const STDIN_BUF_SIZE: usize = 4;
pub fn is_ebadf(_err: &io::Error) -> bool {
false
pub fn is_ebadf(err: &io::Error) -> bool {
if let Some(x) = err.raw_os_error() {
r_efi::efi::Status::UNSUPPORTED.as_usize() == x
} else {
false
}
}
pub fn panic_output() -> Option<impl io::Write> {

View File

@ -63,6 +63,24 @@ fn smoke_port_gone() {
assert!(tx.send(1).is_err());
}
#[test]
fn smoke_receiver_clone() {
let (tx, rx) = channel::<i32>();
let rx2 = rx.clone();
drop(rx);
tx.send(1).unwrap();
assert_eq!(rx2.recv().unwrap(), 1);
}
#[test]
fn smoke_receiver_clone_port_gone() {
let (tx, rx) = channel::<i32>();
let rx2 = rx.clone();
drop(rx);
drop(rx2);
assert!(tx.send(1).is_err());
}
#[test]
fn smoke_shared_port_gone() {
let (tx, rx) = channel::<i32>();
@ -124,6 +142,18 @@ fn chan_gone_concurrent() {
while rx.recv().is_ok() {}
}
#[test]
fn receiver_cloning() {
let (tx, rx) = channel::<i32>();
let rx2 = rx.clone();
tx.send(1).unwrap();
tx.send(2).unwrap();
assert_eq!(rx2.recv(), Ok(1));
assert_eq!(rx.recv(), Ok(2));
}
#[test]
fn stress() {
let count = if cfg!(miri) { 100 } else { 10000 };

View File

@ -3,7 +3,7 @@
use crate::core::build_steps::compile::{
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
};
use crate::core::build_steps::tool::{SourceType, prepare_tool_cargo};
use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo};
use crate::core::builder::{
self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description,
};
@ -416,7 +416,7 @@ impl Step for Compiletest {
&[],
);
cargo.allow_features("test");
cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
// For ./x.py clippy, don't run with --all-targets because
// linting tests and benchmarks can produce very noisy results

View File

@ -15,7 +15,7 @@ use crate::core::build_steps::doc::DocumentationFormat;
use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
use crate::core::build_steps::llvm::get_llvm_version;
use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
use crate::core::build_steps::tool::{self, SourceType, Tool};
use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool};
use crate::core::build_steps::toolstate::ToolState;
use crate::core::build_steps::{compile, dist, llvm};
use crate::core::builder::{
@ -721,7 +721,7 @@ impl Step for CompiletestTest {
SourceType::InTree,
&[],
);
cargo.allow_features("test");
cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
}
}

View File

@ -444,7 +444,11 @@ macro_rules! bootstrap_tool {
SourceType::InTree
},
extra_features: vec![],
allow_features: concat!($($allow_features)*),
allow_features: {
let mut _value = "";
$( _value = $allow_features; )?
_value
},
cargo_args: vec![],
artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* {
ToolArtifactKind::Library
@ -458,6 +462,8 @@ macro_rules! bootstrap_tool {
}
}
pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "test,internal_output_capture";
bootstrap_tool!(
// This is marked as an external tool because it includes dependencies
// from submodules. Trying to keep the lints in sync between all the repos
@ -468,7 +474,7 @@ bootstrap_tool!(
Tidy, "src/tools/tidy", "tidy";
Linkchecker, "src/tools/linkchecker", "linkchecker";
CargoTest, "src/tools/cargotest", "cargotest";
Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test";
Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
BuildManifest, "src/tools/build-manifest", "build-manifest";
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
RustInstaller, "src/tools/rust-installer", "rust-installer";
@ -483,7 +489,8 @@ bootstrap_tool!(
GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
SuggestTests, "src/tools/suggest-tests", "suggest-tests";
GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test";
// rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features.
RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
CoverageDump, "src/tools/coverage-dump", "coverage-dump";
WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization";
UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";

View File

@ -0,0 +1,69 @@
FROM ubuntu:25.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
bzip2 \
g++ \
gcc-multilib \
make \
ninja-build \
file \
curl \
ca-certificates \
python3 \
git \
cmake \
sudo \
gdb \
llvm-20-tools \
llvm-20-dev \
libedit-dev \
libssl-dev \
pkg-config \
zlib1g-dev \
xz-utils \
nodejs \
mingw-w64 \
# libgccjit dependencies
flex \
libmpfr-dev \
libgmp-dev \
libmpc3 \
libmpc-dev \
&& rm -rf /var/lib/apt/lists/*
# Install powershell (universal package) so we can test x.ps1 on Linux
# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep.
RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
dpkg --ignore-depends=libicu72 -i powershell.deb && \
rm -f powershell.deb
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
# We are disabling CI LLVM since this builder is intentionally using a host
# LLVM, rather than the typical src/llvm-project LLVM.
ENV NO_DOWNLOAD_CI_LLVM 1
ENV EXTERNAL_LLVM 1
# Using llvm-link-shared due to libffi issues -- see #34486
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--llvm-root=/usr/lib/llvm-20 \
--enable-llvm-link-shared \
--set rust.randomize-layout=true \
--set rust.thin-lto-import-instr-limit=10
COPY scripts/shared.sh /scripts/
ARG SCRIPT_ARG
COPY scripts/add_dummy_commit.sh /tmp/
COPY scripts/x86_64-gnu-llvm.sh /tmp/
COPY scripts/x86_64-gnu-llvm2.sh /tmp/
COPY scripts/x86_64-gnu-llvm3.sh /tmp/
COPY scripts/stage_2_test_set1.sh /tmp/
COPY scripts/stage_2_test_set2.sh /tmp/
ENV SCRIPT "/tmp/add_dummy_commit.sh && /tmp/${SCRIPT_ARG}"

View File

@ -304,6 +304,31 @@ auto:
- name: x86_64-gnu-distcheck
<<: *job-linux-8c
# The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel.
# x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}.
- name: x86_64-gnu-llvm-20-1
env:
RUST_BACKTRACE: 1
IMAGE: x86_64-gnu-llvm-20
DOCKER_SCRIPT: stage_2_test_set1.sh
<<: *job-linux-4c
# Skip tests that run in x86_64-gnu-llvm-20-{1,3}
- name: x86_64-gnu-llvm-20-2
env:
RUST_BACKTRACE: 1
IMAGE: x86_64-gnu-llvm-20
DOCKER_SCRIPT: x86_64-gnu-llvm2.sh
<<: *job-linux-4c
# Skip tests that run in x86_64-gnu-llvm-20-{1,2}
- name: x86_64-gnu-llvm-20-3
env:
RUST_BACKTRACE: 1
IMAGE: x86_64-gnu-llvm-20
DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
<<: *job-linux-4c
# The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel.
# x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}.
- name: x86_64-gnu-llvm-19-1

View File

@ -31,7 +31,6 @@ Term | Meaning
<span id="generics">generics</span> | The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters.
<span id="hir">HIR</span> | The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md))
<span id="hir-id">`HirId`</span> | Identifies a particular node in the HIR by combining a def-id with an "intra-definition offset". See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
<span id="hir-map">HIR map</span> | The HIR map, accessible via `tcx.hir()`, allows you to quickly navigate the HIR and convert between various forms of identifiers.
<span id="ice">ICE</span> | Short for _internal compiler error_, this is when the compiler crashes.
<span id="ich">ICH</span> | Short for _incremental compilation hash_, these are used as fingerprints for things such as HIR and crate metadata, to check if changes have been made. This is useful in incremental compilation to see if part of a crate has changed and should be recompiled.
<span id="infcx">`infcx`</span> | The type inference context (`InferCtxt`). (see `rustc_middle::infer`)

View File

@ -100,7 +100,7 @@ The HIR uses a bunch of different identifiers that coexist and serve different p
a wrapper around a [`HirId`]. For more info about HIR bodies, please refer to the
[HIR chapter][hir-bodies].
These identifiers can be converted into one another through the [HIR map][map].
These identifiers can be converted into one another through the `TyCtxt`.
[`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
[`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html
@ -110,30 +110,24 @@ These identifiers can be converted into one another through the [HIR map][map].
[`CrateNum`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.CrateNum.html
[`DefIndex`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefIndex.html
[`Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
[hir-map]: ./hir.md#the-hir-map
[hir-bodies]: ./hir.md#hir-bodies
[map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html
## The HIR Map
## HIR Operations
Most of the time when you are working with the HIR, you will do so via
the **HIR Map**, accessible in the tcx via [`tcx.hir()`] (and defined in
the [`hir::map`] module). The [HIR map] contains a [number of methods] to
convert between IDs of various kinds and to lookup data associated
with a HIR node.
`TyCtxt`. It contains a number of methods, defined in the `hir::map` module and
mostly prefixed with `hir_`, to convert between IDs of various kinds and to
lookup data associated with a HIR node.
[`tcx.hir()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir
[`hir::map`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/index.html
[HIR map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html
[number of methods]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#methods
[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
For example, if you have a [`LocalDefId`], and you would like to convert it
to a [`HirId`], you can use [`tcx.hir().local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id].
to a [`HirId`], you can use [`tcx.local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id].
You need a `LocalDefId`, rather than a `DefId`, since only local items have HIR nodes.
[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.local_def_id_to_hir_id
[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.local_def_id_to_hir_id
Similarly, you can use [`tcx.hir().find(n)`][find] to lookup the node for a
Similarly, you can use [`tcx.hir_node(n)`][hir_node] to lookup the node for a
[`HirId`]. This returns a `Option<Node<'hir>>`, where [`Node`] is an enum
defined in the map. By matching on this, you can find out what sort of
node the `HirId` referred to and also get a pointer to the data
@ -142,15 +136,16 @@ that `n` must be some HIR expression, you can do
[`tcx.hir_expect_expr(n)`][expect_expr], which will extract and return the
[`&hir::Expr`][Expr], panicking if `n` is not in fact an expression.
[find]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.find
[hir_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_node
[`Node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html
[expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.expect_expr
[Expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Expr.html
Finally, you can use the HIR map to find the parents of nodes, via
calls like [`tcx.hir().get_parent(n)`][get_parent].
Finally, you can find the parents of nodes, via
calls like [`tcx.parent_hir_node(n)`][parent_hir_node].
[get_parent_item]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.parent_hir_node
[get_parent]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.get_parent
## HIR Bodies
@ -158,10 +153,10 @@ A [`rustc_hir::Body`] represents some kind of executable code, such as the body
of a function/closure or the definition of a constant. Bodies are
associated with an **owner**, which is typically some kind of item
(e.g. an `fn()` or `const`), but could also be a closure expression
(e.g. `|x, y| x + y`). You can use the HIR map to find the body
associated with a given def-id ([`maybe_body_owned_by`]) or to find
the owner of a body ([`body_owner_def_id`]).
(e.g. `|x, y| x + y`). You can use the `TyCtxt` to find the body
associated with a given def-id ([`hir_maybe_body_owned_by`]) or to find
the owner of a body ([`hir_body_owner_def_id`]).
[`rustc_hir::Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
[`maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.maybe_body_owned_by
[`body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.body_owner_def_id
[`hir_maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_maybe_body_owned_by
[`hir_body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_body_owner_def_id

View File

@ -490,17 +490,17 @@ pub(crate) fn build_impl(
return true;
}
if let Some(associated_trait) = associated_trait {
let assoc_kind = match item.kind {
hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
hir::ImplItemKind::Type(..) => ty::AssocKind::Type,
let assoc_tag = match item.kind {
hir::ImplItemKind::Const(..) => ty::AssocTag::Const,
hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn,
hir::ImplItemKind::Type(..) => ty::AssocTag::Type,
};
let trait_item = tcx
.associated_items(associated_trait.def_id)
.find_by_ident_and_kind(
tcx,
item.ident,
assoc_kind,
assoc_tag,
associated_trait.def_id,
)
.unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
@ -527,7 +527,7 @@ pub(crate) fn build_impl(
.find_by_ident_and_kind(
tcx,
item.ident(tcx),
item.kind,
item.as_tag(),
associated_trait.def_id,
)
.unwrap(); // corresponding associated item has to exist

View File

@ -521,7 +521,7 @@ fn projection_to_path_segment<'tcx>(
let item = cx.tcx.associated_item(def_id);
let generics = cx.tcx.generics_of(def_id);
PathSegment {
name: item.name,
name: item.name(),
args: GenericArgs::AngleBracketed {
args: clean_middle_generic_args(
cx,
@ -1340,7 +1340,7 @@ pub(crate) fn clean_impl_item<'tcx>(
pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item {
let tcx = cx.tcx;
let kind = match assoc_item.kind {
ty::AssocKind::Const => {
ty::AssocKind::Const { .. } => {
let ty = clean_middle_ty(
ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()),
cx,
@ -1374,10 +1374,10 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
}
}
}
ty::AssocKind::Fn => {
ty::AssocKind::Fn { has_self, .. } => {
let mut item = inline::build_function(cx, assoc_item.def_id);
if assoc_item.fn_has_self_parameter {
if has_self {
let self_ty = match assoc_item.container {
ty::AssocItemContainer::Impl => {
tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity()
@ -1412,8 +1412,8 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
RequiredMethodItem(item)
}
}
ty::AssocKind::Type => {
let my_name = assoc_item.name;
ty::AssocKind::Type { .. } => {
let my_name = assoc_item.name();
fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
match (&param.kind, arg) {
@ -1554,7 +1554,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
}
};
Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx)
Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name()), kind, cx)
}
fn first_non_private_clean_path<'tcx>(
@ -2223,7 +2223,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
Type::QPath(Box::new(QPathData {
assoc: PathSegment {
name: cx.tcx.associated_item(def_id).name,
name: cx.tcx.associated_item(def_id).name(),
args: GenericArgs::AngleBracketed {
args: clean_middle_generic_args(
cx,

Some files were not shown because too many files have changed in this diff Show More