Skip to content

Commit

Permalink
Auto merge of rust-lang#130722 - matthiaskrgr:rollup-ocqdu4y, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#122565 (Try to write the panic message with a single `write_all` call)
 - rust-lang#129550 (Add str.as_str() for easy Deref to string slices)
 - rust-lang#130659 (Support `char::encode_utf16` in const scenarios.)
 - rust-lang#130705 (No longer mark RTN as incomplete)
 - rust-lang#130712 (Don't call `ty::Const::normalize` in error reporting)
 - rust-lang#130713 (Mark `u8::make_ascii_uppercase` and `u8::make_ascii_lowercase` as const.)
 - rust-lang#130714 (Introduce `structurally_normalize_const`, use it in `rustc_hir_typeck`)
 - rust-lang#130715 (Replace calls to `ty::Const::{try_}eval` in mir build/pattern analysis)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Sep 22, 2024
2 parents 6c6d210 + 4217792 commit 0f1efaf
Show file tree
Hide file tree
Showing 204 changed files with 609 additions and 766 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ declare_features! (
/// be used to describe E or vise-versa.
(unstable, result_ffi_guarantees, "1.80.0", Some(110503)),
/// Allows bounding the return type of AFIT/RPITIT.
(incomplete, return_type_notation, "1.70.0", Some(109417)),
(unstable, return_type_notation, "1.70.0", Some(109417)),
/// Allows `extern "rust-cold"`.
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
/// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics
Expand Down
13 changes: 10 additions & 3 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1668,10 +1668,17 @@ pub enum ArrayLen<'hir> {
}

impl ArrayLen<'_> {
pub fn hir_id(&self) -> HirId {
pub fn span(self) -> Span {
match self {
ArrayLen::Infer(arg) => arg.span,
ArrayLen::Body(body) => body.span(),
}
}

pub fn hir_id(self) -> HirId {
match self {
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(ConstArg { hir_id, .. }) => {
*hir_id
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(&ConstArg { hir_id, .. }) => {
hir_id
}
}
}
Expand Down
66 changes: 35 additions & 31 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1491,8 +1491,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx;
let count = self.lower_array_length(count);
if let Some(count) = count.try_eval_target_usize(tcx, self.param_env) {
let count_span = count.span();
let count = self.try_structurally_resolve_const(count_span, self.lower_array_length(count));

if let Some(count) = count.try_to_target_usize(tcx) {
self.suggest_array_len(expr, count);
}

Expand Down Expand Up @@ -1520,19 +1522,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Ty::new_error(tcx, guar);
}

self.check_repeat_element_needs_copy_bound(element, count, element_ty);
// 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, or unevaluated.
// FIXME(min_const_generic_exprs): We could perhaps defer this check so that
// we don't require `<?0t as Tr>::CONST` doesn't unnecessarily require `Copy`.
if count.try_to_target_usize(tcx).is_none_or(|x| x > 1) {
self.enforce_repeat_element_needs_copy_bound(element, element_ty);
}

let ty = Ty::new_array_with_const_len(tcx, t, count);

self.register_wf_obligation(ty.into(), expr.span, ObligationCauseCode::WellFormed(None));

ty
}

fn check_repeat_element_needs_copy_bound(
/// Requires that `element_ty` is `Copy` (unless it's a const expression itself).
fn enforce_repeat_element_needs_copy_bound(
&self,
element: &hir::Expr<'_>,
count: ty::Const<'tcx>,
element_ty: Ty<'tcx>,
) {
let tcx = self.tcx;
Expand Down Expand Up @@ -1565,27 +1572,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => 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).is_none_or(|len| len > 1) {
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
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);
}
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
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);
}

fn check_expr_tuple(
Expand Down Expand Up @@ -2800,9 +2803,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
len: ty::Const<'tcx>,
) {
err.span_label(field.span, "unknown field");
if let (Some(len), Ok(user_index)) =
(len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::<u64>())
{
if let (Some(len), Ok(user_index)) = (
self.try_structurally_resolve_const(base.span, len).try_to_target_usize(self.tcx),
field.as_str().parse::<u64>(),
) {
let help = "instead of using tuple indexing, use array indexing";
let applicability = if len < user_index {
Applicability::MachineApplicable
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

#[instrument(level = "debug", skip(self, sp), ret)]
pub fn try_structurally_resolve_const(&self, sp: Span, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
// FIXME(min_const_generic_exprs): We could process obligations here if `ct` is a var.

if self.next_trait_solver()
&& let ty::ConstKind::Unevaluated(..) = ct.kind()
{
// We need to use a separate variable here as otherwise the temporary for
// `self.fulfillment_cx.borrow_mut()` is alive in the `Err` branch, resulting
// in a reentrant borrow, causing an ICE.
let result = self
.at(&self.misc(sp), self.param_env)
.structurally_normalize_const(ct, &mut **self.fulfillment_cx.borrow_mut());
match result {
Ok(normalized_ct) => normalized_ct,
Err(errors) => {
let guar = self.err_ctxt().report_fulfillment_errors(errors);
return ty::Const::new_error(self.tcx, guar);
}
}
} else if self.tcx.features().generic_const_exprs {
ct.normalize(self.tcx, self.param_env)
} else {
ct
}
}

/// Resolves `ty` by a single level if `ty` is a type variable.
///
/// When the new solver is enabled, this will also attempt to normalize
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1502,7 +1502,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Create an dummy type `&[_]` so that both &[] and `&Vec<T>` can coerce to it.
let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind()
&& let ty::Infer(_) = elem_ty.kind()
&& size.try_eval_target_usize(self.tcx, self.param_env) == Some(0)
&& self
.try_structurally_resolve_const(provided_expr.span, *size)
.try_to_target_usize(self.tcx)
== Some(0)
{
let slice = Ty::new_slice(self.tcx, *elem_ty);
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice)
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir_typeck/src/intrinsicck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
Ok(SizeSkeleton::Generic(size)) => {
if let Some(size) = size.try_eval_target_usize(tcx, self.param_env) {
if let Some(size) =
self.try_structurally_resolve_const(span, size).try_to_target_usize(tcx)
{
format!("{size} bytes")
} else {
format!("generic size {size}")
Expand Down
15 changes: 1 addition & 14 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1721,20 +1721,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
let msg = "remove this method call";
let mut fallback_span = true;
if let SelfSource::MethodCall(expr) = source {
let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));
if let Some(span) = call_expr.span.trim_start(expr.span) {
err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
fallback_span = false;
}
}
if fallback_span {
err.span_label(span, msg);
}
} else if let Some(similar_candidate) = similar_candidate {
if let Some(similar_candidate) = similar_candidate {
// Don't emit a suggestion if we found an actual method
// that had unsatisfied trait bounds
if unsatisfied_predicates.is_empty()
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2412,7 +2412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
len: ty::Const<'tcx>,
min_len: u64,
) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
let len = len.try_eval_target_usize(self.tcx, self.param_env);
let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);

let guar = if let Some(len) = len {
// Now we know the length...
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value))
}
ExprKind::Repeat { value, count } => {
if Some(0) == count.try_eval_target_usize(this.tcx, this.param_env) {
if Some(0) == count.try_to_target_usize(this.tcx) {
this.build_zero_repeat(block, value, scope, source_info)
} else {
let value_operand = unpack!(
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_mir_build/src/build/matches/match_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let tcx = self.tcx;
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
ty::Array(_, length) => (
length
.try_to_target_usize(tcx)
.expect("expected len of array pat to be definite"),
true,
),
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
}
} else {
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
// Fixed-length array, `[T; len]`.
ty::Array(_, len) => {
let len = len.eval_target_usize(self.tcx, self.param_env);
let len = len
.try_to_target_usize(self.tcx)
.expect("expected len of array pat to be definite");
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
PatKind::Array { prefix, slice, suffix }
}
Expand Down
11 changes: 7 additions & 4 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
ty::Array(sub_ty, len) => {
// We treat arrays of a constant but unknown length like slices.
ConstructorSet::Slice {
array_len: len.try_eval_target_usize(cx.tcx, cx.param_env).map(|l| l as usize),
array_len: len.try_to_target_usize(cx.tcx).map(|l| l as usize),
subtype_is_empty: cx.is_uninhabited(*sub_ty),
}
}
Expand Down Expand Up @@ -685,9 +685,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
}
PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
let array_len = match ty.kind() {
ty::Array(_, length) => {
Some(length.eval_target_usize(cx.tcx, cx.param_env) as usize)
}
ty::Array(_, length) => Some(
length
.try_to_target_usize(cx.tcx)
.expect("expected len of array pat to be definite")
as usize,
),
ty::Slice(_) => None,
_ => span_bug!(pat.span, "bad ty {} for slice pattern", ty.inner()),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc_middle::traits::select::OverflowError;
use rustc_middle::traits::SignatureMismatchData;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{
with_forced_trimmed_paths, FmtPrinter, Print, PrintTraitPredicateExt as _,
PrintTraitRefExt as _,
Expand Down Expand Up @@ -1794,22 +1794,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return false;
}

let cand = self.resolve_vars_if_possible(impl_trait_ref).fold_with(
&mut BottomUpFolder {
tcx: self.tcx,
ty_op: |ty| ty,
lt_op: |lt| lt,
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
},
);
if cand.references_error() {
let impl_trait_ref = self.resolve_vars_if_possible(impl_trait_ref);
if impl_trait_ref.references_error() {
return false;
}
err.highlighted_help(vec![
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
StringPart::normal(format!(
"the trait `{}` ",
impl_trait_ref.print_trait_sugared()
)),
StringPart::highlighted("is"),
StringPart::normal(" implemented for `"),
StringPart::highlighted(cand.self_ty().to_string()),
StringPart::highlighted(impl_trait_ref.self_ty().to_string()),
StringPart::normal("`"),
]);

Expand Down Expand Up @@ -1921,15 +1917,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut impl_candidates: Vec<_> = impl_candidates
.iter()
.cloned()
.filter(|cand| !cand.trait_ref.references_error())
.map(|mut cand| {
// Fold the consts so that they shows up as, e.g., `10`
// instead of `core::::array::{impl#30}::{constant#0}`.
cand.trait_ref = cand.trait_ref.fold_with(&mut BottomUpFolder {
tcx: self.tcx,
ty_op: |ty| ty,
lt_op: |lt| lt,
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
});
// Normalize the trait ref in its *own* param-env so
// that consts are folded and any trivial projections
// are normalized.
cand.trait_ref = self
.tcx
.try_normalize_erasing_regions(
self.tcx.param_env(cand.impl_def_id),
cand.trait_ref,
)
.unwrap_or(cand.trait_ref);
cand
})
.collect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4621,7 +4621,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
format!("&{}{ty}", mutability.prefix_str())
}
}
ty::Array(ty, len) if let Some(len) = len.try_eval_target_usize(tcx, param_env) => {
ty::Array(ty, len) if let Some(len) = len.try_to_target_usize(tcx) => {
if len == 0 {
"[]".to_string()
} else if self.type_is_copy_modulo_regions(param_env, ty) || len == 1 {
Expand Down
40 changes: 40 additions & 0 deletions compiler/rustc_trait_selection/src/traits/structural_normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,44 @@ impl<'tcx> At<'_, 'tcx> {
Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
}
}

fn structurally_normalize_const<E: 'tcx>(
&self,
ct: ty::Const<'tcx>,
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
) -> Result<ty::Const<'tcx>, Vec<E>> {
assert!(!ct.is_ct_infer(), "should have resolved vars before calling");

if self.infcx.next_trait_solver() {
let ty::ConstKind::Unevaluated(..) = ct.kind() else {
return Ok(ct);
};

let new_infer_ct = self.infcx.next_const_var(self.cause.span);

// We simply emit an `alias-eq` goal here, since that will take care of
// normalizing the LHS of the projection until it is a rigid projection
// (or a not-yet-defined opaque in scope).
let obligation = Obligation::new(
self.infcx.tcx,
self.cause.clone(),
self.param_env,
ty::PredicateKind::AliasRelate(
ct.into(),
new_infer_ct.into(),
ty::AliasRelationDirection::Equate,
),
);

fulfill_cx.register_predicate_obligation(self.infcx, obligation);
let errors = fulfill_cx.select_where_possible(self.infcx);
if !errors.is_empty() {
return Err(errors);
}

Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
} else {
Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
}
}
}
Loading

0 comments on commit 0f1efaf

Please sign in to comment.