Skip to content

mem_categorization: handle type-based paths in variant patterns #42969

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
Jun 30, 2017
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
9 changes: 1 addition & 8 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) {
debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat);

let tcx = self.tcx();
let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
if let PatKind::Binding(bmode, def_id, ..) = pat.node {
Expand Down Expand Up @@ -864,13 +863,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
match def {
Def::Variant(variant_did) |
Def::VariantCtor(variant_did, ..) => {
let enum_did = tcx.parent_def_id(variant_did).unwrap();
let downcast_cmt = if tcx.adt_def(enum_did).is_univariant() {
cmt_pat
} else {
let cmt_pat_ty = cmt_pat.ty;
mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
};
let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did);

debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
delegate.matched_pat(pat, downcast_cmt, match_mode);
Expand Down
92 changes: 45 additions & 47 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1032,22 +1032,29 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
ret
}

pub fn cat_downcast<N:ast_node>(&self,
node: &N,
base_cmt: cmt<'tcx>,
downcast_ty: Ty<'tcx>,
variant_did: DefId)
-> cmt<'tcx> {
let ret = Rc::new(cmt_ {
id: node.id(),
span: node.span(),
mutbl: base_cmt.mutbl.inherit(),
cat: Categorization::Downcast(base_cmt, variant_did),
ty: downcast_ty,
note: NoteNone
});
debug!("cat_downcast ret={:?}", ret);
ret
pub fn cat_downcast_if_needed<N:ast_node>(&self,
node: &N,
base_cmt: cmt<'tcx>,
variant_did: DefId)
-> cmt<'tcx> {
// univariant enums do not need downcasts
let base_did = self.tcx.parent_def_id(variant_did).unwrap();
if !self.tcx.adt_def(base_did).is_univariant() {
let base_ty = base_cmt.ty;
let ret = Rc::new(cmt_ {
id: node.id(),
span: node.span(),
mutbl: base_cmt.mutbl.inherit(),
cat: Categorization::Downcast(base_cmt, variant_did),
ty: base_ty,
note: NoteNone
});
debug!("cat_downcast ret={:?}", ret);
ret
} else {
debug!("cat_downcast univariant={:?}", base_cmt);
base_cmt
}
}

pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, mut op: F) -> McResult<()>
Expand Down Expand Up @@ -1109,45 +1116,23 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {

op(cmt.clone(), pat);

// Note: This goes up here (rather than within the PatKind::TupleStruct arm
// alone) because PatKind::Struct can also refer to variants.
let cmt = match pat.node {
PatKind::Path(hir::QPath::Resolved(_, ref path)) |
PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
match path.def {
Def::Err => {
debug!("access to unresolvable pattern {:?}", pat);
return Err(())
}
Def::Variant(variant_did) |
Def::VariantCtor(variant_did, ..) => {
// univariant enums do not need downcasts
let enum_did = self.tcx.parent_def_id(variant_did).unwrap();
if !self.tcx.adt_def(enum_did).is_univariant() {
self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
} else {
cmt
}
}
_ => cmt
}
}
_ => cmt
};

match pat.node {
PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
let def = self.tables.qpath_def(qpath, pat.id);
let expected_len = match def {
let (cmt, expected_len) = match def {
Def::Err => {
debug!("access to unresolvable pattern {:?}", pat);
return Err(())
}
Def::VariantCtor(def_id, CtorKind::Fn) => {
let enum_def = self.tcx.parent_def_id(def_id).unwrap();
self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len()
(self.cat_downcast_if_needed(pat, cmt, def_id),
self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len())
}
Def::StructCtor(_, CtorKind::Fn) => {
match self.pat_ty(&pat)?.sty {
ty::TyAdt(adt_def, _) => {
adt_def.struct_variant().fields.len()
(cmt, adt_def.struct_variant().fields.len())
}
ref ty => {
span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
Expand All @@ -1168,8 +1153,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
}
}

PatKind::Struct(_, ref field_pats, _) => {
PatKind::Struct(ref qpath, ref field_pats, _) => {
// {f1: p1, ..., fN: pN}
let def = self.tables.qpath_def(qpath, pat.id);
let cmt = match def {
Def::Err => {
debug!("access to unresolvable pattern {:?}", pat);
return Err(())
},
Def::Variant(variant_did) |
Def::VariantCtor(variant_did, ..) => {
self.cat_downcast_if_needed(pat, cmt, variant_did)
},
_ => cmt
};

for fp in field_pats {
let field_ty = self.pat_ty(&fp.node.pat)?; // see (*2)
let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.name, field_ty);
Expand Down
18 changes: 18 additions & 0 deletions src/test/compile-fail/issue-42880.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2017 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.

type Value = String;

fn main() {
let f = |&Value::String(_)| (); //~ ERROR no associated item named

let vec: Vec<Value> = Vec::new();
vec.last().map(f);
}