Skip to content

Commit

Permalink
Auto merge of rust-lang#129143 - workingjubilee:rollup-h0hzumu, r=wor…
Browse files Browse the repository at this point in the history
…kingjubilee

Rollup of 9 pull requests

Successful merges:

 - rust-lang#128064 (Improve docs for Waker::noop and LocalWaker::noop)
 - rust-lang#128922 (rust-analyzer: use in-tree `pattern_analysis` crate)
 - rust-lang#128965 (Remove `print::Pat` from the printing of `WitnessPat`)
 - rust-lang#129018 (Migrate `rlib-format-packed-bundled-libs` and `native-link-modifier-bundle` `run-make` tests to rmake)
 - rust-lang#129037 (Port `run-make/libtest-json` and `run-make/libtest-junit` to rmake)
 - rust-lang#129078 (`ParamEnvAnd::fully_perform`: we have an `ocx`, use it)
 - rust-lang#129110 (Add a comment explaining the return type of `Ty::kind`.)
 - rust-lang#129111 (Port the `sysroot-crates-are-unstable` Python script to rmake)
 - rust-lang#129135 (crashes: more tests)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Aug 16, 2024
2 parents be0ea0c + e463490 commit 69e36d6
Show file tree
Hide file tree
Showing 29 changed files with 564 additions and 350 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {

/// Type utilities
impl<'tcx> Ty<'tcx> {
// It would be nicer if this returned the value instead of a reference,
// like how `Predicate::kind` and `Region::kind` do. (It would result in
// many fewer subsequent dereferences.) But that gives a small but
// noticeable performance hit. See #126069 for details.
#[inline(always)]
pub fn kind(self) -> &'tcx TyKind<'tcx> {
self.0.0
Expand Down
83 changes: 45 additions & 38 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,17 +774,16 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
}
}

/// Convert to a [`print::Pat`] for diagnostic purposes.
fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> print::Pat<'tcx> {
use print::{Pat, PatKind};
/// Prints an [`IntRange`] to a string for diagnostic purposes.
fn print_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> String {
use MaybeInfiniteInt::*;
let cx = self;
let kind = if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
PatKind::Wild
if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
"_".to_string()
} else if range.is_singleton() {
let lo = cx.hoist_pat_range_bdy(range.lo, ty);
let value = lo.as_finite().unwrap();
PatKind::Constant { value }
value.to_string()
} else {
// We convert to an inclusive range for diagnostics.
let mut end = rustc_hir::RangeEnd::Included;
Expand All @@ -807,32 +806,24 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
range.hi
};
let hi = cx.hoist_pat_range_bdy(hi, ty);
PatKind::Range(Box::new(PatRange { lo, hi, end, ty: ty.inner() }))
};

Pat { ty: ty.inner(), kind }
PatRange { lo, hi, end, ty: ty.inner() }.to_string()
}
}

/// Prints a [`WitnessPat`] to an owned string, for diagnostic purposes.
///
/// This panics for patterns that don't appear in diagnostics, like float ranges.
pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
// This works by converting the witness pattern to a `print::Pat`
// and then printing that, but callers don't need to know that.
self.hoist_witness_pat(pat).to_string()
}

/// Convert to a [`print::Pat`] for diagnostic purposes. This panics for patterns that don't
/// appear in diagnostics, like float ranges.
fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> {
use print::{FieldPat, Pat, PatKind};
let cx = self;
let hoist = |p| Box::new(cx.hoist_witness_pat(p));
let kind = match pat.ctor() {
Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
IntRange(range) => return self.hoist_pat_range(range, *pat.ty()),
let print = |p| cx.print_witness_pat(p);
match pat.ctor() {
Bool(b) => b.to_string(),
Str(s) => s.to_string(),
IntRange(range) => return self.print_pat_range(range, *pat.ty()),
Struct if pat.ty().is_box() => {
// Outside of the `alloc` crate, the only way to create a struct pattern
// of type `Box` is to use a `box` pattern via #[feature(box_patterns)].
PatKind::Box { subpattern: hoist(&pat.fields[0]) }
format!("box {}", print(&pat.fields[0]))
}
Struct | Variant(_) | UnionField => {
let enum_info = match *pat.ty().kind() {
Expand All @@ -847,12 +838,29 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
let subpatterns = pat
.iter_fields()
.enumerate()
.map(|(i, pat)| FieldPat { field: FieldIdx::new(i), pattern: hoist(pat) })
.map(|(i, pat)| print::FieldPat {
field: FieldIdx::new(i),
pattern: print(pat),
is_wildcard: would_print_as_wildcard(cx.tcx, pat),
})
.collect::<Vec<_>>();

PatKind::StructLike { enum_info, subpatterns }
let mut s = String::new();
print::write_struct_like(
&mut s,
self.tcx,
pat.ty().inner(),
&enum_info,
&subpatterns,
)
.unwrap();
s
}
Ref => {
let mut s = String::new();
print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap();
s
}
Ref => PatKind::Deref { subpattern: hoist(&pat.fields[0]) },
Slice(slice) => {
let (prefix_len, has_dot_dot) = match slice.kind {
SliceKind::FixedLen(len) => (len, false),
Expand All @@ -879,24 +887,23 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
}
}

let prefix = prefix.iter().map(hoist).collect();
let suffix = suffix.iter().map(hoist).collect();
let prefix = prefix.iter().map(print).collect::<Vec<_>>();
let suffix = suffix.iter().map(print).collect::<Vec<_>>();

PatKind::Slice { prefix, has_dot_dot, suffix }
let mut s = String::new();
print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap();
s
}
&Str(value) => PatKind::Constant { value },
Never if self.tcx.features().never_patterns => PatKind::Never,
Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild,
Never if self.tcx.features().never_patterns => "!".to_string(),
Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(),
Missing { .. } => bug!(
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
`Missing` should have been processed in `apply_constructors`"
),
F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => {
bug!("can't convert to pattern: {:?}", pat)
}
};

Pat { ty: pat.ty().inner(), kind }
}
}
}

Expand Down Expand Up @@ -972,7 +979,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
overlaps_on: IntRange,
overlaps_with: &[&crate::pat::DeconstructedPat<Self>],
) {
let overlap_as_pat = self.hoist_pat_range(&overlaps_on, *pat.ty());
let overlap_as_pat = self.print_pat_range(&overlaps_on, *pat.ty());
let overlaps: Vec<_> = overlaps_with
.iter()
.map(|pat| pat.data().span)
Expand Down Expand Up @@ -1012,7 +1019,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
suggested_range.end = rustc_hir::RangeEnd::Included;
suggested_range.to_string()
};
let gap_as_pat = self.hoist_pat_range(&gap, *pat.ty());
let gap_as_pat = self.print_pat_range(&gap, *pat.ty());
if gapped_with.is_empty() {
// If `gapped_with` is empty, `gap == T::MAX`.
self.tcx.emit_node_span_lint(
Expand Down
89 changes: 15 additions & 74 deletions compiler/rustc_pattern_analysis/src/rustc/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,75 +11,16 @@

use std::fmt;

use rustc_middle::thir::PatRange;
use rustc_middle::bug;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
use rustc_middle::{bug, mir};
use rustc_span::sym;
use rustc_target::abi::{FieldIdx, VariantIdx};

#[derive(Clone, Debug)]
pub(crate) struct FieldPat<'tcx> {
pub(crate) struct FieldPat {
pub(crate) field: FieldIdx,
pub(crate) pattern: Box<Pat<'tcx>>,
}

#[derive(Clone, Debug)]
pub(crate) struct Pat<'tcx> {
pub(crate) ty: Ty<'tcx>,
pub(crate) kind: PatKind<'tcx>,
}

#[derive(Clone, Debug)]
pub(crate) enum PatKind<'tcx> {
Wild,

StructLike {
enum_info: EnumInfo<'tcx>,
subpatterns: Vec<FieldPat<'tcx>>,
},

Box {
subpattern: Box<Pat<'tcx>>,
},

Deref {
subpattern: Box<Pat<'tcx>>,
},

Constant {
value: mir::Const<'tcx>,
},

Range(Box<PatRange<'tcx>>),

Slice {
prefix: Box<[Box<Pat<'tcx>>]>,
/// True if this slice-like pattern should include a `..` between the
/// prefix and suffix.
has_dot_dot: bool,
suffix: Box<[Box<Pat<'tcx>>]>,
},

Never,
}

impl<'tcx> fmt::Display for Pat<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
PatKind::Wild => write!(f, "_"),
PatKind::Never => write!(f, "!"),
PatKind::Box { ref subpattern } => write!(f, "box {subpattern}"),
PatKind::StructLike { ref enum_info, ref subpatterns } => {
ty::tls::with(|tcx| write_struct_like(f, tcx, self.ty, enum_info, subpatterns))
}
PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern),
PatKind::Constant { value } => write!(f, "{value}"),
PatKind::Range(ref range) => write!(f, "{range}"),
PatKind::Slice { ref prefix, has_dot_dot, ref suffix } => {
write_slice_like(f, prefix, has_dot_dot, suffix)
}
}
}
pub(crate) pattern: String,
pub(crate) is_wildcard: bool,
}

/// Returns a closure that will return `""` when called the first time,
Expand All @@ -103,12 +44,12 @@ pub(crate) enum EnumInfo<'tcx> {
NotEnum,
}

fn write_struct_like<'tcx>(
pub(crate) fn write_struct_like<'tcx>(
f: &mut impl fmt::Write,
tcx: TyCtxt<'_>,
ty: Ty<'tcx>,
enum_info: &EnumInfo<'tcx>,
subpatterns: &[FieldPat<'tcx>],
subpatterns: &[FieldPat],
) -> fmt::Result {
let variant_and_name = match *enum_info {
EnumInfo::Enum { adt_def, variant_index } => {
Expand Down Expand Up @@ -139,12 +80,12 @@ fn write_struct_like<'tcx>(
write!(f, " {{ ")?;

let mut printed = 0;
for p in subpatterns {
if let PatKind::Wild = p.pattern.kind {
for &FieldPat { field, ref pattern, is_wildcard } in subpatterns {
if is_wildcard {
continue;
}
let name = variant.fields[p.field].name;
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
let field_name = variant.fields[field].name;
write!(f, "{}{field_name}: {pattern}", start_or_comma())?;
printed += 1;
}

Expand Down Expand Up @@ -184,10 +125,10 @@ fn write_struct_like<'tcx>(
Ok(())
}

fn write_ref_like<'tcx>(
pub(crate) fn write_ref_like<'tcx>(
f: &mut impl fmt::Write,
ty: Ty<'tcx>,
subpattern: &Pat<'tcx>,
subpattern: &str,
) -> fmt::Result {
match ty.kind() {
ty::Ref(_, _, mutbl) => {
Expand All @@ -198,11 +139,11 @@ fn write_ref_like<'tcx>(
write!(f, "{subpattern}")
}

fn write_slice_like<'tcx>(
pub(crate) fn write_slice_like(
f: &mut impl fmt::Write,
prefix: &[Box<Pat<'tcx>>],
prefix: &[String],
has_dot_dot: bool,
suffix: &[Box<Pat<'tcx>>],
suffix: &[String],
) -> fmt::Result {
let mut start_or_comma = start_or_comma();
write!(f, "[")?;
Expand Down
38 changes: 3 additions & 35 deletions compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,44 +168,12 @@ where
// collecting region constraints via `region_constraints`.
let (mut output, _) = scrape_region_constraints(
infcx,
|_ocx| {
let (output, ei, mut obligations, _) =
|ocx| {
let (output, ei, obligations, _) =
Q::fully_perform_into(self, infcx, &mut region_constraints, span)?;
error_info = ei;

// Typically, instantiating NLL query results does not
// create obligations. However, in some cases there
// are unresolved type variables, and unify them *can*
// create obligations. In that case, we have to go
// fulfill them. We do this via a (recursive) query.
while !obligations.is_empty() {
trace!("{:#?}", obligations);
let mut progress = false;
for obligation in std::mem::take(&mut obligations) {
let obligation = infcx.resolve_vars_if_possible(obligation);
match ProvePredicate::fully_perform_into(
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
infcx,
&mut region_constraints,
span,
) {
Ok(((), _, new, certainty)) => {
obligations.extend(new);
progress = true;
if let Certainty::Ambiguous = certainty {
obligations.push(obligation);
}
}
Err(_) => obligations.push(obligation),
}
}
if !progress {
infcx.dcx().span_bug(
span,
format!("ambiguity processing {obligations:?} from {self:?}"),
);
}
}
ocx.register_obligations(obligations);
Ok(output)
},
"fully_perform",
Expand Down
20 changes: 19 additions & 1 deletion library/core/src/task/wake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,10 +530,18 @@ impl Waker {

/// Returns a reference to a `Waker` that does nothing when used.
///
// Note! Much of the documentation for this method is duplicated
// in the docs for `LocalWaker::noop`.
// If you edit it, consider editing the other copy too.
//
/// This is mostly useful for writing tests that need a [`Context`] to poll
/// some futures, but are not expecting those futures to wake the waker or
/// do not need to do anything specific if it happens.
///
/// More generally, using `Waker::noop()` to poll a future
/// means discarding the notification of when the future should be polled again.
/// So it should only be used when such a notification will not be needed to make progress.
///
/// If an owned `Waker` is needed, `clone()` this one.
///
/// # Examples
Expand Down Expand Up @@ -783,12 +791,22 @@ impl LocalWaker {
Self { waker }
}

/// Creates a new `LocalWaker` that does nothing when `wake` is called.
/// Returns a reference to a `LocalWaker` that does nothing when used.
///
// Note! Much of the documentation for this method is duplicated
// in the docs for `Waker::noop`.
// If you edit it, consider editing the other copy too.
//
/// This is mostly useful for writing tests that need a [`Context`] to poll
/// some futures, but are not expecting those futures to wake the waker or
/// do not need to do anything specific if it happens.
///
/// More generally, using `LocalWaker::noop()` to poll a future
/// means discarding the notification of when the future should be polled again,
/// So it should only be used when such a notification will not be needed to make progress.
///
/// If an owned `LocalWaker` is needed, `clone()` this one.
///
/// # Examples
///
/// ```
Expand Down
Loading

0 comments on commit 69e36d6

Please sign in to comment.