diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 58e77f40d981..259bd4f09991 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -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 { @@ -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); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 259079cf1604..5c741eccf83c 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1032,22 +1032,29 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - pub fn cat_downcast(&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(&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(&self, cmt: cmt<'tcx>, pat: &hir::Pat, mut op: F) -> McResult<()> @@ -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); @@ -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); diff --git a/src/test/compile-fail/issue-42880.rs b/src/test/compile-fail/issue-42880.rs new file mode 100644 index 000000000000..ebb1ec425d1d --- /dev/null +++ b/src/test/compile-fail/issue-42880.rs @@ -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 or the MIT license +// , 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 = Vec::new(); + vec.last().map(f); +}