Auto merge of #117692 - matthiaskrgr:rollup-umaf5pr, r=matthiaskrgr

Rollup of 4 pull requests

Successful merges:

 - #113925 (Improve diagnostic for const ctors in array repeat expressions)
 - #116399 (Small changes w/ `query::Erase<_>`)
 - #117625 (Fix some clippy perf lints)
 - #117655 (Method suggestion code tweaks)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-11-08 01:01:58 +00:00
commit 0d5ec963bb
28 changed files with 334 additions and 252 deletions

View File

@ -2362,11 +2362,7 @@ impl FileWithAnnotatedLines {
let label = label.as_ref().map(|m| {
normalize_whitespace(
&emitter
.translate_message(m, &args)
.map_err(Report::new)
.unwrap()
.to_string(),
&emitter.translate_message(m, &args).map_err(Report::new).unwrap(),
)
});

View File

@ -13,7 +13,7 @@ use crate::errors::{
YieldExprOutsideOfCoroutine,
};
use crate::fatally_break_rust;
use crate::method::{MethodCallComponents, SelfSource};
use crate::method::SelfSource;
use crate::type_error_struct;
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
use crate::{
@ -512,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
let tcx = self.tcx;
let (res, opt_ty, segs) =
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span, Some(args));
let ty = match res {
Res::Err => {
self.suggest_assoc_method_call(segs);
@ -1332,7 +1332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
segment.ident,
SelfSource::MethodCall(rcvr),
error,
Some(MethodCallComponents { receiver: rcvr, args, full_expr: expr }),
Some(args),
expected,
false,
) {
@ -1551,21 +1551,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
_ => {}
}
// If someone calls a const fn, they can extract that call out into a separate constant (or a const
// block in the future), so we check that to tell them that in the diagnostic. Does not affect typeck.
let is_const_fn = match element.kind {
// If someone calls a const fn or constructs a const value, they can extract that
// out into a separate constant (or a const block in the future), so we check that
// to tell them that in the diagnostic. Does not affect typeck.
let is_constable = match element.kind {
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
ty::FnDef(def_id, _) => tcx.is_const_fn(def_id),
_ => false,
ty::FnDef(def_id, _) if tcx.is_const_fn(def_id) => traits::IsConstable::Fn,
_ => traits::IsConstable::No,
},
_ => false,
hir::ExprKind::Path(qpath) => {
match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) {
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor,
_ => traits::IsConstable::No,
}
}
_ => traits::IsConstable::No,
};
// If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we
// don't copy that one element, we move it. Only check for Copy if the length is larger.
if count.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn };
let code = traits::ObligationCauseCode::RepeatElementCopy {
is_constable,
elt_type: element_ty,
elt_span: element.span,
elt_stmt_span: self
.tcx
.hir()
.parent_iter(element.hir_id)
.find_map(|(_, node)| match node {
hir::Node::Item(it) => Some(it.span),
hir::Node::Stmt(stmt) => Some(stmt.span),
_ => None,
})
.expect("array repeat expressions must be inside an item or statement"),
};
self.require_type_meets(element_ty, element.span, code, lang_item);
}
}

View File

@ -797,6 +797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
qpath: &'tcx QPath<'tcx>,
hir_id: hir::HirId,
span: Span,
args: Option<&'tcx [hir::Expr<'tcx>]>,
) -> (Res, Option<RawTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
debug!(
"resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}",
@ -898,7 +899,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name,
SelfSource::QPath(qself),
error,
None,
args,
Expectation::NoExpectation,
trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
) {

View File

@ -7,7 +7,7 @@ mod prelude2021;
pub mod probe;
mod suggest;
pub use self::suggest::{MethodCallComponents, SelfSource};
pub use self::suggest::SelfSource;
pub use self::MethodError::*;
use crate::errors::OpMethodGenericParams;

View File

@ -34,7 +34,7 @@ use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::def_id::DefIdSet;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
use rustc_span::{edit_distance, ExpnKind, FileName, MacroKind, Span};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
@ -50,15 +50,6 @@ use rustc_hir::intravisit::Visitor;
use std::cmp::{self, Ordering};
use std::iter;
/// After identifying that `full_expr` is a method call, we use this type to keep the expression's
/// components readily available to us to point at the right place in diagnostics.
#[derive(Debug, Clone, Copy)]
pub struct MethodCallComponents<'tcx> {
pub receiver: &'tcx hir::Expr<'tcx>,
pub args: &'tcx [hir::Expr<'tcx>],
pub full_expr: &'tcx hir::Expr<'tcx>,
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
let tcx = self.tcx;
@ -124,7 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name: Ident,
source: SelfSource<'tcx>,
error: MethodError<'tcx>,
args: Option<MethodCallComponents<'tcx>>,
args: Option<&'tcx [hir::Expr<'tcx>]>,
expected: Expectation<'tcx>,
trait_missing_method: bool,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
@ -167,6 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.note_candidates_on_method_error(
rcvr_ty,
item_name,
source,
args,
span,
&mut err,
@ -266,23 +258,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn suggest_missing_writer(
&self,
rcvr_ty: Ty<'tcx>,
args: MethodCallComponents<'tcx>,
rcvr_expr: &hir::Expr<'tcx>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
let mut err = struct_span_err!(
self.tcx.sess,
args.receiver.span,
rcvr_expr.span,
E0599,
"cannot write into `{}`",
ty_str
);
err.span_note(
args.receiver.span,
rcvr_expr.span,
"must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
);
if let ExprKind::Lit(_) = args.receiver.kind {
if let ExprKind::Lit(_) = rcvr_expr.kind {
err.span_help(
args.receiver.span.shrink_to_lo(),
rcvr_expr.span.shrink_to_lo(),
"a writer is needed before this format string",
);
};
@ -296,7 +288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rcvr_ty: Ty<'tcx>,
item_name: Ident,
source: SelfSource<'tcx>,
args: Option<MethodCallComponents<'tcx>>,
args: Option<&'tcx [hir::Expr<'tcx>]>,
sugg_span: Span,
no_match_data: &mut NoMatchData<'tcx>,
expected: Expectation<'tcx>,
@ -377,23 +369,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tcx.is_diagnostic_item(sym::write_macro, def_id)
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
}) && item_name.name == Symbol::intern("write_fmt");
let mut err = if is_write && let Some(args) = args {
self.suggest_missing_writer(rcvr_ty, args)
} else {
tcx.sess.create_err(NoAssociatedItem {
span,
item_kind,
item_name,
ty_prefix: if trait_missing_method {
// FIXME(mu001999) E0599 maybe not suitable here because it is for types
Cow::from("trait")
} else {
rcvr_ty.prefix_string(self.tcx)
},
ty_str: ty_str_reported,
trait_missing_method,
})
};
let mut err =
if is_write && let SelfSource::MethodCall(rcvr_expr) = source
{
self.suggest_missing_writer(rcvr_ty, rcvr_expr)
} else {
tcx.sess.create_err(NoAssociatedItem {
span,
item_kind,
item_name,
ty_prefix: if trait_missing_method {
// FIXME(mu001999) E0599 maybe not suitable here because it is for types
Cow::from("trait")
} else {
rcvr_ty.prefix_string(self.tcx)
},
ty_str: ty_str_reported,
trait_missing_method,
})
};
if tcx.sess.source_map().is_multiline(sugg_span) {
err.span_label(sugg_span.with_hi(span.lo()), "");
}
@ -409,7 +403,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.downgrade_to_delayed_bug();
}
self.find_builder_fn(&mut err, rcvr_ty, source);
if matches!(source, SelfSource::QPath(_)) && args.is_some() {
self.find_builder_fn(&mut err, rcvr_ty);
}
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
err.help(format!(
"method `poll` found on `Pin<&mut {ty_str}>`, \
@ -523,6 +520,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.note_candidates_on_method_error(
rcvr_ty,
item_name,
source,
args,
span,
&mut err,
@ -533,6 +531,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.note_candidates_on_method_error(
rcvr_ty,
item_name,
source,
args,
span,
&mut err,
@ -976,7 +975,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
unsatisfied_bounds = true;
}
} else if let ty::Adt(def, targs) = rcvr_ty.kind()
&& let Some(args) = args
&& let SelfSource::MethodCall(rcvr_expr) = source
{
// This is useful for methods on arbitrary self types that might have a simple
// mutability difference, like calling a method on `Pin<&mut Self>` that is on
@ -999,8 +998,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rcvr_ty,
&item_segment,
span,
args.full_expr,
args.receiver,
tcx.hir().get_parent(rcvr_expr.hir_id).expect_expr(),
rcvr_expr,
) {
err.span_note(
tcx.def_span(method.def_id),
@ -1169,7 +1168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
rcvr_ty,
item_name,
args.map(|MethodCallComponents { args, .. }| args.len() + 1),
args.map(|args| args.len() + 1),
source,
no_match_data.out_of_scope_traits.clone(),
&unsatisfied_predicates,
@ -1250,7 +1249,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
args: Option<MethodCallComponents<'tcx>>,
self_source: SelfSource<'tcx>,
args: Option<&'tcx [hir::Expr<'tcx>]>,
span: Span,
err: &mut Diagnostic,
sources: &mut Vec<CandidateSource>,
@ -1320,38 +1320,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if let Some(sugg_span) = sugg_span
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did)
{
let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id);
let ty = match item.kind {
ty::AssocKind::Const | ty::AssocKind::Type => impl_ty,
ty::AssocKind::Fn => self
.tcx
.fn_sig(item.def_id)
.instantiate_identity()
.inputs()
.skip_binder()
.get(0)
.filter(|ty| ty.is_ref() && !rcvr_ty.is_ref())
.copied()
.unwrap_or(rcvr_ty),
};
if let Some(sugg) = print_disambiguation_help(
item_name,
args,
&& let Some(sugg) = print_disambiguation_help(
self.tcx,
err,
path,
ty,
Some(impl_ty),
item.kind,
self.tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id),
sugg_span,
self_source,
args,
trait_ref.instantiate(
self.tcx,
self.fresh_args_for_item(sugg_span, impl_did)
).with_self_ty(self.tcx, rcvr_ty),
idx,
self.tcx.sess.source_map(),
item.fn_has_self_parameter,
) {
suggs.push(sugg);
}
sugg_span,
item,
)
{
suggs.push(sugg);
}
}
CandidateSource::Trait(trait_did) => {
@ -1373,24 +1356,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_note(item_span, msg);
None
};
if let Some(sugg_span) = sugg_span {
let path = self.tcx.def_path_str(trait_did);
if let Some(sugg) = print_disambiguation_help(
item_name,
args,
if let Some(sugg_span) = sugg_span
&& let Some(sugg) = print_disambiguation_help(
self.tcx,
err,
path,
rcvr_ty,
None,
item.kind,
self.tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id),
sugg_span,
self_source,
args,
ty::TraitRef::new(
self.tcx,
trait_did,
self.fresh_args_for_item(sugg_span, trait_did)
).with_self_ty(self.tcx, rcvr_ty),
idx,
self.tcx.sess.source_map(),
item.fn_has_self_parameter,
) {
suggs.push(sugg);
}
sugg_span,
item,
)
{
suggs.push(sugg);
}
}
}
@ -1410,18 +1392,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Look at all the associated functions without receivers in the type's inherent impls
/// to look for builders that return `Self`, `Option<Self>` or `Result<Self, _>`.
fn find_builder_fn(&self, err: &mut Diagnostic, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>) {
fn find_builder_fn(&self, err: &mut Diagnostic, rcvr_ty: Ty<'tcx>) {
let ty::Adt(adt_def, _) = rcvr_ty.kind() else {
return;
};
let SelfSource::QPath(ty) = source else {
return;
};
let hir = self.tcx.hir();
if let Some(Node::Pat(_)) = hir.find(hir.parent_id(ty.hir_id)) {
// Do not suggest a fn call when a pattern is expected.
return;
}
let mut items = self
.tcx
.inherent_impls(adt_def.did())
@ -1504,7 +1478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rcvr_ty: Ty<'tcx>,
source: SelfSource<'tcx>,
item_name: Ident,
args: Option<MethodCallComponents<'tcx>>,
args: Option<&'tcx [hir::Expr<'tcx>]>,
sugg_span: Span,
) {
let mut has_unsuggestable_args = false;
@ -1578,38 +1552,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
};
let mut applicability = Applicability::MachineApplicable;
let args = if let Some(MethodCallComponents { receiver, args, .. }) = args {
// The first arg is the same kind as the receiver
let explicit_args = if first_arg.is_some() {
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
let args = if let SelfSource::MethodCall(receiver) = source
&& let Some(args) = args
{
// The first arg is the same kind as the receiver
let explicit_args = if first_arg.is_some() {
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
} else {
// There is no `Self` kind to infer the arguments from
if has_unsuggestable_args {
applicability = Applicability::HasPlaceholders;
}
args.iter().collect()
};
format!(
"({}{})",
first_arg.unwrap_or(""),
explicit_args
.iter()
.map(|arg| self
.tcx
.sess
.source_map()
.span_to_snippet(arg.span)
.unwrap_or_else(|_| {
applicability = Applicability::HasPlaceholders;
"_".to_owned()
}))
.collect::<Vec<_>>()
.join(", "),
)
} else {
// There is no `Self` kind to infer the arguments from
if has_unsuggestable_args {
applicability = Applicability::HasPlaceholders;
}
args.iter().collect()
applicability = Applicability::HasPlaceholders;
"(...)".to_owned()
};
format!(
"({}{})",
first_arg.unwrap_or(""),
explicit_args
.iter()
.map(|arg| self
.tcx
.sess
.source_map()
.span_to_snippet(arg.span)
.unwrap_or_else(|_| {
applicability = Applicability::HasPlaceholders;
"_".to_owned()
}))
.collect::<Vec<_>>()
.join(", "),
)
} else {
applicability = Applicability::HasPlaceholders;
"(...)".to_owned()
};
err.span_suggestion(
sugg_span,
"use associated function syntax instead",
@ -3267,56 +3243,59 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
}
fn print_disambiguation_help<'tcx>(
item_name: Ident,
args: Option<MethodCallComponents<'tcx>>,
tcx: TyCtxt<'tcx>,
err: &mut Diagnostic,
trait_name: String,
rcvr_ty: Ty<'_>,
impl_self_ty: Option<Ty<'_>>,
kind: ty::AssocKind,
def_kind_descr: &'static str,
source: SelfSource<'tcx>,
args: Option<&'tcx [hir::Expr<'tcx>]>,
trait_ref: ty::TraitRef<'tcx>,
candidate_idx: Option<usize>,
span: Span,
candidate: Option<usize>,
source_map: &source_map::SourceMap,
fn_has_self_parameter: bool,
item: ty::AssocItem,
) -> Option<String> {
let trait_ref = if item.fn_has_self_parameter {
trait_ref.print_only_trait_name().to_string()
} else {
format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name())
};
Some(
if let (ty::AssocKind::Fn, Some(MethodCallComponents { receiver, args, .. })) = (kind, args)
if matches!(item.kind, ty::AssocKind::Fn)
&& let SelfSource::MethodCall(receiver) = source
&& let Some(args) = args
{
let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id);
let item_name = item.ident(tcx);
let rcvr_ref = tcx.fn_sig(item.def_id).skip_binder().skip_binder().inputs()[0]
.ref_mutability()
.map_or("", |mutbl| mutbl.ref_prefix_str());
let args = format!(
"({}{})",
rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),
rcvr_ref,
std::iter::once(receiver)
.chain(args.iter())
.map(|arg| source_map
.map(|arg| tcx
.sess
.source_map()
.span_to_snippet(arg.span)
.unwrap_or_else(|_| { "_".to_owned() }))
.collect::<Vec<_>>()
.join(", "),
);
let trait_name = if !fn_has_self_parameter && let Some(impl_self_ty) = impl_self_ty {
format!("<{impl_self_ty} as {trait_name}>")
} else {
trait_name
};
err.span_suggestion_verbose(
span,
format!(
"disambiguate the {def_kind_descr} for {}",
if let Some(candidate) = candidate {
if let Some(candidate) = candidate_idx {
format!("candidate #{candidate}")
} else {
"the candidate".to_string()
},
),
format!("{trait_name}::{item_name}{args}"),
format!("{trait_ref}::{item_name}{args}"),
Applicability::HasPlaceholders,
);
return None;
} else if let Some(impl_self_ty) = impl_self_ty {
format!("<{impl_self_ty} as {trait_name}>::")
} else {
format!("{trait_name}::")
format!("{trait_ref}::")
},
)
}

View File

@ -166,9 +166,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;
let path_res = match &pat.kind {
PatKind::Path(qpath) => {
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
}
PatKind::Path(qpath) => Some(
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None),
),
_ => None,
};
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
@ -1060,7 +1060,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Resolve the path and check the definition for errors.
let (res, opt_ty, segments) =
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None);
if res == Res::Err {
let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted");
self.set_tainted_by_errors(e);

View File

@ -2,7 +2,8 @@ use crate::mir;
use crate::query::CyclePlaceholder;
use crate::traits;
use crate::ty::{self, Ty};
use std::mem::{size_of, transmute_copy, MaybeUninit};
use std::intrinsics::transmute_unchecked;
use std::mem::{size_of, MaybeUninit};
#[derive(Copy, Clone)]
pub struct Erased<T: Copy> {
@ -29,8 +30,15 @@ pub fn erase<T: EraseType>(src: T) -> Erase<T> {
};
Erased::<<T as EraseType>::Result> {
// `transmute_unchecked` is needed here because it does not have `transmute`'s size check
// (and thus allows to transmute between `T` and `MaybeUninit<T::Result>`) (we do the size
// check ourselves in the `const` block above).
//
// `transmute_copy` is also commonly used for this (and it would work here since
// `EraseType: Copy`), but `transmute_unchecked` better explains the intent.
//
// SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes.
data: unsafe { transmute_copy(&src) },
data: unsafe { transmute_unchecked::<T, MaybeUninit<T::Result>>(src) },
}
}
@ -38,22 +46,24 @@ pub fn erase<T: EraseType>(src: T) -> Erase<T> {
#[inline(always)]
pub fn restore<T: EraseType>(value: Erase<T>) -> T {
let value: Erased<<T as EraseType>::Result> = value;
// See comment in `erase` for why we use `transmute_unchecked`.
//
// SAFETY: Due to the use of impl Trait in `Erase` the only way to safely create an instance
// of `Erase` is to call `erase`, so we know that `value.data` is a valid instance of `T` of
// the right size.
unsafe { transmute_copy(&value.data) }
unsafe { transmute_unchecked::<MaybeUninit<T::Result>, T>(value.data) }
}
impl<T> EraseType for &'_ T {
type Result = [u8; size_of::<*const ()>()];
type Result = [u8; size_of::<&'static ()>()];
}
impl<T> EraseType for &'_ [T] {
type Result = [u8; size_of::<*const [()]>()];
type Result = [u8; size_of::<&'static [()]>()];
}
impl<T> EraseType for &'_ ty::List<T> {
type Result = [u8; size_of::<*const ()>()];
type Result = [u8; size_of::<&'static ty::List<()>>()];
}
impl<I: rustc_index::Idx, T> EraseType for &'_ rustc_index::IndexSlice<I, T> {

View File

@ -305,9 +305,14 @@ pub enum ObligationCauseCode<'tcx> {
SizedCoroutineInterior(LocalDefId),
/// `[expr; N]` requires `type_of(expr): Copy`.
RepeatElementCopy {
/// If element is a `const fn` we display a help message suggesting to move the
/// function call to a new `const` item while saying that `T` doesn't implement `Copy`.
is_const_fn: bool,
/// If element is a `const fn` or const ctor we display a help message suggesting
/// to move it to a new `const` item while saying that `T` doesn't implement `Copy`.
is_constable: IsConstable,
elt_type: Ty<'tcx>,
elt_span: Span,
/// Span of the statement/item in which the repeat expression occurs. We can use this to
/// place a `const` declaration before it
elt_stmt_span: Span,
},
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
@ -455,6 +460,21 @@ pub enum ObligationCauseCode<'tcx> {
TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId),
}
/// Whether a value can be extracted into a const.
/// Used for diagnostics around array repeat expressions.
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
pub enum IsConstable {
No,
/// Call to a const fn
Fn,
/// Use of a const ctor
Ctor,
}
crate::TrivialTypeTraversalAndLiftImpls! {
IsConstable,
}
/// The 'location' at which we try to perform HIR-based wf checking.
/// This information is used to obtain an `hir::Ty`, which
/// we can walk in order to obtain precise spans for any

View File

@ -274,7 +274,7 @@ pub fn suggest_constraining_type_params<'a>(
span,
if span_to_replace.is_some() {
constraint.clone()
} else if constraint.starts_with("<") {
} else if constraint.starts_with('<') {
constraint.to_string()
} else if bound_list_non_empty {
format!(" + {constraint}")

View File

@ -1545,7 +1545,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
&& let Some(span) = suggestion.span
&& let Some(candidate) = suggestion.candidate.as_str().strip_prefix("_")
&& let Some(candidate) = suggestion.candidate.as_str().strip_prefix('_')
&& snippet == candidate
{
// When the suggested binding change would be from `x` to `_x`, suggest changing the

View File

@ -2477,7 +2477,7 @@ pub fn parse_externs(
let mut error = handler.early_struct_error(format!(
"crate name `{name}` passed to `--extern` is not a valid ASCII identifier"
));
let adjusted_name = name.replace("-", "_");
let adjusted_name = name.replace('-', "_");
if crate::utils::is_ascii_ident(&adjusted_name) {
error.help(format!(
"consider replacing the dashes with underscores: `{adjusted_name}`"

View File

@ -28,6 +28,7 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime};
use rustc_middle::hir::map;
use rustc_middle::traits::IsConstable;
use rustc_middle::ty::error::TypeError::{self, Sorts};
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs,
@ -2768,20 +2769,30 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
));
}
}
ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
ObligationCauseCode::RepeatElementCopy { is_constable, elt_type, elt_span, elt_stmt_span } => {
err.note(
"the `Copy` trait is required because this value will be copied for each element of the array",
);
if is_const_fn {
err.help(
"consider creating a new `const` item and initializing it with the result \
of the function call to be used in the repeat position, like \
`const VAL: Type = const_fn();` and `let x = [VAL; 42];`",
);
let value_kind = match is_constable {
IsConstable::Fn => Some("the result of the function call"),
IsConstable::Ctor => Some("the result of the constructor"),
_ => None
};
let sm = tcx.sess.source_map();
if let Some(value_kind) = value_kind &&
let Ok(snip) = sm.span_to_snippet(elt_span)
{
let help_msg = format!(
"consider creating a new `const` item and initializing it with {value_kind} \
to be used in the repeat position");
let indentation = sm.indentation_before(elt_stmt_span).unwrap_or_default();
err.multipart_suggestion(help_msg, vec![
(elt_stmt_span.shrink_to_lo(), format!("const ARRAY_REPEAT_VALUE: {elt_type} = {snip};\n{indentation}")),
(elt_span, "ARRAY_REPEAT_VALUE".to_string())
], Applicability::MachineApplicable);
}
if self.tcx.sess.is_nightly_build() && is_const_fn {
if self.tcx.sess.is_nightly_build() && matches!(is_constable, IsConstable::Fn|IsConstable::Ctor) {
err.help(
"create an inline `const` block, see RFC #2920 \
<https://github.com/rust-lang/rfcs/pull/2920> for more information",

View File

@ -599,7 +599,7 @@ fn build_module_items(
let prim_ty = clean::PrimitiveType::from(p);
items.push(clean::Item {
name: None,
attrs: Box::new(clean::Attributes::default()),
attrs: Box::default(),
// We can use the item's `DefId` directly since the only information ever used
// from it is `DefId.krate`.
item_id: ItemId::DefId(did),

View File

@ -1327,6 +1327,7 @@ impl WherePredicate {
pub(crate) enum GenericParamDefKind {
Lifetime { outlives: ThinVec<Lifetime> },
Type { did: DefId, bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
// Option<Box<String>> makes this type smaller than `Option<String>` would.
Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool },
}

View File

@ -588,7 +588,7 @@ pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool {
/// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
pub(crate) const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
pub(crate) static DOC_CHANNEL: Lazy<&'static str> =
Lazy::new(|| DOC_RUST_LANG_ORG_CHANNEL.rsplit("/").filter(|c| !c.is_empty()).next().unwrap());
Lazy::new(|| DOC_RUST_LANG_ORG_CHANNEL.rsplit('/').filter(|c| !c.is_empty()).next().unwrap());
/// Render a sequence of macro arms in a format suitable for displaying to the user
/// as part of an item declaration.

View File

@ -356,15 +356,12 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
let content = format!(
"<h1>List of all crates</h1><ul class=\"all-items\">{}</ul>",
krates
.iter()
.map(|s| {
format!(
"<li><a href=\"{trailing_slash}index.html\">{s}</a></li>",
trailing_slash = ensure_trailing_slash(s),
)
})
.collect::<String>()
krates.iter().format_with("", |k, f| {
f(&format_args!(
"<li><a href=\"{trailing_slash}index.html\">{k}</a></li>",
trailing_slash = ensure_trailing_slash(k),
))
})
);
let v = layout::render(&shared.layout, &page, "", content, &shared.style_files);
shared.fs.write(dst, v)?;

View File

@ -87,7 +87,7 @@ fn check_redundant_explicit_link<'md>(
let link_data = collect_link_data(&mut offset_iter);
if let Some(resolvable_link) = link_data.resolvable_link.as_ref() {
if &link_data.display_link.replace("`", "") != resolvable_link {
if &link_data.display_link.replace('`', "") != resolvable_link {
// Skips if display link does not match to actual
// resolvable link, usually happens if display link
// has several segments, e.g.

View File

@ -6,13 +6,17 @@ LL | let _: [Option<Bar>; 2] = [no_copy(); 2];
|
= note: required for `Option<Bar>` to implement `Copy`
= note: the `Copy` trait is required because this value will be copied for each element of the array
= help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
= help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
help: consider annotating `Bar` with `#[derive(Copy)]`
|
LL + #[derive(Copy)]
LL | struct Bar;
|
help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position
|
LL ~ const ARRAY_REPEAT_VALUE: Option<Bar> = no_copy();
LL ~ let _: [Option<Bar>; 2] = [ARRAY_REPEAT_VALUE; 2];
|
error: aborting due to previous error

View File

@ -10,9 +10,13 @@ note: required for `Foo<String>` to implement `Copy`
LL | #[derive(Copy, Clone)]
| ^^^^ unsatisfied trait bound introduced in this `derive` macro
= note: the `Copy` trait is required because this value will be copied for each element of the array
= help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
= help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position
|
LL ~ const ARRAY_REPEAT_VALUE: Foo<String> = Foo(String::new());
LL ~ [ARRAY_REPEAT_VALUE; 4];
|
error: aborting due to previous error

View File

@ -1,7 +1,11 @@
static _MAYBE_STRINGS: [Option<String>; 5] = [None; 5];
//~^ ERROR the trait bound `String: Copy` is not satisfied
fn main() {
// should hint to create an inline `const` block
// or to create a new `const` item
let strings: [String; 5] = [String::new(); 5];
let _strings: [String; 5] = [String::new(); 5];
//~^ ERROR the trait bound `String: Copy` is not satisfied
let _maybe_strings: [Option<String>; 5] = [None; 5];
//~^ ERROR the trait bound `String: Copy` is not satisfied
println!("{:?}", strings);
}

View File

@ -1,13 +1,47 @@
error[E0277]: the trait bound `String: Copy` is not satisfied
--> $DIR/const-fn-in-vec.rs:4:33
--> $DIR/const-fn-in-vec.rs:1:47
|
LL | let strings: [String; 5] = [String::new(); 5];
| ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
LL | static _MAYBE_STRINGS: [Option<String>; 5] = [None; 5];
| ^^^^ the trait `Copy` is not implemented for `String`
|
= note: required for `Option<String>` to implement `Copy`
= note: the `Copy` trait is required because this value will be copied for each element of the array
= help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
help: consider creating a new `const` item and initializing it with the result of the constructor to be used in the repeat position
|
LL + const ARRAY_REPEAT_VALUE: Option<String> = None;
LL ~ static _MAYBE_STRINGS: [Option<String>; 5] = [ARRAY_REPEAT_VALUE; 5];
|
error[E0277]: the trait bound `String: Copy` is not satisfied
--> $DIR/const-fn-in-vec.rs:7:34
|
LL | let _strings: [String; 5] = [String::new(); 5];
| ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
= note: the `Copy` trait is required because this value will be copied for each element of the array
= help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
= help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position
|
LL ~ const ARRAY_REPEAT_VALUE: String = String::new();
LL ~ let _strings: [String; 5] = [ARRAY_REPEAT_VALUE; 5];
|
error: aborting due to previous error
error[E0277]: the trait bound `String: Copy` is not satisfied
--> $DIR/const-fn-in-vec.rs:9:48
|
LL | let _maybe_strings: [Option<String>; 5] = [None; 5];
| ^^^^ the trait `Copy` is not implemented for `String`
|
= note: required for `Option<String>` to implement `Copy`
= note: the `Copy` trait is required because this value will be copied for each element of the array
= help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
help: consider creating a new `const` item and initializing it with the result of the constructor to be used in the repeat position
|
LL ~ const ARRAY_REPEAT_VALUE: Option<String> = None;
LL ~ let _maybe_strings: [Option<String>; 5] = [ARRAY_REPEAT_VALUE; 5];
|
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -29,10 +29,10 @@ LL | fn foo(&self) {}
| ^^^^^^^^^^^^^
help: use fully-qualified syntax to disambiguate
|
LL | <T as A>::foo(&s);
| ~~~~~~~~~~
LL | <T as B>::foo(&s);
| ~~~~~~~~~~
LL | A::foo(&s);
| ~~~
LL | B::foo(&s);
| ~~~
error[E0034]: multiple applicable items in scope
--> $DIR/disambiguate-multiple-blanket-impl.rs:33:8
@ -52,9 +52,9 @@ LL | const CONST: usize = 2;
| ^^^^^^^^^^^^^^^^^^
help: use fully-qualified syntax to disambiguate
|
LL | <T as A>::CONST;
LL | <S as A>::CONST;
| ~~~~~~~~~~
LL | <T as B>::CONST;
LL | <S as B>::CONST;
| ~~~~~~~~~~
error: aborting due to 3 previous errors

View File

@ -29,10 +29,10 @@ LL | fn foo(&self) {}
| ^^^^^^^^^^^^^
help: use fully-qualified syntax to disambiguate
|
LL | <S as A>::foo(&s);
| ~~~~~~~~~~
LL | <S as B>::foo(&s);
| ~~~~~~~~~~
LL | A::foo(&s);
| ~~~
LL | B::foo(&s);
| ~~~
error[E0034]: multiple applicable items in scope
--> $DIR/disambiguate-multiple-impl.rs:34:16

View File

@ -37,12 +37,12 @@ LL | fn foo(&self);
| ^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL | A::foo(t);
| ~~~~~~~~~
LL | A::foo(&t);
| ~~~~~~~~~~
help: disambiguate the method for candidate #2
|
LL | B::foo(t);
| ~~~~~~~~~
LL | B::foo(&t);
| ~~~~~~~~~~
error[E0034]: multiple applicable items in scope
--> $DIR/disambiguate-multiple-trait-2.rs:20:16
@ -62,10 +62,10 @@ LL | const CONST: usize;
| ^^^^^^^^^^^^^^^^^^
help: use fully-qualified syntax to disambiguate
|
LL | let _ = A::CONST;
| ~~~
LL | let _ = B::CONST;
| ~~~
LL | let _ = <T as A>::CONST;
| ~~~~~~~~~~
LL | let _ = <T as B>::CONST;
| ~~~~~~~~~~
error[E0223]: ambiguous associated type
--> $DIR/disambiguate-multiple-trait-2.rs:52:12
@ -98,10 +98,10 @@ LL | fn foo(&self) {}
| ^^^^^^^^^^^^^
help: use fully-qualified syntax to disambiguate
|
LL | <T as A>::foo(&s);
| ~~~~~~~~~~
LL | <T as B>::foo(&s);
| ~~~~~~~~~~
LL | A::foo(&s);
| ~~~
LL | B::foo(&s);
| ~~~
error[E0034]: multiple applicable items in scope
--> $DIR/disambiguate-multiple-trait-2.rs:49:16
@ -121,9 +121,9 @@ LL | const CONST: usize = 1;
| ^^^^^^^^^^^^^^^^^^
help: use fully-qualified syntax to disambiguate
|
LL | let _ = <T as A>::CONST;
LL | let _ = <S as A>::CONST;
| ~~~~~~~~~~
LL | let _ = <T as B>::CONST;
LL | let _ = <S as B>::CONST;
| ~~~~~~~~~~
error: aborting due to 6 previous errors

View File

@ -29,10 +29,10 @@ LL | fn foo(&self) {}
| ^^^^^^^^^^^^^
help: use fully-qualified syntax to disambiguate
|
LL | <T as A>::foo(&s);
| ~~~~~~~~~~
LL | <T as B>::foo(&s);
| ~~~~~~~~~~
LL | A::foo(&s);
| ~~~
LL | B::foo(&s);
| ~~~
error[E0034]: multiple applicable items in scope
--> $DIR/disambiguate-multiple-trait.rs:27:16
@ -52,9 +52,9 @@ LL | const CONST: usize = 2;
| ^^^^^^^^^^^^^^^^^^
help: use fully-qualified syntax to disambiguate
|
LL | let _ = <T as A>::CONST;
LL | let _ = <S as A>::CONST;
| ~~~~~~~~~~
LL | let _ = <T as B>::CONST;
LL | let _ = <S as B>::CONST;
| ~~~~~~~~~~
error: aborting due to 3 previous errors

View File

@ -16,12 +16,12 @@ LL | trait B { fn foo(&self); }
| ^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL | A::foo(t);
| ~~~~~~~~~
LL | A::foo(&t);
| ~~~~~~~~~~
help: disambiguate the method for candidate #2
|
LL | B::foo(t);
| ~~~~~~~~~
LL | B::foo(&t);
| ~~~~~~~~~~
error: aborting due to previous error

View File

@ -54,8 +54,8 @@ LL | let z = NuisanceFoo::foo(x);
| ~~~~~~~~~~~~~~~~~~~
help: disambiguate the method for candidate #3
|
LL | let z = FinalFoo::foo(x);
| ~~~~~~~~~~~~~~~~
LL | let z = FinalFoo::foo(&x);
| ~~~~~~~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:139:24

View File

@ -16,12 +16,12 @@ LL | fn foo(&mut self) {}
| ^^^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
LL | A::foo(&a)
| ~~~~~~~~~~
LL | A::foo(&mut a)
| ~~~~~~~~~~~~~~
help: disambiguate the method for candidate #2
|
LL | B::foo(&a)
| ~~~~~~~~~~
LL | B::foo(&mut a)
| ~~~~~~~~~~~~~~
error[E0034]: multiple applicable items in scope
--> $DIR/issue-37767.rs:22:7