More let_else adoptions

This commit is contained in:
est31 2022-02-02 12:45:20 +01:00
parent d5f9c40e6a
commit 670f5c6ef3
10 changed files with 210 additions and 228 deletions

View File

@ -471,9 +471,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// two imports. // two imports.
for new_node_id in [id1, id2] { for new_node_id in [id1, id2] {
let new_id = self.resolver.local_def_id(new_node_id); let new_id = self.resolver.local_def_id(new_node_id);
let res = if let Some(res) = resolutions.next() { let Some(res) = resolutions.next() else {
res
} else {
// Associate an HirId to both ids even if there is no resolution. // Associate an HirId to both ids even if there is no resolution.
let _old = self let _old = self
.node_id_to_hir_id .node_id_to_hir_id

View File

@ -32,6 +32,7 @@
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(let_else)]
#![feature(never_type)] #![feature(never_type)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]

View File

@ -217,85 +217,81 @@ where
let mut issue_num = None; let mut issue_num = None;
let mut is_soft = false; let mut is_soft = false;
for meta in metas { for meta in metas {
if let Some(mi) = meta.meta_item() { let Some(mi) = meta.meta_item() else {
match mi.name_or_empty() {
sym::feature => {
if !get(mi, &mut feature) {
continue 'outer;
}
}
sym::reason => {
if !get(mi, &mut reason) {
continue 'outer;
}
}
sym::issue => {
if !get(mi, &mut issue) {
continue 'outer;
}
// These unwraps are safe because `get` ensures the meta item
// is a name/value pair string literal.
issue_num = match issue.unwrap().as_str() {
"none" => None,
issue => {
let emit_diag = |msg: &str| {
struct_span_err!(
diagnostic,
mi.span,
E0545,
"`issue` must be a non-zero numeric string \
or \"none\"",
)
.span_label(
mi.name_value_literal_span().unwrap(),
msg,
)
.emit();
};
match issue.parse() {
Ok(0) => {
emit_diag(
"`issue` must not be \"0\", \
use \"none\" instead",
);
continue 'outer;
}
Ok(num) => NonZeroU32::new(num),
Err(err) => {
emit_diag(&err.to_string());
continue 'outer;
}
}
}
};
}
sym::soft => {
if !mi.is_word() {
let msg = "`soft` should not have any arguments";
sess.parse_sess.span_diagnostic.span_err(mi.span, msg);
}
is_soft = true;
}
_ => {
handle_errors(
&sess.parse_sess,
meta.span(),
AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path),
&["feature", "reason", "issue", "soft"],
),
);
continue 'outer;
}
}
} else {
handle_errors( handle_errors(
&sess.parse_sess, &sess.parse_sess,
meta.span(), meta.span(),
AttrError::UnsupportedLiteral("unsupported literal", false), AttrError::UnsupportedLiteral("unsupported literal", false),
); );
continue 'outer; continue 'outer;
};
match mi.name_or_empty() {
sym::feature => {
if !get(mi, &mut feature) {
continue 'outer;
}
}
sym::reason => {
if !get(mi, &mut reason) {
continue 'outer;
}
}
sym::issue => {
if !get(mi, &mut issue) {
continue 'outer;
}
// These unwraps are safe because `get` ensures the meta item
// is a name/value pair string literal.
issue_num = match issue.unwrap().as_str() {
"none" => None,
issue => {
let emit_diag = |msg: &str| {
struct_span_err!(
diagnostic,
mi.span,
E0545,
"`issue` must be a non-zero numeric string \
or \"none\"",
)
.span_label(mi.name_value_literal_span().unwrap(), msg)
.emit();
};
match issue.parse() {
Ok(0) => {
emit_diag(
"`issue` must not be \"0\", \
use \"none\" instead",
);
continue 'outer;
}
Ok(num) => NonZeroU32::new(num),
Err(err) => {
emit_diag(&err.to_string());
continue 'outer;
}
}
}
};
}
sym::soft => {
if !mi.is_word() {
let msg = "`soft` should not have any arguments";
sess.parse_sess.span_diagnostic.span_err(mi.span, msg);
}
is_soft = true;
}
_ => {
handle_errors(
&sess.parse_sess,
meta.span(),
AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path),
&["feature", "reason", "issue", "soft"],
),
);
continue 'outer;
}
} }
} }

View File

@ -4,6 +4,8 @@
//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
//! to this crate. //! to this crate.
#![feature(let_else)]
#[macro_use] #[macro_use]
extern crate rustc_macros; extern crate rustc_macros;

View File

@ -311,43 +311,39 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
ty::BoundRegionKind::BrEnv => { ty::BoundRegionKind::BrEnv => {
let def_ty = self.regioncx.universal_regions().defining_ty; let def_ty = self.regioncx.universal_regions().defining_ty;
if let DefiningTy::Closure(_, substs) = def_ty { let DefiningTy::Closure(_, substs) = def_ty else {
let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) =
tcx.hir().expect_expr(self.mir_hir_id()).kind
{
span
} else {
bug!("Closure is not defined by a closure expr");
};
let region_name = self.synthesize_region_name();
let closure_kind_ty = substs.as_closure().kind_ty();
let note = match closure_kind_ty.to_opt_closure_kind() {
Some(ty::ClosureKind::Fn) => {
"closure implements `Fn`, so references to captured variables \
can't escape the closure"
}
Some(ty::ClosureKind::FnMut) => {
"closure implements `FnMut`, so references to captured variables \
can't escape the closure"
}
Some(ty::ClosureKind::FnOnce) => {
bug!("BrEnv in a `FnOnce` closure");
}
None => bug!("Closure kind not inferred in borrow check"),
};
Some(RegionName {
name: region_name,
source: RegionNameSource::SynthesizedFreeEnvRegion(
args_span,
note.to_string(),
),
})
} else {
// Can't have BrEnv in functions, constants or generators. // Can't have BrEnv in functions, constants or generators.
bug!("BrEnv outside of closure."); bug!("BrEnv outside of closure.");
} };
let hir::ExprKind::Closure(_, _, _, args_span, _) =
tcx.hir().expect_expr(self.mir_hir_id()).kind else {
bug!("Closure is not defined by a closure expr");
};
let region_name = self.synthesize_region_name();
let closure_kind_ty = substs.as_closure().kind_ty();
let note = match closure_kind_ty.to_opt_closure_kind() {
Some(ty::ClosureKind::Fn) => {
"closure implements `Fn`, so references to captured variables \
can't escape the closure"
}
Some(ty::ClosureKind::FnMut) => {
"closure implements `FnMut`, so references to captured variables \
can't escape the closure"
}
Some(ty::ClosureKind::FnOnce) => {
bug!("BrEnv in a `FnOnce` closure");
}
None => bug!("Closure kind not inferred in borrow check"),
};
Some(RegionName {
name: region_name,
source: RegionNameSource::SynthesizedFreeEnvRegion(
args_span,
note.to_string(),
),
})
} }
ty::BoundRegionKind::BrAnon(_) => None, ty::BoundRegionKind::BrAnon(_) => None,
@ -765,48 +761,45 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
let hir = self.infcx.tcx.hir(); let hir = self.infcx.tcx.hir();
if let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind { let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else {
let opaque_ty = hir.item(id);
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
bounds:
[
hir::GenericBound::LangItemTrait(
hir::LangItem::Future,
_,
_,
hir::GenericArgs {
bindings:
[
hir::TypeBinding {
ident: Ident { name: sym::Output, .. },
kind:
hir::TypeBindingKind::Equality {
term: hir::Term::Ty(ty),
},
..
},
],
..
},
),
],
..
}) = opaque_ty.kind
{
ty
} else {
span_bug!(
hir_ty.span,
"bounds from lowered return type of async fn did not match expected format: {:?}",
opaque_ty
);
}
} else {
span_bug!( span_bug!(
hir_ty.span, hir_ty.span,
"lowered return type of async fn is not OpaqueDef: {:?}", "lowered return type of async fn is not OpaqueDef: {:?}",
hir_ty hir_ty
); );
};
let opaque_ty = hir.item(id);
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
bounds:
[
hir::GenericBound::LangItemTrait(
hir::LangItem::Future,
_,
_,
hir::GenericArgs {
bindings:
[
hir::TypeBinding {
ident: Ident { name: sym::Output, .. },
kind:
hir::TypeBindingKind::Equality { term: hir::Term::Ty(ty) },
..
},
],
..
},
),
],
..
}) = opaque_ty.kind
{
ty
} else {
span_bug!(
hir_ty.span,
"bounds from lowered return type of async fn did not match expected format: {:?}",
opaque_ty
);
} }
} }

View File

@ -1427,9 +1427,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
bug!("temporary should be initialized exactly once") bug!("temporary should be initialized exactly once")
}; };
let loc = match init.location { let InitLocation::Statement(loc) = init.location else {
InitLocation::Statement(stmt) => stmt, bug!("temporary initialized in arguments")
_ => bug!("temporary initialized in arguments"),
}; };
let body = self.body; let body = self.body;

View File

@ -602,33 +602,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
for binding in &candidate_ref.bindings { for binding in &candidate_ref.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard); let local = self.var_local_id(binding.var_id, OutsideGuard);
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
)))) = self.local_decls[local].local_info )))) = self.local_decls[local].local_info else {
{
// `try_upvars_resolved` may fail if it is unable to resolve the given
// `PlaceBuilder` inside a closure. In this case, we don't want to include
// a scrutinee place. `scrutinee_place_builder` will fail for destructured
// assignments. This is because a closure only captures the precise places
// that it will read and as a result a closure may not capture the entire
// tuple/struct and rather have individual places that will be read in the
// final MIR.
// Example:
// ```
// let foo = (0, 1);
// let c = || {
// let (v1, v2) = foo;
// };
// ```
if let Ok(match_pair_resolved) =
initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
{
let place =
match_pair_resolved.into_place(self.tcx, self.typeck_results);
*match_place = Some(place);
}
} else {
bug!("Let binding to non-user variable.") bug!("Let binding to non-user variable.")
};
// `try_upvars_resolved` may fail if it is unable to resolve the given
// `PlaceBuilder` inside a closure. In this case, we don't want to include
// a scrutinee place. `scrutinee_place_builder` will fail for destructured
// assignments. This is because a closure only captures the precise places
// that it will read and as a result a closure may not capture the entire
// tuple/struct and rather have individual places that will be read in the
// final MIR.
// Example:
// ```
// let foo = (0, 1);
// let c = || {
// let (v1, v2) = foo;
// };
// ```
if let Ok(match_pair_resolved) =
initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
{
let place = match_pair_resolved.into_place(self.tcx, self.typeck_results);
*match_place = Some(place);
} }
} }
// All of the subcandidates should bind the same locals, so we // All of the subcandidates should bind the same locals, so we

View File

@ -227,16 +227,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let target_blocks = make_target_blocks(self); let target_blocks = make_target_blocks(self);
let terminator = if *switch_ty.kind() == ty::Bool { let terminator = if *switch_ty.kind() == ty::Bool {
assert!(!options.is_empty() && options.len() <= 2); assert!(!options.is_empty() && options.len() <= 2);
if let [first_bb, second_bb] = *target_blocks { let [first_bb, second_bb] = *target_blocks else {
let (true_bb, false_bb) = match options[0] {
1 => (first_bb, second_bb),
0 => (second_bb, first_bb),
v => span_bug!(test.span, "expected boolean value but got {:?}", v),
};
TerminatorKind::if_(self.tcx, Operand::Copy(place), true_bb, false_bb)
} else {
bug!("`TestKind::SwitchInt` on `bool` should have two targets") bug!("`TestKind::SwitchInt` on `bool` should have two targets")
} };
let (true_bb, false_bb) = match options[0] {
1 => (first_bb, second_bb),
0 => (second_bb, first_bb),
v => span_bug!(test.span, "expected boolean value but got {:?}", v),
};
TerminatorKind::if_(self.tcx, Operand::Copy(place), true_bb, false_bb)
} else { } else {
// The switch may be inexhaustive so we have a catch all block // The switch may be inexhaustive so we have a catch all block
debug_assert_eq!(options.len() + 1, target_blocks.len()); debug_assert_eq!(options.len() + 1, target_blocks.len());
@ -285,24 +284,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let hi = self.literal_operand(test.span, hi); let hi = self.literal_operand(test.span, hi);
let val = Operand::Copy(place); let val = Operand::Copy(place);
if let [success, fail] = *target_blocks { let [success, fail] = *target_blocks else {
self.compare(
block,
lower_bound_success,
fail,
source_info,
BinOp::Le,
lo,
val.clone(),
);
let op = match *end {
RangeEnd::Included => BinOp::Le,
RangeEnd::Excluded => BinOp::Lt,
};
self.compare(lower_bound_success, success, fail, source_info, op, val, hi);
} else {
bug!("`TestKind::Range` should have two target blocks"); bug!("`TestKind::Range` should have two target blocks");
} };
self.compare(
block,
lower_bound_success,
fail,
source_info,
BinOp::Le,
lo,
val.clone(),
);
let op = match *end {
RangeEnd::Included => BinOp::Le,
RangeEnd::Excluded => BinOp::Lt,
};
self.compare(lower_bound_success, success, fail, source_info, op, val, hi);
} }
TestKind::Len { len, op } => { TestKind::Len { len, op } => {
@ -317,21 +315,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// expected = <N> // expected = <N>
let expected = self.push_usize(block, source_info, len); let expected = self.push_usize(block, source_info, len);
if let [true_bb, false_bb] = *target_blocks { let [true_bb, false_bb] = *target_blocks else {
// result = actual == expected OR result = actual < expected
// branch based on result
self.compare(
block,
true_bb,
false_bb,
source_info,
op,
Operand::Move(actual),
Operand::Move(expected),
);
} else {
bug!("`TestKind::Len` should have two target blocks"); bug!("`TestKind::Len` should have two target blocks");
} };
// result = actual == expected OR result = actual < expected
// branch based on result
self.compare(
block,
true_bb,
false_bb,
source_info,
op,
Operand::Move(actual),
Operand::Move(expected),
);
} }
} }
} }
@ -459,16 +456,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
); );
self.diverge_from(block); self.diverge_from(block);
if let [success_block, fail_block] = *make_target_blocks(self) { let [success_block, fail_block] = *make_target_blocks(self) else {
// check the result
self.cfg.terminate(
eq_block,
source_info,
TerminatorKind::if_(self.tcx, Operand::Move(eq_result), success_block, fail_block),
);
} else {
bug!("`TestKind::Eq` should have two target blocks") bug!("`TestKind::Eq` should have two target blocks")
} };
// check the result
self.cfg.terminate(
eq_block,
source_info,
TerminatorKind::if_(self.tcx, Operand::Move(eq_result), success_block, fail_block),
);
} }
/// Given that we are performing `test` against `test_place`, this job /// Given that we are performing `test` against `test_place`, this job

View File

@ -47,11 +47,10 @@ use rls_data::{
use tracing::{debug, error}; use tracing::{debug, error};
#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5213
macro_rules! down_cast_data { macro_rules! down_cast_data {
($id:ident, $kind:ident, $sp:expr) => { ($id:ident, $kind:ident, $sp:expr) => {
let $id = if let super::Data::$kind(data) = $id { let super::Data::$kind($id) = $id else {
data
} else {
span_bug!($sp, "unexpected data kind: {:?}", $id); span_bug!($sp, "unexpected data kind: {:?}", $id);
}; };
}; };

View File

@ -1,6 +1,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(nll)] #![feature(nll)]
#![feature(let_else)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]