Rollup merge of #148837 - estebank:let-else, r=Kivooeo

Use `let...else` instead of `match foo { ... _ => return };` and `if let ... else return`
This commit is contained in:
Jacob Pratt 2025-12-13 00:55:55 -05:00 committed by GitHub
commit b32845c61a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 285 additions and 392 deletions

View file

@ -1533,11 +1533,10 @@ impl Expr {
// then type of result is trait object.
// Otherwise we don't assume the result type.
ExprKind::Binary(binop, lhs, rhs) if binop.node == BinOpKind::Add => {
if let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) {
TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None)
} else {
let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) else {
return None;
}
};
TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None)
}
ExprKind::Underscore => TyKind::Infer,

View file

@ -447,20 +447,17 @@ impl MetaItem {
thin_vec![PathSegment::path_root(span)]
};
loop {
if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
{
segments.push(PathSegment::from_ident(Ident::new(name, span)));
} else {
else {
return None;
}
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
iter.peek()
{
iter.next();
} else {
};
segments.push(PathSegment::from_ident(Ident::new(name, span)));
let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = iter.peek()
else {
break;
}
};
iter.next();
}
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
Path { span, segments, tokens: None }

View file

@ -6,6 +6,7 @@
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(array_windows))]
#![deny(clippy::manual_let_else)]
#![doc(test(attr(deny(warnings), allow(internal_features))))]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]

View file

@ -561,11 +561,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
VarDebugInfoContents::Place(ref p) => p == place,
_ => false,
});
let arg_name = if let Some(var_info) = var_info {
var_info.name
} else {
return;
};
let Some(var_info) = var_info else { return };
let arg_name = var_info.name;
struct MatchArgFinder {
expr_span: Span,
match_arg_span: Option<Span>,

View file

@ -850,16 +850,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
// will only ever have one item at any given time, but by using a vector, we can pop from
// it which simplifies the termination logic.
let mut queue = vec![location];
let mut target =
if let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt {
if let Some(local) = place.as_local() {
local
} else {
return false;
}
} else {
return false;
};
let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt else {
return false;
};
let Some(mut target) = place.as_local() else { return false };
debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue);
while let Some(current_location) = queue.pop() {

View file

@ -1124,16 +1124,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
use self::UseSpans::*;
debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
let target = match self.body[location.block].statements.get(location.statement_index) {
Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => {
if let Some(local) = place.as_local() {
local
} else {
return OtherUse(use_span);
}
}
_ => return OtherUse(use_span),
let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) =
self.body[location.block].statements.get(location.statement_index)
else {
return OtherUse(use_span);
};
let Some(target) = place.as_local() else { return OtherUse(use_span) };
if self.body.local_kind(target) != LocalKind::Temp {
// operands are always temporaries.

View file

@ -142,12 +142,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
} else {
item_msg = access_place_desc;
let local_info = self.body.local_decls[local].local_info();
if let LocalInfo::StaticRef { def_id, .. } = *local_info {
let static_name = &self.infcx.tcx.item_name(def_id);
reason = format!(", as `{static_name}` is an immutable static item");
} else {
let LocalInfo::StaticRef { def_id, .. } = *local_info else {
bug!("is_ref_to_static return true, but not ref to static?");
}
};
let static_name = &self.infcx.tcx.item_name(def_id);
reason = format!(", as `{static_name}` is an immutable static item");
}
}
PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => {

View file

@ -847,11 +847,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.scope);
let param = if let Some(param) =
let Some(param) =
find_param_with_region(self.infcx.tcx, self.mir_def_id(), f, outlived_f)
{
param
} else {
else {
return;
};
@ -930,37 +928,27 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let tcx = self.infcx.tcx;
let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category {
let (fn_did, args) = match func_ty.kind() {
ty::FnDef(fn_did, args) => (fn_did, args),
_ => return,
};
debug!(?fn_did, ?args);
let ConstraintCategory::CallArgument(Some(func_ty)) = category else { return };
let ty::FnDef(fn_did, args) = func_ty.kind() else { return };
debug!(?fn_did, ?args);
// Only suggest this on function calls, not closures
let ty = tcx.type_of(fn_did).instantiate_identity();
debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind());
if let ty::Closure(_, _) = ty.kind() {
return;
}
if let Ok(Some(instance)) = ty::Instance::try_resolve(
tcx,
self.infcx.typing_env(self.infcx.param_env),
*fn_did,
self.infcx.resolve_vars_if_possible(args),
) {
instance
} else {
return;
}
} else {
// Only suggest this on function calls, not closures
let ty = tcx.type_of(fn_did).instantiate_identity();
debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind());
if let ty::Closure(_, _) = ty.kind() {
return;
}
let Ok(Some(instance)) = ty::Instance::try_resolve(
tcx,
self.infcx.typing_env(self.infcx.param_env),
*fn_did,
self.infcx.resolve_vars_if_possible(args),
) else {
return;
};
let param = match find_param_with_region(tcx, self.mir_def_id(), f, o) {
Some(param) => param,
None => return,
let Some(param) = find_param_with_region(tcx, self.mir_def_id(), f, o) else {
return;
};
debug!(?param);

View file

@ -2,6 +2,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![deny(clippy::manual_let_else)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(file_buffered)]

View file

@ -67,12 +67,11 @@ impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> {
match context {
PlaceContext::NonMutatingUse(_)
| PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
let path = match self.move_data.rev_lookup.find(place.as_ref()) {
LookupResult::Exact(path) | LookupResult::Parent(Some(path)) => path,
_ => {
// There's no path access to emit.
return;
}
let (LookupResult::Exact(path) | LookupResult::Parent(Some(path))) =
self.move_data.rev_lookup.find(place.as_ref())
else {
// There's no path access to emit.
return;
};
debug!("AccessFactsExtractor - emit path access ({path:?}, {location:?})");
self.facts.path_accessed_at_base.push((path, self.location_to_index(location)));

View file

@ -130,11 +130,9 @@ impl UnwindContext {
return;
}
let unwind_info = if let Some(unwind_info) =
let Some(unwind_info) =
context.compiled_code().unwrap().create_unwind_info(module.isa()).unwrap()
{
unwind_info
} else {
else {
return;
};

View file

@ -29,11 +29,7 @@ pub(crate) fn maybe_known_branch_taken(
arg: Value,
test_zero: bool,
) -> Option<bool> {
let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
arg_inst
} else {
return None;
};
let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) else { return None };
match bcx.func.dfg.insts[arg_inst] {
InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {

View file

@ -774,24 +774,23 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
return Err(());
}};
}
let (elem_ty_str, elem_ty, cast_type) = if let ty::Float(ref f) = *in_elem.kind() {
let elem_ty = bx.cx.type_float_from_ty(*f);
match f.bit_width() {
16 => ("", elem_ty, Some(bx.cx.double_type)),
32 => ("f", elem_ty, None),
64 => ("", elem_ty, None),
_ => {
return_error!(InvalidMonomorphization::FloatingPointVector {
span,
name,
f_ty: *f,
in_ty
});
}
}
} else {
let ty::Float(ref f) = *in_elem.kind() else {
return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
};
let elem_ty = bx.cx.type_float_from_ty(*f);
let (elem_ty_str, elem_ty, cast_type) = match f.bit_width() {
16 => ("", elem_ty, Some(bx.cx.double_type)),
32 => ("f", elem_ty, None),
64 => ("", elem_ty, None),
_ => {
return_error!(InvalidMonomorphization::FloatingPointVector {
span,
name,
f_ty: *f,
in_ty
});
}
};
let vec_ty = bx.cx.type_vector(elem_ty, in_len);

View file

@ -1756,11 +1756,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}};
}
let elem_ty = if let ty::Float(f) = in_elem.kind() {
bx.cx.type_float_from_ty(*f)
} else {
let ty::Float(f) = in_elem.kind() else {
return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
};
let elem_ty = bx.cx.type_float_from_ty(*f);
let vec_ty = bx.type_vector(elem_ty, in_len);

View file

@ -721,11 +721,10 @@ pub fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
};
// First read the ret symbol from the attribute
let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity {
p1.segments.first().unwrap().ident
} else {
let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity else {
span_bug!(attr.span(), "rustc_autodiff attribute must contain the return activity");
};
let ret_symbol = p1.segments.first().unwrap().ident;
// Then parse it into an actual DiffActivity
let Ok(ret_activity) = DiffActivity::from_str(ret_symbol.as_str()) else {

View file

@ -1,5 +1,6 @@
// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![deny(clippy::manual_let_else)]
#![feature(array_try_map)]
#![feature(assert_matches)]
#![feature(box_patterns)]

View file

@ -788,11 +788,10 @@ pub fn compile_declarative_macro(
let lhs_span = lhs_tt.span();
// Convert the lhs into `MatcherLoc` form, which is better for doing the
// actual matching.
let lhs = if let mbe::TokenTree::Delimited(.., delimited) = lhs_tt {
mbe::macro_parser::compute_locs(&delimited.tts)
} else {
let mbe::TokenTree::Delimited(.., delimited) = lhs_tt else {
return dummy_syn_ext(guar.unwrap());
};
let lhs = mbe::macro_parser::compute_locs(&delimited.tts);
if let Some(args) = args {
let args_span = args.span();
let mbe::TokenTree::Delimited(.., delimited) = args else {

View file

@ -4,6 +4,7 @@
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(debug_closure_helpers))]
#![deny(clippy::manual_let_else)]
#![feature(associated_type_defaults)]
#![feature(closure_track_caller)]
#![feature(const_default)]

View file

@ -1551,15 +1551,15 @@ fn const_param_default<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
let default_ct = match tcx.hir_node_by_def_id(def_id) {
hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Const { default: Some(ct), .. },
..
}) => ct,
_ => span_bug!(
let hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Const { default: Some(default_ct), .. },
..
}) = tcx.hir_node_by_def_id(def_id)
else {
span_bug!(
tcx.def_span(def_id),
"`const_param_default` expected a generic parameter with a constant"
),
)
};
let icx = ItemCtxt::new(tcx, def_id);
let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);

View file

@ -188,29 +188,26 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
for (param, var) in std::iter::zip(&generics.own_params, gat_vars) {
let existing = match var.kind() {
ty::GenericArgKind::Lifetime(re) => {
if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
re.kind()
{
mapping.insert(bv.var, tcx.mk_param_from_def(param))
} else {
else {
return None;
}
};
mapping.insert(bv.var, tcx.mk_param_from_def(param))
}
ty::GenericArgKind::Type(ty) => {
if let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() {
mapping.insert(bv.var, tcx.mk_param_from_def(param))
} else {
let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() else {
return None;
}
};
mapping.insert(bv.var, tcx.mk_param_from_def(param))
}
ty::GenericArgKind::Const(ct) => {
if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
ct.kind()
{
mapping.insert(bv.var, tcx.mk_param_from_def(param))
} else {
else {
return None;
}
};
mapping.insert(bv.var, tcx.mk_param_from_def(param))
}
};

View file

@ -763,9 +763,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
&self,
err: &mut Diag<'_, impl EmissionGuarantee>,
) {
let trait_ = match self.tcx.trait_of_assoc(self.def_id) {
Some(def_id) => def_id,
None => return,
let Some(trait_) = self.tcx.trait_of_assoc(self.def_id) else {
return;
};
// Skip suggestion when the associated function is itself generic, it is unclear
@ -1077,15 +1076,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
/// Builds the `type defined here` message.
fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) {
let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
if self.tcx.sess.source_map().is_span_accessible(def_span) {
def_span.into()
} else {
return;
}
} else {
let Some(def_span) = self.tcx.def_ident_span(self.def_id) else { return };
if !self.tcx.sess.source_map().is_span_accessible(def_span) {
return;
};
let mut spans: MultiSpan = def_span.into();
let msg = {
let def_kind = self.tcx.def_descr(self.def_id);

View file

@ -1749,10 +1749,8 @@ fn generics_args_err_extend<'a>(
GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
let span_of_impl = tcx.span_of_impl(def_id);
let def_id = match *ty.kind() {
ty::Adt(self_def, _) => self_def.did(),
_ => return,
};
let ty::Adt(self_def, _) = *ty.kind() else { return };
let def_id = self_def.did();
let type_name = tcx.item_name(def_id);
let span_of_ty = tcx.def_ident_span(def_id);

View file

@ -59,6 +59,7 @@ This API is completely unstable and subject to change.
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(bootstrap, feature(debug_closure_helpers))]
#![deny(clippy::manual_let_else)]
#![feature(assert_matches)]
#![feature(gen_blocks)]
#![feature(if_let_guard)]

View file

@ -458,15 +458,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
// Actually need to unwrap one more layer of HIR to get to
// the _real_ closure...
if let hir::Node::Expr(&hir::Expr {
let hir::Node::Expr(&hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
..
}) = self.tcx.parent_hir_node(parent_hir_id)
{
fn_decl_span
} else {
else {
return;
}
};
fn_decl_span
} else {
return;
};

View file

@ -415,11 +415,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
Some(self.resolve_vars_if_possible(possible_rcvr_ty))
});
if let Some(rcvr_ty) = possible_rcvr_ty {
rcvr_ty
} else {
return false;
}
let Some(rcvr_ty) = possible_rcvr_ty else { return false };
rcvr_ty
}
};

View file

@ -1561,19 +1561,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
base_place: PlaceWithHirId<'tcx>,
) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
let base_curr_ty = base_place.place.ty();
let deref_ty = match self
let Some(deref_ty) = self
.cx
.structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty)
.builtin_deref(true)
{
Some(ty) => ty,
None => {
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
return Err(self.cx.report_bug(
self.cx.tcx().hir_span(node),
"explicit deref of non-derefable type",
));
}
else {
debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
return Err(self
.cx
.report_bug(self.cx.tcx().hir_span(node), "explicit deref of non-derefable type"));
};
let mut projections = base_place.place.projections;
projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });

View file

@ -48,33 +48,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let uninstantiated_pred = match flavor {
ClauseFlavor::Where => {
ClauseFlavor::Where
if let Some(pred) = self
.tcx
.predicates_of(def_id)
.instantiate_identity(self.tcx)
.predicates
.into_iter()
.nth(idx)
{
pred
} else {
return false;
}
.nth(idx) =>
{
pred
}
ClauseFlavor::Const => {
ClauseFlavor::Const
if let Some((pred, _)) = self
.tcx
.const_conditions(def_id)
.instantiate_identity(self.tcx)
.into_iter()
.nth(idx)
{
pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe)
} else {
return false;
}
.nth(idx) =>
{
pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe)
}
_ => return false,
};
let generics = self.tcx.generics_of(def_id);

View file

@ -1467,11 +1467,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => None,
}
});
if let Some(new_def_id) = new_def_id {
def_id = new_def_id;
} else {
return;
}
let Some(new_def_id) = new_def_id else { return };
def_id = new_def_id;
}
}
}

View file

@ -1795,7 +1795,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(ty),
hir::Path { segments: [segment], .. },
))
| hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => {
| hir::ExprKind::Path(QPath::TypeRelative(ty, segment))
if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id)
&& let Ok(pick) = self.probe_for_name(
Mode::Path,
@ -1805,12 +1805,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self_ty,
expr.hir_id,
ProbeScope::TraitsInScope,
)
{
(pick.item, segment)
} else {
return false;
}
) =>
{
(pick.item, segment)
}
hir::ExprKind::Path(QPath::Resolved(
None,
@ -1821,16 +1818,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if old_item_name != segment.ident.name {
return false;
}
if let Some(item) = self
let Some(item) = self
.tcx
.associated_items(self.tcx.parent(old_def_id))
.filter_by_name_unhygienic(capitalized_name)
.next()
{
(*item, segment)
} else {
else {
return false;
}
};
(*item, segment)
}
_ => return false,
};

View file

@ -121,13 +121,12 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
len,
)
};
if let Some(len) = len.try_to_target_usize(self.tcx()) {
(len, ty)
} else {
let Some(len) = len.try_to_target_usize(self.tcx()) else {
return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength(
field.did, len,
));
}
};
(len, ty)
}
_ => (fields.len() as u64, elem_ty),
};

View file

@ -1,4 +1,5 @@
// tidy-alphabetical-start
#![deny(clippy::manual_let_else)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(if_let_guard)]

View file

@ -3543,10 +3543,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
return_type: Option<Ty<'tcx>>,
) {
let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) {
Some(output_ty) => self.resolve_vars_if_possible(output_ty),
_ => return,
};
let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else { return };
let output_ty = self.resolve_vars_if_possible(output_ty);
let method_exists =
self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type);
debug!("suggest_await_before_method: is_method_exist={}", method_exists);

View file

@ -1072,11 +1072,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
cx: &LateContext<'tcx>,
expr: &hir::Expr<'_>,
) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
let def = if let hir::ExprKind::Path(ref qpath) = expr.kind {
cx.qpath_res(qpath, expr.hir_id)
} else {
return None;
};
let hir::ExprKind::Path(ref qpath) = expr.kind else { return None };
let def = cx.qpath_res(qpath, expr.hir_id);
if let Res::Def(DefKind::Fn, did) = def {
if !def_id_is_transmute(cx, did) {
return None;

View file

@ -22,6 +22,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![cfg_attr(bootstrap, feature(array_windows))]
#![deny(clippy::manual_let_else)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(if_let_guard)]

View file

@ -120,10 +120,8 @@ impl Expr2024 {
fn check_ident_token(&mut self, cx: &crate::EarlyContext<'_>, token: &Token) {
debug!("check_ident_token: {:?}", token);
let (sym, edition) = match token.kind {
TokenKind::Ident(sym, _) => (sym, Edition::Edition2024),
_ => return,
};
let TokenKind::Ident(sym, _) = token.kind else { return };
let edition = Edition::Edition2024;
debug!("token.span.edition(): {:?}", token.span.edition());
if token.span.edition() >= edition {

View file

@ -30,6 +30,7 @@
#![allow(rustc::direct_use_of_rustc_type_ir)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(bootstrap, feature(array_windows))]
#![deny(clippy::manual_let_else)]
#![feature(allocator_api)]
#![feature(assert_matches)]
#![feature(associated_type_defaults)]

View file

@ -706,12 +706,9 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
| Bound(_, _)
| Placeholder(_)
| Error(_) => {
if let Some(placeholder) = self.placeholder {
// We replace these with infer (which is passed in from an infcx).
placeholder
} else {
return Err(());
}
let Some(placeholder) = self.placeholder else { return Err(()) };
// We replace these with infer (which is passed in from an infcx).
placeholder
}
Alias(Opaque, AliasTy { def_id, .. }) => {

View file

@ -2395,9 +2395,7 @@ fn typetree_from_ty_impl_inner<'tcx>(
}
if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() {
let inner_ty = if let Some(inner) = ty.builtin_deref(true) {
inner
} else {
let Some(inner_ty) = ty.builtin_deref(true) else {
return TypeTree::new();
};

View file

@ -1528,18 +1528,13 @@ impl<'tcx> Ty<'tcx> {
let mut cor_ty = self;
let mut ty = cor_ty;
loop {
if let ty::Coroutine(def_id, args) = ty.kind() {
cor_ty = ty;
f(ty);
if tcx.is_async_drop_in_place_coroutine(*def_id) {
ty = args.first().unwrap().expect_ty();
continue;
} else {
return cor_ty;
}
} else {
let ty::Coroutine(def_id, args) = ty.kind() else { return cor_ty };
cor_ty = ty;
f(ty);
if !tcx.is_async_drop_in_place_coroutine(*def_id) {
return cor_ty;
}
ty = args.first().unwrap().expect_ty();
}
}

View file

@ -100,11 +100,8 @@ impl<'tcx> MovePath<'tcx> {
move_paths: &IndexSlice<MovePathIndex, MovePath<'_>>,
f: impl Fn(MovePathIndex) -> bool,
) -> Option<MovePathIndex> {
let mut todo = if let Some(child) = self.first_child {
vec![child]
} else {
return None;
};
let Some(child) = self.first_child else { return None };
let mut todo = vec![child];
while let Some(mpi) = todo.pop() {
if f(mpi) {
@ -331,11 +328,10 @@ impl<'tcx> MovePathLookup<'tcx> {
MoveSubPathResult::Stop => None,
};
if let Some(&subpath) = subpath {
result = subpath;
} else {
let Some(&subpath) = subpath else {
return LookupResult::Parent(Some(result));
}
};
result = subpath;
}
LookupResult::Exact(result)

View file

@ -721,11 +721,8 @@ impl<'tcx> Map<'tcx> {
// Enum variant fields and enum discriminants alias each another.
self.for_each_variant_sibling(index, sub, f);
}
if let Some(sub) = sub {
index = sub
} else {
return;
}
let Some(sub) = sub else { return };
index = sub;
}
self.for_each_value_inside(index, f);
}

View file

@ -590,31 +590,30 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
let fields =
fields.iter().map(|&f| self.eval_to_const(f)).collect::<Option<Vec<_>>>()?;
let variant = if ty.ty.is_enum() { Some(variant) } else { None };
if matches!(ty.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..))
{
let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
let variant_dest = if let Some(variant) = variant {
self.ecx.project_downcast(&dest, variant).discard_err()?
} else {
dest.clone()
};
for (field_index, op) in fields.into_iter().enumerate() {
let field_dest = self
.ecx
.project_field(&variant_dest, FieldIdx::from_usize(field_index))
.discard_err()?;
self.ecx.copy_op(op, &field_dest).discard_err()?;
}
self.ecx
.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest)
.discard_err()?;
self.ecx
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
.discard_err()?;
dest.into()
} else {
let (BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) = ty.backend_repr
else {
return None;
};
let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?;
let variant_dest = if let Some(variant) = variant {
self.ecx.project_downcast(&dest, variant).discard_err()?
} else {
dest.clone()
};
for (field_index, op) in fields.into_iter().enumerate() {
let field_dest = self
.ecx
.project_field(&variant_dest, FieldIdx::from_usize(field_index))
.discard_err()?;
self.ecx.copy_op(op, &field_dest).discard_err()?;
}
self.ecx
.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest)
.discard_err()?;
self.ecx
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
.discard_err()?;
dest.into()
}
Union(active_field, field) => {
let field = self.eval_to_const(field)?;

View file

@ -410,14 +410,8 @@ impl<'tcx> Validator<'_, 'tcx> {
// In theory, any zero-sized value could be borrowed
// mutably without consequences. However, only &mut []
// is allowed right now.
if let ty::Array(_, len) = ty.kind() {
match len.try_to_target_usize(self.tcx) {
Some(0) => {}
_ => return Err(Unpromotable),
}
} else {
return Err(Unpromotable);
}
let ty::Array(_, len) = ty.kind() else { return Err(Unpromotable) };
let Some(0) = len.try_to_target_usize(self.tcx) else { return Err(Unpromotable) };
}
}

View file

@ -445,17 +445,15 @@ where
goal_kind: ty::ClosureKind,
) -> Result<Candidate<I>, NoSolution> {
let cx = ecx.cx();
let tupled_inputs_and_output =
match structural_traits::extract_tupled_inputs_and_output_from_callable(
let Some(tupled_inputs_and_output) =
structural_traits::extract_tupled_inputs_and_output_from_callable(
cx,
goal.predicate.self_ty(),
goal_kind,
)? {
Some(tupled_inputs_and_output) => tupled_inputs_and_output,
None => {
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
}
};
)?
else {
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
};
let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output);
// A built-in `Fn` impl only holds if the output is sized.

View file

@ -360,17 +360,15 @@ where
}
let cx = ecx.cx();
let tupled_inputs_and_output =
match structural_traits::extract_tupled_inputs_and_output_from_callable(
let Some(tupled_inputs_and_output) =
structural_traits::extract_tupled_inputs_and_output_from_callable(
cx,
goal.predicate.self_ty(),
goal_kind,
)? {
Some(a) => a,
None => {
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
}
};
)?
else {
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
};
let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output);
// A built-in `Fn` impl only holds if the output is sized.
@ -1409,42 +1407,39 @@ where
let where_bounds: Vec<_> = candidates
.extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
.collect();
if let Some((response, info)) = self.try_merge_candidates(&where_bounds) {
match info {
// If there's an always applicable candidate, the result of all
// other candidates does not matter. This means we can ignore
// them when checking whether we've reached a fixpoint.
//
// We always prefer the first always applicable candidate, even if a
// later candidate is also always applicable and would result in fewer
// reruns. We could slightly improve this by e.g. searching for another
// always applicable candidate which doesn't depend on any cycle heads.
//
// NOTE: This is optimization is observable in case there is an always
// applicable global candidate and another non-global candidate which only
// applies because of a provisional result. I can't even think of a test
// case where this would occur and even then, this would not be unsound.
// Supporting this makes the code more involved, so I am just going to
// ignore this for now.
MergeCandidateInfo::AlwaysApplicable(i) => {
for (j, c) in where_bounds.into_iter().enumerate() {
if i != j {
self.ignore_candidate_head_usages(c.head_usages)
}
}
// If a where-bound does not apply, we don't actually get a
// candidate for it. We manually track the head usages
// of all failed `ParamEnv` candidates instead.
self.ignore_candidate_head_usages(
failed_candidate_info.param_env_head_usages,
);
}
MergeCandidateInfo::EqualResponse => {}
}
return Ok((response, Some(TraitGoalProvenVia::ParamEnv)));
} else {
let Some((response, info)) = self.try_merge_candidates(&where_bounds) else {
return Ok((self.bail_with_ambiguity(&where_bounds), None));
};
match info {
// If there's an always applicable candidate, the result of all
// other candidates does not matter. This means we can ignore
// them when checking whether we've reached a fixpoint.
//
// We always prefer the first always applicable candidate, even if a
// later candidate is also always applicable and would result in fewer
// reruns. We could slightly improve this by e.g. searching for another
// always applicable candidate which doesn't depend on any cycle heads.
//
// NOTE: This is optimization is observable in case there is an always
// applicable global candidate and another non-global candidate which only
// applies because of a provisional result. I can't even think of a test
// case where this would occur and even then, this would not be unsound.
// Supporting this makes the code more involved, so I am just going to
// ignore this for now.
MergeCandidateInfo::AlwaysApplicable(i) => {
for (j, c) in where_bounds.into_iter().enumerate() {
if i != j {
self.ignore_candidate_head_usages(c.head_usages)
}
}
// If a where-bound does not apply, we don't actually get a
// candidate for it. We manually track the head usages
// of all failed `ParamEnv` candidates instead.
self.ignore_candidate_head_usages(failed_candidate_info.param_env_head_usages);
}
MergeCandidateInfo::EqualResponse => {}
}
return Ok((response, Some(TraitGoalProvenVia::ParamEnv)));
}
// Next, prefer any alias bound (nested or otherwise).

View file

@ -1537,86 +1537,80 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
/// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool {
// Detect that we are actually in a `where` predicate.
let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate {
let Some(ast::WherePredicate {
kind:
ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
bounded_ty,
bound_generic_params,
bounds,
}),
span,
span: where_span,
..
}) = self.diag_metadata.current_where_predicate
{
if !bound_generic_params.is_empty() {
return false;
}
(bounded_ty, bounds, span)
} else {
else {
return false;
};
if !bound_generic_params.is_empty() {
return false;
}
// Confirm that the target is an associated type.
let (ty, _, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind {
// use this to verify that ident is a type param.
let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else {
return false;
};
if !matches!(
partial_res.full_res(),
Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _))
) {
return false;
}
(&qself.ty, qself.position, path)
} else {
let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind else { return false };
// use this to verify that ident is a type param.
let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false };
if !matches!(
partial_res.full_res(),
Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _))
) {
return false;
}
let peeled_ty = qself.ty.peel_refs();
let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind else { return false };
// Confirm that the `SelfTy` is a type parameter.
let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
return false;
};
let peeled_ty = ty.peel_refs();
if let ast::TyKind::Path(None, type_param_path) = &peeled_ty.kind {
// Confirm that the `SelfTy` is a type parameter.
let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
if !matches!(
partial_res.full_res(),
Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _))
) {
return false;
}
let ([ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref)]) =
(&type_param_path.segments[..], &bounds[..])
else {
return false;
};
let [ast::PathSegment { ident, args: None, id }] =
&poly_trait_ref.trait_ref.path.segments[..]
else {
return false;
};
if poly_trait_ref.modifiers != ast::TraitBoundModifiers::NONE {
return false;
}
if ident.span == span {
let Some(partial_res) = self.r.partial_res_map.get(&id) else {
return false;
};
if !matches!(
partial_res.full_res(),
Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _))
) {
if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) {
return false;
}
if let (
[ast::PathSegment { args: None, .. }],
[ast::GenericBound::Trait(poly_trait_ref)],
) = (&type_param_path.segments[..], &bounds[..])
&& let [ast::PathSegment { ident, args: None, id }] =
&poly_trait_ref.trait_ref.path.segments[..]
&& poly_trait_ref.modifiers == ast::TraitBoundModifiers::NONE
{
if ident.span == span {
let Some(partial_res) = self.r.partial_res_map.get(&id) else {
return false;
};
if !matches!(partial_res.full_res(), Some(hir::def::Res::Def(..))) {
return false;
}
let Some(new_where_bound_predicate) =
mk_where_bound_predicate(path, poly_trait_ref, ty)
else {
return false;
};
err.span_suggestion_verbose(
*where_span,
format!("constrain the associated type to `{ident}`"),
where_bound_predicate_to_string(&new_where_bound_predicate),
Applicability::MaybeIncorrect,
);
}
return true;
}
let Some(new_where_bound_predicate) =
mk_where_bound_predicate(path, poly_trait_ref, &qself.ty)
else {
return false;
};
err.span_suggestion_verbose(
*where_span,
format!("constrain the associated type to `{ident}`"),
where_bound_predicate_to_string(&new_where_bound_predicate),
Applicability::MaybeIncorrect,
);
}
false
true
}
/// Check if the source is call expression and the first argument is `self`. If true,

View file

@ -10,6 +10,7 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![deny(clippy::manual_let_else)]
#![feature(arbitrary_self_types)]
#![feature(assert_matches)]
#![feature(box_patterns)]