diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index f1b6e196fe413..b00e98891d5e7 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -6,6 +6,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::*; use rustc_index::IndexVec; use rustc_middle::ty::TyCtxt; +use rustc_span::def_id::CRATE_MOD_ID; use rustc_span::{DUMMY_SP, Span, span_bug}; use tracing::{debug, instrument}; @@ -48,9 +49,7 @@ pub(super) fn index_hir<'hir>( }; match item { - OwnerNode::Crate(citem) => { - collector.visit_mod(citem, citem.spans.inner_span, hir::CRATE_HIR_ID) - } + OwnerNode::Crate(citem) => collector.visit_mod(citem, citem.spans.inner_span, CRATE_MOD_ID), OwnerNode::Item(item) => collector.visit_item(item), OwnerNode::TraitItem(item) => collector.visit_trait_item(item), OwnerNode::ImplItem(item) => collector.visit_impl_item(item), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9cd4b5d7d001f..fc8324fb443f8 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -68,7 +68,7 @@ use rustc_ast::Label; use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list}; use rustc_attr_ir::Attribute; use rustc_hir_id::HirId; -use rustc_span::def_id::LocalDefId; +use rustc_span::def_id::{LocalDefId, LocalModId}; use rustc_span::{Ident, Span, Symbol}; use crate::hir::*; @@ -311,7 +311,7 @@ pub trait Visitor<'v>: Sized { fn visit_ident(&mut self, ident: Ident) -> Self::Result { walk_ident(self, ident) } - fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, _n: HirId) -> Self::Result { + fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, _id: LocalModId) -> Self::Result { walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result { @@ -583,7 +583,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: } ItemKind::Mod(ident, ref module) => { try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_mod(module, item.span, item.hir_id())); + try_visit!(visitor.visit_mod( + module, + item.span, + LocalModId::new_unchecked(item.owner_id.def_id) + )); } ItemKind::ForeignMod { abi: _, items } => { walk_list!(visitor, visit_foreign_item_ref, items); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e581774747601..f1c330aaeed57 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -37,6 +37,7 @@ use rustc_middle::ty::{ self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized, fold_regions, }; +use rustc_span::def_id::LocalModId; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, bug, kw, span_bug, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::infer::InferCtxtExt; @@ -497,6 +498,10 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.item_def_id } + fn mod_id(&self) -> LocalModId { + self.tcx.parent_module_from_def_id(self.item_def_id) + } + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { if let RegionInferReason::ObjectLifetimeDefault(sugg_sp) = reason { // FIXME: Account for trailing plus `dyn Trait+`, the need of parens in 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 2a3728573f31e..5d4770e1fc7de 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -96,7 +96,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Do not suggest the other syntax if we are in trait impl: // the desugaring would contain an associated type constraint. if !is_impl { - err.span_suggestion( + err.span_suggestion_verbose( span, "use parenthetical notation instead", fn_trait_to_string(self.tcx(), trait_segment, true), @@ -199,8 +199,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .visible_traits() .filter(|trait_def_id| { let viz = tcx.visibility(*trait_def_id); - let def_id = self.item_def_id(); - viz.is_accessible_from(def_id, tcx) + viz.is_accessible_from(self.mod_id(), tcx) }) .collect(); @@ -568,7 +567,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) .filter(|header| { // Consider only accessible traits - tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) + tcx.visibility(trait_def_id).is_accessible_from(self.mod_id(), tcx) && header.polarity != ty::ImplPolarity::Negative }) .map(|header| header.trait_ref.instantiate_identity().skip_norm_wip().self_ty()) @@ -2036,7 +2035,7 @@ impl<'a, 'tcx> rustc_errors::Diagnostic<'a, ()> for AmbiguityBetweenVariantAndAs could_refer_to(DefKind::Variant, variant_def_id, ""); could_refer_to(mode.def_kind_for_diagnostics(), item_def_id, " also"); - lint.span_suggestion( + lint.span_suggestion_verbose( span, "use fully-qualified syntax", format!("<{} as {}>::{}", self_ty, tcx.item_name(bound_def_id), segment_ident), 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 ecfe5d3c2c7c2..309757aa66021 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -48,7 +48,7 @@ use rustc_middle::ty::{ const_lit_matches_ty, fold_regions, }; use rustc_session::diagnostics::feature_err; -use rustc_span::def_id::ModId; +use rustc_span::def_id::{LocalModId, ModId}; use rustc_span::{DUMMY_SP, Ident, Span, bug, kw, span_bug, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, FulfillmentError}; @@ -142,6 +142,9 @@ pub trait HirTyLowerer<'tcx> { /// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered. fn item_def_id(&self) -> LocalDefId; + /// Returns the containing module. + fn mod_id(&self) -> LocalModId; + /// Returns the region to use when a lifetime is omitted (and not elided). fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx>; @@ -1814,7 +1817,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) -> Option<(ty::AssocItem, /*scope*/ ModId)> { let tcx = self.tcx(); - let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, self.item_def_id()); + let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, self.mod_id()); // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()` // instead of calling `filter_by_name_and_kind` which would needlessly normalize the // `ident` again and again. @@ -1879,7 +1882,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) // Consider only accessible traits && tcx.visibility(*trait_def_id) - .is_accessible_from(self.item_def_id(), tcx) + .is_accessible_from(self.mod_id(), tcx) && tcx.all_impls(*trait_def_id) .any(|impl_def_id| { let header = tcx.impl_trait_header(impl_def_id); @@ -3424,7 +3427,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } hir::TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => self.lower_field_of( self.lower_ty(ty), - self.item_def_id(), + self.mod_id(), ty.span, hir_ty.hir_id, *variant, @@ -3478,7 +3481,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_field_of( &self, ty: Ty<'tcx>, - item_def_id: LocalDefId, + mod_id: LocalModId, ty_span: Span, hir_id: HirId, variant: Option, @@ -3528,8 +3531,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } (FIRST_VARIANT, def.non_enum_variant()) }; - let (ident, def_scope) = - tcx.adjust_ident_and_get_scope(field, def.did(), item_def_id); + let (ident, def_scope) = tcx.adjust_ident_and_get_scope(field, def.did(), mod_id); if let Some((field_idx, field)) = variant .fields .iter_enumerated() diff --git a/compiler/rustc_hir_id/src/lib.rs b/compiler/rustc_hir_id/src/lib.rs index dce7e7fd31a36..0e01600f9cb3d 100644 --- a/compiler/rustc_hir_id/src/lib.rs +++ b/compiler/rustc_hir_id/src/lib.rs @@ -16,7 +16,7 @@ use rustc_data_structures::stable_hash::{ StableHash, StableHashCtxt, StableHasher, StableOrd, ToStableHashKey, }; use rustc_macros::{Decodable, Encodable, StableHash}; -use rustc_span::def_id::{CRATE_DEF_ID, DefId, DefIndex, DefPathHash, LocalDefId}; +use rustc_span::def_id::{CRATE_DEF_ID, DefId, DefIndex, DefPathHash, LocalDefId, LocalModId}; #[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)] pub struct OwnerId { @@ -42,6 +42,12 @@ impl From for DefId { } } +impl From for OwnerId { + fn from(value: LocalModId) -> Self { + OwnerId { def_id: value.to_local_def_id() } + } +} + impl OwnerId { #[inline] pub fn to_def_id(self) -> DefId { @@ -141,6 +147,12 @@ impl fmt::Display for HirId { } } +impl From for HirId { + fn from(id: LocalModId) -> Self { + HirId::make_owner(id.to_local_def_id()) + } +} + rustc_data_structures::define_stable_id_collections!(HirIdMap, HirIdSet, HirIdMapEntry, HirId); rustc_data_structures::define_id_collections!( ItemLocalMap, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index d18745e24fd84..55eecef732aa4 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,5 +1,5 @@ -use rustc_errors::{Applicability, Diag, MultiSpan, listify}; -use rustc_hir::def::Res; +use rustc_errors::{Applicability, Diag, MultiSpan, listify, pluralize}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, find_attr}; use rustc_infer::infer::DefineOpaqueTypes; @@ -28,7 +28,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if expr_ty == expected { return; } - self.annotate_alternative_method_deref(err, expr, error); + self.annotate_alternative_method_deref_for_unop(err, expr, error); self.explain_self_literal(err, expr, expected, expr_ty); // Use `||` to give these suggestions a precedence @@ -752,11 +752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ExprKind::Path(hir::QPath::Resolved( None, hir::Path { - res: - hir::def::Res::Def( - hir::def::DefKind::Static { .. } | hir::def::DefKind::Const, - def_id, - ), + res: hir::def::Res::Def(DefKind::Static { .. } | DefKind::Const, def_id), .. }, )) => { @@ -929,7 +925,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn annotate_alternative_method_deref( + fn annotate_alternative_method_deref_for_unop( &self, err: &mut Diag<'_>, expr: &hir::Expr<'_>, @@ -949,7 +945,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; }; - let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { + self.annotate_alternative_method_deref(err, deref, Some(expected)) + } + + #[tracing::instrument(skip(self, err), level = "debug")] + pub(crate) fn annotate_alternative_method_deref( + &self, + err: &mut Diag<'_>, + expr: &hir::Expr<'_>, + expected: Option>, + ) { + let hir::ExprKind::MethodCall(path, base, args, _) = expr.kind else { return; }; let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { @@ -959,7 +965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Ok(pick) = self.lookup_probe_for_diagnostic( path.ident, self_ty, - deref, + expr, probe::ProbeScope::TraitsInScope, None, ) else { @@ -969,10 +975,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Ok(in_scope_methods) = self.probe_for_name_many( probe::Mode::MethodCall, path.ident, - Some(expected), + expected, probe::IsSuggestion(true), self_ty, - deref.hir_id, + expr.hir_id, probe::ProbeScope::TraitsInScope, ) else { return; @@ -984,10 +990,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Ok(all_methods) = self.probe_for_name_many( probe::Mode::MethodCall, path.ident, - Some(expected), + expected, probe::IsSuggestion(true), self_ty, - deref.hir_id, + expr.hir_id, probe::ProbeScope::AllTraits, ) else { return; @@ -995,34 +1001,51 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suggestions: Vec<_> = all_methods .into_iter() - .filter(|c| c.item.def_id != pick.item.def_id) - .map(|c| { + .filter_map(|c| { + if c.item.def_id == pick.item.def_id { + return None; + } let m = c.item; let generic_args = ty::GenericArgs::for_item(self.tcx, m.def_id, |param, _| { - self.var_for_def(deref.span, param) + self.var_for_def(expr.span, param) }); - let mutability = - match self.tcx.fn_sig(m.def_id).skip_binder().input(0).skip_binder().kind() { - ty::Ref(_, _, hir::Mutability::Mut) => "&mut ", - ty::Ref(_, _, _) => "&", - _ => "", - }; - vec![ - ( - deref.span.until(base.span), - format!( - "{}({}", - with_no_trimmed_paths!( - self.tcx.def_path_str_with_args(m.def_id, generic_args,) - ), - mutability, - ), - ), + let fn_sig = self.tcx.fn_sig(m.def_id); + if fn_sig.skip_binder().inputs().skip_binder().len() != args.len() + 1 { + return None; + } + let rcvr_ty = fn_sig.skip_binder().input(0).skip_binder(); + let (mutability, ty) = match rcvr_ty.kind() { + ty::Ref(_, ty, hir::Mutability::Mut) => ("&mut ", ty), + ty::Ref(_, ty, _) => ("&", ty), + _ => ("", &rcvr_ty), + }; + let path = match self.tcx.assoc_parent(m.def_id) { + Some((_, DefKind::Impl { of_trait: true })) => { + // We have `impl Trait for T {}`, suggest `::method`. + self.tcx.def_path_str_with_args(m.def_id, generic_args).to_string() + } + Some((_, DefKind::Impl { of_trait: false })) => { + if let ty::Adt(def, _) = ty.kind() { + // We have `impl T {}`, suggest `T::method`. + format!("{}::{}", self.tcx.def_path_str(def.did()), path.ident) + } else { + // This should be unreachable, as `impl &'a T {}` is invalid. + format!("{ty}::{}", path.ident) + } + } + // Fallback for arbitrary self types. + _ => with_no_trimmed_paths!( + self.tcx.def_path_str_with_args(m.def_id, generic_args) + ) + .to_string(), + }; + Some(vec![ + (expr.span.until(base.span), format!("{path}({}", mutability)), match &args { - [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()), + [] => (base.span.shrink_to_hi().with_hi(expr.span.hi()), ")".to_string()), [first, ..] => (base.span.between(first.span), ", ".to_string()), }, - ] + ]) }) .collect(); if suggestions.is_empty() { @@ -1076,9 +1099,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); if suggestions.len() > other_methods_in_scope.len() { + let n = suggestions.len() - other_methods_in_scope.len(); err.note(format!( - "additionally, there are {} other available methods that aren't in scope", - suggestions.len() - other_methods_in_scope.len() + "additionally, there {are} {n} other available method{s} that {are}n't in scope", + are = pluralize!("is", n), + s = pluralize!(n), )); } err.multipart_suggestions( @@ -1293,7 +1318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::def::Res::Def(kind, def_id) = path.res else { return; }; - let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) { + let callable_kind = if matches!(kind, DefKind::Ctor(_, _)) { CallableKind::Constructor } else { CallableKind::Function diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index a8898acf3a415..92122c38e4ed3 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -617,6 +617,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr_and_args.map_or(expr.span, |(e, _)| e.span), expr.span, expr.hir_id, + call_expr_and_args.is_some(), ) .0 } @@ -2240,9 +2241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let private_fields: Vec<&ty::FieldDef> = variant .fields .iter() - .filter(|field| { - !field.vis.is_accessible_from(tcx.parent_module(expr.hir_id), tcx) - }) + .filter(|field| !field.vis.is_accessible_from(self.mod_id, tcx)) .collect(); if !private_fields.is_empty() { @@ -2714,7 +2713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .filter(|field| { skip_fields.iter().all(|&skip| skip.ident.name != field.name) - && self.is_field_suggestable(field, expr.hir_id, expr.span) + && self.is_field_suggestable(field, expr.span) }) .map(|field| field.name) .collect() @@ -2790,11 +2789,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_error(self.tcx(), guar); } - let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope( - field, - base_def.did(), - self.body_def_id, - ); + let (ident, def_scope) = + self.tcx.adjust_ident_and_get_scope(field, base_def.did(), self.mod_id); if let Some((idx, field)) = self.find_adt_field(*base_def, ident) { self.write_field_index(expr.hir_id, idx); @@ -3269,7 +3265,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // try to add a suggestion in case the field is a nested field of a field of the Adt - let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); let (ty, unwrap) = if let ty::Adt(def, args) = base_ty.kind() && (self.tcx.is_diagnostic_item(sym::Result, def.did()) || self.tcx.is_diagnostic_item(sym::Option, def.did())) @@ -3280,9 +3275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { (base_ty, "") }; - for found_fields in - self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, expr.hir_id) - { + for found_fields in self.get_field_candidates_considering_privacy_for_diag(span, ty) { let field_names = found_fields.iter().map(|field| field.0.name).collect::>(); let mut candidate_fields: Vec<_> = found_fields .into_iter() @@ -3292,8 +3285,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &|candidate_field, _| candidate_field == field, candidate_field, vec![], - mod_id, - expr.hir_id, ) }) .map(|mut field_path| { @@ -3354,8 +3345,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, base_ty: Ty<'tcx>, - mod_id: DefId, - hir_id: HirId, ) -> Vec)>> { debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); @@ -3379,15 +3368,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Some struct, e.g. some that impl `Deref`, have all private fields // because you're expected to deref them to access the _real_ fields. // This, for example, will help us suggest accessing a field through a `Box`. - if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { + if fields + .iter() + .all(|field| !field.vis.is_accessible_from(self.mod_id, tcx)) + { return None; } return Some( fields .iter() .filter(move |field| { - field.vis.is_accessible_from(mod_id, tcx) - && self.is_field_suggestable(field, hir_id, span) + field.vis.is_accessible_from(self.mod_id, tcx) + && self.is_field_suggestable(field, span) }) // For compile-time reasons put a limit on number of fields we search .take(100) @@ -3419,15 +3411,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This method is called after we have encountered a missing field error to recursively /// search for the field - #[instrument(skip(self, matches, mod_id, hir_id), level = "debug")] + #[instrument(skip(self, matches), level = "debug")] pub(crate) fn check_for_nested_field_satisfying_condition_for_diag( &self, span: Span, matches: &impl Fn(Ident, Ty<'tcx>) -> bool, (candidate_name, candidate_ty): (Ident, Ty<'tcx>), mut field_path: Vec, - mod_id: DefId, - hir_id: HirId, ) -> Option> { if field_path.len() > 3 { // For compile-time reasons and to avoid infinite recursion we only check for fields @@ -3438,12 +3428,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if matches(candidate_name, candidate_ty) { return Some(field_path); } - for nested_fields in self.get_field_candidates_considering_privacy_for_diag( - span, - candidate_ty, - mod_id, - hir_id, - ) { + for nested_fields in + self.get_field_candidates_considering_privacy_for_diag(span, candidate_ty) + { // recursively search fields of `candidate_field` if it's a ty::Adt for field in nested_fields { if let Some(field_path) = self.check_for_nested_field_satisfying_condition_for_diag( @@ -3451,8 +3438,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { matches, field, field_path.clone(), - mod_id, - hir_id, ) { return Some(field_path); } @@ -3864,11 +3849,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit(); break; }; - let (subident, sub_def_scope) = self.tcx.adjust_ident_and_get_scope( - subfield, - variant.def_id, - self.body_def_id, - ); + let (subident, sub_def_scope) = + self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, self.mod_id); let Some((subindex, field)) = variant .fields @@ -3919,7 +3901,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope( field, container_def.did(), - self.body_def_id, + self.mod_id, ); let fields = &container_def.non_enum_variant().fields; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index e655e0857d858..b9f3e2479a903 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1006,6 +1006,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, path_span: Span, hir_id: HirId, + has_args: bool, ) -> (Ty<'tcx>, Res) { let tcx = self.tcx; @@ -1238,7 +1239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap(); // Check the visibility of the ctor. let vis = tcx.visibility(ctor_def_id); - if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) { + if !vis.is_accessible_from(self.mod_id, tcx) { self.dcx() .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) }); } @@ -1253,17 +1254,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the `Self` constructor can only be used with tuple or unit structs", ); if let Some(adt_def) = ty.normalized.ty_adt_def() { - match adt_def.adt_kind() { - AdtKind::Enum => { - err.help("did you mean to use one of the enum's variants?"); - } - AdtKind::Struct | AdtKind::Union => { - err.span_suggestion( - span, - "use curly brackets", - "Self { /* fields */ }", - Applicability::HasPlaceholders, - ); + let def_id = self.body_def_id.to_def_id(); + if !has_args + && let Some(assoc) = tcx.opt_associated_item(def_id) + && assoc.is_method() + { + let self_ty = + tcx.fn_sig(def_id).instantiate_identity().skip_binder().inputs()[0]; + let applicability = if let ty::Adt(..) = self_ty.kind() { + // We're within a method that takes ownership of `Self`, likely a + // builder, so this is most likely a typo. + Applicability::MachineApplicable + } else { + // We still might have meant `self` instead of `Self`. + Applicability::MaybeIncorrect + }; + err.span_suggestion_verbose( + span, + format!( + "you might have meant to refer to the `self` binding of type \ + `{self_ty}`", + ), + "self".to_string(), + applicability, + ); + } else { + match adt_def.adt_kind() { + AdtKind::Enum => { + err.span_help( + tcx.def_span(adt_def.did()), + if adt_def.variants().is_empty() { + "the enum is unconstructable because it has no variants" + } else { + "you might have meant to use one of the enum's variants" + }, + ); + } + AdtKind::Struct | AdtKind::Union => { + err.span_suggestion_verbose( + span, + "use curly brackets", + "Self { /* fields */ }", + Applicability::HasPlaceholders, + ); + } } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 074b95321db3b..9965a9d071031 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -3186,6 +3186,8 @@ impl<'a, 'tcx> ArgMatchingCtxt<'a, 'tcx> { ); return; } + + self.annotate_alternative_method_deref(err, self.call_expr, None); } /// A "softer" version of the `demand_compatible`, which checks types without persisting them, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 3e2d35da5307d..b2b49dc06b7a6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -22,6 +22,7 @@ use rustc_middle::ty::{ self, CantBeErased, Const, Flags, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized, }; use rustc_session::Session; +use rustc_span::def_id::LocalModId; use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span}; use rustc_trait_selection::error_reporting::TypeErrCtxt; use rustc_trait_selection::traits::{ @@ -239,6 +240,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { self.body_def_id } + fn mod_id(&self) -> LocalModId { + self.mod_id + } + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { let v = match reason { RegionInferReason::Param(def) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index ab8020a3182e0..8895faef0890f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2285,14 +2285,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(crate) fn is_field_suggestable( - &self, - field: &ty::FieldDef, - hir_id: HirId, - span: Span, - ) -> bool { + pub(crate) fn is_field_suggestable(&self, field: &ty::FieldDef, span: Span) -> bool { // The field must be visible in the containing module. - field.vis.is_accessible_from(self.tcx.parent_module(hir_id), self.tcx) + field.vis.is_accessible_from(self.mod_id, self.tcx) // The field must not be unstable. && !matches!( self.tcx.eval_stability(field.did, None, rustc_span::DUMMY_SP, None), diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 02b3255e795ac..79b8ef15d7e13 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -859,8 +859,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let is_accessible = if let Some(name) = self.method_name { let item = candidate.item; let container_id = item.container_id(self.tcx); - let def_scope = - self.tcx.adjust_ident_and_get_scope(name, container_id, self.body_def_id).1; + let def_scope = self.tcx.adjust_ident_and_get_scope(name, container_id, self.mod_id).1; item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx) } else { true diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 545516f2e41a0..aebfeac2e7e85 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2836,8 +2836,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }); if let Some((field, field_ty)) = field_receiver { - let scope = tcx.parent_module_from_def_id(self.body_def_id); - let is_accessible = field.vis.is_accessible_from(scope, tcx); + let is_accessible = field.vis.is_accessible_from(self.mod_id, tcx); if is_accessible { if let Some((what, _, _)) = self.extract_callable_info(field_ty) { @@ -3199,13 +3198,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return_type: Option>, ) { if let SelfSource::MethodCall(expr) = source { - let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); - for fields in self.get_field_candidates_considering_privacy_for_diag( - span, - actual, - mod_id, - expr.hir_id, - ) { + for fields in self.get_field_candidates_considering_privacy_for_diag(span, actual) { let call_expr = self.tcx.hir_expect_expr(self.tcx.parent_hir_id(expr.hir_id)); let lang_items = self.tcx.lang_items(); @@ -3240,8 +3233,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, candidate_field, vec![], - mod_id, - expr.hir_id, ) }) .map(|field_path| { @@ -3991,11 +3982,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let parent_map = self.tcx.visible_parent_map(()); - let scope = self.tcx.parent_module_from_def_id(self.body_def_id); let (accessible_candidates, inaccessible_candidates): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|id| { let vis = self.tcx.visibility(*id); - vis.is_accessible_from(scope, self.tcx) + vis.is_accessible_from(self.mod_id, self.tcx) // Visibility alone does not make `fn_name::Trait` an importable path. // We need to make sure all parent are modules, otherwise the path is not importable. && std::iter::successors(self.tcx.opt_parent(*id), |&id| self.tcx.opt_parent(id)) @@ -4053,7 +4043,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let accessible_sugg = sugg(accessible_candidates, true); let inaccessible_sugg = sugg(inaccessible_candidates, false); - let (module, _, _) = self.tcx.hir_get_module(scope); + let (module, _) = self.tcx.hir_get_module(self.mod_id); let span = module.spans.inject_use_span; handle_candidates(accessible_sugg, inaccessible_sugg, span); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index caffef6a217a8..a017b0dfcb507 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -911,7 +911,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rustc_hir::PatExprKind::Path(qpath) => { let (res, opt_ty, segments) = self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span); - self.instantiate_value_path(segments, opt_ty, res, lt.span, lt.span, lt.hir_id).0 + self.instantiate_value_path( + segments, opt_ty, res, lt.span, lt.span, lt.hir_id, false, + ) + .0 } }; self.write_ty(lt.hir_id, ty); @@ -1624,7 +1627,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find the type of the path pattern, for later checking. let (pat_ty, pat_res) = - self.instantiate_value_path(segments, opt_ty, res, span, span, path_id); + self.instantiate_value_path(segments, opt_ty, res, span, span, path_id, false); Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } }) } @@ -1784,8 +1787,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Type-check the path. - let (pat_ty, res) = - self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id); + let (pat_ty, res) = self + .instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id, false); if !pat_ty.is_fn() { return report_unexpected_res(res); } @@ -2163,7 +2166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let accessible_unmentioned_fields: Vec<_> = unmentioned_fields .iter() .copied() - .filter(|(field, _)| self.is_field_suggestable(field, pat.hir_id, pat.span)) + .filter(|(field, _)| self.is_field_suggestable(field, pat.span)) .collect(); if !has_rest_pat { @@ -2336,7 +2339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if let [(field_def, field)] = unmentioned_fields.as_slice() - && self.is_field_suggestable(field_def, pat.hir_id, pat.span) + && self.is_field_suggestable(field_def, pat.span) { let suggested_name = find_best_match_for_name(&[field.name], pat_field.ident.name, None); diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 37b753062c708..1c037cc2e2d7e 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, HirId, HirIdMap}; use rustc_infer::infer::{InferCtxt, InferOk, OpaqueTypeStorageEntries, TyCtxtInferExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TyVid, TypeVisitableExt, TypingMode}; -use rustc_span::def_id::LocalDefIdMap; +use rustc_span::def_id::{LocalDefIdMap, LocalModId}; use rustc_span::{Span, span_bug}; use rustc_trait_selection::traits::{self, FulfillmentEngine, FulfillmentError, TraitEngine}; use tracing::instrument; @@ -67,6 +67,9 @@ pub(crate) struct TypeckRootCtxt<'tcx> { /// we record that type variable here. This is later used to inform /// fallback. See the `fallback` module for details. pub(super) diverging_type_vars: RefCell>, + + /// Parent module + pub(super) mod_id: LocalModId, } impl<'tcx> Deref for TypeckRootCtxt<'tcx> { @@ -78,6 +81,7 @@ impl<'tcx> Deref for TypeckRootCtxt<'tcx> { impl<'tcx> TypeckRootCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { + let mod_id = tcx.parent_module_from_def_id(def_id); let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; let infcx = tcx @@ -102,6 +106,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { deferred_asm_checks: RefCell::new(Vec::new()), deferred_repeat_expr_checks: RefCell::new(Vec::new()), diverging_type_vars: RefCell::new(Default::default()), + mod_id, } } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 0679d8abe3d78..ac185c65aa127 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -13,6 +13,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::Session; use rustc_span::Span; +use rustc_span::def_id::CRATE_MOD_ID; use tracing::debug; use crate::passes::LateLintPassObject; @@ -75,9 +76,9 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { self.context.param_env = old_param_env; } - fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, n: HirId) { - lint_callback!(self, check_mod, m, n); - hir_visit::walk_mod(self, m); + fn process_mod(&mut self, module: &'tcx hir::Mod<'tcx>, id: LocalModId) { + lint_callback!(self, check_mod, module, id); + hir_visit::walk_mod(self, module); } } @@ -220,9 +221,9 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas hir_visit::walk_ty(self, t); } - fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _: Span, n: HirId) { + fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _: Span, id: LocalModId) { if !self.context.only_module { - self.process_mod(m, n); + self.process_mod(m, id); } } @@ -385,17 +386,17 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( actually_rustdoc: tcx.sess.opts.actually_rustdoc, }; - let (module, _span, hir_id) = tcx.hir_get_module(mod_id); + let (module, _span) = tcx.hir_get_module(mod_id); - cx.with_lint_attrs(hir_id, |cx| { + cx.with_lint_attrs(mod_id.into(), |cx| { // There is no module lint that will have the crate itself as an item, so check it here. - if hir_id == hir::CRATE_HIR_ID { + if mod_id == CRATE_MOD_ID { lint_callback!(cx, check_crate,); } - cx.process_mod(module, hir_id); + cx.process_mod(module, mod_id); - if hir_id == hir::CRATE_HIR_ID { + if mod_id == CRATE_MOD_ID { lint_callback!(cx, check_crate_post,); } }); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 472835388620c..7f3d7fa8d2a10 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -26,6 +26,7 @@ use rustc_middle::lint::{ use rustc_middle::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::Session; +use rustc_span::def_id::CRATE_MOD_ID; use rustc_span::{AttrId, DUMMY_SP, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -190,7 +191,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe hir::OwnerNode::ImplItem(item) => levels.visit_impl_item(item), hir::OwnerNode::Crate(mod_) => { levels.add_id(hir::CRATE_HIR_ID); - levels.visit_mod(mod_, mod_.spans.inner_span, hir::CRATE_HIR_ID) + levels.visit_mod(mod_, mod_.spans.inner_span, CRATE_MOD_ID) } hir::OwnerNode::Synthetic => unreachable!(), }, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index a0db07e187cba..d1057c4f9ead3 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -11,7 +11,7 @@ use rustc_hir::{Attribute, GenericParamKind, PatExprKind, PatKind, find_attr}; use rustc_lint_defs::{declare_lint, declare_lint_pass}; use rustc_middle::hir::nested_filter::All; use rustc_middle::ty::AssocContainer; -use rustc_span::def_id::LocalDefId; +use rustc_span::def_id::{CRATE_MOD_ID, LocalDefId, LocalModId}; use rustc_span::{BytePos, Ident, Span, sym}; use rustc_structures::CrateType; @@ -328,8 +328,8 @@ impl NonSnakeCase { } impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { - fn check_mod(&mut self, cx: &LateContext<'_>, _: &'tcx hir::Mod<'tcx>, id: hir::HirId) { - if id != hir::CRATE_HIR_ID { + fn check_mod(&mut self, cx: &LateContext<'_>, _: &'tcx hir::Mod<'tcx>, id: LocalModId) { + if id != CRATE_MOD_ID { return; } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index f870bce669e58..6b7955db483f1 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -11,7 +11,7 @@ macro_rules! late_lint_methods { fn check_body_post(a: &rustc_hir::Body<'tcx>); fn check_crate(); fn check_crate_post(); - fn check_mod(a: &'tcx rustc_hir::Mod<'tcx>, b: rustc_hir::HirId); + fn check_mod(a: &'tcx rustc_hir::Mod<'tcx>, b: rustc_span::def_id::LocalModId); fn check_foreign_item(a: &'tcx rustc_hir::ForeignItem<'tcx>); fn check_item(a: &'tcx rustc_hir::Item<'tcx>); fn check_item_post(a: &'tcx rustc_hir::Item<'tcx>); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 1743f0d05dfcd..affadfd0c6aaf 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -409,11 +409,10 @@ impl<'tcx> TyCtxt<'tcx> { find_attr!(self.hir_krate_attrs(), RustcCoherenceIsCore) } - pub fn hir_get_module(self, module: LocalModId) -> (&'tcx Mod<'tcx>, Span, HirId) { - let hir_id = HirId::make_owner(module.to_local_def_id()); - match self.hir_owner_node(hir_id.owner) { - OwnerNode::Item(&Item { span, kind: ItemKind::Mod(_, m), .. }) => (m, span, hir_id), - OwnerNode::Crate(item) => (item, item.spans.inner_span, hir_id), + pub fn hir_get_module(self, module: LocalModId) -> (&'tcx Mod<'tcx>, Span) { + match self.hir_owner_node(module.into()) { + OwnerNode::Item(&Item { span, kind: ItemKind::Mod(_, m), .. }) => (m, span), + OwnerNode::Crate(item) => (item, item.spans.inner_span), node => panic!("not a module: {node:?}"), } } @@ -423,8 +422,8 @@ impl<'tcx> TyCtxt<'tcx> { where V: Visitor<'tcx>, { - let (top_mod, span, hir_id) = self.hir_get_module(CRATE_MOD_ID); - visitor.visit_mod(top_mod, span, hir_id) + let (top_mod, span) = self.hir_get_module(CRATE_MOD_ID); + visitor.visit_mod(top_mod, span, CRATE_MOD_ID) } /// Walks the attributes in a crate. @@ -1254,8 +1253,8 @@ fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> { pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModId) -> ModuleItems { let mut collector = ItemCollector::new(tcx, false); - let (hir_mod, span, hir_id) = tcx.hir_get_module(module_id); - collector.visit_mod(hir_mod, span, hir_id); + let (hir_mod, span) = tcx.hir_get_module(module_id); + collector.visit_mod(hir_mod, span, module_id); let ItemCollector { submodules, diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 50e823f88178f..6e838c4454c4c 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -411,6 +411,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.impl_super_outlives(impl_def_id) } + fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator { + rustc_type_ir::elaborate::supertrait_def_ids(self, trait_def_id) + } + fn impl_is_const(self, def_id: DefId) -> bool { debug_assert_matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true }); self.is_conditionally_const(def_id) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e23ce6b246f12..94345380a544e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -428,19 +428,19 @@ impl Visibility { } } -impl> Visibility { - /// Returns `true` if an item with this visibility is accessible from the given module. - pub fn is_accessible_from(self, module: impl Into, tcx: TyCtxt<'_>) -> bool { +impl> Visibility { + /// Returns `true` if an item with this visibility is accessible from the given definition. + pub fn is_accessible_from(self, def_id: impl Into, tcx: TyCtxt<'_>) -> bool { match self { // Public items are visible everywhere. Visibility::Public => true, - Visibility::Restricted(id) => tcx.is_descendant_of(module, id), + Visibility::Restricted(id) => tcx.is_descendant_of(def_id, id.into()), } } pub fn partial_cmp( self, - vis: Visibility>, + vis: Visibility>, tcx: TyCtxt<'_>, ) -> Option { match (self, vis) { @@ -449,18 +449,18 @@ impl> Visibility { (Visibility::Restricted(_), Visibility::Public) => Some(Ordering::Less), (Visibility::Restricted(lhs_id), Visibility::Restricted(rhs_id)) => { let (lhs_id, rhs_id) = (lhs_id.into(), rhs_id.into()); - tcx.def_id_partial_cmp(lhs_id, rhs_id) + tcx.def_id_partial_cmp(lhs_id.to_def_id(), rhs_id.to_def_id()) } } } } -impl + Debug + Copy> Visibility { +impl + Debug + Copy> Visibility { /// Returns `true` if this visibility is strictly larger than the given visibility. #[track_caller] pub fn greater_than( self, - vis: Visibility + Debug + Copy>, + vis: Visibility + Debug + Copy>, tcx: TyCtxt<'_>, ) -> bool { match self.partial_cmp(vis, tcx) { @@ -2183,13 +2183,13 @@ impl<'tcx> TyCtxt<'tcx> { self, mut ident: Ident, scope: DefId, - item_id: LocalDefId, + mod_id: LocalModId, ) -> (Ident, ModId) { let scope = ident .span .normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope)) .and_then(|actual_expansion| actual_expansion.expn_data().parent_module) - .unwrap_or_else(|| self.parent_module_from_def_id(item_id).to_mod_id()); + .unwrap_or(mod_id.to_mod_id()); (ident, scope) } diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 5b25bdc01117b..e8ff3c3a08b79 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -2,7 +2,7 @@ use rustc_hir::HirId; use rustc_lint_defs::builtin::CONST_ITEM_MUTATION; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::Span; use rustc_span::def_id::DefId; @@ -35,8 +35,9 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { fn is_const_item_without_destructor(&self, local: Local) -> Option { let def_id = self.is_const_item(local)?; - // We avoid linting mutation of a const item if the const's type has a - // Drop impl. The Drop logic observes the mutation which was performed. + // We avoid linting mutation of a const item if the const's type needs + // drop. Any drop logic (including that of fields) may observe the + // mutation which was performed. // // pub struct Log { msg: &'static str } // pub const LOG: Log = Log { msg: "" }; @@ -46,21 +47,30 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { // // LOG.msg = "wow"; // prints "wow" // + // Likewise, if a field of the const type has its own Drop impl, that + // drop logic may also observe the mutation: + // + // struct Inner { val: u32 } + // impl Drop for Inner { fn drop(&mut self) { println!("{}", self.val); } } + // struct Outer { inner: Inner } + // const O: Outer = Outer { inner: Inner { val: 0 } }; + // + // O.inner.val = 42; // Inner::drop prints "42" + // // FIXME(https://github.com/rust-lang/rust/issues/77425): // Drop this exception once there is a stable attribute to suppress the - // const item mutation lint for a single specific const only. Something - // equivalent to: - // - // #[const_mutation_allowed] - // pub const LOG: Log = Log { msg: "" }; - // FIXME: this should not be checking for `Drop` impls, - // but whether it or any field has a Drop impl (`needs_drop`) - // as fields' Drop impls may make this observable, too. - match self.tcx.type_of(def_id).skip_binder().ty_adt_def().map(|adt| adt.has_dtor(self.tcx)) - { - Some(true) => None, - Some(false) | None => Some(def_id), + // const item mutation lint for a single specific const only. + let ty = self.tcx.type_of(def_id).instantiate_identity().skip_norm_wip(); + // `needs_drop` is overly conservative for types that contain type + // parameters (e.g. `Self` in a trait associated const): it always + // returns `true` because the parameter *might* implement Drop, even + // when the concrete type at the call site does not. In that case we + // cannot suppress the lint, so fall through and warn. + if ty.has_param() { + return Some(def_id); } + let typing_env = ty::TypingEnv::non_body_analysis(self.tcx, def_id); + if ty.needs_drop(self.tcx, typing_env) { None } else { Some(def_id) } } /// If we should lint on this usage, return the [`HirId`], source [`Span`] 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 294c887b5062c..79db6ba43e228 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1096,7 +1096,8 @@ where .auto_traits() .into_iter() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { - elaborate::supertrait_def_ids(self.cx(), principal_def_id) + self.cx() + .supertrait_def_ids(principal_def_id) .filter(|def_id| self.cx().trait_is_auto(*def_id)) })) .collect(); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 58e98a64b5e41..6bc42a0a40734 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -210,9 +210,7 @@ impl<'a> Parser<'a> { let (rhs, span) = finish_parsing_bin_op(self)?; self.mk_expr(span, ExprKind::Assign(lhs, rhs, op.span)) } - AssocOp::Cast => { - self.parse_assoc_op_cast(lhs, lhs_span, op.span, ExprKind::Cast)? - } + AssocOp::Cast => self.parse_assoc_op_cast(lhs, lhs_span, op.span)?, AssocOp::Range(limits) => self.parse_expr_range(min_prec, lhs, limits, op.span)?, }; @@ -555,17 +553,17 @@ impl<'a> Parser<'a> { lhs: Box, lhs_span: Span, op_span: Span, - expr_kind: fn(Box, Box) -> ExprKind, ) -> PResult<'a, Box> { - let mk_expr = |this: &mut Self, lhs: Box, rhs: Box| { - this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs)) + let mk_expr = |this: &mut Self, rhs: Box| { + let span = this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span); + this.mk_expr(span, ExprKind::Cast(lhs, rhs)) }; // Save the state of the parser before parsing type normally, in case there is a // LessThan comparison after this cast. let parser_snapshot_before_type = self.clone(); let cast_expr = match self.parse_as_cast_ty() { - Ok(rhs) => mk_expr(self, lhs, rhs), + Ok(rhs) => mk_expr(self, rhs), Err(type_err) => { if !self.may_recover() { return Err(type_err); @@ -576,46 +574,11 @@ impl<'a> Parser<'a> { // `usize < y` as a type with generic arguments. let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type); - // Check for typo of `'a: loop { break 'a }` with a missing `'`. - match (&lhs.kind, &self.token.kind) { - ( - // `foo: ` - ExprKind::Path(None, ast::Path { segments, .. }), - token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No), - ) if let [segment] = segments.as_slice() => { - let snapshot = self.create_snapshot_for_diagnostic(); - let label = Label { - ident: Ident::from_str_and_span( - &format!("'{}", segment.ident), - segment.ident.span, - ), - }; - match self.parse_expr_labeled(label, false) { - Ok(expr) => { - type_err.cancel(); - self.dcx().emit_err(crate::diagnostics::MalformedLoopLabel { - span: label.ident.span, - suggestion: label.ident.span.shrink_to_lo(), - }); - return Ok(expr); - } - Err(err) => { - err.cancel(); - self.restore_snapshot(snapshot); - } - } - } - _ => {} - } - match self.parse_path(PathStyle::Expr) { Ok(path) => { let span_after_type = parser_snapshot_after_type.token.span; - let expr = mk_expr( - self, - lhs, - self.mk_ty(path.span, TyKind::Path(None, path.clone())), - ); + let expr = + mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path.clone()))); let args_span = self.look_ahead(1, |t| t.span).to(span_after_type); match self.token.kind { @@ -674,48 +637,38 @@ impl<'a> Parser<'a> { // written `((&x) as T)[0]`. let span = cast_expr.span; - let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?; // Check if an illegal postfix operator has been added after the cast. // If the resulting expression is not a cast, it is an illegal postfix operator. if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) { - let msg = format!( - "cast cannot be followed by {}", - match with_postfix.kind { - ExprKind::Index(..) => "indexing", - ExprKind::Try(_) => "`?`", - ExprKind::Field(_, _) => "a field access", - ExprKind::MethodCall(_) => "a method call", - ExprKind::Call(_, _) => "a function call", - ExprKind::Await(_, _) => "`.await`", - ExprKind::Use(_, _) => "`.use`", - ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`", - ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match", - ExprKind::Err(_) => return Ok(with_postfix), - _ => unreachable!( - "did not expect {:?} as an illegal postfix operator following cast", - with_postfix.kind - ), - } - ); - let mut err = self.dcx().struct_span_err(span, msg); - - let suggest_parens = |err: &mut Diag<'_>| { - let suggestions = vec![ - (span.shrink_to_lo(), "(".to_string()), - (span.shrink_to_hi(), ")".to_string()), - ]; - err.multipart_suggestion( + let kind = match with_postfix.kind { + ExprKind::Index(..) => "indexing", + ExprKind::Try(_) => "`?`", + ExprKind::Field(_, _) => "a field access", + ExprKind::MethodCall(_) => "a method call", + ExprKind::Call(_, _) => "a function call", + ExprKind::Await(_, _) => "`.await`", + ExprKind::Use(_, _) => "`.use`", + ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`", + ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match", + ExprKind::Err(_) => return Ok(with_postfix), + _ => unreachable!( + "did not expect {:?} as an illegal postfix operator following cast", + with_postfix.kind + ), + }; + self.dcx() + .struct_span_err(span, format!("cast cannot be followed by {kind}")) + .with_multipart_suggestion( "try surrounding the expression in parentheses", - suggestions, + vec![ + (span.shrink_to_lo(), "(".to_string()), + (span.shrink_to_hi(), ")".to_string()), + ], Applicability::MachineApplicable, - ); - }; - - suggest_parens(&mut err); - - err.emit(); + ) + .emit(); }; Ok(with_postfix) } @@ -1401,6 +1354,9 @@ impl<'a> Parser<'a> { if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? { return Ok(expr); } + if let Some(arr) = this.recover_from_c_array(lo) { + return Ok(arr); + } this.parse_expr_block(None, lo, BlockCheckMode::Default) } else if this.check(exp!(Or)) || this.check(exp!(OrOr)) { this.parse_expr_closure().map_err(|mut err| { @@ -2227,39 +2183,6 @@ impl<'a> Parser<'a> { } } - fn is_array_like_block(&mut self) -> bool { - self.token.kind == TokenKind::OpenBrace - && self - .look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_))) - && self.look_ahead(2, |t| t == &token::Comma) - && self.look_ahead(3, |t| t.can_begin_expr()) - } - - /// Emits a suggestion if it looks like the user meant an array but - /// accidentally used braces, causing the code to be interpreted as a block - /// expression. - fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option> { - let mut snapshot = self.create_snapshot_for_diagnostic(); - match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) { - Ok(arr) => { - let guar = self.dcx().emit_err(crate::diagnostics::ArrayBracketsInsteadOfBraces { - span: arr.span, - sub: crate::diagnostics::ArrayBracketsInsteadOfBracesSugg { - left: lo, - right: snapshot.prev_token.span, - }, - }); - - self.restore_snapshot(snapshot); - Some(self.mk_expr_err(arr.span, guar)) - } - Err(e) => { - e.cancel(); - None - } - } - } - fn suggest_missing_semicolon_before_array( &self, prev_span: Span, @@ -2309,12 +2232,6 @@ impl<'a> Parser<'a> { lo: Span, blk_mode: BlockCheckMode, ) -> PResult<'a, Box> { - if self.may_recover() && self.is_array_like_block() { - if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) { - return Ok(arr); - } - } - if self.token.is_metavar_block() { self.dcx().emit_err(crate::diagnostics::InvalidBlockMacroSegment { span: self.token.span, diff --git a/compiler/rustc_parse/src/parser/expr/diagnostics.rs b/compiler/rustc_parse/src/parser/expr/diagnostics.rs index 707ae5d34bc75..6e56ea6c616fd 100644 --- a/compiler/rustc_parse/src/parser/expr/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/expr/diagnostics.rs @@ -3,8 +3,8 @@ use rustc_ast::{BinOpKind, Expr, ExprKind, token}; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{Span, Spanned, respan, sym}; -use crate::diagnostics; use crate::parser::Parser; +use crate::{diagnostics, exp}; impl<'a> Parser<'a> { /// Recover from alphabetic logic operators `and` and `or` as found in e.g., Python and PHP. @@ -216,6 +216,38 @@ impl<'a> Parser<'a> { } err } + + /// Recover from array expressions as found in C like `{0, 1, 2, 3}`. + pub(super) fn recover_from_c_array(&mut self, lo: Span) -> Option> { + if !self.may_recover() + || self.token.kind != token::OpenBrace + || self.look_ahead(1, |t| !matches!(t.kind, token::Literal(_))) + || self.look_ahead(2, |t| t != &token::Comma) + || self.look_ahead(3, |t| !t.can_begin_expr()) + { + return None; + } + + let mut snapshot = self.create_snapshot_for_diagnostic(); + match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) { + Ok(arr) => { + let guar = self.dcx().emit_err(diagnostics::ArrayBracketsInsteadOfBraces { + span: arr.span, + sub: diagnostics::ArrayBracketsInsteadOfBracesSugg { + left: lo, + right: snapshot.prev_token.span, + }, + }); + + self.restore_snapshot(snapshot); + Some(self.mk_expr_err(arr.span, guar)) + } + Err(e) => { + e.cancel(); + None + } + } + } } #[derive(Copy, Clone)] diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ff057e61f7a04..4fd3649a6dc3c 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -5,6 +5,7 @@ use std::ops::Bound; use ast::Label; use rustc_ast as ast; use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; +use rustc_ast::tokenstream::TokenTree; use rustc_ast::util::classify::{self, TrailingBrace}; use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{ @@ -12,7 +13,7 @@ use rustc_ast::{ LocalKind, MacCall, MacCallStmt, MacStmtStyle, Recovered, Stmt, StmtKind, }; use rustc_errors::{Applicability, Diag, PResult}; -use rustc_span::{BytePos, ErrorGuaranteed, Ident, Span, kw, sym}; +use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use super::attr::InnerAttrForbiddenReason; @@ -363,6 +364,14 @@ impl<'a> Parser<'a> { } else { (None, None, None) }; + + let init_wrapped = self + .tree_look_ahead(2, |tree| match tree { + TokenTree::Token(tok, _) => tok.is_keyword(kw::Else), + TokenTree::Delimited(..) => false, + }) + .unwrap_or(false); + let init = match (self.parse_initializer(err.is_some()), err) { (Ok(init), None) => { // init parsed, ty parsed @@ -400,6 +409,7 @@ impl<'a> Parser<'a> { return Err(err); } }; + let trailing_token = self.prev_token; let kind = match init { None => LocalKind::Decl, Some(init) => { @@ -411,8 +421,14 @@ impl<'a> Parser<'a> { return Err(self.error_block_no_opening_brace_msg(Cow::from(msg))); } let els = self.parse_block()?; - self.check_let_else_init_bool_expr(&init); - self.check_let_else_init_trailing_brace(&init); + // These checks should also respect invisible delimiter + if !init_wrapped { + self.check_let_else_init_bool_expr(&init); + } + if matches!(trailing_token.kind, TokenKind::CloseBrace) { + self.check_let_else_init_trailing_brace(&init); + } + LocalKind::InitElse(init, els) } else { LocalKind::Init(init) @@ -467,7 +483,7 @@ impl<'a> Parser<'a> { ), }; self.dcx().emit_err(diagnostics::InvalidCurlyInLetElse { - span: span.with_lo(span.hi() - BytePos(1)), + span: self.psess.source_map().end_point(span), sugg, }); } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 88c07c6e2778c..42fb9121076f4 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -3,8 +3,8 @@ use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnPtrTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, - Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, - TyKind, UnsafeBinderTy, + Path, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, + Ty, TyKind, UnsafeBinderTy, }; use rustc_errors::{Applicability, Diag, E0516, PResult}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; @@ -406,7 +406,23 @@ impl<'a> Parser<'a> { let msg = format!("expected type, found {}", super::token_descr(&self.token)); let mut err = self.dcx().struct_span_err(lo, msg); err.span_label(lo, "expected type"); - return Err(err); + if self.may_recover() + && (self.eat_keyword_noexpect(kw::True) || self.eat_keyword_noexpect(kw::False)) + { + err.span_suggestion( + self.prev_token.span, + "the type is called", + "bool", + Applicability::MachineApplicable, + ); + err.emit(); + TyKind::Path( + None, + Path::from_ident(Ident { span: self.prev_token.span, name: sym::bool }), + ) + } else { + return Err(err); + } }; let span = lo.to(self.prev_token.span); diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index f2a7cb6e46fca..961e6e63a81da 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -9,7 +9,7 @@ use rustc_data_structures::thousands::usize_with_underscores; use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; -use rustc_span::def_id::LocalDefId; +use rustc_span::def_id::{LocalDefId, LocalModId}; struct NodeStats { count: usize, @@ -277,7 +277,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_body(self, b); } - fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, _n: HirId) { + fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, _id: LocalModId) { self.record("Mod", None, m); hir_visit::walk_mod(self, m) } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 8430b78d75f1b..97475c8fdccf0 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -922,6 +922,7 @@ impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> { /// This pass performs remaining checks for fields in struct expressions and patterns. struct NamePrivacyVisitor<'tcx> { tcx: TyCtxt<'tcx>, + mod_id: LocalModId, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, } @@ -938,7 +939,6 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { // Checks that a field in a struct constructor (expression or pattern) is accessible. fn check_field( &self, - hir_id: hir::HirId, // ID of the field use use_ctxt: Span, // syntax context of the field name at the use site def: ty::AdtDef<'tcx>, // definition of the struct or enum field: &'tcx ty::FieldDef, @@ -949,8 +949,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { // definition of the field let ident = Ident::new(sym::dummy, use_ctxt); - let (_, def_id) = - self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id.owner.def_id); + let (_, def_id) = self.tcx.adjust_ident_and_get_scope(ident, def.did(), self.mod_id); !field.vis.is_accessible_from(def_id, self.tcx) } @@ -1023,7 +1022,6 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { adt: ty::AdtDef<'tcx>, variant: &'tcx ty::VariantDef, fields: &[hir::ExprField<'tcx>], - hir_id: hir::HirId, span: Span, struct_span: Span, ) { @@ -1031,11 +1029,11 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { for (vf_index, variant_field) in variant.fields.iter_enumerated() { let field = fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index); - let (hir_id, use_ctxt, span) = match field { - Some(field) => (field.hir_id, field.ident.span, field.span), - None => (hir_id, span, span), + let (use_ctxt, span) = match field { + Some(field) => (field.ident.span, field.span), + None => (span, span), }; - if self.check_field(hir_id, use_ctxt, adt, variant_field) { + if self.check_field(use_ctxt, adt, variant_field) { let name = match field { Some(field) => field.ident.name, None => variant_field.name, @@ -1069,31 +1067,16 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { // If the expression uses FRU we need to make sure all the unmentioned fields // are checked for privacy (RFC 736). Rather than computing the set of // unmentioned fields, just check them all. - self.check_expanded_fields( - adt, - variant, - fields, - base.hir_id, - base.span, - qpath.span(), - ); + self.check_expanded_fields(adt, variant, fields, base.span, qpath.span()); } hir::StructTailExpr::DefaultFields(span) => { - self.check_expanded_fields( - adt, - variant, - fields, - expr.hir_id, - span, - qpath.span(), - ); + self.check_expanded_fields(adt, variant, fields, span, qpath.span()); } hir::StructTailExpr::None | hir::StructTailExpr::NoneWithError(_) => { let mut failed_fields = vec![]; for field in fields { - let (hir_id, use_ctxt) = (field.hir_id, field.ident.span); let index = self.typeck_results().field_index(field.hir_id); - if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) { + if self.check_field(field.ident.span, adt, &variant.fields[index]) { failed_fields.push((field.ident.name, field.ident.span, true)); } } @@ -1112,9 +1095,8 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { let variant = adt.variant_of_res(res); let mut failed_fields = vec![]; for field in fields { - let (hir_id, use_ctxt) = (field.hir_id, field.ident.span); let index = self.typeck_results().field_index(field.hir_id); - if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) { + if self.check_field(field.ident.span, adt, &variant.fields[index]) { failed_fields.push((field.ident.name, field.ident.span, true)); } } @@ -1753,7 +1735,7 @@ pub fn provide(providers: &mut Providers) { fn check_mod_privacy(tcx: TyCtxt<'_>, mod_id: LocalModId) { // Check privacy of names not checked in previous compilation stages. - let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None }; + let mut visitor = NamePrivacyVisitor { tcx, mod_id, maybe_typeck_results: None }; tcx.hir_visit_item_likes_in_module(mod_id, &mut visitor); // Check privacy of explicitly written types and traits as well as diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 87479a4fbedd0..e479ef6a621c9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2431,7 +2431,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.pat_span_map.insert(node, span); } - fn is_accessible_from(&self, vis: Visibility>, module: Module<'ra>) -> bool { + fn is_accessible_from(&self, vis: Visibility>, module: Module<'ra>) -> bool { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index b5235fa443575..4ccc7ab986f1e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -521,7 +521,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let found_sig = self.normalize_fn_sig(self.tcx.fn_sig(*did2).instantiate(self.tcx, args2)); - if self.same_type_modulo_infer(expected_sig, found_sig) { + let expected_sig_anon = self.tcx.anonymize_bound_vars(expected_sig); + let found_sig_anon = self.tcx.anonymize_bound_vars(found_sig); + if self.same_type_modulo_infer(expected_sig_anon, found_sig_anon) { diag.subdiagnostic(FnUniqTypes); } 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 8de0514b9ef27..fffe80be255ce 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -346,7 +346,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let (adjusted_ident, def_scope) = self.tcx.adjust_ident_and_get_scope( field_ident, base_def.did(), - typeck_results.hir_owner.def_id, + self.tcx.parent_module_from_def_id(typeck_results.hir_owner.def_id), ); let Some((_, field_def)) = diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 912a5ac90f632..2110521eae764 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -318,6 +318,9 @@ impl> Iterator for Elaborator { /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used /// to identify which traits may define a given associated type to help avoid cycle errors, /// and to make size estimates for vtable layout computation. +/// +/// rust-analyzer has a query for this, so don't use this function there. +#[cfg(feature = "nightly")] pub fn supertrait_def_ids( cx: I, trait_def_id: I::TraitId, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 289f5dc2e1b46..0a11a82c99e76 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -402,6 +402,9 @@ pub trait Interner: impl_def_id: Self::ImplId, ) -> ty::EarlyBinder>; + fn supertrait_def_ids(self, trait_def_id: Self::TraitId) + -> impl Iterator; + fn impl_is_const(self, def_id: Self::ImplId) -> bool; fn fn_is_const(self, def_id: Self::FunctionId) -> bool; fn closure_is_const(self, def_id: Self::ClosureId) -> bool; diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 5282b39782181..9d871d8c5745d 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -712,16 +712,18 @@ pub const fn needs_drop() -> bool { /// This means that, for example, the padding byte in `(u8, u16)` is not /// necessarily zeroed. /// -/// There is no guarantee that an all-zero byte-pattern represents a valid value -/// of some type `T`. For example, the all-zero byte-pattern is not a valid value -/// for reference types (`&T`, `&mut T`) and function pointers. Using `zeroed` -/// on such types causes immediate [undefined behavior][ub] because [the Rust -/// compiler assumes][inv] that there always is a valid value in a variable it -/// considers initialized. -/// /// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. /// It is useful for FFI sometimes, but should generally be avoided. /// +/// +/// # Safety +/// +/// The all-zero byte-pattern must represent a valid value of type `T`. +/// For example, it is not valid for reference types (`&T`, `&mut T`) or function +/// pointers. Using `zeroed` on such types causes immediate [undefined behavior][ub] +/// because [the Rust compiler assumes][inv] that there always is a valid value in a +/// variable it considers initialized. +/// /// [zeroed]: MaybeUninit::zeroed /// [ub]: ../../reference/behavior-considered-undefined.html /// [inv]: MaybeUninit#initialization-invariant diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 0563c225f7e0b..d0ae6c31267f3 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1412,7 +1412,8 @@ macro_rules! nonzero_integer { } #[stable(feature = "nonzero_parse", since = "1.35.0")] - impl FromStr for NonZero<$Int> { + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + const impl FromStr for NonZero<$Int> { type Err = ParseIntError; /// Parses a non-zero integer from a string slice with decimal digits. diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 8df809264a6dd..65b8ed634bc05 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1869,6 +1869,28 @@ impl Dir { pub fn remove_dir>(&self, path: P) -> io::Result<()> { self.inner.remove_dir(path.as_ref()) } + + /// Creates a new `Dir` instance that shares the same underlying directory handle + /// as the existing `Dir` instance. + /// + /// # Examples + /// + /// Creates two handles for a directory named `foo`: + /// + /// ```no_run + /// #![feature(dirfd)] + /// use std::fs::Dir; + /// + /// fn main() -> std::io::Result<()> { + /// let dir = Dir::open("foo")?; + /// let dir_copy = dir.try_clone()?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "dirfd", issue = "120426")] + pub fn try_clone(&self) -> io::Result { + Ok(Dir { inner: self.inner.duplicate()? }) + } } impl AsInner for Dir { diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 148f1c32b08b9..e79b5cf17bc2b 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -775,6 +775,273 @@ fn file_test_io_seek_read_write() { check!(fs::remove_file(&filename)); } +#[test] +#[cfg(windows)] +fn file_test_io_seek_read_exact_write_all() { + use crate::os::windows::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_seek_read_exact_write_all.txt"); + let mut buf = [0; 256]; + let write1 = "asdf"; + let write2 = "qwer-"; + let write3 = "-zxcv"; + let content = "qwer-asdf-zxcv"; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + check!(rw.seek_write_all(write1.as_bytes(), 5)); + assert_eq!(check!(rw.stream_position()), 9); + check!(rw.seek_read_exact(&mut buf[..write1.len()], 5)); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.stream_position()), 9); + assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0); + assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); + assert_eq!(check!(rw.stream_position()), 5); + assert_eq!(check!(rw.read(&mut buf)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.stream_position()), 9); + check!(rw.seek_read_exact(&mut buf[..write2.len()], 0)); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); + assert_eq!(check!(rw.stream_position()), 5); + check!(rw.seek_write_all(write3.as_bytes(), 9)); + assert_eq!(check!(rw.stream_position()), 14); + } + { + let mut read = check!(File::open(&filename)); + check!(read.seek_read_exact(&mut buf[..content.len()], 0)); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.stream_position()), 14); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + check!(read.seek_read_exact(&mut buf[..content.len()], 0)); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.stream_position()), 14); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.read(&mut buf)), write3.len()); + assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); + assert_eq!(check!(read.stream_position()), 14); + check!(read.seek_read_exact(&mut buf[..content.len()], 0)); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.stream_position()), 14); + assert!(read.seek_read_exact(&mut buf, 14).is_err()); + assert!(read.seek_read_exact(&mut buf, 15).is_err()); + } + check!(fs::remove_file(&filename)); +} + +#[test] +#[cfg(windows)] +fn file_test_windows_fileext_trait_case_1() { + use crate::os::windows::fs::FileExt; + + // Test when seek_read_exact(), seek_write_all() are called with empty buffers. + struct MockFile {} + + impl FileExt for MockFile { + fn seek_read(&self, _buf: &mut [u8], _offset: u64) -> io::Result { + panic!("should not be called"); + } + + fn seek_write(&self, _buf: &[u8], _offset: u64) -> io::Result { + panic!("should not be called"); + } + } + + let mock_file = MockFile {}; + check!(mock_file.seek_read_exact(&mut [], 0)); + check!(mock_file.seek_write_all(&[], 0)); + check!(mock_file.seek_read_exact(&mut [], 420)); + check!(mock_file.seek_write_all(&[], 420)); +} + +#[test] +#[cfg(windows)] +fn file_test_windows_fileext_trait_case_2() { + use crate::os::windows::fs::FileExt; + + // Test when seek_read(), seek_write() return Ok(0) + struct MockFile { + expected_offset: u64, + } + + impl FileExt for MockFile { + fn seek_read(&self, _buf: &mut [u8], offset: u64) -> io::Result { + assert_eq!(offset, self.expected_offset); + Ok(0) + } + + fn seek_write(&self, _buf: &[u8], offset: u64) -> io::Result { + assert_eq!(offset, self.expected_offset); + Ok(0) + } + } + + { + let mock_file = MockFile { expected_offset: 0 }; + let mut buf = [0; 256]; + assert_eq!( + mock_file.seek_read_exact(&mut buf, 0).unwrap_err().kind(), + io::ErrorKind::UnexpectedEof + ); + assert_eq!(mock_file.seek_write_all(&buf, 0).unwrap_err().kind(), io::ErrorKind::WriteZero); + } + + { + let mock_file = MockFile { expected_offset: 420 }; + let mut buf = [0; 256]; + assert_eq!( + mock_file.seek_read_exact(&mut buf, 420).unwrap_err().kind(), + io::ErrorKind::UnexpectedEof + ); + assert_eq!( + mock_file.seek_write_all(&buf, 420).unwrap_err().kind(), + io::ErrorKind::WriteZero + ); + } +} + +#[test] +#[cfg(windows)] +fn file_test_windows_fileext_trait_case_3() { + use crate::os::windows::fs::FileExt; + + // Test that Err other than io::ErrorKind::Interrupted are propagated up. + struct MockFile { + expected_offset: u64, + } + + impl FileExt for MockFile { + fn seek_read(&self, _buf: &mut [u8], offset: u64) -> io::Result { + assert_eq!(offset, self.expected_offset); + Err(io::Error::new(io::ErrorKind::PermissionDenied, "seek_read")) + } + + fn seek_write(&self, _buf: &[u8], offset: u64) -> io::Result { + assert_eq!(offset, self.expected_offset); + Err(io::Error::new(io::ErrorKind::ConnectionRefused, "seek_write")) + } + } + + { + let mock_file = MockFile { expected_offset: 0 }; + let mut buf = [0; 256]; + assert_eq!( + mock_file.seek_read_exact(&mut buf, 0).unwrap_err().kind(), + io::ErrorKind::PermissionDenied + ); + assert_eq!( + mock_file.seek_write_all(&buf, 0).unwrap_err().kind(), + io::ErrorKind::ConnectionRefused + ); + } + + { + let mock_file = MockFile { expected_offset: 420 }; + let mut buf = [0; 256]; + assert_eq!( + mock_file.seek_read_exact(&mut buf, 420).unwrap_err().kind(), + io::ErrorKind::PermissionDenied + ); + assert_eq!( + mock_file.seek_write_all(&buf, 420).unwrap_err().kind(), + io::ErrorKind::ConnectionRefused + ); + } + // FIXME: Cover io::ErrorKind::Interrupted, but don't infinite loop ;) +} + +#[test] +#[cfg(windows)] +fn file_test_windows_fileext_trait_case_4() { + use crate::os::windows::fs::FileExt; + + const MSG: &[u8] = + b"The Rust programming language helps you write faster, more reliable software."; + + // Test when the entire read or write is satisfied by only one call to seek_read() or + // seek_write(), respectively. + struct MockFile { + expected_offset: u64, + } + + impl FileExt for MockFile { + fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result { + assert_eq!(offset, self.expected_offset); + assert_eq!(buf.len(), MSG.len()); + assert_eq!(buf, &[0; MSG.len()]); + buf.copy_from_slice(MSG); + Ok(MSG.len()) + } + + fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result { + assert_eq!(offset, self.expected_offset); + assert_eq!(buf.len(), MSG.len()); + assert_eq!(buf, MSG); + Ok(MSG.len()) + } + } + + { + let mock_file = MockFile { expected_offset: 0 }; + let mut buf = [0; MSG.len()]; + check!(mock_file.seek_read_exact(&mut buf, 0)); + assert_eq!(&buf, MSG); + check!(mock_file.seek_write_all(&buf, 0)); + } + + { + let mock_file = MockFile { expected_offset: 420 }; + let mut buf = [0; MSG.len()]; + check!(mock_file.seek_read_exact(&mut buf, 420)); + assert_eq!(&buf, MSG); + check!(mock_file.seek_write_all(&buf, 420)); + } +} + +#[test] +#[cfg(windows)] +fn file_test_windows_fileext_trait_case_5() { + use crate::os::windows::fs::FileExt; + + const MSG: &[u8] = + b"Rust is for students and those who are interested in learning about systems concepts."; + + // Test pathological case where seek_read(), seek_write() only do 1 byte per call, return Ok(1) + struct MockFile { + base_offset: u64, + } + + impl FileExt for MockFile { + fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result { + let offset = (offset - self.base_offset) as usize; + buf[0..1].copy_from_slice(&MSG[offset..offset + 1]); + Ok(1) + } + + fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result { + let offset = (offset - self.base_offset) as usize; + assert_eq!(buf[0..1], MSG[offset..offset + 1]); + Ok(1) + } + } + + { + let mock_file = MockFile { base_offset: 0 }; + let mut buf = [0; MSG.len()]; + check!(mock_file.seek_read_exact(&mut buf, 0)); + assert_eq!(&buf, MSG); + check!(mock_file.seek_write_all(&buf, 0)); + } + + { + let mock_file = MockFile { base_offset: 420 }; + let mut buf = [0; MSG.len()]; + check!(mock_file.seek_read_exact(&mut buf, 420)); + assert_eq!(&buf, MSG); + check!(mock_file.seek_write_all(&buf, 420)); + } +} + #[test] #[cfg(windows)] fn test_seek_read_buf() { @@ -2726,6 +2993,19 @@ fn test_dir_read_file() { assert_eq!("bar", &buf); } +#[test] +fn test_dir_clone() { + let tmpdir = tmpdir(); + let mut f = check!(File::create(tmpdir.join("foo.txt"))); + check!(f.write_all(b"bar")); + drop(f); + + let dir = check!(Dir::open(tmpdir.path())); + let dir2 = check!(dir.try_clone()); + let f = check!(dir2.open_file("foo.txt")); + drop(f); +} + #[test] fn test_dir_metadata() { let tmpdir = tmpdir(); diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index 21560638c1d0f..3e6a934f318b2 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -50,6 +50,69 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result; + /// Seeks to a given position and reads the exact number of bytes required to fill `buf`. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. The current cursor **is** affected by this + /// function, it is set to the end of the read. + /// + /// Similar to [`io::Read::read_exact`] but uses [`seek_read`] instead of `read`. + /// + /// [`seek_read`]: FileExt::seek_read + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation + /// will continue. + /// + /// If this function encounters an "end of file" before completely filling + /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`]. + /// The contents of `buf` are unspecified in this case. + /// + /// If any other read error is encountered then this function immediately + /// returns. The contents of `buf` are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + /// + /// # Examples + /// + #[cfg_attr(windows, doc = "```no_run")] + #[cfg_attr(not(windows), doc = "```ignore (needs windows)")] + /// #![feature(seek_read_exact_seek_write_all)] + /// + /// use std::io; + /// use std::fs::File; + /// use std::os::windows::prelude::*; + /// + /// fn main() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; + /// + /// // Read 10 bytes, starting 72 bytes from the + /// // start of the file. + /// file.seek_read_exact(&mut buffer[..], 72)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "seek_read_exact_seek_write_all", issue = "162868")] + fn seek_read_exact(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.seek_read(buf, offset) { + Ok(0) => break, + Ok(n) => { + buf = &mut buf[n..]; + offset += n as u64; + } + Err(ref e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) } + } + /// Seeks to a given position and reads some bytes into the buffer. /// /// This is equivalent to the [`seek_read`](FileExt::seek_read) method, except that it is passed @@ -122,6 +185,62 @@ pub trait FileExt { /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result; + + /// Seeks to a given position and attempts to write an entire buffer. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. The current cursor **is** affected by this + /// function, it is set to the end of the write. + /// + /// This method will continuously call [`seek_write`] until there is no more data + /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be + /// returned. + /// + /// # Errors + /// + /// This function will return the first error of + /// non-[`io::ErrorKind::Interrupted`] kind that [`seek_write`] returns. + /// + /// [`seek_write`]: FileExt::seek_write + /// + /// # Examples + /// + #[cfg_attr(windows, doc = "```no_run")] + #[cfg_attr(not(windows), doc = "```ignore (needs windows)")] + /// #![feature(seek_read_exact_seek_write_all)] + /// + /// use std::fs::File; + /// use std::os::windows::prelude::*; + /// + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// // Write a byte string starting 72 bytes from + /// // the start of the file. + /// buffer.seek_write_all(b"some bytes", 72)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "seek_read_exact_seek_write_all", issue = "162868")] + fn seek_write_all(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.seek_write(buf, offset) { + Ok(0) => { + return Err(io::Error::WRITE_ALL_EOF); + } + Ok(n) => { + buf = &buf[n..]; + offset += n as u64 + } + Err(ref e) if e.is_interrupted() => {} + Err(e) => return Err(e), + } + } + Ok(()) + } } #[stable(feature = "file_offset", since = "1.15.0")] diff --git a/library/std/src/sys/fs/common.rs b/library/std/src/sys/fs/common.rs index 17b98a4506544..96bafb26bb969 100644 --- a/library/std/src/sys/fs/common.rs +++ b/library/std/src/sys/fs/common.rs @@ -77,6 +77,10 @@ impl Dir { Self::open(path, &opts) } + pub fn duplicate(&self) -> io::Result { + Ok(Self { path: self.path.clone() }) + } + pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { File::open(&self.path.join(path), opts) } diff --git a/library/std/src/sys/fs/unix/dir.rs b/library/std/src/sys/fs/unix/dir.rs index 3fe952d942927..cf0dece265054 100644 --- a/library/std/src/sys/fs/unix/dir.rs +++ b/library/std/src/sys/fs/unix/dir.rs @@ -47,6 +47,10 @@ impl Dir { run_path_with_cstr(path, &|path| Self::open_traversal_c(path)) } + pub fn duplicate(&self) -> io::Result { + Ok(Self(self.0.try_clone()?)) + } + pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { run_path_with_cstr(path.as_ref(), &|path| self.open_file_c(path, opts, 0)) .map(FileDesc::from_inner) diff --git a/library/std/src/sys/fs/windows/dir.rs b/library/std/src/sys/fs/windows/dir.rs index 70bade84f58fd..d4674ad24f87e 100644 --- a/library/std/src/sys/fs/windows/dir.rs +++ b/library/std/src/sys/fs/windows/dir.rs @@ -72,6 +72,10 @@ impl Dir { with_native_path(path, &|path| Self::open_with_native(path, &opts)) } + pub fn duplicate(&self) -> io::Result { + Ok(Self { handle: self.handle.try_clone()? }) + } + pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { // NtCreateFile will fail if given an absolute path and a non-null RootDirectory if path.is_absolute() { diff --git a/src/librustdoc/html/span_map.rs b/src/librustdoc/html/span_map.rs index 424b3c94fcbb1..c1e6e23f41c38 100644 --- a/src/librustdoc/html/span_map.rs +++ b/src/librustdoc/html/span_map.rs @@ -8,6 +8,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::LocalModId; use rustc_span::{BytePos, ExpnKind}; use crate::clean::{self, PrimitiveType, rustc_span}; @@ -309,13 +310,13 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { } } - fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: rustc_span::Span, id: HirId) { + fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: rustc_span::Span, id: LocalModId) { // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another // file, we want to link to it. Otherwise no need to create a link. if !span.overlaps(m.spans.inner_span) { // Now that we confirmed it's a file import, we want to get the span for the module // name only and not all the "mod foo;". - if let Node::Item(item) = self.tcx.hir_node(id) { + if let Node::Item(item) = self.tcx.hir_node_by_def_id(id.into()) { let (ident, _) = item.expect_mod(); self.matches.insert( ident.span.into(), @@ -324,7 +325,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { } } else { // If it's a "mod foo {}", we want to look to its documentation page. - self.extract_info_from_hir_id(id); + self.extract_info_from_hir_id(id.into()); } intravisit::walk_mod(self, m); } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ae5a76545eefb..ee30c6d153c0b 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -14,7 +14,7 @@ use rustc_hir::{Node, find_attr}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::Span; -use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalModId}; use rustc_span::symbol::{Symbol, kw}; use tracing::debug; @@ -642,7 +642,7 @@ impl<'tcx> Visitor<'tcx> for RustdocVisitor<'_, 'tcx> { self.is_importable_from_parent = prev; } - fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) { + fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: LocalModId) { // Handled in `visit_item_inner` } diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index 8984184269421..5da0323167fe6 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -8,12 +8,13 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::is_cfg_test; use rustc_attr_ir::AttributeKind; use rustc_hir::{ - Attribute, FieldDef, HirId, ImplItemId, IsAuto, Item, ItemKind, Mod, OwnerId, QPath, TraitItemId, TyKind, Variant, + Attribute, FieldDef, ImplItemId, IsAuto, Item, ItemKind, Mod, OwnerId, QPath, TraitItemId, TyKind, Variant, VariantData, }; use rustc_lint::{LateContext, LateLintPass, LintContext, impl_lint_pass}; use rustc_middle::ty::{AssocKind, TyCtxt}; use rustc_span::{Ident, Symbol, bug}; +use rustc_span::def_id::LocalModId; declare_clippy_lint! { /// ### What it does @@ -486,7 +487,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { } } - fn check_mod(&mut self, cx: &LateContext<'tcx>, module: &'tcx Mod<'tcx>, _: HirId) { + fn check_mod(&mut self, cx: &LateContext<'tcx>, module: &'tcx Mod<'tcx>, _: LocalModId) { struct CurItem<'a> { item: &'a Item<'a>, order: usize, diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs index dac7a24bf2a8d..b09c77b849f5f 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs @@ -2,9 +2,10 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::SpanExt as _; use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use rustc_errors::{Applicability, SuggestionStyle}; -use rustc_hir::{HirId, Item, ItemKind, Mod}; +use rustc_hir::{Item, ItemKind, Mod}; use rustc_lint::{LateContext, LateLintPass, declare_lint_pass}; use rustc_span::hygiene::AstPass; +use rustc_span::def_id::LocalModId; use rustc_span::{ExpnKind, sym}; declare_clippy_lint! { @@ -56,7 +57,7 @@ fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool { } impl LateLintPass<'_> for ItemsAfterTestModule { - fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) { + fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: LocalModId) { let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir_item(id)); let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else { diff --git a/src/tools/clippy/clippy_lints/src/redundant_test_prefix.rs b/src/tools/clippy/clippy_lints/src/redundant_test_prefix.rs index 6f7750939fd95..db3814748719c 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_test_prefix.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_test_prefix.rs @@ -131,7 +131,7 @@ fn name_conflicts<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, fn_name: S let id = body.id().hir_id; // Iterate over items in the same module/scope - let (module, _module_span, _module_hir) = tcx.hir_get_module(tcx.parent_module(id)); + let (module, _module_span) = tcx.hir_get_module(tcx.parent_module(id)); if module .item_ids .iter() diff --git a/tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr b/tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr index c9b49e9ed2b25..8cc48b64e79fe 100644 --- a/tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr +++ b/tests/ui/cast/dyn-any-to-fn-with-missing-generics.stderr @@ -2,11 +2,15 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/dyn-any-to-fn-with-missing-generics.rs:9:39 | LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); - | ^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL | println!("{:?}",(vfnfer[0] as dyn Fn() -> ())(3)); + | ++++++++ error[E0107]: missing generics for trait `Fn` --> $DIR/dyn-any-to-fn-with-missing-generics.rs:9:39 diff --git a/tests/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs b/tests/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs index 070ffaa1eff00..99d63929db484 100644 --- a/tests/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs +++ b/tests/ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs @@ -1,18 +1,42 @@ +// Test that we can recover from very basic C arrays in the parser & provide a good diagnostic. + fn main() {} -const FOO: [u8; 3] = { +const INTS: [u8; 3] = { //~^ ERROR this is a block expression, not an array 1, 2, 3 }; -const BAR: [&str; 3] = {"one", "two", "three"}; +const STRS: [&str; 3] = {"one", "two", "three"}; //~^ ERROR this is a block expression, not an array -fn foo() { +fn expr_stmt() { {1, 2, 3}; //~^ ERROR this is a block expression, not an array } -fn bar() { +// Don't trigger here. +fn unsafe_block() { + unsafe { 1, 2, 3 } //~ ERROR expected one of +} + +// Don't trigger here. +fn labeled_block() { + 'label: { 1, 2, 3 } //~ ERROR expected one of +} + +// Don't trigger here, this is not a block expression, only a block. +fn fn_body_block() { 1, 2, 3 //~ ERROR expected one of } + +// Don't trigger here, this is not a block expression, only a block. +fn closure_body_block() { + || -> i32 { 1, 2, 3 }; //~ ERROR expected one of +} + +// Don't trigger here. +fn const_arg() { + struct Casket; + Casket::<{ 1, 2, 3 }>; //~ ERROR expected one of +} diff --git a/tests/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr b/tests/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr index 58232e2307d8e..531d54a9e3f1e 100644 --- a/tests/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr +++ b/tests/ui/did_you_mean/issue-87830-try-brackets-for-arrays.stderr @@ -1,8 +1,8 @@ error: this is a block expression, not an array - --> $DIR/issue-87830-try-brackets-for-arrays.rs:3:22 + --> $DIR/issue-87830-try-brackets-for-arrays.rs:5:23 | -LL | const FOO: [u8; 3] = { - | ______________________^ +LL | const INTS: [u8; 3] = { + | _______________________^ LL | | LL | | 1, 2, 3 LL | | }; @@ -10,26 +10,26 @@ LL | | }; | help: to make an array, use square brackets instead of curly braces | -LL ~ const FOO: [u8; 3] = [ +LL ~ const INTS: [u8; 3] = [ LL | LL | 1, 2, 3 LL ~ ]; | error: this is a block expression, not an array - --> $DIR/issue-87830-try-brackets-for-arrays.rs:8:24 + --> $DIR/issue-87830-try-brackets-for-arrays.rs:10:25 | -LL | const BAR: [&str; 3] = {"one", "two", "three"}; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | const STRS: [&str; 3] = {"one", "two", "three"}; + | ^^^^^^^^^^^^^^^^^^^^^^^ | help: to make an array, use square brackets instead of curly braces | -LL - const BAR: [&str; 3] = {"one", "two", "three"}; -LL + const BAR: [&str; 3] = ["one", "two", "three"]; +LL - const STRS: [&str; 3] = {"one", "two", "three"}; +LL + const STRS: [&str; 3] = ["one", "two", "three"]; | error: this is a block expression, not an array - --> $DIR/issue-87830-try-brackets-for-arrays.rs:12:5 + --> $DIR/issue-87830-try-brackets-for-arrays.rs:14:5 | LL | {1, 2, 3}; | ^^^^^^^^^ @@ -41,10 +41,34 @@ LL + [1, 2, 3]; | error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` - --> $DIR/issue-87830-try-brackets-for-arrays.rs:17:6 + --> $DIR/issue-87830-try-brackets-for-arrays.rs:20:15 + | +LL | unsafe { 1, 2, 3 } + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/issue-87830-try-brackets-for-arrays.rs:25:16 + | +LL | 'label: { 1, 2, 3 } + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/issue-87830-try-brackets-for-arrays.rs:30:6 | LL | 1, 2, 3 | ^ expected one of `.`, `;`, `?`, `}`, or an operator -error: aborting due to 4 previous errors +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/issue-87830-try-brackets-for-arrays.rs:35:18 + | +LL | || -> i32 { 1, 2, 3 }; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/issue-87830-try-brackets-for-arrays.rs:41:17 + | +LL | Casket::<{ 1, 2, 3 }>; + | ^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: aborting due to 8 previous errors diff --git a/tests/ui/fn/fn-item-type-note-late-bound-145558.rs b/tests/ui/fn/fn-item-type-note-late-bound-145558.rs new file mode 100644 index 0000000000000..3e8fc0e8b14a7 --- /dev/null +++ b/tests/ui/fn/fn-item-type-note-late-bound-145558.rs @@ -0,0 +1,20 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/145558 +//! +//! The note explaining that distinct fn items have distinct types was suppressed when the +//! signatures contained a late-bound lifetime, because the two binders name their bound +//! region differently. + +//@ dont-require-annotations: NOTE + +struct A; + +fn f1<'a>(_: &'a A) {} +fn f2<'a>(_: &'a A) {} + +fn main() { + let mut map = vec![]; + map.push(f1); + map.push(f2); + //~^ ERROR mismatched types + //~| NOTE different fn items have unique types +} diff --git a/tests/ui/fn/fn-item-type-note-late-bound-145558.stderr b/tests/ui/fn/fn-item-type-note-late-bound-145558.stderr new file mode 100644 index 0000000000000..bf0a1c3316e57 --- /dev/null +++ b/tests/ui/fn/fn-item-type-note-late-bound-145558.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/fn-item-type-note-late-bound-145558.rs:17:14 + | +LL | map.push(f1); + | --- -- this argument has type `for<'a> fn(&'a A) {f1}`... + | | + | ... which causes `map` to have type `Vec fn(&'a A) {f1}>` +LL | map.push(f2); + | ---- ^^ expected fn item, found a different fn item + | | + | arguments to this method are incorrect + | + = note: expected fn item `for<'a> fn(&'a A) {f1}` + found fn item `for<'a> fn(&'a A) {f2}` + = note: different fn items have unique types, even if their signatures are the same +note: method defined here + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr index ffa58f4faeeee..6cec3ea88d515 100644 --- a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr +++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr @@ -37,22 +37,32 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/opaque-used-in-extraneous-argument.rs:5:19 | LL | fn frob() -> impl Fn + '_ {} - | ^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(P) -> T` + | ^^^^^^^^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL - fn frob() -> impl Fn + '_ {} +LL + fn frob() -> impl Fn(P) -> T + '_ {} + | error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/opaque-used-in-extraneous-argument.rs:5:19 | LL | fn frob() -> impl Fn + '_ {} - | ^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(P) -> T` + | ^^^^^^^^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use parenthetical notation instead + | +LL - fn frob() -> impl Fn + '_ {} +LL + fn frob() -> impl Fn(P) -> T + '_ {} + | error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/opaque-used-in-extraneous-argument.rs:17:20 diff --git a/tests/ui/let-else/detect-invisible-delimiter.rs b/tests/ui/let-else/detect-invisible-delimiter.rs new file mode 100644 index 0000000000000..76c231bd21e6d --- /dev/null +++ b/tests/ui/let-else/detect-invisible-delimiter.rs @@ -0,0 +1,16 @@ +// The user shouldn't need to wrap the expression in parentheses(#147899) +//@check-pass +#![allow(irrefutable_let_patterns)] +struct Thing {} +macro_rules! foo { + ($e:expr) => { + let _ = $e else { + return; + }; + }; +} + +fn main() { + foo!(true && true); + foo!(Thing {}); +} diff --git a/tests/ui/lint/future-incompatible-lint-group.stderr b/tests/ui/lint/future-incompatible-lint-group.stderr index 8f234c6216065..353009dd2a93b 100644 --- a/tests/ui/lint/future-incompatible-lint-group.stderr +++ b/tests/ui/lint/future-incompatible-lint-group.stderr @@ -12,7 +12,7 @@ error: ambiguous associated item --> $DIR/future-incompatible-lint-group.rs:19:17 | LL | fn foo() -> Self::V { 0 } - | ^^^^^^^ help: use fully-qualified syntax: `::V` + | ^^^^^^^ | note: `V` could refer to the variant defined here --> $DIR/future-incompatible-lint-group.rs:8:10 @@ -32,6 +32,11 @@ note: the lint level is defined here LL | #![deny(future_incompatible)] | ^^^^^^^^^^^^^^^^^^^ = note: `#[deny(ambiguous_associated_items)]` implied by `#[deny(future_incompatible)]` +help: use fully-qualified syntax + | +LL - fn foo() -> Self::V { 0 } +LL + fn foo() -> ::V { 0 } + | error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/lint/lint-const-item-mutation.rs b/tests/ui/lint/lint-const-item-mutation.rs index d51d3c394937c..877455e7bb869 100644 --- a/tests/ui/lint/lint-const-item-mutation.rs +++ b/tests/ui/lint/lint-const-item-mutation.rs @@ -18,16 +18,19 @@ impl Drop for Mutable { } } -struct Mutable2 { // this one has drop glue but not a Drop impl +struct Mutable2 { // this one has drop glue but not a direct Drop impl msg: &'static str, other: String, } +struct WithFieldDrop { inner: Mutable } // no Drop on this type, but Mutable has one + const ARRAY: [u8; 1] = [25]; const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; const RAW_PTR: *mut u8 = 1 as *mut u8; const MUTABLE: Mutable = Mutable { msg: "" }; const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; +const WFD: WithFieldDrop = WithFieldDrop { inner: Mutable { msg: "" } }; const VEC: Vec = Vec::new(); const PTR: *mut () = 1 as *mut _; const PTR_TO_ARRAY: *mut [u32; 4] = 0x12345678 as _; @@ -50,8 +53,9 @@ fn main() { *MY_STRUCT.raw_ptr = 0; } - MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation - MUTABLE2.msg = "wow"; //~ WARN attempting to modify + MUTABLE.msg = "wow"; // no warning — Drop impl observes the mutation + MUTABLE2.msg = "wow"; // no warning — field String has drop glue (needs_drop = true) + WFD.inner.msg = "observed"; // no warning — Mutable's Drop observes the field mutation VEC.push(0); //~ WARN taking a mutable reference to a `const` item // Test that we don't warn when converting a raw pointer diff --git a/tests/ui/lint/lint-const-item-mutation.stderr b/tests/ui/lint/lint-const-item-mutation.stderr index 0e405c306fe46..84f5e78953e60 100644 --- a/tests/ui/lint/lint-const-item-mutation.stderr +++ b/tests/ui/lint/lint-const-item-mutation.stderr @@ -1,45 +1,45 @@ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:37:5 + --> $DIR/lint-const-item-mutation.rs:40:5 | LL | ARRAY[0] = 5; | ^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:26:1 + --> $DIR/lint-const-item-mutation.rs:28:1 | LL | const ARRAY: [u8; 1] = [25]; | ^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:38:5 + --> $DIR/lint-const-item-mutation.rs:41:5 | LL | MY_STRUCT.field = false; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:27:1 + --> $DIR/lint-const-item-mutation.rs:29:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:39:5 + --> $DIR/lint-const-item-mutation.rs:42:5 | LL | MY_STRUCT.inner_array[0] = 'b'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:27:1 + --> $DIR/lint-const-item-mutation.rs:29:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:40:5 + --> $DIR/lint-const-item-mutation.rs:43:5 | LL | MY_STRUCT.use_mut(); | ^^^^^^^^^^^^^^^^^^^ @@ -52,13 +52,13 @@ note: mutable reference created due to call to this method LL | fn use_mut(&mut self) {} | ^^^^^^^^^^^^^^^^^^^^^ note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:27:1 + --> $DIR/lint-const-item-mutation.rs:29:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:41:5 + --> $DIR/lint-const-item-mutation.rs:44:5 | LL | &mut MY_STRUCT; | ^^^^^^^^^^^^^^ @@ -66,13 +66,13 @@ LL | &mut MY_STRUCT; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:27:1 + --> $DIR/lint-const-item-mutation.rs:29:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:42:5 + --> $DIR/lint-const-item-mutation.rs:45:5 | LL | (&mut MY_STRUCT).use_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,26 +85,13 @@ note: mutable reference created due to call to this method LL | fn use_mut(&mut self) {} | ^^^^^^^^^^^^^^^^^^^^^ note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:27:1 + --> $DIR/lint-const-item-mutation.rs:29:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:54:5 - | -LL | MUTABLE2.msg = "wow"; - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified -note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:30:1 - | -LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:55:5 + --> $DIR/lint-const-item-mutation.rs:59:5 | LL | VEC.push(0); | ^^^^^^^^^^^ @@ -114,10 +101,10 @@ LL | VEC.push(0); note: mutable reference created due to call to this method --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:31:1 + --> $DIR/lint-const-item-mutation.rs:34:1 | LL | const VEC: Vec = Vec::new(); | ^^^^^^^^^^^^^^^^^^^ -warning: 8 warnings emitted +warning: 7 warnings emitted diff --git a/tests/ui/methods/shadowed-intrinsic-method.rs b/tests/ui/methods/shadowed-intrinsic-method.rs new file mode 100644 index 0000000000000..8350d6a7ba5f0 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method.rs @@ -0,0 +1,37 @@ +// Can't use rustfix because we provide two suggestions: +// to remove the arg for `Borrow::borrow` or to call `Type::borrow`. +use std::borrow::Borrow; + +struct A; + +impl A { fn borrow(&mut self, _: ()) {} } + +struct B; + +fn main() { + // The fully-qualified path for items within functions is unnameable from outside that function. + impl B { fn borrow(&mut self, _: ()) {} } + + struct C; + // The fully-qualified path for items within functions is unnameable from outside that function. + impl C { fn borrow(&mut self, _: ()) {} } + + let mut a = A; + a.borrow(()); //~ ERROR E0061 + // A::borrow(&mut a, ()); + let mut b = B; + b.borrow(()); //~ ERROR E0061 + // This currently suggests `main::::borrow`, which is not correct, it should be + // B::borrow(&mut b, ()); + let mut c = C; + c.borrow(()); //~ ERROR E0061 + // This currently suggests `main::C::borrow`, which is not correct, it should be + // C::borrow(&mut c, ()); +} + +fn foo() { + let mut b = B; + b.borrow(()); //~ ERROR E0061 + // This currently suggests `main::::borrow`, which is not correct, it should be + // B::borrow(&mut b, ()); +} diff --git a/tests/ui/methods/shadowed-intrinsic-method.stderr b/tests/ui/methods/shadowed-intrinsic-method.stderr new file mode 100644 index 0000000000000..a832714cd1f97 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method.stderr @@ -0,0 +1,111 @@ +error[E0061]: this method takes 0 arguments but 1 argument was supplied + --> $DIR/shadowed-intrinsic-method.rs:20:7 + | +LL | a.borrow(()); + | ^^^^^^ -- unexpected argument of type `()` + | +note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `A` + --> $DIR/shadowed-intrinsic-method.rs:20:7 + | +LL | use std::borrow::Borrow; + | ------------------- `std::borrow::Borrow` imported here +... +LL | a.borrow(()); + | ^^^^^^ refers to `std::borrow::Borrow::borrow` +note: method defined here + --> $SRC_DIR/core/src/borrow.rs:LL:COL +help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly + | +LL - a.borrow(()); +LL + A::borrow(&mut a, ()); + | +help: remove the extra argument + | +LL - a.borrow(()); +LL + a.borrow(); + | + +error[E0061]: this method takes 0 arguments but 1 argument was supplied + --> $DIR/shadowed-intrinsic-method.rs:23:7 + | +LL | b.borrow(()); + | ^^^^^^ -- unexpected argument of type `()` + | +note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `main::` + --> $DIR/shadowed-intrinsic-method.rs:23:7 + | +LL | use std::borrow::Borrow; + | ------------------- `std::borrow::Borrow` imported here +... +LL | b.borrow(()); + | ^^^^^^ refers to `std::borrow::Borrow::borrow` +note: method defined here + --> $SRC_DIR/core/src/borrow.rs:LL:COL +help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly + | +LL - b.borrow(()); +LL + B::borrow(&mut b, ()); + | +help: remove the extra argument + | +LL - b.borrow(()); +LL + b.borrow(); + | + +error[E0061]: this method takes 0 arguments but 1 argument was supplied + --> $DIR/shadowed-intrinsic-method.rs:27:7 + | +LL | c.borrow(()); + | ^^^^^^ -- unexpected argument of type `()` + | +note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `main::C` + --> $DIR/shadowed-intrinsic-method.rs:27:7 + | +LL | use std::borrow::Borrow; + | ------------------- `std::borrow::Borrow` imported here +... +LL | c.borrow(()); + | ^^^^^^ refers to `std::borrow::Borrow::borrow` +note: method defined here + --> $SRC_DIR/core/src/borrow.rs:LL:COL +help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly + | +LL - c.borrow(()); +LL + C::borrow(&mut c, ()); + | +help: remove the extra argument + | +LL - c.borrow(()); +LL + c.borrow(); + | + +error[E0061]: this method takes 0 arguments but 1 argument was supplied + --> $DIR/shadowed-intrinsic-method.rs:34:7 + | +LL | b.borrow(()); + | ^^^^^^ -- unexpected argument of type `()` + | +note: the `borrow` call is resolved to the method in `std::borrow::Borrow`, shadowing the method of the same name on the inherent impl for `main::` + --> $DIR/shadowed-intrinsic-method.rs:34:7 + | +LL | use std::borrow::Borrow; + | ------------------- `std::borrow::Borrow` imported here +... +LL | b.borrow(()); + | ^^^^^^ refers to `std::borrow::Borrow::borrow` +note: method defined here + --> $SRC_DIR/core/src/borrow.rs:LL:COL +help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly + | +LL - b.borrow(()); +LL + B::borrow(&mut b, ()); + | +help: remove the extra argument + | +LL - b.borrow(()); +LL + b.borrow(); + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.rs b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.rs index fd41beecb0a2a..26365d4d3e359 100644 --- a/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.rs +++ b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.rs @@ -1,7 +1,7 @@ fn main() { let target: Target = create_target(); - target.get(0); // correct arguments work - target.get(10.0); // (used to crash here) + target.unique_name(0); // correct arguments work + target.unique_name(10.0); // (used to crash here) //~^ ERROR mismatched types } @@ -12,14 +12,14 @@ fn create_target() -> T { // unimplemented trait, but contains function with the same name pub trait RandomTrait { - fn get(&mut self); // but less arguments + fn unique_name(&mut self); // but less arguments } struct Target; impl Target { // correct function with arguments - pub fn get(&self, data: i32) { + pub fn unique_name(&self, data: i32) { unimplemented!() } } diff --git a/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr index 0f86916fcdae4..43aa923a2a758 100644 --- a/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr +++ b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr @@ -1,16 +1,16 @@ error[E0308]: mismatched types - --> $DIR/diagnostic-method-lookup-returns-sig-with-fewer-args.rs:4:16 + --> $DIR/diagnostic-method-lookup-returns-sig-with-fewer-args.rs:4:24 | -LL | target.get(10.0); // (used to crash here) - | --- ^^^^ expected `i32`, found floating-point number +LL | target.unique_name(10.0); // (used to crash here) + | ----------- ^^^^ expected `i32`, found floating-point number | | | arguments to this method are incorrect | note: method defined here --> $DIR/diagnostic-method-lookup-returns-sig-with-fewer-args.rs:22:12 | -LL | pub fn get(&self, data: i32) { - | ^^^ --------- +LL | pub fn unique_name(&self, data: i32) { + | ^^^^^^^^^^^ --------- error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/true-false-type-issue-162947.fixed b/tests/ui/parser/issues/true-false-type-issue-162947.fixed new file mode 100644 index 0000000000000..8d3037ea0f458 --- /dev/null +++ b/tests/ui/parser/issues/true-false-type-issue-162947.fixed @@ -0,0 +1,17 @@ +//@ run-rustfix + +struct A; + +impl A { + fn _a() -> bool { //~ ERROR: expected type, found keyword `true` + false + } + fn b(&self) {} +} + +fn main() { + let a = A; + a.b(); + + let _b: bool = true; //~ ERROR: expected type, found keyword `true` +} diff --git a/tests/ui/parser/issues/true-false-type-issue-162947.rs b/tests/ui/parser/issues/true-false-type-issue-162947.rs new file mode 100644 index 0000000000000..1c3a35b3f16f1 --- /dev/null +++ b/tests/ui/parser/issues/true-false-type-issue-162947.rs @@ -0,0 +1,17 @@ +//@ run-rustfix + +struct A; + +impl A { + fn _a() -> true { //~ ERROR: expected type, found keyword `true` + false + } + fn b(&self) {} +} + +fn main() { + let a = A; + a.b(); + + let _b: true = true; //~ ERROR: expected type, found keyword `true` +} diff --git a/tests/ui/parser/issues/true-false-type-issue-162947.stderr b/tests/ui/parser/issues/true-false-type-issue-162947.stderr new file mode 100644 index 0000000000000..558587d8ebe88 --- /dev/null +++ b/tests/ui/parser/issues/true-false-type-issue-162947.stderr @@ -0,0 +1,20 @@ +error: expected type, found keyword `true` + --> $DIR/true-false-type-issue-162947.rs:6:16 + | +LL | fn _a() -> true { + | ^^^^ + | | + | expected type + | help: the type is called: `bool` + +error: expected type, found keyword `true` + --> $DIR/true-false-type-issue-162947.rs:16:13 + | +LL | let _b: true = true; + | ^^^^ + | | + | expected type + | help: the type is called: `bool` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/let-else-fullwidth-brace.rs b/tests/ui/parser/let-else-fullwidth-brace.rs new file mode 100644 index 0000000000000..98bd65605faa8 --- /dev/null +++ b/tests/ui/parser/let-else-fullwidth-brace.rs @@ -0,0 +1,7 @@ +#![allow(irrefutable_let_patterns)] + +fn main() { + let x = {1} else { return; }; + //~^ ERROR unknown start of token: \u{ff5d} + //~| ERROR right curly brace `}` before `else` in a `let...else` statement not allowed +} diff --git a/tests/ui/parser/let-else-fullwidth-brace.stderr b/tests/ui/parser/let-else-fullwidth-brace.stderr new file mode 100644 index 0000000000000..a5bb4d029dbc5 --- /dev/null +++ b/tests/ui/parser/let-else-fullwidth-brace.stderr @@ -0,0 +1,25 @@ +error: unknown start of token: \u{ff5d} + --> $DIR/let-else-fullwidth-brace.rs:4:15 + | +LL | let x = {1} else { return; }; + | ^^ + | +help: Unicode character '}' (Fullwidth Right Curly Bracket) looks like '}' (Right Curly Brace), but it is not + | +LL - let x = {1} else { return; }; +LL + let x = {1} else { return; }; + | + +error: right curly brace `}` before `else` in a `let...else` statement not allowed + --> $DIR/let-else-fullwidth-brace.rs:4:15 + | +LL | let x = {1} else { return; }; + | ^^ + | +help: wrap the expression in parentheses + | +LL | let x = ({1}) else { return; }; + | + + + +error: aborting due to 2 previous errors + diff --git a/tests/ui/structs/invalid-self-constructor-56835.stderr b/tests/ui/structs/invalid-self-constructor-56835.stderr index 045781ec42bd2..9b25348d87d39 100644 --- a/tests/ui/structs/invalid-self-constructor-56835.stderr +++ b/tests/ui/structs/invalid-self-constructor-56835.stderr @@ -2,7 +2,13 @@ error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/invalid-self-constructor-56835.rs:5:12 | LL | fn bar(Self(foo): Self) {} - | ^^^^^^^^^ help: use curly brackets: `Self { /* fields */ }` + | ^^^^^^^^^ + | +help: use curly brackets + | +LL - fn bar(Self(foo): Self) {} +LL + fn bar(Self { /* fields */ }: Self) {} + | error[E0164]: expected tuple struct or tuple variant, found self constructor `Self` --> $DIR/invalid-self-constructor-56835.rs:5:12 diff --git a/tests/ui/suggestions/fn-trait-notation.stderr b/tests/ui/suggestions/fn-trait-notation.stderr index ef7d5fe362820..37cfcf3b8b5f8 100644 --- a/tests/ui/suggestions/fn-trait-notation.stderr +++ b/tests/ui/suggestions/fn-trait-notation.stderr @@ -2,31 +2,46 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/fn-trait-notation.rs:4:8 | LL | F: Fn, - | ^^^^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(i32) -> i32` + | ^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL - F: Fn, +LL + F: Fn(i32) -> i32, + | error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/fn-trait-notation.rs:6:8 | LL | G: Fn<(i32, i32, ), Output = (i32, i32)>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(i32, i32) -> (i32, i32)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL - G: Fn<(i32, i32, ), Output = (i32, i32)>, +LL + G: Fn(i32, i32) -> (i32, i32), + | error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/fn-trait-notation.rs:7:8 | LL | H: Fn<(i32,), Output = i32>, - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(i32) -> i32` + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL - H: Fn<(i32,), Output = i32>, +LL + H: Fn(i32) -> i32, + | error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/fn-trait-notation.rs:4:8 diff --git a/tests/ui/suggestions/shadowed-lplace-method.fixed b/tests/ui/suggestions/shadowed-lplace-method.fixed index 87db01a3b230b..e7f6df9fff8fb 100644 --- a/tests/ui/suggestions/shadowed-lplace-method.fixed +++ b/tests/ui/suggestions/shadowed-lplace-method.fixed @@ -6,5 +6,5 @@ use std::rc::Rc; fn main() { let rc = Rc::new(RefCell::new(true)); - *std::cell::RefCell::<_>::borrow_mut(&rc) = false; //~ ERROR E0308 + *RefCell::borrow_mut(&rc) = false; //~ ERROR E0308 } diff --git a/tests/ui/suggestions/shadowed-lplace-method.stderr b/tests/ui/suggestions/shadowed-lplace-method.stderr index aab9e442007ff..dfd52b9b5587b 100644 --- a/tests/ui/suggestions/shadowed-lplace-method.stderr +++ b/tests/ui/suggestions/shadowed-lplace-method.stderr @@ -19,7 +19,7 @@ LL | *rc.borrow_mut() = false; help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly | LL - *rc.borrow_mut() = false; -LL + *std::cell::RefCell::<_>::borrow_mut(&rc) = false; +LL + *RefCell::borrow_mut(&rc) = false; | error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/assertion-left-right-goal.stderr b/tests/ui/traits/next-solver/assertion-left-right-goal.stderr index 40986169b177b..e714a969df07b 100644 --- a/tests/ui/traits/next-solver/assertion-left-right-goal.stderr +++ b/tests/ui/traits/next-solver/assertion-left-right-goal.stderr @@ -2,44 +2,64 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/assertion-left-right-goal.rs:6:28 | LL | async fn new() -> impl Fn<()> { - | ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL - async fn new() -> impl Fn<()> { +LL + async fn new() -> impl Fn() -> () { + | error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/assertion-left-right-goal.rs:6:28 | LL | async fn new() -> impl Fn<()> { - | ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use parenthetical notation instead + | +LL - async fn new() -> impl Fn<()> { +LL + async fn new() -> impl Fn() -> () { + | error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/assertion-left-right-goal.rs:6:28 | LL | async fn new() -> impl Fn<()> { - | ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use parenthetical notation instead + | +LL - async fn new() -> impl Fn<()> { +LL + async fn new() -> impl Fn() -> () { + | error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/assertion-left-right-goal.rs:6:28 | LL | async fn new() -> impl Fn<()> { - | ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: use parenthetical notation instead + | +LL - async fn new() -> impl Fn<()> { +LL + async fn new() -> impl Fn() -> () { + | error[E0308]: mismatched types --> $DIR/assertion-left-right-goal.rs:6:35 diff --git a/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr b/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr index 918d05b5d6781..1cb7b9df6ff7b 100644 --- a/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr +++ b/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr @@ -2,7 +2,7 @@ error: ambiguous associated item --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:32:15 | LL | fn f() -> Self::V { 0 } - | ^^^^^^^ help: use fully-qualified syntax: `::V` + | ^^^^^^^ | note: `V` could refer to the variant defined here --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:22:5 @@ -17,6 +17,11 @@ LL | type V; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57644 = note: `#[deny(ambiguous_associated_items)]` (part of `#[deny(future_incompatible)]`) on by default +help: use fully-qualified syntax + | +LL - fn f() -> Self::V { 0 } +LL + fn f() -> ::V { 0 } + | error: aborting due to 1 previous error diff --git a/tests/ui/typeck/self-constructor-type-error-56199.rs b/tests/ui/typeck/self-constructor-type-error-56199.rs index b08d69189807a..34af8bed25c47 100644 --- a/tests/ui/typeck/self-constructor-type-error-56199.rs +++ b/tests/ui/typeck/self-constructor-type-error-56199.rs @@ -1,5 +1,8 @@ // https://github.com/rust-lang/rust/issues/56199 enum Foo {} +enum Lab { + Qux, +} struct Bar {} impl Foo { @@ -9,6 +12,12 @@ impl Foo { let _ = Self(); //~^ ERROR the `Self` constructor can only be used with tuple or unit structs } + fn foo_method(self) { + let _ = Self; + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + let _ = Self(); + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + } } impl Bar { @@ -18,6 +27,28 @@ impl Bar { let _ = Self(); //~^ ERROR the `Self` constructor can only be used with tuple or unit structs } + fn bar_method(self) { + let _ = Self; + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + let _ = Self(); + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + } +} + +impl Lab { + fn lab() { + let _ = Self; + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + let _ = Self(); + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + } + fn lab_method(self) { + let _ = Self; + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + let _ = Self(); + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + } } + fn main() {} diff --git a/tests/ui/typeck/self-constructor-type-error-56199.stderr b/tests/ui/typeck/self-constructor-type-error-56199.stderr index 6e9d0fcd90c05..d0d124c6f3149 100644 --- a/tests/ui/typeck/self-constructor-type-error-56199.stderr +++ b/tests/ui/typeck/self-constructor-type-error-56199.stderr @@ -1,30 +1,145 @@ error: the `Self` constructor can only be used with tuple or unit structs - --> $DIR/self-constructor-type-error-56199.rs:7:17 + --> $DIR/self-constructor-type-error-56199.rs:10:17 | LL | let _ = Self; | ^^^^ | - = help: did you mean to use one of the enum's variants? +help: the enum is unconstructable because it has no variants + --> $DIR/self-constructor-type-error-56199.rs:2:1 + | +LL | enum Foo {} + | ^^^^^^^^ error: the `Self` constructor can only be used with tuple or unit structs - --> $DIR/self-constructor-type-error-56199.rs:9:17 + --> $DIR/self-constructor-type-error-56199.rs:12:17 | LL | let _ = Self(); | ^^^^^^ | - = help: did you mean to use one of the enum's variants? +help: the enum is unconstructable because it has no variants + --> $DIR/self-constructor-type-error-56199.rs:2:1 + | +LL | enum Foo {} + | ^^^^^^^^ error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/self-constructor-type-error-56199.rs:16:17 | LL | let _ = Self; - | ^^^^ help: use curly brackets: `Self { /* fields */ }` + | ^^^^ + | +help: you might have meant to refer to the `self` binding of type `Foo` (notice the capitalization) + | +LL - let _ = Self; +LL + let _ = self; + | error: the `Self` constructor can only be used with tuple or unit structs --> $DIR/self-constructor-type-error-56199.rs:18:17 | LL | let _ = Self(); - | ^^^^^^ help: use curly brackets: `Self { /* fields */ }` + | ^^^^^^ + | +help: the enum is unconstructable because it has no variants + --> $DIR/self-constructor-type-error-56199.rs:2:1 + | +LL | enum Foo {} + | ^^^^^^^^ + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/self-constructor-type-error-56199.rs:25:17 + | +LL | let _ = Self; + | ^^^^ + | +help: use curly brackets + | +LL | let _ = Self { /* fields */ }; + | ++++++++++++++++ + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/self-constructor-type-error-56199.rs:27:17 + | +LL | let _ = Self(); + | ^^^^^^ + | +help: use curly brackets + | +LL - let _ = Self(); +LL + let _ = Self { /* fields */ }; + | + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/self-constructor-type-error-56199.rs:31:17 + | +LL | let _ = Self; + | ^^^^ + | +help: you might have meant to refer to the `self` binding of type `Bar` (notice the capitalization) + | +LL - let _ = Self; +LL + let _ = self; + | + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/self-constructor-type-error-56199.rs:33:17 + | +LL | let _ = Self(); + | ^^^^^^ + | +help: use curly brackets + | +LL - let _ = Self(); +LL + let _ = Self { /* fields */ }; + | + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/self-constructor-type-error-56199.rs:40:17 + | +LL | let _ = Self; + | ^^^^ + | +help: you might have meant to use one of the enum's variants + --> $DIR/self-constructor-type-error-56199.rs:3:1 + | +LL | enum Lab { + | ^^^^^^^^ + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/self-constructor-type-error-56199.rs:42:17 + | +LL | let _ = Self(); + | ^^^^^^ + | +help: you might have meant to use one of the enum's variants + --> $DIR/self-constructor-type-error-56199.rs:3:1 + | +LL | enum Lab { + | ^^^^^^^^ + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/self-constructor-type-error-56199.rs:46:17 + | +LL | let _ = Self; + | ^^^^ + | +help: you might have meant to refer to the `self` binding of type `Lab` (notice the capitalization) + | +LL - let _ = Self; +LL + let _ = self; + | + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/self-constructor-type-error-56199.rs:48:17 + | +LL | let _ = Self(); + | ^^^^^^ + | +help: you might have meant to use one of the enum's variants + --> $DIR/self-constructor-type-error-56199.rs:3:1 + | +LL | enum Lab { + | ^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/unboxed-closures/missing-fn-trait-args-issue-136407.feature_disabled.stderr b/tests/ui/unboxed-closures/missing-fn-trait-args-issue-136407.feature_disabled.stderr index 2a62cdfec2566..33b304d63e4bb 100644 --- a/tests/ui/unboxed-closures/missing-fn-trait-args-issue-136407.feature_disabled.stderr +++ b/tests/ui/unboxed-closures/missing-fn-trait-args-issue-136407.feature_disabled.stderr @@ -2,11 +2,15 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/missing-fn-trait-args-issue-136407.rs:9:18 | LL | pub fn shared() {} - | ^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL | pub fn shared ()>() {} + | ++++++++ error[E0107]: missing generics for trait `Fn` --> $DIR/missing-fn-trait-args-issue-136407.rs:9:18 @@ -18,11 +22,15 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/missing-fn-trait-args-issue-136407.rs:13:19 | LL | pub fn mutable() {} - | ^^^^^ help: use parenthetical notation instead: `FnMut() -> ()` + | ^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL | pub fn mutable ()>() {} + | ++++++++ error[E0107]: missing generics for trait `FnMut` --> $DIR/missing-fn-trait-args-issue-136407.rs:13:19 @@ -34,11 +42,15 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/missing-fn-trait-args-issue-136407.rs:17:16 | LL | pub fn once() {} - | ^^^^^^ help: use parenthetical notation instead: `FnOnce() -> ()` + | ^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL | pub fn once ()>() {} + | ++++++++ error[E0107]: missing generics for trait `FnOnce` --> $DIR/missing-fn-trait-args-issue-136407.rs:17:16 @@ -50,11 +62,15 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/missing-fn-trait-args-issue-136407.rs:21:24 | LL | pub fn async_shared() {} - | ^^^^^^^ help: use parenthetical notation instead: `AsyncFn() -> ()` + | ^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL | pub fn async_shared ()>() {} + | ++++++++ error[E0107]: missing generics for trait `AsyncFn` --> $DIR/missing-fn-trait-args-issue-136407.rs:21:24 @@ -66,11 +82,15 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/missing-fn-trait-args-issue-136407.rs:25:25 | LL | pub fn async_mutable() {} - | ^^^^^^^^^^ help: use parenthetical notation instead: `AsyncFnMut() -> ()` + | ^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL | pub fn async_mutable ()>() {} + | ++++++++ error[E0107]: missing generics for trait `AsyncFnMut` --> $DIR/missing-fn-trait-args-issue-136407.rs:25:25 @@ -82,11 +102,15 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/missing-fn-trait-args-issue-136407.rs:29:22 | LL | pub fn async_once() {} - | ^^^^^^^^^^^ help: use parenthetical notation instead: `AsyncFnOnce() -> ()` + | ^^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL | pub fn async_once ()>() {} + | ++++++++ error[E0107]: missing generics for trait `AsyncFnOnce` --> $DIR/missing-fn-trait-args-issue-136407.rs:29:22 @@ -98,11 +122,16 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/missing-fn-trait-args-issue-136407.rs:33:23 | LL | pub fn with_output>() {} - | ^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^^^^^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL - pub fn with_output>() {} +LL + pub fn with_output ()>() {} + | error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied --> $DIR/missing-fn-trait-args-issue-136407.rs:33:23 diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr index e6f34d7e3b4b7..05f960dcf89a8 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr @@ -2,21 +2,31 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:3:17 | LL | fn bar1(x: &dyn Fn<(), Output=()>) { - | ^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^^^^^^^^^^^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL - fn bar1(x: &dyn Fn<(), Output=()>) { +LL + fn bar1(x: &dyn Fn() -> ()) { + | error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:7:28 | LL | fn bar2(x: &T) where T: Fn<()> { - | ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()` + | ^^^^^^ | = note: see issue #29625 for more information = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: use parenthetical notation instead + | +LL - fn bar2(x: &T) where T: Fn<()> { +LL + fn bar2(x: &T) where T: Fn() -> () { + | error: aborting due to 2 previous errors diff --git a/triagebot.toml b/triagebot.toml index 475cf6e044f9b..60098a038ea73 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -702,6 +702,7 @@ topic = "#{number}: {title}" message_on_add = """\ @*T-types* issue #{number} "{title}" has been nominated for team discussion. """ +github_comment = ":robot: A [dedicated `#t-types/nominated` topic]({zulip_topic_url}) has been opened for humans to discuss this issue :robot:" message_on_remove = "Issue #{number}'s nomination has been removed. Thanks all for participating!" message_on_close = "Issue #{number} has been closed. Thanks for participating!" message_on_reopen = "Issue #{number} has been reopened. Pinging @*T-types*."