Skip to content

Commit

Permalink
Auto merge of #27929 - w00ns:issue-27889-same-field-names, r=pnkfelix
Browse files Browse the repository at this point in the history
Fix for issue #27889: same field names in enum variants
  • Loading branch information
bors committed Dec 12, 2015
2 parents da31c14 + 43725dc commit 5e82941
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 21 deletions.
4 changes: 2 additions & 2 deletions src/librustc_borrowck/borrowck/check_loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
self.check_if_assigned_path_is_moved(id, span,
use_kind, lp_base);
}
LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => {
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
match lp_base.to_type().sty {
ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => {
// In the case where the owner implements drop, then
Expand All @@ -770,7 +770,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
self.check_if_assigned_path_is_moved(id, span,
use_kind, lp_base);
}
LpExtend(ref lp_base, _, LpInterior(InteriorElement(..))) |
LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) |
LpExtend(ref lp_base, _, LpDeref(_)) => {
// assigning to `P[i]` requires `P` is initialized
// assigning to `(*P)` requires `P` is initialized
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_borrowck/borrowck/fragments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,15 +379,15 @@ fn add_fragment_siblings<'tcx>(this: &MoveData<'tcx>,
// bind.
//
// Anyway, for now: LV[j] is not tracked precisely
LpExtend(_, _, LpInterior(InteriorElement(..))) => {
LpExtend(_, _, LpInterior(_, InteriorElement(..))) => {
let mp = this.move_path(tcx, lp.clone());
gathered_fragments.push(AllButOneFrom(mp));
}

// field access LV.x and tuple access LV#k are the cases
// we are interested in
LpExtend(ref loan_parent, mc,
LpInterior(InteriorField(ref field_name))) => {
LpInterior(_, InteriorField(ref field_name))) => {
let enum_variant_info = match loan_parent.kind {
LpDowncast(ref loan_parent_2, variant_def_id) =>
Some((variant_def_id, loan_parent_2.clone())),
Expand Down Expand Up @@ -516,7 +516,7 @@ fn add_fragment_sibling_core<'tcx>(this: &MoveData<'tcx>,
LpVar(..) | LpUpvar(..) | LpExtend(..) => enum_variant_did,
};

let loan_path_elem = LpInterior(InteriorField(new_field_name));
let loan_path_elem = LpInterior(opt_variant_did, InteriorField(new_field_name));
let new_lp_type = match new_field_name {
mc::NamedField(ast_name) =>
tcx.named_element_ty(parent.to_type(), ast_name, opt_variant_did),
Expand Down
6 changes: 5 additions & 1 deletion src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,12 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
// Overwriting the base would not change the type of
// the memory, so no additional restrictions are
// needed.
let opt_variant_id = match cmt_base.cat {
Categorization::Downcast(_, variant_id) => Some(variant_id),
_ => None
};
let result = self.restrict(cmt_base);
self.extend(result, &cmt, LpInterior(i.cleaned()))
self.extend(result, &cmt, LpInterior(opt_variant_id, i.cleaned()))
}

Categorization::StaticItem => {
Expand Down
41 changes: 27 additions & 14 deletions src/librustc_borrowck/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,10 +377,18 @@ impl ToInteriorKind for mc::InteriorKind {
}
}

// This can be:
// - a pointer dereference (`*LV` in README.md)
// - a field reference, with an optional definition of the containing
// enum variant (`LV.f` in README.md)
// `DefId` is present when the field is part of struct that is in
// a variant of an enum. For instance in:
// `enum E { X { foo: u32 }, Y { foo: u32 }}`
// each `foo` is qualified by the definitition id of the variant (`X` or `Y`).
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum LoanPathElem {
LpDeref(mc::PointerKind), // `*LV` in README.md
LpInterior(InteriorKind), // `LV.f` in README.md
LpDeref(mc::PointerKind),
LpInterior(Option<DefId>, InteriorKind),
}

pub fn closure_to_block(closure_id: ast::NodeId,
Expand Down Expand Up @@ -413,8 +421,9 @@ impl<'tcx> LoanPath<'tcx> {

fn has_fork(&self, other: &LoanPath<'tcx>) -> bool {
match (&self.kind, &other.kind) {
(&LpExtend(ref base, _, LpInterior(id)), &LpExtend(ref base2, _, LpInterior(id2))) =>
if id == id2 {
(&LpExtend(ref base, _, LpInterior(opt_variant_id, id)),
&LpExtend(ref base2, _, LpInterior(opt_variant_id2, id2))) =>
if id == id2 && opt_variant_id == opt_variant_id2 {
base.has_fork(&**base2)
} else {
true
Expand All @@ -428,23 +437,23 @@ impl<'tcx> LoanPath<'tcx> {
fn depth(&self) -> usize {
match self.kind {
LpExtend(ref base, _, LpDeref(_)) => base.depth(),
LpExtend(ref base, _, LpInterior(_)) => base.depth() + 1,
LpExtend(ref base, _, LpInterior(_, _)) => base.depth() + 1,
_ => 0,
}
}

fn common(&self, other: &LoanPath<'tcx>) -> Option<LoanPath<'tcx>> {
match (&self.kind, &other.kind) {
(&LpExtend(ref base, a, LpInterior(id)),
&LpExtend(ref base2, _, LpInterior(id2))) => {
if id == id2 {
(&LpExtend(ref base, a, LpInterior(opt_variant_id, id)),
&LpExtend(ref base2, _, LpInterior(opt_variant_id2, id2))) => {
if id == id2 && opt_variant_id == opt_variant_id2 {
base.common(&**base2).map(|x| {
let xd = x.depth();
if base.depth() == xd && base2.depth() == xd {
assert_eq!(base.ty, base2.ty);
assert_eq!(self.ty, other.ty);
LoanPath {
kind: LpExtend(Rc::new(x), a, LpInterior(id)),
kind: LpExtend(Rc::new(x), a, LpInterior(opt_variant_id, id)),
ty: self.ty,
}
} else {
Expand Down Expand Up @@ -509,7 +518,11 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {

Categorization::Interior(ref cmt_base, ik) => {
opt_loan_path(cmt_base).map(|lp| {
new_lp(LpExtend(lp, cmt.mutbl, LpInterior(ik.cleaned())))
let opt_variant_id = match cmt_base.cat {
Categorization::Downcast(_, did) => Some(did),
_ => None
};
new_lp(LpExtend(lp, cmt.mutbl, LpInterior(opt_variant_id, ik.cleaned())))
})
}

Expand Down Expand Up @@ -1068,7 +1081,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}


LpExtend(ref lp_base, _, LpInterior(InteriorField(fname))) => {
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => {
self.append_autoderefd_loan_path_to_string(&**lp_base, out);
match fname {
mc::NamedField(fname) => {
Expand All @@ -1082,7 +1095,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
}

LpExtend(ref lp_base, _, LpInterior(InteriorElement(..))) => {
LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) => {
self.append_autoderefd_loan_path_to_string(&**lp_base, out);
out.push_str("[..]");
}
Expand Down Expand Up @@ -1210,7 +1223,7 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> {
write!(f, "{:?}.*", lp)
}

LpExtend(ref lp, _, LpInterior(ref interior)) => {
LpExtend(ref lp, _, LpInterior(_, ref interior)) => {
write!(f, "{:?}.{:?}", lp, interior)
}
}
Expand Down Expand Up @@ -1242,7 +1255,7 @@ impl<'tcx> fmt::Display for LoanPath<'tcx> {
write!(f, "{}.*", lp)
}

LpExtend(ref lp, _, LpInterior(ref interior)) => {
LpExtend(ref lp, _, LpInterior(_, ref interior)) => {
write!(f, "{}.{:?}", lp, interior)
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_borrowck/borrowck/move_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
LpVar(_) | LpUpvar(_) => {
true
}
LpExtend(_, _, LpInterior(InteriorKind::InteriorElement(..))) => {
LpExtend(_, _, LpInterior(_, InteriorKind::InteriorElement(..))) => {
// Paths involving element accesses a[i] do not refer to a unique
// location, as there is no accurate tracking of the indices.
//
Expand Down
31 changes: 31 additions & 0 deletions src/test/run-pass/issue-27889.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that a field can have the same name in different variants
// of an enum
// FIXME #27889

pub enum Foo {
X { foo: u32 },
Y { foo: u32 }
}

pub fn foo(mut x: Foo) {
let mut y = None;
let mut z = None;
if let Foo::X { ref foo } = x {
z = Some(foo);
}
if let Foo::Y { ref mut foo } = x {
y = Some(foo);
}
}

fn main() {}

0 comments on commit 5e82941

Please sign in to comment.