X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;ds=sidebyside;f=src%2Flibrustc_typeck%2Fcheck%2F_match.rs;h=38c714fa8f292ec0b755769be81e01fa0529b3a3;hb=462ec057649e11ce1967b0eea6c0353375c160ea;hp=5ffe34d61bf7d72243f3d9a70997cd3e0d779fa4;hpb=f24077f8cea8622ea94f6b0b3f9dd263dc8b2e94;p=rust.git diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5ffe34d61bf..38c714fa8f2 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -21,11 +21,11 @@ use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type}; use require_same_types; use util::nodemap::FnvHashMap; +use session::Session; use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; -use syntax::ext::mtwt; use syntax::codemap::{Span, Spanned}; use syntax::ptr::P; @@ -136,6 +136,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } hir::PatEnum(..) | hir::PatIdent(..) if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => { + if let hir::PatEnum(ref path, ref subpats) = pat.node { + if !(subpats.is_some() && subpats.as_ref().unwrap().is_empty()) { + bad_struct_kind_err(tcx.sess, pat.span, path, false); + return; + } + } let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id(); let const_scheme = tcx.lookup_item_type(const_did); assert!(const_scheme.generics.is_empty()); @@ -180,7 +186,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // if there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be - let canon_id = *pcx.map.get(&mtwt::resolve(path.node)).unwrap(); + let canon_id = *pcx.map.get(&path.node.name).unwrap(); if canon_id != pat.id { let ct = fcx.local_ty(pat.span, canon_id); demand::eqtype(fcx, pat.span, ct, typ); @@ -192,11 +198,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } hir::PatIdent(_, ref path, _) => { let path = hir_util::ident_to_path(path.span, path.node); - check_pat_enum(pcx, pat, &path, Some(&[]), expected); + check_pat_enum(pcx, pat, &path, Some(&[]), expected, false); } hir::PatEnum(ref path, ref subpats) => { let subpats = subpats.as_ref().map(|v| &v[..]); - check_pat_enum(pcx, pat, path, subpats, expected); + let is_tuple_struct_pat = !(subpats.is_some() && subpats.unwrap().is_empty()); + check_pat_enum(pcx, pat, path, subpats, expected, is_tuple_struct_pat); } hir::PatQPath(ref qself, ref path) => { let self_ty = fcx.to_ty(&qself.ty); @@ -443,7 +450,7 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // supertype, as the "discriminant type" (issue #23116). let contains_ref_bindings = arms.iter() .filter_map(|a| tcx.arm_contains_ref_binding(a)) - .max_by(|m| match *m { + .max_by_key(|m| match *m { hir::MutMutable => 1, hir::MutImmutable => 0, }); @@ -572,11 +579,19 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx hir::Pat, fcx.write_substs(pat.id, ty::ItemSubsts { substs: item_substs.clone() }); } +// This function exists due to the warning "diagnostic code E0164 already used" +fn bad_struct_kind_err(sess: &Session, span: Span, path: &hir::Path, is_warning: bool) { + let name = pprust::path_to_string(path); + span_err_or_warn!(is_warning, sess, span, E0164, + "`{}` does not name a tuple variant or a tuple struct", name); +} + pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &hir::Pat, path: &hir::Path, subpats: Option<&'tcx [P]>, - expected: Ty<'tcx>) + expected: Ty<'tcx>, + is_tuple_struct_pat: bool) { // Typecheck the path. let fcx = pcx.fcx; @@ -618,25 +633,55 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, path_scheme, &ctor_predicates, opt_ty, def, pat.span, pat.id); + let report_bad_struct_kind = |is_warning| { + bad_struct_kind_err(tcx.sess, pat.span, path, is_warning); + if is_warning { + return + } + + fcx.write_error(pat.id); + if let Some(subpats) = subpats { + for pat in subpats { + check_pat(pcx, &**pat, tcx.types.err); + } + } + }; + // If we didn't have a fully resolved path to start with, we had an // associated const, and we should quit now, since the rest of this // function uses checks specific to structs and enums. if path_res.depth != 0 { - let pat_ty = fcx.node_ty(pat.id); - demand::suptype(fcx, pat.span, expected, pat_ty); + if is_tuple_struct_pat { + report_bad_struct_kind(false); + } else { + let pat_ty = fcx.node_ty(pat.id); + demand::suptype(fcx, pat.span, expected, pat_ty); + } return; } let pat_ty = fcx.node_ty(pat.id); demand::eqtype(fcx, pat.span, expected, pat_ty); - let real_path_ty = fcx.node_ty(pat.id); let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty { ty::TyEnum(enum_def, expected_substs) if def == def::DefVariant(enum_def.did, def.def_id(), false) => { let variant = enum_def.variant_of_def(def); + if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple { + // Matching unit variants with tuple variant patterns (`UnitVariant(..)`) + // is allowed for backward compatibility. + let is_special_case = variant.kind() == ty::VariantKind::Unit; + report_bad_struct_kind(is_special_case); + if !is_special_case { + return + } else { + span_note!(tcx.sess, pat.span, + "this warning will become a HARD ERROR in a future release. \ + See RFC 218 for details."); + } + } (variant.fields .iter() .map(|f| fcx.instantiate_type_scheme(pat.span, @@ -646,26 +691,21 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, "variant") } ty::TyStruct(struct_def, expected_substs) => { - (struct_def.struct_variant() - .fields - .iter() - .map(|f| fcx.instantiate_type_scheme(pat.span, - expected_substs, - &f.unsubst_ty())) - .collect(), + let variant = struct_def.struct_variant(); + if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple { + report_bad_struct_kind(false); + return; + } + (variant.fields + .iter() + .map(|f| fcx.instantiate_type_scheme(pat.span, + expected_substs, + &f.unsubst_ty())) + .collect(), "struct") } _ => { - let name = pprust::path_to_string(path); - span_err!(tcx.sess, pat.span, E0164, - "`{}` does not name a non-struct variant or a tuple struct", name); - fcx.write_error(pat.id); - - if let Some(subpats) = subpats { - for pat in subpats { - check_pat(pcx, &**pat, tcx.types.err); - } - } + report_bad_struct_kind(false); return; } };