Give temporaries in if let guards correct scopes
- Make temporaries in if-let guards be the same variable in MIR when the guard is duplicated due to or-patterns. - Change the "destruction scope" for match arms to be the arm scope rather than the arm body scope. - Add tests.
This commit is contained in:
parent
68d684cbff
commit
d437a111f5
10 changed files with 178 additions and 10 deletions
|
@ -43,7 +43,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let expr_ty = expr.ty;
|
||||
let temp = {
|
||||
let deduplicate_temps =
|
||||
this.fixed_temps_scope.is_some() && this.fixed_temps_scope == temp_lifetime;
|
||||
let temp = if deduplicate_temps && let Some(temp_index) = this.fixed_temps.get(&expr_id) {
|
||||
*temp_index
|
||||
} else {
|
||||
let mut local_decl = LocalDecl::new(expr_ty, expr_span);
|
||||
if mutability.is_not() {
|
||||
local_decl = local_decl.immutable();
|
||||
|
@ -72,6 +76,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
**local_decl.local_info.as_mut().assert_crate_local() = local_info;
|
||||
this.local_decls.push(local_decl)
|
||||
};
|
||||
if deduplicate_temps {
|
||||
this.fixed_temps.insert(expr_id, temp);
|
||||
}
|
||||
let temp_place = Place::from(temp);
|
||||
|
||||
match expr.kind {
|
||||
|
|
|
@ -396,6 +396,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let arm_scope = (arm.scope, arm_source_info);
|
||||
let match_scope = self.local_scope();
|
||||
self.in_scope(arm_scope, arm.lint_level, |this| {
|
||||
let old_dedup_scope =
|
||||
mem::replace(&mut this.fixed_temps_scope, Some(arm.scope));
|
||||
|
||||
// `try_to_place` 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 to be resolved
|
||||
|
@ -427,6 +430,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
false,
|
||||
);
|
||||
|
||||
this.fixed_temps_scope = old_dedup_scope;
|
||||
|
||||
if let Some(source_scope) = scope {
|
||||
this.source_scope = source_scope;
|
||||
}
|
||||
|
|
|
@ -210,6 +210,12 @@ struct Builder<'a, 'tcx> {
|
|||
/// finish building it.
|
||||
guard_context: Vec<GuardFrame>,
|
||||
|
||||
/// Temporaries with fixed indexes. Used so that if-let guards on arms
|
||||
/// with an or-pattern are only created once.
|
||||
fixed_temps: FxHashMap<ExprId, Local>,
|
||||
/// Scope of temporaries that should be deduplicated using [Self::fixed_temps].
|
||||
fixed_temps_scope: Option<region::Scope>,
|
||||
|
||||
/// Maps `HirId`s of variable bindings to the `Local`s created for them.
|
||||
/// (A match binding can have two locals; the 2nd is for the arm's guard.)
|
||||
var_indices: FxHashMap<LocalVarId, LocalsForNode>,
|
||||
|
@ -752,6 +758,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
source_scopes: IndexVec::new(),
|
||||
source_scope: OUTERMOST_SOURCE_SCOPE,
|
||||
guard_context: vec![],
|
||||
fixed_temps: Default::default(),
|
||||
fixed_temps_scope: None,
|
||||
in_scope_unsafe: safety,
|
||||
local_decls: IndexVec::from_elem_n(LocalDecl::new(return_ty, return_span), 1),
|
||||
canonical_user_type_annotations: IndexVec::new(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue