Auto merge of #120025 - matthiaskrgr:rollup-e9ai06k, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #118361 (stabilise bound_map) - #119816 (Define hidden types in confirmation) - #119900 (Inline `check_closure`, simplify `deduce_sig_from_projection`) - #119969 (Simplify `closure_env_ty` and `closure_env_param`) - #119990 (Add private `NonZero<T>` type alias.) - #119998 (Update books) - #120002 (Lint `overlapping_ranges_endpoints` directly instead of collecting into a Vec) - #120018 (Don't allow `.html` files in `tests/mir-opt/`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e64f8495e7
@ -668,7 +668,11 @@ fn compute_inputs_and_output(
|
||||
kind: ty::BrEnv,
|
||||
};
|
||||
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
|
||||
let closure_ty = tcx.closure_env_ty(def_id, args, env_region).unwrap();
|
||||
let closure_ty = tcx.closure_env_ty(
|
||||
Ty::new_closure(tcx, def_id, args),
|
||||
args.as_closure().kind(),
|
||||
env_region,
|
||||
);
|
||||
|
||||
// The "inputs" of the closure in the
|
||||
// signature appear as a tuple. The MIR side
|
||||
|
@ -14,7 +14,7 @@
|
||||
use rustc_middle::ty::GenericArgs;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits;
|
||||
use rustc_trait_selection::traits::error_reporting::ArgKind;
|
||||
@ -49,7 +49,9 @@ pub fn check_expr_closure(
|
||||
expr_span: Span,
|
||||
expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
trace!("decl = {:#?}", closure.fn_decl);
|
||||
let tcx = self.tcx;
|
||||
let body = tcx.hir().body(closure.body);
|
||||
let expr_def_id = closure.def_id;
|
||||
|
||||
// It's always helpful for inference if we know the kind of
|
||||
// closure sooner rather than later, so first examine the expected
|
||||
@ -61,24 +63,6 @@ pub fn check_expr_closure(
|
||||
None => (None, None),
|
||||
};
|
||||
|
||||
self.check_closure(closure, expr_span, expected_kind, expected_sig)
|
||||
}
|
||||
|
||||
#[instrument(skip(self, closure), level = "debug", ret)]
|
||||
fn check_closure(
|
||||
&self,
|
||||
closure: &hir::Closure<'tcx>,
|
||||
expr_span: Span,
|
||||
opt_kind: Option<ty::ClosureKind>,
|
||||
expected_sig: Option<ExpectedSig<'tcx>>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let body = tcx.hir().body(closure.body);
|
||||
|
||||
trace!("decl = {:#?}", closure.fn_decl);
|
||||
let expr_def_id = closure.def_id;
|
||||
debug!(?expr_def_id);
|
||||
|
||||
let ClosureSignatures { bound_sig, liberated_sig } =
|
||||
self.sig_of_closure(expr_def_id, closure.fn_decl, closure.kind, expected_sig);
|
||||
|
||||
@ -139,9 +123,8 @@ fn check_closure(
|
||||
}
|
||||
};
|
||||
|
||||
let mut fcx = FnCtxt::new(self, self.param_env, closure.def_id);
|
||||
check_fn(
|
||||
&mut fcx,
|
||||
&mut FnCtxt::new(self, self.param_env, closure.def_id),
|
||||
liberated_sig,
|
||||
coroutine_types,
|
||||
closure.fn_decl,
|
||||
@ -174,9 +157,9 @@ fn check_closure(
|
||||
)
|
||||
});
|
||||
|
||||
debug!(?sig, ?opt_kind);
|
||||
debug!(?sig, ?expected_kind);
|
||||
|
||||
let closure_kind_ty = match opt_kind {
|
||||
let closure_kind_ty = match expected_kind {
|
||||
Some(kind) => Ty::from_closure_kind(tcx, kind),
|
||||
|
||||
// Create a type variable (for now) to represent the closure kind.
|
||||
@ -204,11 +187,11 @@ fn check_closure(
|
||||
let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else {
|
||||
bug!("expected coroutine to have yield/resume types");
|
||||
};
|
||||
let interior = fcx.next_ty_var(TypeVariableOrigin {
|
||||
let interior = self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: body.value.span,
|
||||
});
|
||||
fcx.deferred_coroutine_interiors.borrow_mut().push((
|
||||
self.deferred_coroutine_interiors.borrow_mut().push((
|
||||
expr_def_id,
|
||||
body.id(),
|
||||
interior,
|
||||
@ -364,36 +347,16 @@ fn deduce_sig_from_projection(
|
||||
let tcx = self.tcx;
|
||||
|
||||
let trait_def_id = projection.trait_def_id(tcx);
|
||||
|
||||
let is_fn = tcx.is_fn_trait(trait_def_id);
|
||||
|
||||
let coroutine_trait = tcx.lang_items().coroutine_trait();
|
||||
let is_gen = coroutine_trait == Some(trait_def_id);
|
||||
|
||||
if !is_fn && !is_gen {
|
||||
debug!("not fn or coroutine");
|
||||
// For now, we only do signature deduction based off of the `Fn` traits.
|
||||
if !tcx.is_fn_trait(trait_def_id) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Check that we deduce the signature from the `<_ as std::ops::Coroutine>::Return`
|
||||
// associated item and not yield.
|
||||
if is_gen && self.tcx.associated_item(projection.projection_def_id()).name != sym::Return {
|
||||
debug!("not `Return` assoc item of `Coroutine`");
|
||||
return None;
|
||||
}
|
||||
let arg_param_ty = projection.skip_binder().projection_ty.args.type_at(1);
|
||||
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
|
||||
debug!(?arg_param_ty);
|
||||
|
||||
let input_tys = if is_fn {
|
||||
let arg_param_ty = projection.skip_binder().projection_ty.args.type_at(1);
|
||||
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
|
||||
debug!(?arg_param_ty);
|
||||
|
||||
match arg_param_ty.kind() {
|
||||
&ty::Tuple(tys) => tys,
|
||||
_ => return None,
|
||||
}
|
||||
} else {
|
||||
// Coroutines with a `()` resume type may be defined with 0 or 1 explicit arguments,
|
||||
// else they must have exactly 1 argument. For now though, just give up in this case.
|
||||
let ty::Tuple(input_tys) = *arg_param_ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
|
@ -604,19 +604,15 @@ pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
|
||||
/// wrapped in a binder.
|
||||
pub fn closure_env_ty(
|
||||
self,
|
||||
closure_def_id: DefId,
|
||||
closure_args: GenericArgsRef<'tcx>,
|
||||
closure_ty: Ty<'tcx>,
|
||||
closure_kind: ty::ClosureKind,
|
||||
env_region: ty::Region<'tcx>,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
let closure_ty = Ty::new_closure(self, closure_def_id, closure_args);
|
||||
let closure_kind_ty = closure_args.as_closure().kind_ty();
|
||||
let closure_kind = closure_kind_ty.to_opt_closure_kind()?;
|
||||
let env_ty = match closure_kind {
|
||||
) -> Ty<'tcx> {
|
||||
match closure_kind {
|
||||
ty::ClosureKind::Fn => Ty::new_imm_ref(self, env_region, closure_ty),
|
||||
ty::ClosureKind::FnMut => Ty::new_mut_ref(self, env_region, closure_ty),
|
||||
ty::ClosureKind::FnOnce => closure_ty,
|
||||
};
|
||||
Some(env_ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the node pointed to by `def_id` is a `static` item.
|
||||
|
@ -117,50 +117,32 @@ fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Box<Pat<'tcx>> {
|
||||
pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
|
||||
}
|
||||
|
||||
fn closure_env_param(&self, owner_def: LocalDefId, owner_id: HirId) -> Option<Param<'tcx>> {
|
||||
match self.tcx.def_kind(owner_def) {
|
||||
DefKind::Closure if self.tcx.is_coroutine(owner_def.to_def_id()) => {
|
||||
let coroutine_ty = self.typeck_results.node_type(owner_id);
|
||||
let coroutine_param = Param {
|
||||
ty: coroutine_ty,
|
||||
pat: None,
|
||||
ty_span: None,
|
||||
self_kind: None,
|
||||
hir_id: None,
|
||||
};
|
||||
Some(coroutine_param)
|
||||
}
|
||||
DefKind::Closure => {
|
||||
let closure_ty = self.typeck_results.node_type(owner_id);
|
||||
|
||||
let ty::Closure(closure_def_id, closure_args) = *closure_ty.kind() else {
|
||||
bug!("closure expr does not have closure type: {:?}", closure_ty);
|
||||
};
|
||||
|
||||
let bound_vars =
|
||||
self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region(ty::BrEnv)]);
|
||||
let br = ty::BoundRegion {
|
||||
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
|
||||
kind: ty::BrEnv,
|
||||
};
|
||||
let env_region = ty::Region::new_bound(self.tcx, ty::INNERMOST, br);
|
||||
let closure_env_ty =
|
||||
self.tcx.closure_env_ty(closure_def_id, closure_args, env_region).unwrap();
|
||||
let liberated_closure_env_ty = self.tcx.instantiate_bound_regions_with_erased(
|
||||
ty::Binder::bind_with_vars(closure_env_ty, bound_vars),
|
||||
);
|
||||
let env_param = Param {
|
||||
ty: liberated_closure_env_ty,
|
||||
pat: None,
|
||||
ty_span: None,
|
||||
self_kind: None,
|
||||
hir_id: None,
|
||||
};
|
||||
|
||||
Some(env_param)
|
||||
}
|
||||
_ => None,
|
||||
fn closure_env_param(&self, owner_def: LocalDefId, expr_id: HirId) -> Option<Param<'tcx>> {
|
||||
if self.tcx.def_kind(owner_def) != DefKind::Closure {
|
||||
return None;
|
||||
}
|
||||
|
||||
let closure_ty = self.typeck_results.node_type(expr_id);
|
||||
Some(match *closure_ty.kind() {
|
||||
ty::Coroutine(..) => {
|
||||
Param { ty: closure_ty, pat: None, ty_span: None, self_kind: None, hir_id: None }
|
||||
}
|
||||
ty::Closure(_, closure_args) => {
|
||||
let closure_env_ty = self.tcx.closure_env_ty(
|
||||
closure_ty,
|
||||
closure_args.as_closure().kind(),
|
||||
self.tcx.lifetimes.re_erased,
|
||||
);
|
||||
Param {
|
||||
ty: closure_env_ty,
|
||||
pat: None,
|
||||
ty_span: None,
|
||||
self_kind: None,
|
||||
hir_id: None,
|
||||
}
|
||||
}
|
||||
_ => bug!("unexpected closure type: {closure_ty}"),
|
||||
})
|
||||
}
|
||||
|
||||
fn explicit_params<'a>(
|
||||
|
@ -27,11 +27,9 @@
|
||||
#[cfg(feature = "rustc")]
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
use crate::constructor::{Constructor, ConstructorSet};
|
||||
use crate::constructor::{Constructor, ConstructorSet, IntRange};
|
||||
#[cfg(feature = "rustc")]
|
||||
use crate::lints::{
|
||||
lint_nonexhaustive_missing_variants, lint_overlapping_range_endpoints, PatternColumn,
|
||||
};
|
||||
use crate::lints::{lint_nonexhaustive_missing_variants, PatternColumn};
|
||||
use crate::pat::DeconstructedPat;
|
||||
#[cfg(feature = "rustc")]
|
||||
use crate::rustc::RustcMatchCheckCtxt;
|
||||
@ -77,6 +75,17 @@ pub trait TypeCx: Sized + fmt::Debug {
|
||||
|
||||
/// Raise a bug.
|
||||
fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
|
||||
|
||||
/// Lint that the range `pat` overlapped with all the ranges in `overlaps_with`, where the range
|
||||
/// they overlapped over is `overlaps_on`. We only detect singleton overlaps.
|
||||
/// The default implementation does nothing.
|
||||
fn lint_overlapping_range_endpoints(
|
||||
&self,
|
||||
_pat: &DeconstructedPat<'_, Self>,
|
||||
_overlaps_on: IntRange,
|
||||
_overlaps_with: &[&DeconstructedPat<'_, Self>],
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Context that provides information global to a match.
|
||||
@ -111,16 +120,10 @@ pub fn analyze_match<'p, 'tcx>(
|
||||
|
||||
let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity)?;
|
||||
|
||||
let pat_column = PatternColumn::new(arms);
|
||||
|
||||
// Lint ranges that overlap on their endpoints, which is likely a mistake.
|
||||
if !report.overlapping_range_endpoints.is_empty() {
|
||||
lint_overlapping_range_endpoints(cx, &report.overlapping_range_endpoints);
|
||||
}
|
||||
|
||||
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
|
||||
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
|
||||
if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
|
||||
let pat_column = PatternColumn::new(arms);
|
||||
lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)?;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,11 @@
|
||||
use rustc_session::lint;
|
||||
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
use crate::errors::{
|
||||
self, NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered,
|
||||
};
|
||||
use crate::errors::{NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Uncovered};
|
||||
use crate::pat::PatOrWild;
|
||||
use crate::rustc::{
|
||||
self, Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy,
|
||||
RustcMatchCheckCtxt, SplitConstructorSet, WitnessPat,
|
||||
Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy, RustcMatchCheckCtxt,
|
||||
SplitConstructorSet, WitnessPat,
|
||||
};
|
||||
|
||||
/// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that
|
||||
@ -196,26 +193,3 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
|
||||
cx: MatchCtxt<'a, 'p, 'tcx>,
|
||||
overlapping_range_endpoints: &[rustc::OverlappingRanges<'p, 'tcx>],
|
||||
) {
|
||||
let rcx = cx.tycx;
|
||||
for overlap in overlapping_range_endpoints {
|
||||
let overlap_as_pat = rcx.hoist_pat_range(&overlap.overlaps_on, overlap.pat.ty());
|
||||
let overlaps: Vec<_> = overlap
|
||||
.overlaps_with
|
||||
.iter()
|
||||
.map(|pat| pat.data().unwrap().span)
|
||||
.map(|span| errors::Overlap { range: overlap_as_pat.clone(), span })
|
||||
.collect();
|
||||
let pat_span = overlap.pat.data().unwrap().span;
|
||||
rcx.tcx.emit_spanned_lint(
|
||||
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
|
||||
rcx.match_lint_level,
|
||||
pat_span,
|
||||
errors::OverlappingRangeEndpoints { overlap: overlaps, range: pat_span },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt;
|
||||
use std::iter::once;
|
||||
|
||||
@ -5,24 +6,21 @@
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::mir::interpret::Scalar;
|
||||
use rustc_middle::mir::{self, Const};
|
||||
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, VariantDef};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeVisitableExt, VariantDef};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::constructor::{
|
||||
IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
|
||||
};
|
||||
use crate::TypeCx;
|
||||
use crate::{errors, TypeCx};
|
||||
|
||||
use crate::constructor::Constructor::*;
|
||||
|
||||
@ -34,8 +32,6 @@
|
||||
crate::pat::DeconstructedPat<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
|
||||
pub type MatchArm<'p, 'tcx> = crate::MatchArm<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
|
||||
pub type MatchCtxt<'a, 'p, 'tcx> = crate::MatchCtxt<'a, RustcMatchCheckCtxt<'p, 'tcx>>;
|
||||
pub type OverlappingRanges<'p, 'tcx> =
|
||||
crate::usefulness::OverlappingRanges<'p, RustcMatchCheckCtxt<'p, 'tcx>>;
|
||||
pub(crate) type PlaceCtxt<'a, 'p, 'tcx> =
|
||||
crate::usefulness::PlaceCtxt<'a, RustcMatchCheckCtxt<'p, 'tcx>>;
|
||||
pub(crate) type SplitConstructorSet<'p, 'tcx> =
|
||||
@ -991,6 +987,27 @@ fn debug_pat(
|
||||
fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
|
||||
span_bug!(self.scrut_span, "{}", fmt)
|
||||
}
|
||||
|
||||
fn lint_overlapping_range_endpoints(
|
||||
&self,
|
||||
pat: &crate::pat::DeconstructedPat<'_, Self>,
|
||||
overlaps_on: IntRange,
|
||||
overlaps_with: &[&crate::pat::DeconstructedPat<'_, Self>],
|
||||
) {
|
||||
let overlap_as_pat = self.hoist_pat_range(&overlaps_on, pat.ty());
|
||||
let overlaps: Vec<_> = overlaps_with
|
||||
.iter()
|
||||
.map(|pat| pat.data().unwrap().span)
|
||||
.map(|span| errors::Overlap { range: overlap_as_pat.clone(), span })
|
||||
.collect();
|
||||
let pat_span = pat.data().unwrap().span;
|
||||
self.tcx.emit_spanned_lint(
|
||||
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
|
||||
self.match_lint_level,
|
||||
pat_span,
|
||||
errors::OverlappingRangeEndpoints { overlap: overlaps, range: pat_span },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
|
||||
|
@ -1340,10 +1340,10 @@ fn extend(&mut self, other: Self) {
|
||||
/// We can however get false negatives because exhaustiveness does not explore all cases. See the
|
||||
/// section on relevancy at the top of the file.
|
||||
fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
|
||||
mcx: MatchCtxt<'_, Cx>,
|
||||
overlap_range: IntRange,
|
||||
matrix: &Matrix<'p, Cx>,
|
||||
specialized_matrix: &Matrix<'p, Cx>,
|
||||
overlapping_range_endpoints: &mut Vec<OverlappingRanges<'p, Cx>>,
|
||||
) {
|
||||
let overlap = overlap_range.lo;
|
||||
// Ranges that look like `lo..=overlap`.
|
||||
@ -1373,11 +1373,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
|
||||
.map(|&(_, pat)| pat)
|
||||
.collect();
|
||||
if !overlaps_with.is_empty() {
|
||||
overlapping_range_endpoints.push(OverlappingRanges {
|
||||
pat,
|
||||
overlaps_on: overlap_range,
|
||||
overlaps_with,
|
||||
});
|
||||
mcx.tycx.lint_overlapping_range_endpoints(pat, overlap_range, &overlaps_with);
|
||||
}
|
||||
}
|
||||
suffixes.push((child_row_id, pat))
|
||||
@ -1393,11 +1389,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
|
||||
.map(|&(_, pat)| pat)
|
||||
.collect();
|
||||
if !overlaps_with.is_empty() {
|
||||
overlapping_range_endpoints.push(OverlappingRanges {
|
||||
pat,
|
||||
overlaps_on: overlap_range,
|
||||
overlaps_with,
|
||||
});
|
||||
mcx.tycx.lint_overlapping_range_endpoints(pat, overlap_range, &overlaps_with);
|
||||
}
|
||||
}
|
||||
prefixes.push((child_row_id, pat))
|
||||
@ -1423,7 +1415,6 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
|
||||
fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||
mcx: MatchCtxt<'a, Cx>,
|
||||
matrix: &mut Matrix<'p, Cx>,
|
||||
overlapping_range_endpoints: &mut Vec<OverlappingRanges<'p, Cx>>,
|
||||
is_top_level: bool,
|
||||
) -> Result<WitnessMatrix<Cx>, Cx::Error> {
|
||||
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
|
||||
@ -1503,12 +1494,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||
let ctor_is_relevant = matches!(ctor, Constructor::Missing) || missing_ctors.is_empty();
|
||||
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant);
|
||||
let mut witnesses = ensure_sufficient_stack(|| {
|
||||
compute_exhaustiveness_and_usefulness(
|
||||
mcx,
|
||||
&mut spec_matrix,
|
||||
overlapping_range_endpoints,
|
||||
false,
|
||||
)
|
||||
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
|
||||
})?;
|
||||
|
||||
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
|
||||
@ -1537,12 +1523,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||
&& spec_matrix.rows.len() >= 2
|
||||
&& spec_matrix.rows.iter().any(|row| !row.intersects.is_empty())
|
||||
{
|
||||
collect_overlapping_range_endpoints(
|
||||
overlap_range,
|
||||
matrix,
|
||||
&spec_matrix,
|
||||
overlapping_range_endpoints,
|
||||
);
|
||||
collect_overlapping_range_endpoints(mcx, overlap_range, matrix, &spec_matrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1569,15 +1550,6 @@ pub enum Usefulness<'p, Cx: TypeCx> {
|
||||
Redundant,
|
||||
}
|
||||
|
||||
/// Indicates that the range `pat` overlapped with all the ranges in `overlaps_with`, where the
|
||||
/// range they overlapped over is `overlaps_on`. We only detect singleton overlaps.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OverlappingRanges<'p, Cx: TypeCx> {
|
||||
pub pat: &'p DeconstructedPat<'p, Cx>,
|
||||
pub overlaps_on: IntRange,
|
||||
pub overlaps_with: Vec<&'p DeconstructedPat<'p, Cx>>,
|
||||
}
|
||||
|
||||
/// The output of checking a match for exhaustiveness and arm usefulness.
|
||||
pub struct UsefulnessReport<'p, Cx: TypeCx> {
|
||||
/// For each arm of the input, whether that arm is useful after the arms above it.
|
||||
@ -1585,7 +1557,6 @@ pub struct UsefulnessReport<'p, Cx: TypeCx> {
|
||||
/// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
|
||||
/// exhaustiveness.
|
||||
pub non_exhaustiveness_witnesses: Vec<WitnessPat<Cx>>,
|
||||
pub overlapping_range_endpoints: Vec<OverlappingRanges<'p, Cx>>,
|
||||
}
|
||||
|
||||
/// Computes whether a match is exhaustive and which of its arms are useful.
|
||||
@ -1596,14 +1567,9 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
|
||||
scrut_ty: Cx::Ty,
|
||||
scrut_validity: ValidityConstraint,
|
||||
) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
|
||||
let mut overlapping_range_endpoints = Vec::new();
|
||||
let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity);
|
||||
let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(
|
||||
cx,
|
||||
&mut matrix,
|
||||
&mut overlapping_range_endpoints,
|
||||
true,
|
||||
)?;
|
||||
let non_exhaustiveness_witnesses =
|
||||
compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?;
|
||||
|
||||
let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
|
||||
let arm_usefulness: Vec<_> = arms
|
||||
@ -1621,9 +1587,5 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(UsefulnessReport {
|
||||
arm_usefulness,
|
||||
non_exhaustiveness_witnesses,
|
||||
overlapping_range_endpoints,
|
||||
})
|
||||
Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses })
|
||||
}
|
||||
|
@ -2466,7 +2466,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
|
||||
debug!(?cache_projection, ?obligation_projection);
|
||||
|
||||
match infcx.at(cause, param_env).eq(
|
||||
DefineOpaqueTypes::No,
|
||||
DefineOpaqueTypes::Yes,
|
||||
cache_projection,
|
||||
obligation_projection,
|
||||
) {
|
||||
|
@ -83,7 +83,11 @@ fn fn_sig_for_fn_abi<'tcx>(
|
||||
kind: ty::BoundRegionKind::BrEnv,
|
||||
};
|
||||
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
|
||||
let env_ty = tcx.closure_env_ty(def_id, args, env_region).unwrap();
|
||||
let env_ty = tcx.closure_env_ty(
|
||||
Ty::new_closure(tcx, def_id, args),
|
||||
args.as_closure().kind(),
|
||||
env_region,
|
||||
);
|
||||
|
||||
let sig = sig.skip_binder();
|
||||
ty::Binder::bind_with_vars(
|
||||
|
@ -59,6 +59,8 @@ macro_rules! unlikely {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use error::ParseIntError;
|
||||
|
||||
pub(crate) use nonzero::NonZero;
|
||||
|
||||
#[stable(feature = "nonzero", since = "1.28.0")]
|
||||
pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
|
||||
|
||||
@ -482,7 +484,7 @@ impl u8 {
|
||||
Self = u8,
|
||||
ActualT = u8,
|
||||
SignedT = i8,
|
||||
NonZeroT = NonZeroU8,
|
||||
NonZeroT = NonZero<u8>,
|
||||
BITS = 8,
|
||||
MAX = 255,
|
||||
rot = 2,
|
||||
@ -1097,7 +1099,7 @@ impl u16 {
|
||||
Self = u16,
|
||||
ActualT = u16,
|
||||
SignedT = i16,
|
||||
NonZeroT = NonZeroU16,
|
||||
NonZeroT = NonZero<u16>,
|
||||
BITS = 16,
|
||||
MAX = 65535,
|
||||
rot = 4,
|
||||
@ -1146,7 +1148,7 @@ impl u32 {
|
||||
Self = u32,
|
||||
ActualT = u32,
|
||||
SignedT = i32,
|
||||
NonZeroT = NonZeroU32,
|
||||
NonZeroT = NonZero<u32>,
|
||||
BITS = 32,
|
||||
MAX = 4294967295,
|
||||
rot = 8,
|
||||
@ -1170,7 +1172,7 @@ impl u64 {
|
||||
Self = u64,
|
||||
ActualT = u64,
|
||||
SignedT = i64,
|
||||
NonZeroT = NonZeroU64,
|
||||
NonZeroT = NonZero<u64>,
|
||||
BITS = 64,
|
||||
MAX = 18446744073709551615,
|
||||
rot = 12,
|
||||
@ -1194,7 +1196,7 @@ impl u128 {
|
||||
Self = u128,
|
||||
ActualT = u128,
|
||||
SignedT = i128,
|
||||
NonZeroT = NonZeroU128,
|
||||
NonZeroT = NonZero<u128>,
|
||||
BITS = 128,
|
||||
MAX = 340282366920938463463374607431768211455,
|
||||
rot = 16,
|
||||
@ -1220,7 +1222,7 @@ impl usize {
|
||||
Self = usize,
|
||||
ActualT = u16,
|
||||
SignedT = isize,
|
||||
NonZeroT = NonZeroUsize,
|
||||
NonZeroT = NonZero<usize>,
|
||||
BITS = 16,
|
||||
MAX = 65535,
|
||||
rot = 4,
|
||||
@ -1245,7 +1247,7 @@ impl usize {
|
||||
Self = usize,
|
||||
ActualT = u32,
|
||||
SignedT = isize,
|
||||
NonZeroT = NonZeroUsize,
|
||||
NonZeroT = NonZero<usize>,
|
||||
BITS = 32,
|
||||
MAX = 4294967295,
|
||||
rot = 8,
|
||||
@ -1270,7 +1272,7 @@ impl usize {
|
||||
Self = usize,
|
||||
ActualT = u64,
|
||||
SignedT = isize,
|
||||
NonZeroT = NonZeroUsize,
|
||||
NonZeroT = NonZero<usize>,
|
||||
BITS = 64,
|
||||
MAX = 18446744073709551615,
|
||||
rot = 12,
|
||||
|
@ -8,6 +8,69 @@
|
||||
use super::{IntErrorKind, ParseIntError};
|
||||
use crate::intrinsics;
|
||||
|
||||
mod private {
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
#[const_trait]
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
/// A marker trait for primitive types which can be zero.
|
||||
///
|
||||
/// This is an implementation detail for [`NonZero<T>`](NonZero) which may disappear or be replaced at any time.
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
#[const_trait]
|
||||
pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {
|
||||
type NonZero;
|
||||
}
|
||||
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
pub(crate) type NonZero<T> = <T as ZeroablePrimitive>::NonZero;
|
||||
|
||||
macro_rules! impl_zeroable_primitive {
|
||||
($NonZero:ident ( $primitive:ty )) => {
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
impl const private::Sealed for $primitive {}
|
||||
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
impl const ZeroablePrimitive for $primitive {
|
||||
type NonZero = $NonZero;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_zeroable_primitive!(NonZeroU8(u8));
|
||||
impl_zeroable_primitive!(NonZeroU16(u16));
|
||||
impl_zeroable_primitive!(NonZeroU32(u32));
|
||||
impl_zeroable_primitive!(NonZeroU64(u64));
|
||||
impl_zeroable_primitive!(NonZeroU128(u128));
|
||||
impl_zeroable_primitive!(NonZeroUsize(usize));
|
||||
impl_zeroable_primitive!(NonZeroI8(i8));
|
||||
impl_zeroable_primitive!(NonZeroI16(i16));
|
||||
impl_zeroable_primitive!(NonZeroI32(i32));
|
||||
impl_zeroable_primitive!(NonZeroI64(i64));
|
||||
impl_zeroable_primitive!(NonZeroI128(i128));
|
||||
impl_zeroable_primitive!(NonZeroIsize(isize));
|
||||
|
||||
macro_rules! impl_nonzero_fmt {
|
||||
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
|
||||
$(
|
||||
|
@ -3,7 +3,7 @@ macro_rules! uint_impl {
|
||||
Self = $SelfT:ty,
|
||||
ActualT = $ActualT:ident,
|
||||
SignedT = $SignedT:ident,
|
||||
NonZeroT = $NonZeroT:ident,
|
||||
NonZeroT = $NonZeroT:ty,
|
||||
|
||||
// There are all for use *only* in doc comments.
|
||||
// As such, they're all passed as literals -- passing them as a string
|
||||
@ -842,6 +842,7 @@ pub const fn checked_ilog(self, base: Self) -> Option<u32> {
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn checked_ilog2(self) -> Option<u32> {
|
||||
// FIXME: Simply use `NonZero::new` once it is actually generic.
|
||||
if let Some(x) = <$NonZeroT>::new(self) {
|
||||
Some(x.ilog2())
|
||||
} else {
|
||||
@ -864,6 +865,7 @@ pub const fn checked_ilog2(self) -> Option<u32> {
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn checked_ilog10(self) -> Option<u32> {
|
||||
// FIXME: Simply use `NonZero::new` once it is actually generic.
|
||||
if let Some(x) = <$NonZeroT>::new(self) {
|
||||
Some(x.ilog10())
|
||||
} else {
|
||||
|
@ -710,7 +710,6 @@ pub fn as_mut(&mut self) -> Bound<&mut T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(bound_map)]
|
||||
/// use std::ops::Bound::*;
|
||||
///
|
||||
/// let bound_string = Included("Hello, World!");
|
||||
@ -719,7 +718,6 @@ pub fn as_mut(&mut self) -> Bound<&mut T> {
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(bound_map)]
|
||||
/// use std::ops::Bound;
|
||||
/// use Bound::*;
|
||||
///
|
||||
@ -728,7 +726,7 @@ pub fn as_mut(&mut self) -> Bound<&mut T> {
|
||||
/// assert_eq!(unbounded_string.map(|s| s.len()), Unbounded);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "bound_map", issue = "86026")]
|
||||
#[stable(feature = "bound_map", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Bound<U> {
|
||||
match self {
|
||||
Unbounded => Unbounded,
|
||||
|
@ -12,7 +12,7 @@
|
||||
};
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::{self, SizedTypeProperties};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::num::{NonZero, NonZeroUsize};
|
||||
use crate::ptr::{self, invalid, invalid_mut, NonNull};
|
||||
|
||||
use super::{from_raw_parts, from_raw_parts_mut};
|
||||
@ -1305,12 +1305,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
pub struct Windows<'a, T: 'a> {
|
||||
v: &'a [T],
|
||||
size: NonZeroUsize,
|
||||
size: NonZero<usize>,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> Windows<'a, T> {
|
||||
#[inline]
|
||||
pub(super) fn new(slice: &'a [T], size: NonZeroUsize) -> Self {
|
||||
pub(super) fn new(slice: &'a [T], size: NonZero<usize>) -> Self {
|
||||
Self { v: slice, size }
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit f6bd083c4ccfc4ce6699b8b4154e3c45c5a27a8c
|
||||
Subproject commit 6bc2415218d4dd0cb01433d8320f5ccf79c343a1
|
@ -1 +1 @@
|
||||
Subproject commit 3565c7978cfc9662f5963b135690ff9cbbfa0318
|
||||
Subproject commit 8c77e8be9da1a9c70545556218d563c8d061f1fd
|
@ -1 +1 @@
|
||||
Subproject commit c0be6299e52e4164c30ba6f41bd0ad0aaee64972
|
||||
Subproject commit ddf5cb0e6ee54ba2dd84c8ca3e1314120014e20d
|
@ -1 +1 @@
|
||||
Subproject commit d13e85152a977cd0bcaf583cf5f49e86225697de
|
||||
Subproject commit 4af29d1a7f64f88a36539662c6a84fe1fbe6cde1
|
@ -98,11 +98,12 @@ pub fn files_for_miropt_test(
|
||||
from_file = format!("{}.{}.mir", test_name, first_pass);
|
||||
to_file = Some(second_file);
|
||||
} else {
|
||||
let ext_re = regex::Regex::new(r#"(\.(mir|dot|html))$"#).unwrap();
|
||||
let cap = ext_re
|
||||
.captures_iter(test_name)
|
||||
.next()
|
||||
.expect("test_name has an invalid extension");
|
||||
// Allow-list for file extensions that can be produced by MIR dumps.
|
||||
// Other extensions can be added here, as needed by new dump flags.
|
||||
let ext_re = regex::Regex::new(r#"(\.(mir|dot))$"#).unwrap();
|
||||
let cap = ext_re.captures_iter(test_name).next().unwrap_or_else(|| {
|
||||
panic!("in {testfile:?}:\nEMIT_MIR has an unrecognized extension: {test_name}")
|
||||
});
|
||||
let extension = cap.get(1).unwrap().as_str();
|
||||
|
||||
expected_file =
|
||||
|
28
tests/ui/type-alias-impl-trait/nested_inference_failure.rs
Normal file
28
tests/ui/type-alias-impl-trait/nested_inference_failure.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// check-pass
|
||||
// revisions: new old
|
||||
//[new] compile-flags: -Znext-solver
|
||||
|
||||
//! This test checks that we can successfully infer
|
||||
//! the hidden type of `FooImpl` to be `Foo<i32, {closure}>`
|
||||
//! and `ImplT` to be `i32`. This test used to fail, because
|
||||
//! we were unable to make the connection that the closure
|
||||
//! argument is the same as the first argument of `Foo`.
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct Foo<T: Debug, F: FnOnce(T)> {
|
||||
f: F,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
type ImplT = impl Debug;
|
||||
type FooImpl = Foo<ImplT, impl FnOnce(ImplT)>;
|
||||
|
||||
fn bar() -> FooImpl {
|
||||
Foo::<i32, _> { f: |_| (), _phantom: PhantomData }
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user