Auto merge of #120136 - matthiaskrgr:rollup-3zzb0z9, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #117561 (Stabilize `slice_first_last_chunk`) - #117662 ([rustdoc] Allows links in headings) - #119815 (Format sources into the error message when loading codegen backends) - #119835 (Exhaustiveness: simplify empty pattern logic) - #119984 (Change return type of unstable `Waker::noop()` from `Waker` to `&Waker`.) - #120009 (never_patterns: typecheck never patterns) - #120122 (Don't add needs-triage to A-diagnostics) - #120126 (Suggest `.swap()` when encountering conflicting borrows from `mem::swap` on a slice) - #120134 (Restrict access to the private field of newtype indexes) Failed merges: - #119968 (Remove unused/unnecessary features) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
128148d4cf
64 changed files with 745 additions and 593 deletions
|
@ -26,6 +26,7 @@ use rustc_span::hygiene::DesugaringKind;
|
|||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use std::iter;
|
||||
|
||||
|
@ -1304,14 +1305,96 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
place: Place<'tcx>,
|
||||
borrowed_place: Place<'tcx>,
|
||||
) {
|
||||
if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) =
|
||||
(&place.projection[..], &borrowed_place.projection[..])
|
||||
let tcx = self.infcx.tcx;
|
||||
let hir = tcx.hir();
|
||||
|
||||
if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)])
|
||||
| (
|
||||
[ProjectionElem::Deref, ProjectionElem::Index(index1)],
|
||||
[ProjectionElem::Deref, ProjectionElem::Index(index2)],
|
||||
) = (&place.projection[..], &borrowed_place.projection[..])
|
||||
{
|
||||
err.help(
|
||||
"consider using `.split_at_mut(position)` or similar method to obtain \
|
||||
two mutable non-overlapping sub-slices",
|
||||
)
|
||||
.help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
|
||||
let mut note_default_suggestion = || {
|
||||
err.help(
|
||||
"consider using `.split_at_mut(position)` or similar method to obtain \
|
||||
two mutable non-overlapping sub-slices",
|
||||
)
|
||||
.help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
|
||||
};
|
||||
|
||||
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let mut expr_finder =
|
||||
FindExprBySpan::new(self.body.local_decls[*index1].source_info.span);
|
||||
expr_finder.visit_expr(hir.body(body_id).value);
|
||||
let Some(index1) = expr_finder.result else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span);
|
||||
expr_finder.visit_expr(hir.body(body_id).value);
|
||||
let Some(index2) = expr_finder.result else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let sm = tcx.sess.source_map();
|
||||
|
||||
let Ok(index1_str) = sm.span_to_snippet(index1.span) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(index2_str) = sm.span_to_snippet(index2.span) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(object) = hir.parent_id_iter(index1.hir_id).find_map(|id| {
|
||||
if let hir::Node::Expr(expr) = tcx.hir_node(id)
|
||||
&& let hir::ExprKind::Index(obj, ..) = expr.kind
|
||||
{
|
||||
Some(obj)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok(obj_str) = sm.span_to_snippet(object.span) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(swap_call) = hir.parent_id_iter(object.hir_id).find_map(|id| {
|
||||
if let hir::Node::Expr(call) = tcx.hir_node(id)
|
||||
&& let hir::ExprKind::Call(callee, ..) = call.kind
|
||||
&& let hir::ExprKind::Path(qpath) = callee.kind
|
||||
&& let hir::QPath::Resolved(None, res) = qpath
|
||||
&& let hir::def::Res::Def(_, did) = res.res
|
||||
&& tcx.is_diagnostic_item(sym::mem_swap, did)
|
||||
{
|
||||
Some(call)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) else {
|
||||
note_default_suggestion();
|
||||
return;
|
||||
};
|
||||
|
||||
err.span_suggestion(
|
||||
swap_call.span,
|
||||
"use `.swap()` to swap elements at the specified indices instead",
|
||||
format!("{obj_str}.swap({index1_str}, {index2_str})"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -246,12 +246,12 @@ checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
|||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.4"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -19,7 +19,7 @@ gimli = { version = "0.28", default-features = false, features = ["write"]}
|
|||
object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
|
||||
indexmap = "2.0.0"
|
||||
libloading = { version = "0.7.3", optional = true }
|
||||
libloading = { version = "0.8.0", optional = true }
|
||||
smallvec = "1.8.1"
|
||||
|
||||
[patch.crates-io]
|
||||
|
|
|
@ -178,8 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let ty = match pat.kind {
|
||||
PatKind::Wild | PatKind::Err(_) => expected,
|
||||
// FIXME(never_patterns): check the type is uninhabited. If that is not possible within
|
||||
// typeck, do that in a later phase.
|
||||
// We allow any type here; we ensure that the type is uninhabited during match checking.
|
||||
PatKind::Never => expected,
|
||||
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
||||
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
||||
|
|
|
@ -104,7 +104,7 @@ impl Parse for Newtype {
|
|||
#gate_rustc_only
|
||||
impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name {
|
||||
fn encode(&self, e: &mut E) {
|
||||
e.emit_u32(self.private);
|
||||
e.emit_u32(self.as_u32());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ impl Parse for Newtype {
|
|||
#[inline]
|
||||
fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
|
||||
if #max_val < u32::MAX {
|
||||
l.map(|i| i.private).unwrap_or(#max_val+1) == r.map(|i| i.private).unwrap_or(#max_val+1)
|
||||
l.map(|i| i.as_u32()).unwrap_or(#max_val+1) == r.map(|i| i.as_u32()).unwrap_or(#max_val+1)
|
||||
} else {
|
||||
match (l, r) {
|
||||
(Some(l), Some(r)) => r == l,
|
||||
|
@ -188,7 +188,7 @@ impl Parse for Newtype {
|
|||
#[cfg_attr(#gate_rustc_only_cfg, rustc_layout_scalar_valid_range_end(#max))]
|
||||
#[cfg_attr(#gate_rustc_only_cfg, rustc_pass_by_value)]
|
||||
#vis struct #name {
|
||||
private: u32,
|
||||
private_use_as_methods_instead: u32,
|
||||
}
|
||||
|
||||
#(#consts)*
|
||||
|
@ -238,7 +238,7 @@ impl Parse for Newtype {
|
|||
/// Prefer using `from_u32`.
|
||||
#[inline]
|
||||
#vis const unsafe fn from_u32_unchecked(value: u32) -> Self {
|
||||
Self { private: value }
|
||||
Self { private_use_as_methods_instead: value }
|
||||
}
|
||||
|
||||
/// Extracts the value of this index as a `usize`.
|
||||
|
@ -250,7 +250,7 @@ impl Parse for Newtype {
|
|||
/// Extracts the value of this index as a `u32`.
|
||||
#[inline]
|
||||
#vis const fn as_u32(self) -> u32 {
|
||||
self.private
|
||||
self.private_use_as_methods_instead
|
||||
}
|
||||
|
||||
/// Extracts the value of this index as a `usize`.
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
libloading = "0.7.1"
|
||||
libloading = "0.8.0"
|
||||
rustc-rayon = { version = "0.5.0", optional = true }
|
||||
rustc-rayon-core = { version = "0.5.0", optional = true }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#![feature(box_patterns)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(error_iter)]
|
||||
#![feature(internal_output_capture)]
|
||||
#![feature(thread_spawn_unchecked)]
|
||||
#![feature(lazy_cell)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(thread_spawn_unchecked)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
|
|
|
@ -162,15 +162,21 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||
}
|
||||
|
||||
fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn {
|
||||
fn format_err(e: &(dyn std::error::Error + 'static)) -> String {
|
||||
e.sources().map(|e| format!(": {e}")).collect()
|
||||
}
|
||||
let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
|
||||
let err = format!("couldn't load codegen backend {path:?}: {err}");
|
||||
let err = format!("couldn't load codegen backend {path:?}{}", format_err(&err));
|
||||
early_dcx.early_fatal(err);
|
||||
});
|
||||
|
||||
let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
|
||||
.unwrap_or_else(|e| {
|
||||
let err = format!("couldn't load codegen backend: {e}");
|
||||
early_dcx.early_fatal(err);
|
||||
let e = format!(
|
||||
"`__rustc_codegen_backend` symbol lookup in the codegen backend failed{}",
|
||||
format_err(&e)
|
||||
);
|
||||
early_dcx.early_fatal(e);
|
||||
});
|
||||
|
||||
// Intentionally leak the dynamic library. We can't ever unload it
|
||||
|
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
libloading = "0.7.1"
|
||||
libloading = "0.8.0"
|
||||
odht = { version = "0.3.1", features = ["nightly"] }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_attr = { path = "../rustc_attr" }
|
||||
|
|
|
@ -234,6 +234,11 @@ mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsa
|
|||
|
||||
mir_build_non_const_path = runtime values cannot be referenced in patterns
|
||||
|
||||
mir_build_non_empty_never_pattern =
|
||||
mismatched types
|
||||
.label = a never pattern must be used on an uninhabited type
|
||||
.note = the matched value is of type `{$ty}`
|
||||
|
||||
mir_build_non_exhaustive_match_all_arms_guarded =
|
||||
match arms with guards don't count towards exhaustivity
|
||||
|
||||
|
|
|
@ -788,6 +788,16 @@ pub struct FloatPattern;
|
|||
#[diag(mir_build_pointer_pattern)]
|
||||
pub struct PointerPattern;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_non_empty_never_pattern)]
|
||||
#[note]
|
||||
pub struct NonEmptyNeverPattern<'tcx> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_indirect_structural_match)]
|
||||
#[note(mir_build_type_not_structural_tip)]
|
||||
|
|
|
@ -276,10 +276,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
|||
} else {
|
||||
// Check the pattern for some things unrelated to exhaustiveness.
|
||||
let refutable = if cx.refutable { Refutable } else { Irrefutable };
|
||||
let mut err = Ok(());
|
||||
pat.walk_always(|pat| {
|
||||
check_borrow_conflicts_in_at_patterns(self, pat);
|
||||
check_for_bindings_named_same_as_variants(self, pat, refutable);
|
||||
err = err.and(check_never_pattern(cx, pat));
|
||||
});
|
||||
err?;
|
||||
Ok(cx.pattern_arena.alloc(cx.lower_pat(pat)))
|
||||
}
|
||||
}
|
||||
|
@ -289,7 +292,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
|||
fn is_known_valid_scrutinee(&self, scrutinee: &Expr<'tcx>) -> bool {
|
||||
use ExprKind::*;
|
||||
match &scrutinee.kind {
|
||||
// Both pointers and references can validly point to a place with invalid data.
|
||||
// Pointers can validly point to a place with invalid data. It is undecided whether
|
||||
// references can too, so we conservatively assume they can.
|
||||
Deref { .. } => false,
|
||||
// Inherit validity of the parent place, unless the parent is an union.
|
||||
Field { lhs, .. } => {
|
||||
|
@ -811,6 +815,19 @@ fn check_for_bindings_named_same_as_variants(
|
|||
}
|
||||
}
|
||||
|
||||
/// Check that never patterns are only used on inhabited types.
|
||||
fn check_never_pattern<'tcx>(
|
||||
cx: &MatchCheckCtxt<'_, 'tcx>,
|
||||
pat: &Pat<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
if let PatKind::Never = pat.kind {
|
||||
if !cx.is_uninhabited(pat.ty) {
|
||||
return Err(cx.tcx.dcx().emit_err(NonEmptyNeverPattern { span: pat.span, ty: pat.ty }));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn report_irrefutable_let_patterns(
|
||||
tcx: TyCtxt<'_>,
|
||||
id: HirId,
|
||||
|
|
|
@ -861,12 +861,14 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
|
|||
/// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges
|
||||
/// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation
|
||||
/// and its invariants.
|
||||
#[instrument(level = "debug", skip(self, pcx, ctors), ret)]
|
||||
#[instrument(level = "debug", skip(self, ctors), ret)]
|
||||
pub(crate) fn split<'a>(
|
||||
&self,
|
||||
pcx: &PlaceCtxt<'a, Cx>,
|
||||
ctors: impl Iterator<Item = &'a Constructor<Cx>> + Clone,
|
||||
) -> SplitConstructorSet<Cx> {
|
||||
) -> SplitConstructorSet<Cx>
|
||||
where
|
||||
Cx: 'a,
|
||||
{
|
||||
let mut present: SmallVec<[_; 1]> = SmallVec::new();
|
||||
// Empty constructors found missing.
|
||||
let mut missing_empty = Vec::new();
|
||||
|
@ -1006,17 +1008,6 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
|
|||
}
|
||||
}
|
||||
|
||||
// We have now grouped all the constructors into 3 buckets: present, missing, missing_empty.
|
||||
// In the absence of the `exhaustive_patterns` feature however, we don't count nested empty
|
||||
// types as empty. Only non-nested `!` or `enum Foo {}` are considered empty.
|
||||
if !pcx.mcx.tycx.is_exhaustive_patterns_feature_on()
|
||||
&& !(pcx.is_scrutinee && matches!(self, Self::NoConstructors))
|
||||
{
|
||||
// Treat all missing constructors as nonempty.
|
||||
// This clears `missing_empty`.
|
||||
missing.append(&mut missing_empty);
|
||||
}
|
||||
|
||||
SplitConstructorSet { present, missing, missing_empty }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
|
|||
) -> Result<SplitConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
|
||||
let column_ctors = self.patterns.iter().map(|p| p.ctor());
|
||||
let ctors_for_ty = &pcx.ctors_for_ty()?;
|
||||
Ok(ctors_for_ty.split(pcx, column_ctors))
|
||||
Ok(ctors_for_ty.split(column_ctors))
|
||||
}
|
||||
|
||||
/// Does specialization: given a constructor, this takes the patterns from the column that match
|
||||
|
|
|
@ -737,15 +737,13 @@ pub(crate) struct PlaceCtxt<'a, Cx: TypeCx> {
|
|||
pub(crate) mcx: MatchCtxt<'a, Cx>,
|
||||
/// Type of the place under investigation.
|
||||
pub(crate) ty: Cx::Ty,
|
||||
/// Whether the place is the original scrutinee place, as opposed to a subplace of it.
|
||||
pub(crate) is_scrutinee: bool,
|
||||
}
|
||||
|
||||
impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
|
||||
/// A `PlaceCtxt` when code other than `is_useful` needs one.
|
||||
#[cfg_attr(not(feature = "rustc"), allow(dead_code))]
|
||||
pub(crate) fn new_dummy(mcx: MatchCtxt<'a, Cx>, ty: Cx::Ty) -> Self {
|
||||
PlaceCtxt { mcx, ty, is_scrutinee: false }
|
||||
PlaceCtxt { mcx, ty }
|
||||
}
|
||||
|
||||
pub(crate) fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize {
|
||||
|
@ -768,9 +766,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
|
|||
pub enum ValidityConstraint {
|
||||
ValidOnly,
|
||||
MaybeInvalid,
|
||||
/// Option for backwards compatibility: the place is not known to be valid but we allow omitting
|
||||
/// `useful && !reachable` arms anyway.
|
||||
MaybeInvalidButAllowOmittingArms,
|
||||
}
|
||||
|
||||
impl ValidityConstraint {
|
||||
|
@ -778,20 +773,9 @@ impl ValidityConstraint {
|
|||
if is_valid_only { ValidOnly } else { MaybeInvalid }
|
||||
}
|
||||
|
||||
fn allow_omitting_side_effecting_arms(self) -> Self {
|
||||
match self {
|
||||
MaybeInvalid | MaybeInvalidButAllowOmittingArms => MaybeInvalidButAllowOmittingArms,
|
||||
// There are no side-effecting empty arms here, nothing to do.
|
||||
ValidOnly => ValidOnly,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_known_valid(self) -> bool {
|
||||
matches!(self, ValidOnly)
|
||||
}
|
||||
fn allows_omitting_empty_arms(self) -> bool {
|
||||
matches!(self, ValidOnly | MaybeInvalidButAllowOmittingArms)
|
||||
}
|
||||
|
||||
/// If the place has validity given by `self` and we read that the value at the place has
|
||||
/// constructor `ctor`, this computes what we can assume about the validity of the constructor
|
||||
|
@ -814,7 +798,7 @@ impl fmt::Display for ValidityConstraint {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let s = match self {
|
||||
ValidOnly => "✓",
|
||||
MaybeInvalid | MaybeInvalidButAllowOmittingArms => "?",
|
||||
MaybeInvalid => "?",
|
||||
};
|
||||
write!(f, "{s}")
|
||||
}
|
||||
|
@ -1447,41 +1431,44 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
|||
};
|
||||
|
||||
debug!("ty: {ty:?}");
|
||||
let pcx = &PlaceCtxt { mcx, ty, is_scrutinee: is_top_level };
|
||||
let pcx = &PlaceCtxt { mcx, ty };
|
||||
let ctors_for_ty = pcx.ctors_for_ty()?;
|
||||
|
||||
// Whether the place/column we are inspecting is known to contain valid data.
|
||||
let place_validity = matrix.place_validity[0];
|
||||
// For backwards compability we allow omitting some empty arms that we ideally shouldn't.
|
||||
let place_validity = place_validity.allow_omitting_side_effecting_arms();
|
||||
// We treat match scrutinees of type `!` or `EmptyEnum` differently.
|
||||
let is_toplevel_exception =
|
||||
is_top_level && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
|
||||
// Whether empty patterns can be omitted for exhaustiveness.
|
||||
let can_omit_empty_arms = is_toplevel_exception || mcx.tycx.is_exhaustive_patterns_feature_on();
|
||||
// Whether empty patterns are counted as useful or not.
|
||||
let empty_arms_are_unreachable = place_validity.is_known_valid() && can_omit_empty_arms;
|
||||
|
||||
// Analyze the constructors present in this column.
|
||||
let ctors = matrix.heads().map(|p| p.ctor());
|
||||
let ctors_for_ty = pcx.ctors_for_ty()?;
|
||||
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
|
||||
let split_set = ctors_for_ty.split(pcx, ctors);
|
||||
let mut split_set = ctors_for_ty.split(ctors);
|
||||
let all_missing = split_set.present.is_empty();
|
||||
|
||||
// Build the set of constructors we will specialize with. It must cover the whole type.
|
||||
// We need to iterate over a full set of constructors, so we add `Missing` to represent the
|
||||
// missing ones. This is explained under "Constructor Splitting" at the top of this file.
|
||||
let mut split_ctors = split_set.present;
|
||||
if !split_set.missing.is_empty() {
|
||||
// We need to iterate over a full set of constructors, so we add `Missing` to represent the
|
||||
// missing ones. This is explained under "Constructor Splitting" at the top of this file.
|
||||
split_ctors.push(Constructor::Missing);
|
||||
} else if !split_set.missing_empty.is_empty() && !place_validity.is_known_valid() {
|
||||
// The missing empty constructors are reachable if the place can contain invalid data.
|
||||
if !(split_set.missing.is_empty()
|
||||
&& (split_set.missing_empty.is_empty() || empty_arms_are_unreachable))
|
||||
{
|
||||
split_ctors.push(Constructor::Missing);
|
||||
}
|
||||
|
||||
// Decide what constructors to report.
|
||||
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. });
|
||||
let always_report_all = is_top_level && !is_integers;
|
||||
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
|
||||
let report_individual_missing_ctors = always_report_all || !all_missing;
|
||||
// Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
|
||||
// split_ctors.contains(Missing)`. The converse usually holds except in the
|
||||
// `MaybeInvalidButAllowOmittingArms` backwards-compatibility case.
|
||||
// split_ctors.contains(Missing)`. The converse usually holds except when
|
||||
// `!place_validity.is_known_valid()`.
|
||||
let mut missing_ctors = split_set.missing;
|
||||
if !place_validity.allows_omitting_empty_arms() {
|
||||
missing_ctors.extend(split_set.missing_empty);
|
||||
if !can_omit_empty_arms {
|
||||
missing_ctors.append(&mut split_set.missing_empty);
|
||||
}
|
||||
|
||||
let mut ret = WitnessMatrix::empty();
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(ptr_sub_ptr)]
|
||||
#![feature(slice_first_last_chunk)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![allow(rustc::internal)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
|
|
|
@ -327,21 +327,21 @@ impl UniverseIndex {
|
|||
/// name the region `'a`, but that region was not nameable from
|
||||
/// `U` because it was not in scope there.
|
||||
pub fn next_universe(self) -> UniverseIndex {
|
||||
UniverseIndex::from_u32(self.private.checked_add(1).unwrap())
|
||||
UniverseIndex::from_u32(self.as_u32().checked_add(1).unwrap())
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` can name a name from `other` -- in other words,
|
||||
/// if the set of names in `self` is a superset of those in
|
||||
/// `other` (`self >= other`).
|
||||
pub fn can_name(self, other: UniverseIndex) -> bool {
|
||||
self.private >= other.private
|
||||
self >= other
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` cannot name some names from `other` -- in other
|
||||
/// words, if the set of names in `self` is a strict subset of
|
||||
/// those in `other` (`self < other`).
|
||||
pub fn cannot_name(self, other: UniverseIndex) -> bool {
|
||||
self.private < other.private
|
||||
self < other
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue