diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 2296b05f69b4c..93c627f64c967 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -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"), } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index df4fd2ef52fe7..8e1a3cd14354b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -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 { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 59099e5a55451..d8b55bea3d763 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -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); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8a8ecc3b96e3c..fe6dff7ff1b63 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -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; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 05e0bb3f9f343..3c00b819a96bb 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -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", + ), + } } } } diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 3b48adb7e918a..6eef97c14dd28 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -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(); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 2706a5eb3d7f9..4edaf68c89ae2 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -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; 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 { + 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 { diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index b04fd1b48f7ad..c96bb48a0368c 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -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` diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 93d20dfa79966..3c2897ef1d953 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -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. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index d4488b4b65760..b9f4a8cd165d8 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -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 diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f50746dd18d6d..4f338c6a19e69 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -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 { .. } => {} } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 29a9931696ffa..af26d2ee00caf 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -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) + } } } @@ -654,7 +656,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, @@ -1032,11 +1034,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()); @@ -1255,7 +1257,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) => { @@ -1266,14 +1268,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)); } @@ -1286,14 +1288,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)); @@ -1363,7 +1365,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() @@ -1373,7 +1375,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, }) @@ -1386,7 +1388,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 = arg_spans(trait_.kind, trait_item.generics); + let arg_spans: Vec = arg_spans(&trait_, trait_item.generics); let impl_trait_spans: Vec = trait_item .generics .params @@ -1412,7 +1414,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( @@ -1421,7 +1423,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, @@ -1512,7 +1514,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 @@ -1527,7 +1529,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( @@ -1581,7 +1583,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 { @@ -1703,7 +1705,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| { @@ -1741,7 +1743,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)) ); @@ -1877,7 +1879,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| { @@ -2235,16 +2237,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 { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index ed8ca27d21705..89fb35154b75e 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -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 + // 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 { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 30921b6f055d5..5fbd771976bbb 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -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::>() .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, }; - 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) } } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 6292d03bf6ac9..33d5a86beb3b0 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -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(()); } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index dc616576c9c1b..242639125b19a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -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 } }) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index deded6904d484..4520fbe352cea 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -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), })) } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 9bcda35ee87ad..1c477755e5ac6 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -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, &'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; }; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 772197a53ace1..50e20a19edaef 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -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 { .. } => {} } } diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 610b293a114e6..526ee30209c7d 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -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()) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 24d05b49861c5..bf91eb1b8fdac 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -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`, we want to produce a predicate like @@ -453,7 +453,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // trait SuperTrait { 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)) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index e64cd8ec302c7..2e39beed8ae3c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -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, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 5a0524d33fdea..72f219bfeb802 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -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::>()[..] { @@ -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>, 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", } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 8e62dce21913b..483b61add3380 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -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( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 83aa0d9562015..7605c6c6a420a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -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::::None` or `Option::::Some` which resolve to const ctors/fn items respectively + // FIXME(mgca): Support paths like `Option::::None` or `Option::::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, 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)>, 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 { - 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, )?; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index c30b39dfe7656..cbdc501291bc8 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -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(); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e5ab317685f9f..ff4385c3bccec 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -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("..."); } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index fec459954107e..d1bc54ed73ead 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -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 diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index de2f039cb1c86..532c5092a4e94 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -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::>(); items.sort_by_key(|(order, _, _)| *order); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 81eb8510785b5..da0e8e362d663 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -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; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e14f1528d2c4c..74cc8181418c5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -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, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 912098c4e2d65..91eb1989864ff 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -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); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d30272b823695..af8ec37393472 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -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 { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index ddfd27ccf6b7f..1b67e2306aa74 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -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)) } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 0a01ec89a327d..ba4396a5ab35b 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -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::>(); 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>) { - 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, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 68f13d654d6e8..6a9fd7cdd483b 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -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` // 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 { 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 { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 93f77b8409f00..0e42a84ca32ae 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -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() }); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 16c9e08c78d38..dd3c514704a1a 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -855,11 +855,11 @@ impl<'tcx> LateContext<'tcx> { &self, self_ty: Ty<'tcx>, trait_id: DefId, - name: &str, + name: Symbol, ) -> Option> { 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() diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index ec8f84415759f..5989ef9519cd7 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -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() // `::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` diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4cc12ca2e0bfd..3c2245347f97c 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -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, } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5c8e2888ec984..177318bfe15e9 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -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!( diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index daf95420c4328..fee707f7b4c90 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -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 { self.hir_crate_items(()).body_owners.iter().copied() diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 640ac70d3a759..a28dcb0cb8efd 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -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) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4dfb362f3a22b..db19c858e7c18 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -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 { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 28a59d3e73e80..e94f088304b19 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -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) } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index f8ab555305f05..3425da4855950 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -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 } diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index bbaf735fbdb94..0c44fd2758d52 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -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, - - /// 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, } impl AssocItem { + // Gets the identifier, if it has one. + pub fn opt_name(&self) -> Option { + 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, + items: SortedIndexMultiMap, 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) -> 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 { - 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)) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6e5ac13bd2cf3..fa2f1cf1a1c87 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -464,7 +464,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator { 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)> { 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( diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index d3abb3d64b8cb..09db6eee2c9ec 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -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, 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, diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 07f2a602f2bf2..faad0a82acbf8 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -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 = diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 61e869f5de419..4de9aa5d90b01 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1462,7 +1462,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator { 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 { - 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 } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2f93197bcef13..d739218af5ee7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -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..]; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9984fb085ef2c..301ae60457434 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -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() diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 857b462b9eb1e..dfc11de283d80 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -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", diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index d1f9d4c34fe1e..73cc3c86e22f7 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -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); diff --git a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs index ed3b1ae4f42f1..daddb5dedbcf9 100644 --- a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs +++ b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs @@ -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(); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index c9771467e499c..c13ffae364983 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -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; diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs index 55d52d5075dcc..7251ef478c6f1 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs @@ -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); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 384a304c4a9d6..ee000b1174866 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -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 => { diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index d42c9980f4633..9262da2906d08 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -164,6 +164,7 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, 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, I: Interner, { + #[instrument(level = "debug", skip(self, goal), ret)] pub(super) fn merge_trait_candidates( &mut self, goal: Goal>, - candidates: Vec>, + mut candidates: Vec>, ) -> Result<(CanonicalResponse, Option), 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))) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c2761bd2717f4..d4fe446cc9f76 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -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::>(); items.sort_by_key(|(order, _, _)| *order); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 129a32c6edd81..d2917478e4e43 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -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; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 28fc68d5e491b..a757329bcf2ae 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -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)), } } } diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs index 439ebe978e591..8a6be0cd37a0b 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs @@ -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"), } } } diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 3fcbbb0e138be..4b153007bd863 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -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, +} - /// 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, +#[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(_) }) } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index d28f10ba9e38b..a4e1266e76439 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -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() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 40f8af1f6913a..fdd547448f004 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2334,13 +2334,13 @@ impl<'tcx> ObligationCause<'tcx> { subdiags: Vec, ) -> 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) -> 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", diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index 742059228510d..b66bd2c6ab787 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -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)) { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index fd2d2fa721054..4a71ab4e06a35 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -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()) } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 5583deda99a49..be508c8cee13e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -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| { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 49c6acedcfa47..df3cce880dd48 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -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}`") diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 59c93db9c8fff..54b50851b74de 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -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 diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index b963e4a2c7c4d..7d95a7b3fed24 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -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!("::{}", self.tcx.def_path_str(trait_ref), assoc_item.name), + format!( + "::{}", + self.tcx.def_path_str(trait_ref), + assoc_item.name() + ), Applicability::HasPlaceholders, ); } @@ -5411,7 +5415,7 @@ fn point_at_assoc_type_restriction( 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, ) { diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index bf9fcb0915a56..519394685a8e7 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -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, _), diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 83591219b14dc..0dce504903ca4 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -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 diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 69e7b2a43ff9b..d71d1e9ae0faf 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -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 { diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 165174c0bcc15..3565c11249ad1 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -197,10 +197,8 @@ fn own_existential_vtable_entries_iter( tcx: TyCtxt<'_>, trait_def_id: DefId, ) -> impl Iterator { - 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| { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 9520d948f51f3..6cb9fdc6f931f 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -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. diff --git a/library/core/src/contracts.rs b/library/core/src/contracts.rs index 8b79a3a7eba86..495f84bce4bf2 100644 --- a/library/core/src/contracts.rs +++ b/library/core/src/contracts.rs @@ -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(cond: C) -> impl (Fn(Ret) -> Ret) + Copy +pub const fn build_check_ensures(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 } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 077aaeddfa170..e5604d277f57a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -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 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 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 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) { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5f701921eb66f..09e17c8617f9b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -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)] diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index f6d4825c67b24..e7d547966a5d5 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -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) diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 1b5c221425ec6..75d82d7465404 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -81,16 +81,8 @@ macro_rules! with_api { $self: $S::TokenStream ) -> Vec>; }, - 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; @@ -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; fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>; fn subspan($self: $S::Span, start: Bound, end: Bound) -> 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, diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 97e5a603c3ac9..5beda7c3c96e5 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -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; } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index f1cf0c5a2db7c..c46dcebedcab8 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -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 `""`. + #[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 { + 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)] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index da518011a0e4c..76ce7bce81b15 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1286,6 +1286,40 @@ pub struct Output { pub stderr: Vec, } +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.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")] diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index f8733eb611986..3a790d9c868c9 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -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, diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 9078dd1c23166..4f1517b7ef420 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -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 = 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())); diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index b46418ae9bb67..5f922292d0542 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -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, stdout: Option, stderr: Option, + stdin: Option, 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>> { + 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, Vec)> { 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, stdout: Option>, stderr: Option>, + stdin: Option>, st: OwnedTable, 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) { 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) { + 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 = system_table().cast(); + unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) } + } + pub fn stderr(&self) -> io::Result> { 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; diff --git a/library/std/src/sys/stdio/uefi.rs b/library/std/src/sys/stdio/uefi.rs index 257e321dd03d7..ccd6bf658b0ff 100644 --- a/library/std/src/sys/stdio/uefi.rs +++ b/library/std/src/sys/stdio/uefi.rs @@ -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 { diff --git a/library/std/tests/sync/mpmc.rs b/library/std/tests/sync/mpmc.rs index 81b92297f76a3..78abcb3bcbe1d 100644 --- a/library/std/tests/sync/mpmc.rs +++ b/library/std/tests/sync/mpmc.rs @@ -63,6 +63,24 @@ fn smoke_port_gone() { assert!(tx.send(1).is_err()); } +#[test] +fn smoke_receiver_clone() { + let (tx, rx) = channel::(); + 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::(); + let rx2 = rx.clone(); + drop(rx); + drop(rx2); + assert!(tx.send(1).is_err()); +} + #[test] fn smoke_shared_port_gone() { let (tx, rx) = channel::(); @@ -124,6 +142,18 @@ fn chan_gone_concurrent() { while rx.recv().is_ok() {} } +#[test] +fn receiver_cloning() { + let (tx, rx) = channel::(); + 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 }; diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index b191d0f6b306b..ae9511b786741 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -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 diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index e23c1ab5a238b..b1a3bba08871d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -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); } } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index ded7220fcedcd..3426da51a808c 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -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"; diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile new file mode 100644 index 0000000000000..408b87125e0c6 --- /dev/null +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile @@ -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}" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index fbda749b6a2a8..fd4650ba28532 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -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 diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index a7c3236d356ba..1837b59e850ae 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -31,7 +31,6 @@ Term | Meaning generics | The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters. HIR | The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md)) `HirId` | 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). -HIR map | The HIR map, accessible via `tcx.hir()`, allows you to quickly navigate the HIR and convert between various forms of identifiers. ICE | Short for _internal compiler error_, this is when the compiler crashes. ICH | 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. `infcx` | The type inference context (`InferCtxt`). (see `rustc_middle::infer`) diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md index 75f5a9e204528..65779f3129d94 100644 --- a/src/doc/rustc-dev-guide/src/hir.md +++ b/src/doc/rustc-dev-guide/src/hir.md @@ -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>`, 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 diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 3a2b6974681bc..2f6870e3c368f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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 diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 45a915719e9f2..2a95acc622ea8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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 (¶m.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, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 06e75fe1764e0..7786b216112bf 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2504,7 +2504,7 @@ impl Impl { self.trait_ .as_ref() .map(|t| t.def_id()) - .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect()) + .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect()) .unwrap_or_default() } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fdbb792d25dab..297597b3deacc 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -60,7 +60,7 @@ fn filter_assoc_items_by_name_and_namespace( ns: Namespace, ) -> impl Iterator { tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| { - item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) + item.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) }) } @@ -743,7 +743,7 @@ impl<'tcx> LinkCollector<'_, 'tcx> { ns, ) .map(|item| { - let res = Res::Def(item.kind.as_def_kind(), item.def_id); + let res = Res::Def(item.as_def_kind(), item.def_id); (res, item.def_id) }) .collect::>(), diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index ab34af7c31745..e5439a6d401b9 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -111,8 +111,8 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { // Only suggest if `clone_from`/`clone_into` is explicitly implemented && resolved_assoc_items.in_definition_order().any(|assoc| match which_trait { - CloneTrait::Clone => assoc.name == sym::clone_from, - CloneTrait::ToOwned => assoc.name.as_str() == "clone_into", + CloneTrait::Clone => assoc.name() == sym::clone_from, + CloneTrait::ToOwned => assoc.name().as_str() == "clone_into", } ) && !clone_source_borrows_from_dest(cx, lhs, rhs.span) diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index ad18c7039eedf..4a876b854165e 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -56,7 +56,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - cx.tcx.associated_items(trait_id).find_by_ident_and_kind( cx.tcx, Ident::from_str("Output"), - ty::AssocKind::Type, + ty::AssocTag::Type, trait_id, ) }) diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 3862ff7921db8..06224f57c5c5b 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -550,7 +550,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { // a `Target` that is in `self.ty_msrv_map`. if let Some(deref_trait_id) = self.cx.tcx.lang_items().deref_trait() && implements_trait(self.cx, ty, deref_trait_id, &[]) - && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, "Target") + && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, sym::Target) && let Some(msrv) = self.ty_msrv_map.get(&target_ty) && msrv.is_none_or(|msrv| self.msrv.meets(self.cx, msrv)) { diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index d02d9b2102bda..430f24111832c 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -315,7 +315,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { assocs .filter_by_name_unhygienic(constraint.ident.name) .next() - .is_some_and(|assoc| assoc.kind == ty::AssocKind::Type) + .is_some_and(|assoc| assoc.is_type()) }) { emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound); diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 72e22ae59d8f4..77085d52a32ed 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -13,7 +13,7 @@ use rustc_hir::{ QPath, TraitItemRef, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; +use rustc_middle::ty::{self, FnSig, Ty}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; @@ -288,8 +288,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden .items() .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty)) .any(|i| { - i.kind == AssocKind::Fn - && i.fn_has_self_parameter + i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1 }); @@ -466,7 +465,7 @@ fn check_for_is_empty( .inherent_impls(impl_ty) .iter() .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty)) - .find(|item| item.kind == AssocKind::Fn); + .find(|item| item.is_fn()); let (msg, is_empty_span, self_kind) = match is_empty { None => ( @@ -486,7 +485,7 @@ fn check_for_is_empty( None, ), Some(is_empty) - if !(is_empty.fn_has_self_parameter + if !(is_empty.is_method() && check_is_empty_sig( cx, cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(), @@ -608,7 +607,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool { fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool { - if item.kind == AssocKind::Fn { + if item.is_fn() { let sig = cx.tcx.fn_sig(item.def_id).skip_binder(); let ty = sig.skip_binder(); ty.inputs().len() == 1 @@ -644,7 +643,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { && cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| { implements_trait(cx, ty, deref_id, &[]) && cx - .get_associated_type(ty, deref_id, "Target") + .get_associated_type(ty, deref_id, sym::Target) .is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1)) })) }, diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs index e82211bbf3ef7..b5adc69e9a790 100644 --- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args) // find the provided definition of Iterator::last && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last") + && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last") // if the resolved method is the same as the provided definition && fn_def.def_id() == last_def.def_id { diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index f51bdc78f8a51..7bb625222ec0f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -48,7 +48,7 @@ pub(super) fn check<'tcx>( && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id) && cx.tcx.trait_of_item(method_id) == Some(iter_id) && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv) - && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item") + && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, sym::Item) && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty)) { if needs_into_iter diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 239ee6c729fb0..e4a29b6560e52 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -17,7 +17,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; use rustc_span::symbol::Ident; use rustc_span::{Span, sym}; @@ -241,7 +241,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_ident_and_kind( cx.tcx, Ident::with_dummy_span(sym::Item), - AssocKind::Type, + AssocTag::Type, iter_trait, ) && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index c03420a5143e6..6eeeea5d77c70 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -78,7 +78,7 @@ pub(super) fn check<'tcx>( .iter() .flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg)) .find_map(|assoc| { - if assoc.fn_has_self_parameter + if assoc.is_method() && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1 { Some(assoc.def_id) diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index c0e0156858811..20cf35363d13f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -99,7 +99,7 @@ pub fn check_for_loop_iter( && let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) && let collection_ty = cx.typeck_results().expr_ty(collection) && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) - && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") + && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, sym::Item) && iter_item_ty == into_iter_item_ty && let Some(collection_snippet) = collection.span.get_source_text(cx) { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 62ba3012643ce..206b0a8ae3cd6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -153,7 +153,7 @@ fn check_addr_of_expr( } if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && implements_trait(cx, receiver_ty, deref_trait_id, &[]) - && cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty) + && cx.get_associated_type(receiver_ty, deref_trait_id, sym::Target) == Some(target_ty) // Make sure that it's actually calling the right `.to_string()`, (#10033) // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow) // but that's ok for Cow::into_owned specifically) @@ -322,7 +322,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb // add `.as_ref()` to the suggestion. let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String) && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) - && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, "Target") + && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, sym::Target) != Some(cx.tcx.types.str_) { ".as_ref()" @@ -648,7 +648,7 @@ fn is_to_string_on_string_like<'a>( && let GenericArgKind::Type(ty) = generic_arg.unpack() && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) - && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) + && (cx.get_associated_type(ty, deref_trait_id, sym::Target) == Some(cx.tcx.types.str_) || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { true diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 7ee746365d102..e266c36b6e734 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { cx, MISSING_TRAIT_METHODS, cx.tcx.def_span(item.owner_id), - format!("missing trait method provided by default: `{}`", assoc.name), + format!("missing trait method provided by default: `{}`", assoc.name()), |diag| { diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method"); }, diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index f686cc912ddb0..e579dd5947d74 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -299,7 +299,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool { .associated_items(trait_def_id) .in_definition_order() .any(|assoc_item| { - if assoc_item.fn_has_self_parameter { + if assoc_item.is_method() { let self_ty = cx .tcx .fn_sig(assoc_item.def_id) diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 552135b15fd8f..33815cc3bac1b 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::AssocKind; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::symbol::Symbol; @@ -85,8 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { cx.tcx .associated_items(did) .in_definition_order() - .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn)) - .map(|assoc_item| assoc_item.name) + .filter(|assoc_item| assoc_item.is_fn()) + .map(|assoc_item| assoc_item.name()) .collect() } else { BTreeSet::new() diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index 51c7d6fce3128..0c17cc5d8f667 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -10,7 +10,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, kw}; use rustc_span::{Span, sym}; @@ -322,7 +322,7 @@ impl UnconditionalRecursion { .in_definition_order() // We're not interested in foreign implementations of the `Default` trait. .find(|item| { - item.kind == AssocKind::Fn && item.def_id.is_local() && item.name == kw::Default + item.is_fn() && item.def_id.is_local() && item.name() == kw::Default }) && let Some(body_node) = cx.tcx.hir_get_if_local(assoc_item.def_id) && let Some(body_id) = body_node.body_id() diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 582aa6e6001e8..d0067b1a65e71 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { .is_some() }; if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind - && assoc_item.fn_has_self_parameter + && assoc_item.is_method() && let ImplItemKind::Fn(.., body_id) = &impl_item.kind && (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api) && let body = cx.tcx.hir_body(*body_id) diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 29cbf62c3d4c1..d33e59342a598 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, + self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; @@ -156,7 +156,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { cx.tcx .get_diagnostic_item(sym::Iterator) - .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item")) + .and_then(|iter_did| cx.get_associated_type(ty, iter_did, sym::Item)) } /// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type @@ -1112,7 +1112,7 @@ pub fn make_projection<'tcx>( let Some(assoc_item) = tcx.associated_items(container_id).find_by_ident_and_kind( tcx, Ident::with_dummy_span(assoc_ty), - AssocKind::Type, + AssocTag::Type, container_id, ) else { debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`"); @@ -1345,7 +1345,7 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n .associated_items(did) .filter_by_name_unhygienic(method_name) .next() - .filter(|item| item.kind == AssocKind::Fn) + .filter(|item| item.as_tag() == AssocTag::Fn) }) } else { None diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 604c5fcbddff0..31c696ed41ff4 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -414,6 +414,11 @@ pub struct Config { /// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g. /// ABI tests. pub minicore_path: Utf8PathBuf, + + /// If true, run tests with the "new" executor that was written to replace + /// compiletest's dependency on libtest. Eventually this will become the + /// default, and the libtest dependency will be removed. + pub new_executor: bool, } impl Config { diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 527d6b8a36eb1..0c173d476affa 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -1,22 +1,251 @@ -//! This module encapsulates all of the code that interacts directly with -//! libtest, to execute the collected tests. -//! -//! This will hopefully make it easier to migrate away from libtest someday. +//! This module contains a reimplementation of the subset of libtest +//! functionality needed by compiletest. use std::borrow::Cow; -use std::io; -use std::sync::Arc; +use std::collections::HashMap; +use std::hash::{BuildHasherDefault, DefaultHasher}; +use std::num::NonZero; +use std::sync::{Arc, Mutex, mpsc}; +use std::{env, hint, io, mem, panic, thread}; use crate::common::{Config, TestPaths}; -/// Delegates to libtest to run the list of collected tests. +mod deadline; +mod json; +pub(crate) mod libtest; + +pub(crate) fn run_tests(config: &Config, tests: Vec) -> bool { + let tests_len = tests.len(); + let filtered = filter_tests(config, tests); + // Iterator yielding tests that haven't been started yet. + let mut fresh_tests = (0..).map(TestId).zip(&filtered); + + let concurrency = get_concurrency(); + assert!(concurrency > 0); + let concurrent_capacity = concurrency.min(filtered.len()); + + let mut listener = json::Listener::new(); + let mut running_tests = HashMap::with_capacity_and_hasher( + concurrent_capacity, + BuildHasherDefault::::new(), + ); + let mut deadline_queue = deadline::DeadlineQueue::with_capacity(concurrent_capacity); + + let num_filtered_out = tests_len - filtered.len(); + listener.suite_started(filtered.len(), num_filtered_out); + + // Channel used by test threads to report the test outcome when done. + let (completion_tx, completion_rx) = mpsc::channel::(); + + // Unlike libtest, we don't have a separate code path for concurrency=1. + // In that case, the tests will effectively be run serially anyway. + loop { + // Spawn new test threads, up to the concurrency limit. + // FIXME(let_chains): Use a let-chain here when stable in bootstrap. + 'spawn: while running_tests.len() < concurrency { + let Some((id, test)) = fresh_tests.next() else { break 'spawn }; + listener.test_started(test); + deadline_queue.push(id, test); + let join_handle = spawn_test_thread(id, test, completion_tx.clone()); + running_tests.insert(id, RunningTest { test, join_handle }); + } + + // If all running tests have finished, and there weren't any unstarted + // tests to spawn, then we're done. + if running_tests.is_empty() { + break; + } + + let completion = deadline_queue + .read_channel_while_checking_deadlines(&completion_rx, |_id, test| { + listener.test_timed_out(test); + }) + .expect("receive channel should never be closed early"); + + let RunningTest { test, join_handle } = running_tests.remove(&completion.id).unwrap(); + if let Some(join_handle) = join_handle { + join_handle.join().unwrap_or_else(|_| { + panic!("thread for `{}` panicked after reporting completion", test.desc.name) + }); + } + + listener.test_finished(test, &completion); + + if completion.outcome.is_failed() && config.fail_fast { + // Prevent any other in-flight threads from panicking when they + // write to the completion channel. + mem::forget(completion_rx); + break; + } + } + + let suite_passed = listener.suite_finished(); + suite_passed +} + +/// Spawns a thread to run a single test, and returns the thread's join handle. /// -/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed. -pub(crate) fn execute_tests(config: &Config, tests: Vec) -> io::Result { - let opts = test_opts(config); - let tests = tests.into_iter().map(|t| t.into_libtest()).collect::>(); +/// Returns `None` if the test was ignored, so no thread was spawned. +fn spawn_test_thread( + id: TestId, + test: &CollectedTest, + completion_tx: mpsc::Sender, +) -> Option> { + if test.desc.ignore && !test.config.run_ignored { + completion_tx + .send(TestCompletion { id, outcome: TestOutcome::Ignored, stdout: None }) + .unwrap(); + return None; + } + + let runnable_test = RunnableTest::new(test); + let should_panic = test.desc.should_panic; + let run_test = move || run_test_inner(id, should_panic, runnable_test, completion_tx); + + let thread_builder = thread::Builder::new().name(test.desc.name.clone()); + let join_handle = thread_builder.spawn(run_test).unwrap(); + Some(join_handle) +} + +/// Runs a single test, within the dedicated thread spawned by the caller. +fn run_test_inner( + id: TestId, + should_panic: ShouldPanic, + runnable_test: RunnableTest, + completion_sender: mpsc::Sender, +) { + let is_capture = !runnable_test.config.nocapture; + let capture_buf = is_capture.then(|| Arc::new(Mutex::new(vec![]))); + + if let Some(capture_buf) = &capture_buf { + io::set_output_capture(Some(Arc::clone(capture_buf))); + } + + let panic_payload = panic::catch_unwind(move || runnable_test.run()).err(); + + if is_capture { + io::set_output_capture(None); + } + + let outcome = match (should_panic, panic_payload) { + (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded, + (ShouldPanic::No, Some(_)) => TestOutcome::Failed { message: None }, + (ShouldPanic::Yes, None) => { + TestOutcome::Failed { message: Some("test did not panic as expected") } + } + }; + let stdout = capture_buf.map(|mutex| mutex.lock().unwrap_or_else(|e| e.into_inner()).to_vec()); + + completion_sender.send(TestCompletion { id, outcome, stdout }).unwrap(); +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +struct TestId(usize); + +struct RunnableTest { + config: Arc, + testpaths: TestPaths, + revision: Option, +} + +impl RunnableTest { + fn new(test: &CollectedTest) -> Self { + let config = Arc::clone(&test.config); + let testpaths = test.testpaths.clone(); + let revision = test.revision.clone(); + Self { config, testpaths, revision } + } + + fn run(&self) { + __rust_begin_short_backtrace(|| { + crate::runtest::run( + Arc::clone(&self.config), + &self.testpaths, + self.revision.as_deref(), + ); + }); + } +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +#[inline(never)] +fn __rust_begin_short_backtrace T>(f: F) -> T { + let result = f(); + + // prevent this frame from being tail-call optimised away + hint::black_box(result) +} - test::run_tests_console(&opts, tests) +struct RunningTest<'a> { + test: &'a CollectedTest, + join_handle: Option>, +} + +/// Test completion message sent by individual test threads when their test +/// finishes (successfully or unsuccessfully). +struct TestCompletion { + id: TestId, + outcome: TestOutcome, + stdout: Option>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +enum TestOutcome { + Succeeded, + Failed { message: Option<&'static str> }, + Ignored, +} + +impl TestOutcome { + fn is_failed(&self) -> bool { + matches!(self, Self::Failed { .. }) + } +} + +/// Applies command-line arguments for filtering/skipping tests by name. +/// +/// Adapted from `filter_tests` in libtest. +/// +/// FIXME(#139660): After the libtest dependency is removed, redesign the whole +/// filtering system to do a better job of understanding and filtering _paths_, +/// instead of being tied to libtest's substring/exact matching behaviour. +fn filter_tests(opts: &Config, tests: Vec) -> Vec { + let mut filtered = tests; + + let matches_filter = |test: &CollectedTest, filter_str: &str| { + let test_name = &test.desc.name; + if opts.filter_exact { test_name == filter_str } else { test_name.contains(filter_str) } + }; + + // Remove tests that don't match the test filter + if !opts.filters.is_empty() { + filtered.retain(|test| opts.filters.iter().any(|filter| matches_filter(test, filter))); + } + + // Skip tests that match any of the skip filters + if !opts.skip.is_empty() { + filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf))); + } + + filtered +} + +/// Determines the number of tests to run concurrently. +/// +/// Copied from `get_concurrency` in libtest. +/// +/// FIXME(#139660): After the libtest dependency is removed, consider making +/// bootstrap specify the number of threads on the command-line, instead of +/// propagating the `RUST_TEST_THREADS` environment variable. +fn get_concurrency() -> usize { + if let Ok(value) = env::var("RUST_TEST_THREADS") { + match value.parse::>().ok() { + Some(n) => n.get(), + _ => panic!("RUST_TEST_THREADS is `{value}`, should be a positive integer."), + } + } else { + thread::available_parallelism().map(|n| n.get()).unwrap_or(1) + } } /// Information needed to create a `test::TestDescAndFn`. @@ -35,45 +264,6 @@ pub(crate) struct CollectedTestDesc { pub(crate) should_panic: ShouldPanic, } -impl CollectedTest { - fn into_libtest(self) -> test::TestDescAndFn { - let Self { desc, config, testpaths, revision } = self; - let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc; - - // Libtest requires the ignore message to be a &'static str, so we might - // have to leak memory to create it. This is fine, as we only do so once - // per test, so the leak won't grow indefinitely. - let ignore_message = ignore_message.map(|msg| match msg { - Cow::Borrowed(s) => s, - Cow::Owned(s) => &*String::leak(s), - }); - - let desc = test::TestDesc { - name: test::DynTestName(name), - ignore, - ignore_message, - source_file: "", - start_line: 0, - start_col: 0, - end_line: 0, - end_col: 0, - should_panic: should_panic.to_libtest(), - compile_fail: false, - no_run: false, - test_type: test::TestType::Unknown, - }; - - // This closure is invoked when libtest returns control to compiletest - // to execute the test. - let testfn = test::DynTestFn(Box::new(move || { - crate::runtest::run(config, &testpaths, revision.as_deref()); - Ok(()) - })); - - test::TestDescAndFn { desc, testfn } - } -} - /// Whether console output should be colored or not. #[derive(Copy, Clone, Default, Debug)] pub enum ColorConfig { @@ -83,16 +273,6 @@ pub enum ColorConfig { NeverColor, } -impl ColorConfig { - fn to_libtest(self) -> test::ColorConfig { - match self { - Self::AutoColor => test::ColorConfig::AutoColor, - Self::AlwaysColor => test::ColorConfig::AlwaysColor, - Self::NeverColor => test::ColorConfig::NeverColor, - } - } -} - /// Format of the test results output. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum OutputFormat { @@ -105,52 +285,9 @@ pub enum OutputFormat { Json, } -impl OutputFormat { - fn to_libtest(self) -> test::OutputFormat { - match self { - Self::Pretty => test::OutputFormat::Pretty, - Self::Terse => test::OutputFormat::Terse, - Self::Json => test::OutputFormat::Json, - } - } -} - /// Whether test is expected to panic or not. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub(crate) enum ShouldPanic { No, Yes, } - -impl ShouldPanic { - fn to_libtest(self) -> test::ShouldPanic { - match self { - Self::No => test::ShouldPanic::No, - Self::Yes => test::ShouldPanic::Yes, - } - } -} - -fn test_opts(config: &Config) -> test::TestOpts { - test::TestOpts { - exclude_should_panic: false, - filters: config.filters.clone(), - filter_exact: config.filter_exact, - run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, - format: config.format.to_libtest(), - logfile: None, - run_tests: true, - bench_benchmarks: true, - nocapture: config.nocapture, - color: config.color.to_libtest(), - shuffle: false, - shuffle_seed: None, - test_threads: None, - skip: config.skip.clone(), - list: false, - options: test::Options::new(), - time_options: None, - force_run_in_process: false, - fail_fast: config.fail_fast, - } -} diff --git a/src/tools/compiletest/src/executor/deadline.rs b/src/tools/compiletest/src/executor/deadline.rs new file mode 100644 index 0000000000000..83b8591a41642 --- /dev/null +++ b/src/tools/compiletest/src/executor/deadline.rs @@ -0,0 +1,78 @@ +use std::collections::VecDeque; +use std::sync::mpsc::{self, RecvError, RecvTimeoutError}; +use std::time::{Duration, Instant}; + +use crate::executor::{CollectedTest, TestId}; + +const TEST_WARN_TIMEOUT_S: u64 = 60; + +struct DeadlineEntry<'a> { + id: TestId, + test: &'a CollectedTest, + deadline: Instant, +} + +pub(crate) struct DeadlineQueue<'a> { + queue: VecDeque>, +} + +impl<'a> DeadlineQueue<'a> { + pub(crate) fn with_capacity(capacity: usize) -> Self { + Self { queue: VecDeque::with_capacity(capacity) } + } + + pub(crate) fn push(&mut self, id: TestId, test: &'a CollectedTest) { + let deadline = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S); + self.queue.push_back(DeadlineEntry { id, test, deadline }); + } + + /// Equivalent to `rx.read()`, except that if any test exceeds its deadline + /// during the wait, the given callback will also be called for that test. + pub(crate) fn read_channel_while_checking_deadlines( + &mut self, + rx: &mpsc::Receiver, + mut on_deadline_passed: impl FnMut(TestId, &CollectedTest), + ) -> Result { + loop { + let Some(next_deadline) = self.next_deadline() else { + // All currently-running tests have already exceeded their + // deadline, so do a normal receive. + return rx.recv(); + }; + let wait_duration = next_deadline.saturating_duration_since(Instant::now()); + + let recv_result = rx.recv_timeout(wait_duration); + match recv_result { + Ok(value) => return Ok(value), + Err(RecvTimeoutError::Timeout) => { + // Notify the callback of tests that have exceeded their + // deadline, then loop and do annother channel read. + for DeadlineEntry { id, test, .. } in self.remove_tests_past_deadline() { + on_deadline_passed(id, test); + } + } + Err(RecvTimeoutError::Disconnected) => return Err(RecvError), + } + } + } + + fn next_deadline(&self) -> Option { + Some(self.queue.front()?.deadline) + } + + fn remove_tests_past_deadline(&mut self) -> Vec> { + let now = Instant::now(); + let mut timed_out = vec![]; + while let Some(deadline_entry) = pop_front_if(&mut self.queue, |entry| now < entry.deadline) + { + timed_out.push(deadline_entry); + } + timed_out + } +} + +/// FIXME(vec_deque_pop_if): Use `VecDeque::pop_front_if` when it is stable in bootstrap. +fn pop_front_if(queue: &mut VecDeque, predicate: impl FnOnce(&T) -> bool) -> Option { + let first = queue.front()?; + if predicate(first) { queue.pop_front() } else { None } +} diff --git a/src/tools/compiletest/src/executor/json.rs b/src/tools/compiletest/src/executor/json.rs new file mode 100644 index 0000000000000..c74ed81a36b85 --- /dev/null +++ b/src/tools/compiletest/src/executor/json.rs @@ -0,0 +1,111 @@ +//! Collects statistics and emits suite/test events as JSON messages, using +//! the same JSON format as libtest's JSON formatter. +//! +//! These messages are then parsed by bootstrap, which replaces them with +//! user-friendly terminal output. + +use std::time::Instant; + +use serde_json::json; + +use crate::executor::{CollectedTest, TestCompletion, TestOutcome}; + +pub(crate) struct Listener { + suite_start: Option, + passed: usize, + failed: usize, + ignored: usize, + filtered_out: usize, +} + +impl Listener { + pub(crate) fn new() -> Self { + Self { suite_start: None, passed: 0, failed: 0, ignored: 0, filtered_out: 0 } + } + + fn print_message(&self, message: &serde_json::Value) { + println!("{message}"); + } + + fn now(&self) -> Instant { + Instant::now() + } + + pub(crate) fn suite_started(&mut self, test_count: usize, filtered_out: usize) { + self.suite_start = Some(self.now()); + self.filtered_out = filtered_out; + let message = json!({ "type": "suite", "event": "started", "test_count": test_count }); + self.print_message(&message); + } + + pub(crate) fn test_started(&mut self, test: &CollectedTest) { + let name = test.desc.name.as_str(); + let message = json!({ "type": "test", "event": "started", "name": name }); + self.print_message(&message); + } + + pub(crate) fn test_timed_out(&mut self, test: &CollectedTest) { + let name = test.desc.name.as_str(); + let message = json!({ "type": "test", "event": "timeout", "name": name }); + self.print_message(&message); + } + + pub(crate) fn test_finished(&mut self, test: &CollectedTest, completion: &TestCompletion) { + let event; + let name = test.desc.name.as_str(); + let mut maybe_message = None; + let maybe_stdout = completion.stdout.as_deref().map(String::from_utf8_lossy); + + match completion.outcome { + TestOutcome::Succeeded => { + self.passed += 1; + event = "ok"; + } + TestOutcome::Failed { message } => { + self.failed += 1; + maybe_message = message; + event = "failed"; + } + TestOutcome::Ignored => { + self.ignored += 1; + maybe_message = test.desc.ignore_message.as_deref(); + event = "ignored"; + } + }; + + // This emits optional fields as `null`, instead of omitting them + // completely as libtest does, but bootstrap can parse the result + // either way. + let json = json!({ + "type": "test", + "event": event, + "name": name, + "message": maybe_message, + "stdout": maybe_stdout, + }); + + self.print_message(&json); + } + + pub(crate) fn suite_finished(&mut self) -> bool { + let exec_time = self.suite_start.map(|start| (self.now() - start).as_secs_f64()); + let suite_passed = self.failed == 0; + + let event = if suite_passed { "ok" } else { "failed" }; + let message = json!({ + "type": "suite", + "event": event, + "passed": self.passed, + "failed": self.failed, + "ignored": self.ignored, + // Compiletest doesn't run any benchmarks, but we still need to set this + // field to 0 so that bootstrap's JSON parser can read our message. + "measured": 0, + "filtered_out": self.filtered_out, + "exec_time": exec_time, + }); + + self.print_message(&message); + suite_passed + } +} diff --git a/src/tools/compiletest/src/executor/libtest.rs b/src/tools/compiletest/src/executor/libtest.rs new file mode 100644 index 0000000000000..032b3f4fa9a87 --- /dev/null +++ b/src/tools/compiletest/src/executor/libtest.rs @@ -0,0 +1,111 @@ +//! This submodule encapsulates all of the code that actually interacts with +//! libtest, so that it can be easily removed after the new executor becomes +//! the default. + +use std::borrow::Cow; +use std::io; + +use crate::common::Config; +use crate::executor::{CollectedTest, CollectedTestDesc, ColorConfig, OutputFormat, ShouldPanic}; + +/// Delegates to libtest to run the list of collected tests. +/// +/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed. +pub(crate) fn execute_tests(config: &Config, tests: Vec) -> io::Result { + let opts = test_opts(config); + let tests = tests.into_iter().map(|t| t.into_libtest()).collect::>(); + + test::run_tests_console(&opts, tests) +} + +impl CollectedTest { + fn into_libtest(self) -> test::TestDescAndFn { + let Self { desc, config, testpaths, revision } = self; + let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc; + + // Libtest requires the ignore message to be a &'static str, so we might + // have to leak memory to create it. This is fine, as we only do so once + // per test, so the leak won't grow indefinitely. + let ignore_message = ignore_message.map(|msg| match msg { + Cow::Borrowed(s) => s, + Cow::Owned(s) => &*String::leak(s), + }); + + let desc = test::TestDesc { + name: test::DynTestName(name), + ignore, + ignore_message, + source_file: "", + start_line: 0, + start_col: 0, + end_line: 0, + end_col: 0, + should_panic: should_panic.to_libtest(), + compile_fail: false, + no_run: false, + test_type: test::TestType::Unknown, + }; + + // This closure is invoked when libtest returns control to compiletest + // to execute the test. + let testfn = test::DynTestFn(Box::new(move || { + crate::runtest::run(config, &testpaths, revision.as_deref()); + Ok(()) + })); + + test::TestDescAndFn { desc, testfn } + } +} + +impl ColorConfig { + fn to_libtest(self) -> test::ColorConfig { + match self { + Self::AutoColor => test::ColorConfig::AutoColor, + Self::AlwaysColor => test::ColorConfig::AlwaysColor, + Self::NeverColor => test::ColorConfig::NeverColor, + } + } +} + +impl OutputFormat { + fn to_libtest(self) -> test::OutputFormat { + match self { + Self::Pretty => test::OutputFormat::Pretty, + Self::Terse => test::OutputFormat::Terse, + Self::Json => test::OutputFormat::Json, + } + } +} + +impl ShouldPanic { + fn to_libtest(self) -> test::ShouldPanic { + match self { + Self::No => test::ShouldPanic::No, + Self::Yes => test::ShouldPanic::Yes, + } + } +} + +fn test_opts(config: &Config) -> test::TestOpts { + test::TestOpts { + exclude_should_panic: false, + filters: config.filters.clone(), + filter_exact: config.filter_exact, + run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, + format: config.format.to_libtest(), + logfile: None, + run_tests: true, + bench_benchmarks: true, + nocapture: config.nocapture, + color: config.color.to_libtest(), + shuffle: false, + shuffle_seed: None, + test_threads: None, + skip: config.skip.clone(), + list: false, + options: test::Options::new(), + time_options: None, + force_run_in_process: false, + fail_fast: config.fail_fast, + } +} diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index b969b22750bc0..4bbd4ab4790d8 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1,7 +1,8 @@ #![crate_name = "compiletest"] -// The `test` crate is the only unstable feature -// allowed here, just to share similar code. +// Needed by the libtest-based test executor. #![feature(test)] +// Needed by the "new" test executor that does not depend on libtest. +#![feature(internal_output_capture)] extern crate test; @@ -202,6 +203,7 @@ pub fn parse_config(args: Vec) -> Config { "COMMAND", ) .reqopt("", "minicore-path", "path to minicore aux library", "PATH") + .optflag("n", "new-executor", "enables the new test executor instead of using libtest") .optopt( "", "debugger", @@ -447,6 +449,8 @@ pub fn parse_config(args: Vec) -> Config { diff_command: matches.opt_str("compiletest-diff-tool"), minicore_path: opt_path(matches, "minicore-path"), + + new_executor: matches.opt_present("new-executor"), } } @@ -570,10 +574,14 @@ pub fn run_tests(config: Arc) { tests.sort_by(|a, b| Ord::cmp(&a.desc.name, &b.desc.name)); - // Delegate to libtest to filter and run the big list of structures created - // during test discovery. When libtest decides to run a test, it will - // return control to compiletest by invoking a closure. - let res = crate::executor::execute_tests(&config, tests); + // Delegate to the executor to filter and run the big list of test structures + // created during test discovery. When the executor decides to run a test, + // it will return control to the rest of compiletest by calling `runtest::run`. + let res = if config.new_executor { + Ok(executor::run_tests(&config, tests)) + } else { + crate::executor::libtest::execute_tests(&config, tests) + }; // Check the outcome reported by libtest. match res { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 59293ee3f9659..80f6d85a3d05c 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -11,7 +11,7 @@ use std::{ use intern::Symbol; use proc_macro::bridge::{self, server}; -use span::{FileId, Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; +use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; use tt::{TextRange, TextSize}; use crate::server_impl::{literal_kind_to_internal, token_stream::TokenStreamBuilder, TopSubtree}; @@ -27,10 +27,6 @@ mod tt { type TokenStream = crate::server_impl::TokenStream; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct SourceFile { - file_id: FileId, -} pub struct FreeFunctions; pub struct RaSpanServer { @@ -46,7 +42,6 @@ pub struct RaSpanServer { impl server::Types for RaSpanServer { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type SourceFile = SourceFile; type Span = Span; type Symbol = Symbol; } @@ -245,25 +240,17 @@ impl server::TokenStream for RaSpanServer { } } -impl server::SourceFile for RaSpanServer { - fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool { - file1 == file2 - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - // FIXME - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - impl server::Span for RaSpanServer { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span) } - fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { - SourceFile { file_id: span.anchor.file_id.file_id() } + fn file(&mut self, _: Self::Span) -> String { + // FIXME + String::new() + } + fn local_file(&mut self, _: Self::Span) -> Option { + // FIXME + None } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index 409cf3cc78134..4d7c7c46766b0 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -24,8 +24,6 @@ type Literal = tt::Literal; type Span = tt::TokenId; type TokenStream = crate::server_impl::TokenStream; -#[derive(Clone)] -pub struct SourceFile; pub struct FreeFunctions; pub struct TokenIdServer { @@ -37,7 +35,6 @@ pub struct TokenIdServer { impl server::Types for TokenIdServer { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; - type SourceFile = SourceFile; type Span = Span; type Symbol = Symbol; } @@ -223,24 +220,15 @@ impl server::TokenStream for TokenIdServer { } } -impl server::SourceFile for TokenIdServer { - fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool { - true - } - fn path(&mut self, _file: &Self::SourceFile) -> String { - String::new() - } - fn is_real(&mut self, _file: &Self::SourceFile) -> bool { - true - } -} - impl server::Span for TokenIdServer { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span.0) } - fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile { - SourceFile {} + fn file(&mut self, _span: Self::Span) -> String { + String::new() + } + fn local_file(&mut self, _span: Self::Span) -> Option { + None } fn save_span(&mut self, _span: Self::Span) -> usize { 0 diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index 15de88ea656d0..4bd365be7ca8b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -97,6 +97,7 @@ fn test_fn_like_macro_clone_raw_ident() { } #[test] +#[cfg(not(bootstrap))] fn test_fn_like_fn_like_span_join() { assert_expand( "fn_like_span_join", @@ -111,6 +112,7 @@ fn test_fn_like_fn_like_span_join() { } #[test] +#[cfg(not(bootstrap))] fn test_fn_like_fn_like_span_ops() { assert_expand( "fn_like_span_ops", diff --git a/tests/assembly/cstring-merging.rs b/tests/assembly/cstring-merging.rs index 07f25d1e1a427..b5c530ac35d76 100644 --- a/tests/assembly/cstring-merging.rs +++ b/tests/assembly/cstring-merging.rs @@ -5,7 +5,7 @@ use std::ffi::CStr; -// CHECK: .section .rodata.str1.1,"aMS" +// CHECK: .section .rodata.str1.{{[12]}},"aMS" // CHECK: .Lanon.{{.+}}: // CHECK-NEXT: .asciz "foo" #[unsafe(no_mangle)] diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index dfbaff696440b..b6bc8e95127f7 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -13,3 +13,39 @@ } unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::() } + +fn main() { + fn g1(_: extern "C" fn(_: u8, va: ...)) { } + fn g2(_: extern "C" fn(_: u8, ...)) { } + fn g3(_: extern "C" fn(u8, va: ...)) { } + fn g4(_: extern "C" fn(u8, ...)) { } + + fn g5(_: extern "C" fn(va: ...)) { } + fn g6(_: extern "C" fn(...)) { } + + { + let _ = + { + unsafe extern "C" fn f1(_: u8, va: ...) { } + }; + }; + { + let _ = + { + unsafe extern "C" fn f2(_: u8, _: ...) { } + }; + }; + + { + let _ = + { + unsafe extern "C" fn f5(va: ...) { } + }; + }; + { + let _ = + { + unsafe extern "C" fn f6(_: ...) { } + }; + }; +} diff --git a/tests/pretty/hir-fn-variadic.rs b/tests/pretty/hir-fn-variadic.rs index 3d3f7ee18315c..99aa402c480b0 100644 --- a/tests/pretty/hir-fn-variadic.rs +++ b/tests/pretty/hir-fn-variadic.rs @@ -11,3 +11,19 @@ extern "C" { pub unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::() } + +fn main() { + fn g1(_: extern "C" fn(_: u8, va: ...)) {} + fn g2(_: extern "C" fn(_: u8, ...)) {} + fn g3(_: extern "C" fn(u8, va: ...)) {} + fn g4(_: extern "C" fn(u8, ...)) {} + + fn g5(_: extern "C" fn(va: ...)) {} + fn g6(_: extern "C" fn(...)) {} + + _ = { unsafe extern "C" fn f1(_: u8, va: ...) {} }; + _ = { unsafe extern "C" fn f2(_: u8, ...) {} }; + + _ = { unsafe extern "C" fn f5(va: ...) {} }; + _ = { unsafe extern "C" fn f6(...) {} }; +} diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr index 4a47671fee191..b6f2e014e0a86 100644 --- a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr +++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr @@ -16,6 +16,7 @@ LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz | | within this `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}` | | this tail expression is of type `{closure@contract-captures-via-closure-noncopy.rs:12:42}` | unsatisfied trait bound + | required by a bound introduced by this call | = help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}`, the trait `std::marker::Copy` is not implemented for `Baz` note: required because it's used within this closure diff --git a/tests/ui/contracts/contract-const-fn.all_pass.stderr b/tests/ui/contracts/contract-const-fn.all_pass.stderr new file mode 100644 index 0000000000000..e5b1df6558235 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.all_pass.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contract-const-fn.rs:17:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/contract-const-fn.rs b/tests/ui/contracts/contract-const-fn.rs new file mode 100644 index 0000000000000..733a06ae57090 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.rs @@ -0,0 +1,56 @@ +//! Check if we can annotate a constant function with contracts. +//! +//! The contract is only checked at runtime, and it will not fail if evaluated statically. +//! This is an existing limitation due to the existing architecture and the lack of constant +//! closures. +//! +//@ revisions: all_pass runtime_fail_pre runtime_fail_post +// +//@ [all_pass] run-pass +// +//@ [runtime_fail_pre] run-fail +//@ [runtime_fail_post] run-fail +// +//@ [all_pass] compile-flags: -Zcontract-checks=yes +//@ [runtime_fail_pre] compile-flags: -Zcontract-checks=yes +//@ [runtime_fail_post] compile-flags: -Zcontract-checks=yes +#![feature(contracts)] +//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] + +extern crate core; +use core::contracts::*; + +#[requires(x < 100)] +const fn less_than_100(x: u8) -> u8 { + x +} + +// This is wrong on purpose. +#[ensures(|ret| *ret)] +const fn always_true(b: bool) -> bool { + b +} + +const ZERO: u8 = less_than_100(0); +// This is no-op because the contract cannot be checked at compilation time. +const TWO_HUNDRED: u8 = less_than_100(200); + +/// Example from . +#[ensures(move |ret: &u32| *ret > x)] +const fn broken_sum(x: u32, y: u32) -> u32 { + x + y +} + +fn main() { + assert_eq!(ZERO, 0); + assert_eq!(TWO_HUNDRED, 200); + assert_eq!(broken_sum(0, 1), 1); + assert_eq!(always_true(true), true); + + #[cfg(runtime_fail_post)] + let _ok = always_true(false); + + // Runtime check should fail. + #[cfg(runtime_fail_pre)] + let _200 = less_than_100(200); +} diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr new file mode 100644 index 0000000000000..e5b1df6558235 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contract-const-fn.rs:17:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr new file mode 100644 index 0000000000000..e5b1df6558235 --- /dev/null +++ b/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr @@ -0,0 +1,11 @@ +warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/contract-const-fn.rs:17:12 + | +LL | #![feature(contracts)] + | ^^^^^^^^^ + | + = note: see issue #128044 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs index ae692afd146fe..c62b8cca75ab7 100644 --- a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs +++ b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs @@ -26,11 +26,11 @@ fn main() { #[cfg(any(default, unchk_pass, chk_fail_requires))] core::intrinsics::contract_check_requires(|| false); - let doubles_to_two = { let old = 2; move |ret| ret + ret == old }; + let doubles_to_two = { let old = 2; move |ret: &u32 | ret + ret == old }; // Always pass - core::intrinsics::contract_check_ensures(&1, doubles_to_two); + core::intrinsics::contract_check_ensures(doubles_to_two, 1); // Fail if enabled #[cfg(any(default, unchk_pass, chk_fail_ensures))] - core::intrinsics::contract_check_ensures(&2, doubles_to_two); + core::intrinsics::contract_check_ensures(doubles_to_two, 2); } diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs index e91bbed294d12..73c5919453101 100644 --- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs +++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs @@ -15,14 +15,14 @@ #![feature(contracts)] // to access core::contracts //~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #![feature(contracts_internals)] // to access check_requires lang item - +#![feature(core_intrinsics)] fn foo(x: Baz) -> i32 { let injected_checker = { core::contracts::build_check_ensures(|ret| *ret > 100) }; let ret = x.baz + 50; - injected_checker(ret) + core::intrinsics::contract_check_ensures(injected_checker, ret) } struct Baz { baz: i32 } diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs index 1b76eef6780fe..6e5a7a3f95005 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs @@ -6,7 +6,7 @@ fn main() { //~^ ERROR use of unstable library feature `contracts_internals` core::intrinsics::contract_check_requires(|| true); //~^ ERROR use of unstable library feature `contracts_internals` - core::intrinsics::contract_check_ensures(&1, |_|true); + core::intrinsics::contract_check_ensures( |_|true, &1); //~^ ERROR use of unstable library feature `contracts_internals` core::contracts::build_check_ensures(|_: &()| true); diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr index 7302694a7874a..1e39bd62e245b 100644 --- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr +++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr @@ -41,7 +41,7 @@ LL | core::intrinsics::contract_check_requires(|| true); error[E0658]: use of unstable library feature `contracts_internals` --> $DIR/internal-feature-gating.rs:9:5 | -LL | core::intrinsics::contract_check_ensures(&1, |_|true); +LL | core::intrinsics::contract_check_ensures( |_|true, &1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #128044 for more information diff --git a/tests/ui/generic-associated-types/impl_bounds.stderr b/tests/ui/generic-associated-types/impl_bounds.stderr index 231c0dd89c52d..7847bbd813cd5 100644 --- a/tests/ui/generic-associated-types/impl_bounds.stderr +++ b/tests/ui/generic-associated-types/impl_bounds.stderr @@ -57,14 +57,14 @@ note: required for `Fooy` to implement `Copy` | LL | #[derive(Copy, Clone)] | ^^^^ unsatisfied trait bound introduced in this `derive` macro -note: the requirement `Fooy: Copy` appears on the `impl`'s method `d` but not on the corresponding trait's method +note: the requirement `Fooy: Copy` appears on the `impl`'s associated function `d` but not on the corresponding trait's associated function --> $DIR/impl_bounds.rs:7:8 | LL | trait Foo { | --- in this trait ... LL | fn d() where Self: Clone; - | ^ this trait's method doesn't have the requirement `Fooy: Copy` + | ^ this trait's associated function doesn't have the requirement `Fooy: Copy` help: consider restricting type parameter `T` with trait `Copy` | LL | impl Foo for Fooy { diff --git a/tests/ui/impl-trait/auto-trait-coherence.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-coherence.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.rs diff --git a/tests/ui/impl-trait/auto-trait-coherence.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-coherence.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.stderr diff --git a/tests/ui/impl-trait/auto-trait-contains-err.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-contains-err.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.rs diff --git a/tests/ui/impl-trait/auto-trait-contains-err.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-contains-err.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.stderr diff --git a/tests/ui/impl-trait/auto-trait-leak-rpass.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak-rpass.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak-rpass.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak-rpass.rs diff --git a/tests/ui/impl-trait/auto-trait-leak.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs diff --git a/tests/ui/impl-trait/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr diff --git a/tests/ui/impl-trait/auto-trait-leak2.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak2.rs rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs diff --git a/tests/ui/impl-trait/auto-trait-leak2.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr similarity index 100% rename from tests/ui/impl-trait/auto-trait-leak2.stderr rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr diff --git a/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs b/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs new file mode 100644 index 0000000000000..7f366fdcabd28 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs @@ -0,0 +1,33 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +// When proving auto trait bounds, make sure that we depend on auto trait +// leakage if we can also prove it via an item bound. +fn is_send(_: T) {} + +fn direct() -> impl Send { + is_send(check(false)); // leaks auto traits, depends on `check` + 1u16 +} + +trait Indir: Send {} +impl Indir for u32 {} +fn indir() -> impl Indir { + is_send(check(false)); // leaks auto traits, depends on `check` + 1u32 +} + +fn check(b: bool) -> impl Sized { + if b { + // must not leak auto traits, as we otherwise get a query cycle. + is_send(direct()); + is_send(indir()); + } + 1u64 +} + +fn main() { + check(true); +} diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr new file mode 100644 index 0000000000000..bf598d6270940 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr @@ -0,0 +1,58 @@ +error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `::foo::{opaque#0}: core::marker::Send`... +note: ...which requires computing type of opaque `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `::foo` contains FFI-unwind calls... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 + | +LL | impl Trait for u32 { + | ^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr new file mode 100644 index 0000000000000..6bec5bbc06323 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr @@ -0,0 +1,122 @@ +error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires computing type of `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires computing type of opaque `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `::foo` contains FFI-unwind calls... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 + | +LL | impl Trait for u32 { + | ^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when computing type of `::{anon_assoc#0}` + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ + | +note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires computing type of `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires computing type of opaque `::foo::{opaque#0}`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:24 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires checking if `::foo` contains FFI-unwind calls... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `::foo`... + --> $DIR/method-compatability-via-leakage-cycle.rs:21:5 + | +LL | fn foo(b: bool) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `::{anon_assoc#0}`, completing the cycle +note: cycle used when checking that `` is well-formed + --> $DIR/method-compatability-via-leakage-cycle.rs:17:1 + | +LL | impl Trait for u32 { + | ^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs new file mode 100644 index 0000000000000..917820dc2b8b0 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs @@ -0,0 +1,30 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ known-bug: #139788 + +// Recursively using the trait method inside of an impl in case checking +// method compatability relies on opaque type leakage currently causes a +// cycle error. + +trait Trait { + // desugars to + // type Assoc: Sized + Send; + // fn foo(b: bool) -> Self::Assoc; + fn foo(b: bool) -> impl Sized + Send; +} + +impl Trait for u32 { + // desugars to + // type Assoc = impl_rpit::; + // fn foo(b: bool) -> Self::Assoc { .. } + fn foo(b: bool) -> impl Sized { + if b { + u32::foo(false) + } else { + 1u32 + } + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs new file mode 100644 index 0000000000000..249ec0728c1a0 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +trait Trait { + fn foo() -> impl Sized + Send; +} + +impl Trait for u32 { + fn foo() -> impl Sized {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/refine-cycle.rs b/tests/ui/impl-trait/in-trait/refine-cycle.rs index 78d672a7ed60a..d97f9821347ef 100644 --- a/tests/ui/impl-trait/in-trait/refine-cycle.rs +++ b/tests/ui/impl-trait/in-trait/refine-cycle.rs @@ -1,4 +1,7 @@ //@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) // Make sure that refinement checking doesn't cause a cycle in `Instance::resolve` // which calls `compare_impl_item`. diff --git a/tests/ui/proc-macro/auxiliary/expand-expr.rs b/tests/ui/proc-macro/auxiliary/expand-expr.rs index 78c9fa75d9ff2..14efc3c6b9f17 100644 --- a/tests/ui/proc-macro/auxiliary/expand-expr.rs +++ b/tests/ui/proc-macro/auxiliary/expand-expr.rs @@ -3,9 +3,10 @@ extern crate proc_macro; -use proc_macro::*; use std::str::FromStr; +use proc_macro::*; + // Flatten the TokenStream, removing any toplevel `Delimiter::None`s for // comparison. fn flatten(ts: TokenStream) -> Vec { @@ -136,9 +137,8 @@ pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream { .to_string(); assert_eq!(input_t, parse_t); - // Check that the literal matches `Span::call_site().source_file().path()` - let expect_t = - Literal::string(&Span::call_site().source_file().path().to_string_lossy()).to_string(); + // Check that the literal matches `Span::call_site().file()` + let expect_t = Literal::string(&Span::call_site().file()).to_string(); assert_eq!(input_t, expect_t); TokenStream::new() diff --git a/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs b/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs index 4971de284b760..11e1910288eee 100644 --- a/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs +++ b/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs @@ -79,7 +79,7 @@ fn check_useful_span(token: TokenTree, expected_filename: &str) { let span = token.span(); assert!(span.column() < span.end().column()); - let source_path = span.source_file().path(); + let source_path = span.local_file().unwrap(); let filename = source_path.components().last().unwrap(); assert_eq!(filename, Component::Normal(expected_filename.as_ref())); } diff --git a/tests/ui/proc-macro/auxiliary/span-api-tests.rs b/tests/ui/proc-macro/auxiliary/span-api-tests.rs index 99db66ed6a94c..036f2e3ac3f5e 100644 --- a/tests/ui/proc-macro/auxiliary/span-api-tests.rs +++ b/tests/ui/proc-macro/auxiliary/span-api-tests.rs @@ -11,20 +11,9 @@ pub fn reemit(input: TokenStream) -> TokenStream { } #[proc_macro] -pub fn assert_fake_source_file(input: TokenStream) -> TokenStream { +pub fn assert_local_file(input: TokenStream) -> TokenStream { for tk in input { - let source_file = tk.span().source_file(); - assert!(!source_file.is_real(), "Source file is real: {:?}", source_file); - } - - "".parse().unwrap() -} - -#[proc_macro] -pub fn assert_source_file(input: TokenStream) -> TokenStream { - for tk in input { - let source_file = tk.span().source_file(); - assert!(source_file.is_real(), "Source file is not real: {:?}", source_file); + assert!(tk.span().local_file().is_some(), "No local file for span: {:?}", tk.span()); } "".parse().unwrap() diff --git a/tests/ui/proc-macro/span-api-tests.rs b/tests/ui/proc-macro/span-api-tests.rs index ac42a7ea611ab..792859ed05b16 100644 --- a/tests/ui/proc-macro/span-api-tests.rs +++ b/tests/ui/proc-macro/span-api-tests.rs @@ -8,26 +8,24 @@ extern crate span_test_macros; extern crate span_api_tests; -// FIXME(69775): Investigate `assert_fake_source_file`. - -use span_api_tests::{reemit, assert_source_file, macro_stringify}; +use span_api_tests::{reemit, assert_local_file, macro_stringify}; macro_rules! say_hello { ($macname:ident) => ( $macname! { "Hello, world!" }) } -assert_source_file! { "Hello, world!" } +assert_local_file! { "Hello, world!" } -say_hello! { assert_source_file } +say_hello! { assert_local_file } reemit_legacy! { - assert_source_file! { "Hello, world!" } + assert_local_file! { "Hello, world!" } } -say_hello_extern! { assert_source_file } +say_hello_extern! { assert_local_file } reemit! { - assert_source_file! { "Hello, world!" } + assert_local_file! { "Hello, world!" } } fn main() { diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs index b0c778e7f5742..754fc872e457c 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs @@ -34,9 +34,17 @@ where MultipleNested: Trait, {} +// We ignore the trivially true global where-bounds when checking that this +// impl is well-formed, meaning that we depend on `MultipleNested: Trait` when +// recursively proving `MultipleCandidates: Trait`. +// +// These overflow errors will disappear once we treat these cycles as either +// productive or an error. impl Trait for MultipleNested +//~^ ERROR overflow evaluating the requirement `MultipleNested: Trait` where MultipleCandidates: Trait, + //~^ ERROR overflow evaluating the requirement `MultipleCandidates: Trait` DoesNotImpl: Trait, {} diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr index acacaf6a331d9..7895a2636345a 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr @@ -1,16 +1,29 @@ +error[E0275]: overflow evaluating the requirement `MultipleNested: Trait` + --> $DIR/inductive-cycle-but-err.rs:43:16 + | +LL | impl Trait for MultipleNested + | ^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `MultipleCandidates: Trait` + --> $DIR/inductive-cycle-but-err.rs:46:25 + | +LL | MultipleCandidates: Trait, + | ^^^^^ + error[E0277]: the trait bound `MultipleCandidates: Trait` is not satisfied - --> $DIR/inductive-cycle-but-err.rs:46:19 + --> $DIR/inductive-cycle-but-err.rs:54:19 | LL | impls_trait::(); | ^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `MultipleCandidates` | = help: the trait `Trait` is implemented for `MultipleCandidates` note: required by a bound in `impls_trait` - --> $DIR/inductive-cycle-but-err.rs:43:19 + --> $DIR/inductive-cycle-but-err.rs:51:19 | LL | fn impls_trait() {} | ^^^^^ required by this bound in `impls_trait` -error: aborting due to 1 previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0275, E0277. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr index 74a0a90885da5..d179c80596238 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr @@ -4,14 +4,14 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` LL | Self::Assoc: A, | ^^^^ | -note: the requirement `<() as A>::Assoc: A` appears on the `impl`'s method `f` but not on the corresponding trait's method +note: the requirement `<() as A>::Assoc: A` appears on the `impl`'s associated function `f` but not on the corresponding trait's associated function --> $DIR/normalize-param-env-2.rs:12:8 | LL | trait A { | - in this trait ... LL | fn f() - | ^ this trait's method doesn't have the requirement `<() as A>::Assoc: A` + | ^ this trait's associated function doesn't have the requirement `<() as A>::Assoc: A` error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` --> $DIR/normalize-param-env-2.rs:24:22 diff --git a/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs b/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs new file mode 100644 index 0000000000000..d422605a2923e --- /dev/null +++ b/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs @@ -0,0 +1,33 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#172. +// +// In this test the global where-bound simply constrains the +// object lifetime bound to 'static while the builtin impl +// ends up also emitting a `dyn Any: 'static` type outlives +// constraint. This previously resulted in ambiguity. We now +// always prefer the impl. + +pub trait Any: 'static {} + +pub trait Downcast: Any +where + T: Any, +{ +} + +// elided object lifetime: `dyn Any + 'static` +impl dyn Any { + pub fn is(&self) + where + T: Any, + // elaboration adds global where-clause `dyn Any + 'static: Any` + Self: Downcast, + { + } +} + +fn main() {} diff --git a/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs b/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs new file mode 100644 index 0000000000000..3bc8b0438bf82 --- /dev/null +++ b/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs @@ -0,0 +1,29 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#172. +// +// The next-generation trait solver previously simply tried +// to merge the global where-bounds with the impl candidates. +// This caused ambiguity in case the where-bound had stricter +// region requirements than the impl. + +trait Trait {} +struct Foo<'a, 'b>(&'a (), &'b ()); +impl<'a> Trait for Foo<'a, 'static> {} + +fn impls_trait() {} +fn foo() +where + Foo<'static, 'static>: Trait, +{ + // impl requires `'1 to be 'static + // global where-bound requires both '0 and '1 to be 'static + // + // we always prefer the impl here. + impls_trait::>(); +} + +fn main() {} diff --git a/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs new file mode 100644 index 0000000000000..cdfb0ee45af4d --- /dev/null +++ b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs @@ -0,0 +1,29 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Make sure we prefer the `I::IntoIterator: Iterator` +// where-bound over the `I::Intoiterator: Iterator` +// alias-bound. + +trait Iterator { + type Item; +} + +trait IntoIterator { + type Item; + type IntoIter: Iterator; +} + +fn normalize>() {} + +fn foo() +where + I: IntoIterator, + I::IntoIter: Iterator, +{ + normalize::(); +} + +fn main() {} diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs index 3878c47554d98..a3959b3831779 100644 --- a/tests/ui/type/pattern_types/derives.rs +++ b/tests/ui/type/pattern_types/derives.rs @@ -1,4 +1,5 @@ -//! Check that pattern types don't implement traits of their base automatically +//! Check that pattern types don't implement traits of their base automatically. +//! Exceptions are `Clone` and `Copy`, which have builtin impls for pattern types. #![feature(pattern_types)] #![feature(pattern_type_macro)] diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr index f59617ebc4564..2d83684b152ef 100644 --- a/tests/ui/type/pattern_types/derives.stderr +++ b/tests/ui/type/pattern_types/derives.stderr @@ -1,5 +1,5 @@ error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` - --> $DIR/derives.rs:10:20 + --> $DIR/derives.rs:11:20 | LL | #[derive(Clone, Copy, PartialEq)] | --------- in this derive macro expansion diff --git a/tests/ui/type/pattern_types/derives_fail.rs b/tests/ui/type/pattern_types/derives_fail.rs new file mode 100644 index 0000000000000..a3fbad6672071 --- /dev/null +++ b/tests/ui/type/pattern_types/derives_fail.rs @@ -0,0 +1,26 @@ +//! Check that pattern types don't implement traits of their base automatically. +//! Exceptions are `Clone` and `Copy`, which have bultin impls for pattern types. + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] +#[repr(transparent)] +struct Nanoseconds(NanoI32); +//~^ ERROR: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied +//~| ERROR: `(i32) is 0..=999999999` doesn't implement `Debug` +//~| ERROR: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied +//~| ERROR: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied +//~| ERROR: the trait bound `(i32) is 0..=999999999: Default` is not satisfied +//~| ERROR: can't compare `(i32) is 0..=999999999` with `_` +//~| ERROR: `==` cannot be applied + +type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999); + +fn main() { + let x = Nanoseconds(unsafe { std::mem::transmute(42) }); + let y = x.clone(); + if y == x {} +} diff --git a/tests/ui/type/pattern_types/derives_fail.stderr b/tests/ui/type/pattern_types/derives_fail.stderr new file mode 100644 index 0000000000000..78bef726341d6 --- /dev/null +++ b/tests/ui/type/pattern_types/derives_fail.stderr @@ -0,0 +1,74 @@ +error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | --------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ + +error[E0277]: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | -- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Eq` is not implemented for `(i32) is 0..=999999999` + | +note: required by a bound in `AssertParamIsEq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL + +error[E0277]: `(i32) is 0..=999999999` doesn't implement `Debug` + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ----- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = help: the trait `Debug` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | --- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Ord` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: can't compare `(i32) is 0..=999999999` with `_` + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ---------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ no implementation for `(i32) is 0..=999999999 < _` and `(i32) is 0..=999999999 > _` + | + = help: the trait `PartialOrd<_>` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ---- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Hash` is not implemented for `(i32) is 0..=999999999` + +error[E0277]: the trait bound `(i32) is 0..=999999999: Default` is not satisfied + --> $DIR/derives_fail.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)] + | ------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ the trait `Default` is not implemented for `(i32) is 0..=999999999` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/type/pattern_types/matching.rs b/tests/ui/type/pattern_types/matching.rs new file mode 100644 index 0000000000000..b8463a8e82298 --- /dev/null +++ b/tests/ui/type/pattern_types/matching.rs @@ -0,0 +1,26 @@ +#![feature(pattern_types, pattern_type_macro, structural_match)] + +//@ check-pass + +use std::marker::StructuralPartialEq; +use std::pat::pattern_type; + +struct Thing(pattern_type!(u32 is 1..)); + +impl StructuralPartialEq for Thing {} +impl PartialEq for Thing { + fn eq(&self, other: &Thing) -> bool { + unsafe { std::mem::transmute::<_, u32>(self.0) == std::mem::transmute::<_, u32>(other.0) } + } +} + +impl Eq for Thing {} + +const TWO: Thing = Thing(2); + +const _: () = match TWO { + TWO => {} + _ => unreachable!(), +}; + +fn main() {} diff --git a/tests/ui/type/pattern_types/matching_fail.rs b/tests/ui/type/pattern_types/matching_fail.rs new file mode 100644 index 0000000000000..8e2c741e3e0ab --- /dev/null +++ b/tests/ui/type/pattern_types/matching_fail.rs @@ -0,0 +1,25 @@ +#![feature(pattern_types, pattern_type_macro, structural_match)] + +use std::pat::pattern_type; + +const THREE: pattern_type!(u32 is 1..) = 3; + +const _: () = match THREE { + THREE => {} + //~^ ERROR non-structural type + _ => unreachable!(), +}; + +const _: () = match THREE { + 3 => {} + //~^ ERROR mismatched types + _ => unreachable!(), +}; + +const _: () = match 3 { + THREE => {} + //~^ ERROR mismatched types + _ => unreachable!(), +}; + +fn main() {} diff --git a/tests/ui/type/pattern_types/matching_fail.stderr b/tests/ui/type/pattern_types/matching_fail.stderr new file mode 100644 index 0000000000000..446180d80f24b --- /dev/null +++ b/tests/ui/type/pattern_types/matching_fail.stderr @@ -0,0 +1,43 @@ +error: constant of non-structural type `(u32) is 1..` in a pattern + --> $DIR/matching_fail.rs:8:5 + | +LL | const THREE: pattern_type!(u32 is 1..) = 3; + | -------------------------------------- constant defined here +... +LL | THREE => {} + | ^^^^^ constant of non-structural type + | + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details + +error[E0308]: mismatched types + --> $DIR/matching_fail.rs:14:5 + | +LL | const _: () = match THREE { + | ----- this expression has type `(u32) is 1..` +LL | 3 => {} + | ^ expected `(u32) is 1..`, found integer + | + = note: expected pattern type `(u32) is 1..` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/matching_fail.rs:20:5 + | +LL | const THREE: pattern_type!(u32 is 1..) = 3; + | -------------------------------------- constant defined here +... +LL | const _: () = match 3 { + | - this expression has type `{integer}` +LL | THREE => {} + | ^^^^^ + | | + | expected integer, found `(u32) is 1..` + | `THREE` is interpreted as a constant, not a new binding + | help: introduce a new binding instead: `other_three` + | + = note: expected type `{integer}` + found pattern type `(u32) is 1..` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`.