Skip to content

Fix for issue #27889: same field names in enum variants #27929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from Dec 12, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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() {}