lower let-else in MIR instead
This commit is contained in:
parent
38b72154de
commit
6c529ded86
71 changed files with 421 additions and 264 deletions
|
@ -99,6 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
ref pattern,
|
||||
initializer,
|
||||
lint_level,
|
||||
else_block,
|
||||
} => {
|
||||
let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
|
||||
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
|
||||
|
@ -124,18 +125,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|this| {
|
||||
let scope = (*init_scope, source_info);
|
||||
this.in_scope(scope, *lint_level, |this| {
|
||||
this.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
ArmHasGuard(false),
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
this.expr_into_pattern(block, pattern.clone(), init)
|
||||
if let Some(else_block) = else_block {
|
||||
this.ast_let_else(
|
||||
block,
|
||||
init,
|
||||
initializer_span,
|
||||
else_block,
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
)
|
||||
} else {
|
||||
this.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
ArmHasGuard(false),
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
);
|
||||
)
|
||||
} else {
|
||||
let scope = (*init_scope, source_info);
|
||||
unpack!(this.in_scope(scope, *lint_level, |this| {
|
||||
|
|
|
@ -1615,7 +1615,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// those N possible outcomes, create a (initially empty)
|
||||
// vector of candidates. Those are the candidates that still
|
||||
// apply if the test has that particular outcome.
|
||||
debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
|
||||
debug!("test_candidates: test={:?} match_pair={:?}", test, match_pair);
|
||||
let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![];
|
||||
target_candidates.resize_with(test.targets(), Default::default);
|
||||
|
||||
|
@ -1635,8 +1635,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
// at least the first candidate ought to be tested
|
||||
assert!(total_candidate_count > candidates.len());
|
||||
debug!("tested_candidates: {}", total_candidate_count - candidates.len());
|
||||
debug!("untested_candidates: {}", candidates.len());
|
||||
debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len());
|
||||
debug!("test_candidates: untested_candidates: {}", candidates.len());
|
||||
|
||||
// HACK(matthewjasper) This is a closure so that we can let the test
|
||||
// create its blocks before the rest of the match. This currently
|
||||
|
@ -2274,4 +2274,75 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
debug!("declare_binding: vars={:?}", locals);
|
||||
self.var_indices.insert(var_id, locals);
|
||||
}
|
||||
|
||||
pub(crate) fn ast_let_else(
|
||||
&mut self,
|
||||
mut block: BasicBlock,
|
||||
init: &Expr<'tcx>,
|
||||
initializer_span: Span,
|
||||
else_block: &Block,
|
||||
visibility_scope: Option<SourceScope>,
|
||||
remainder_span: Span,
|
||||
pattern: &Pat<'tcx>,
|
||||
) -> BlockAnd<()> {
|
||||
let scrutinee = unpack!(block = self.lower_scrutinee(block, init, initializer_span));
|
||||
let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) };
|
||||
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
|
||||
self.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
ArmHasGuard(false),
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
|
||||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
initializer_span,
|
||||
pattern.span,
|
||||
false,
|
||||
&mut [&mut candidate, &mut wildcard],
|
||||
);
|
||||
// This block is for the matching case
|
||||
let matching = self.bind_pattern(
|
||||
self.source_info(pattern.span),
|
||||
candidate,
|
||||
None,
|
||||
&fake_borrow_temps,
|
||||
initializer_span,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
// This block is for the failure case
|
||||
let failure = self.bind_pattern(
|
||||
self.source_info(else_block.span),
|
||||
wildcard,
|
||||
None,
|
||||
&fake_borrow_temps,
|
||||
initializer_span,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
// This place is not really used because this destination place
|
||||
// should never be used to take values at the end of the failure
|
||||
// block.
|
||||
let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() };
|
||||
let failure_block;
|
||||
unpack!(
|
||||
failure_block = self.ast_block(
|
||||
dummy_place,
|
||||
failure,
|
||||
else_block,
|
||||
self.source_info(else_block.span),
|
||||
)
|
||||
);
|
||||
self.cfg.terminate(
|
||||
failure_block,
|
||||
self.source_info(else_block.span),
|
||||
TerminatorKind::Unreachable,
|
||||
);
|
||||
matching.unit()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ impl<'tcx> Cx<'tcx> {
|
|||
.filter_map(|(index, stmt)| {
|
||||
let hir_id = stmt.hir_id;
|
||||
let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
|
||||
match stmt.kind {
|
||||
match &stmt.kind {
|
||||
hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
|
||||
let stmt = Stmt {
|
||||
kind: StmtKind::Expr {
|
||||
|
@ -66,7 +66,7 @@ impl<'tcx> Cx<'tcx> {
|
|||
// ignore for purposes of the MIR
|
||||
None
|
||||
}
|
||||
hir::StmtKind::Local(ref local) => {
|
||||
hir::StmtKind::Local(local, els) => {
|
||||
let remainder_scope = region::Scope {
|
||||
id: block_id,
|
||||
data: region::ScopeData::Remainder(region::FirstStatementIndex::new(
|
||||
|
@ -74,6 +74,8 @@ impl<'tcx> Cx<'tcx> {
|
|||
)),
|
||||
};
|
||||
|
||||
let else_block = els.map(|els| self.mirror_block(els));
|
||||
|
||||
let mut pattern = self.pattern_from_hir(local.pat);
|
||||
debug!(?pattern);
|
||||
|
||||
|
@ -110,6 +112,7 @@ impl<'tcx> Cx<'tcx> {
|
|||
},
|
||||
pattern,
|
||||
initializer: local.init.map(|init| self.mirror_expr(init)),
|
||||
else_block,
|
||||
lint_level: LintLevel::Explicit(local.hir_id),
|
||||
},
|
||||
opt_destruction_scope: opt_dxn_ext,
|
||||
|
|
|
@ -21,7 +21,7 @@ use rustc_session::lint::builtin::{
|
|||
};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span};
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
||||
pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||
let body_id = match def_id.as_local() {
|
||||
|
@ -75,8 +75,11 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) {
|
||||
intravisit::walk_local(self, loc);
|
||||
fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) {
|
||||
intravisit::walk_local(self, loc, els);
|
||||
if let Some(init) = &loc.init && els.is_some() {
|
||||
self.check_let(&loc.pat, &init, loc.span);
|
||||
}
|
||||
|
||||
let (msg, sp) = match loc.source {
|
||||
hir::LocalSource::Normal => ("local binding", Some(loc.span)),
|
||||
|
@ -84,7 +87,9 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
|
|||
hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
|
||||
hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
|
||||
};
|
||||
self.check_irrefutable(&loc.pat, msg, sp);
|
||||
if els.is_none() {
|
||||
self.check_irrefutable(&loc.pat, msg, sp);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
||||
|
@ -1125,17 +1130,16 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
|
|||
}) if Some(*hir_id) == pat_id => {
|
||||
return LetSource::IfLetGuard;
|
||||
}
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => {
|
||||
let expn_data = span.ctxt().outer_expn_data();
|
||||
if let ExpnKind::Desugaring(DesugaringKind::LetElse) = expn_data.kind {
|
||||
return LetSource::LetElse(expn_data.call_site);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let parent_parent = hir.get_parent_node(parent);
|
||||
let parent_parent_node = hir.get(parent_parent);
|
||||
if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_, Some(_)), span, .. }) =
|
||||
parent_parent_node
|
||||
{
|
||||
return LetSource::LetElse(*span);
|
||||
}
|
||||
|
||||
let parent_parent_parent = hir.get_parent_node(parent_parent);
|
||||
let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue