From 03ceec556ee0638825ba8f653c4044eb087933fe Mon Sep 17 00:00:00 2001 From: mark Date: Tue, 5 May 2020 23:02:09 -0500 Subject: [PATCH 01/23] make all uses of ty::Error or ConstKind::Error delay a span bug --- src/librustc_infer/infer/canonical/mod.rs | 2 +- src/librustc_infer/infer/mod.rs | 2 +- src/librustc_infer/infer/resolve.rs | 8 ++-- src/librustc_infer/infer/sub.rs | 2 +- src/librustc_middle/lib.rs | 1 + src/librustc_middle/ty/_match.rs | 2 +- src/librustc_middle/ty/context.rs | 30 ++++++++++++-- src/librustc_middle/ty/query/values.rs | 4 +- src/librustc_middle/ty/relate.rs | 2 +- src/librustc_middle/ty/sty.rs | 4 +- .../borrow_check/type_check/mod.rs | 4 +- src/librustc_mir_build/build/mod.rs | 2 +- src/librustc_mir_build/hair/pattern/_match.rs | 6 +-- src/librustc_trait_selection/opaque_types.rs | 6 +-- .../traits/project.rs | 10 ++--- src/librustc_typeck/astconv.rs | 22 +++++----- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/closure.rs | 6 +-- src/librustc_typeck/check/coercion.rs | 8 ++-- src/librustc_typeck/check/expr.rs | 40 +++++++++---------- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/mod.rs | 24 +++++------ src/librustc_typeck/check/op.rs | 4 +- src/librustc_typeck/check/pat.rs | 40 +++++++++---------- src/librustc_typeck/check/writeback.rs | 6 +-- src/librustc_typeck/collect.rs | 14 +++---- src/librustc_typeck/collect/type_of.rs | 14 +++---- 29 files changed, 146 insertions(+), 125 deletions(-) diff --git a/src/librustc_infer/infer/canonical/mod.rs b/src/librustc_infer/infer/canonical/mod.rs index b7890cf9e925a..d2a702bd30006 100644 --- a/src/librustc_infer/infer/canonical/mod.rs +++ b/src/librustc_infer/infer/canonical/mod.rs @@ -154,7 +154,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { self.tcx .mk_const(ty::Const { val: ty::ConstKind::Placeholder(placeholder_mapped), - ty: self.tcx.types.err, // FIXME(const_generics) + ty: self.tcx.err(), // FIXME(const_generics) }) .into() } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 54f80e8f38812..6a48d87cb16ac 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -1746,7 +1746,7 @@ impl<'tcx> TypeTrace<'tcx> { pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> { TypeTrace { cause: ObligationCause::dummy(), - values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err }), + values: Types(ExpectedFound { expected: tcx.err(), found: tcx.err() }), } } } diff --git a/src/librustc_infer/infer/resolve.rs b/src/librustc_infer/infer/resolve.rs index bd9d108cfe871..9899137c63912 100644 --- a/src/librustc_infer/infer/resolve.rs +++ b/src/librustc_infer/infer/resolve.rs @@ -188,15 +188,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { match t.kind { ty::Infer(ty::TyVar(vid)) => { self.err = Some(FixupError::UnresolvedTy(vid)); - self.tcx().types.err + self.tcx().err() } ty::Infer(ty::IntVar(vid)) => { self.err = Some(FixupError::UnresolvedIntTy(vid)); - self.tcx().types.err + self.tcx().err() } ty::Infer(ty::FloatVar(vid)) => { self.err = Some(FixupError::UnresolvedFloatTy(vid)); - self.tcx().types.err + self.tcx().err() } ty::Infer(_) => { bug!("Unexpected type in full type resolver: {:?}", t); @@ -227,7 +227,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { match c.val { ty::ConstKind::Infer(InferConst::Var(vid)) => { self.err = Some(FixupError::UnresolvedConst(vid)); - return self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: c.ty }); + return self.tcx().err_const(c.ty); } ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("Unexpected const in full const resolver: {:?}", c); diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index 080af37492d89..8a390c08c54ab 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -119,7 +119,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { (&ty::Error, _) | (_, &ty::Error) => { infcx.set_tainted_by_errors(); - Ok(self.tcx().types.err) + Ok(self.tcx().err()) } _ => { diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs index 9b38b43c93ae2..5fa565b482bdc 100644 --- a/src/librustc_middle/lib.rs +++ b/src/librustc_middle/lib.rs @@ -52,6 +52,7 @@ #![feature(rustc_attrs)] #![feature(hash_raw_entry)] #![feature(int_error_matching)] +#![feature(track_caller)] #![recursion_limit = "512"] #[macro_use] diff --git a/src/librustc_middle/ty/_match.rs b/src/librustc_middle/ty/_match.rs index 02abe868f3943..6749e5a80672a 100644 --- a/src/librustc_middle/ty/_match.rs +++ b/src/librustc_middle/ty/_match.rs @@ -79,7 +79,7 @@ impl TypeRelation<'tcx> for Match<'tcx> { Err(TypeError::Sorts(relate::expected_found(self, &a, &b))) } - (&ty::Error, _) | (_, &ty::Error) => Ok(self.tcx().types.err), + (&ty::Error, _) | (_, &ty::Error) => Ok(self.tcx().err()), _ => relate::super_relate_tys(self, a, b), } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index e43eb01ad96f7..f4546f5db9612 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -59,7 +59,7 @@ use rustc_session::lint::{Level, Lint}; use rustc_session::Session; use rustc_span::source_map::MultiSpan; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; @@ -152,7 +152,6 @@ pub struct CommonTypes<'tcx> { pub f64: Ty<'tcx>, pub never: Ty<'tcx>, pub self_param: Ty<'tcx>, - pub err: Ty<'tcx>, /// Dummy type used for the `Self` of a `TraitRef` created for converting /// a trait object, and which gets removed in `ExistentialTraitRef`. @@ -811,7 +810,6 @@ impl<'tcx> CommonTypes<'tcx> { bool: mk(Bool), char: mk(Char), never: mk(Never), - err: mk(Error), isize: mk(Int(ast::IntTy::Isize)), i8: mk(Int(ast::IntTy::I8)), i16: mk(Int(ast::IntTy::I16)), @@ -1180,6 +1178,32 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. + #[track_caller] + pub fn err(self) -> Ty<'tcx> { + self.sess.delay_span_bug( + DUMMY_SP, + &format!( + "TyKind::Error constructed but no error reported. {}", + std::panic::Location::caller() + ), + ); + self.mk_ty(Error) + } + + /// Like `err` but for constants. + #[track_caller] + pub fn err_const(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { + self.sess.delay_span_bug( + DUMMY_SP, + &format!( + "ty::ConstKind::Error constructed but no error reported. {}", + std::panic::Location::caller() + ), + ); + self.mk_const(ty::Const { val: ty::ConstKind::Error, ty }) + } + pub fn consider_optimizing String>(&self, msg: T) -> bool { let cname = self.crate_name(LOCAL_CRATE).as_str(); self.sess.consider_optimizing(&cname, msg) diff --git a/src/librustc_middle/ty/query/values.rs b/src/librustc_middle/ty/query/values.rs index b01d15c29b2db..155d3f9ae6ea9 100644 --- a/src/librustc_middle/ty/query/values.rs +++ b/src/librustc_middle/ty/query/values.rs @@ -15,7 +15,7 @@ impl<'tcx, T> Value<'tcx> for T { impl<'tcx> Value<'tcx> for Ty<'tcx> { fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.types.err + tcx.err() } } @@ -27,6 +27,6 @@ impl<'tcx> Value<'tcx> for ty::SymbolName { impl<'tcx> Value<'tcx> for AdtSizedConstraint<'tcx> { fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { - AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])) + AdtSizedConstraint(tcx.intern_type_list(&[tcx.err()])) } } diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index faa74f81e818b..48f8634bf3f5e 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -354,7 +354,7 @@ pub fn super_relate_tys>( bug!("bound types encountered in super_relate_tys") } - (&ty::Error, _) | (_, &ty::Error) => Ok(tcx.types.err), + (&ty::Error, _) | (_, &ty::Error) => Ok(tcx.err()), (&ty::Never, _) | (&ty::Char, _) diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index ac5477edcc3c0..b274f07dd4e5f 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -2378,9 +2378,7 @@ impl<'tcx> Const<'tcx> { // can leak through `val` into the const we return. Ok(val) => Const::from_value(tcx, val, self.ty), Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self, - Err(ErrorHandled::Reported(ErrorReported)) => { - tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: self.ty }) - } + Err(ErrorHandled::Reported(ErrorReported)) => tcx.err_const(self.ty), } } else { self diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 36ccc0aaa8bb4..f7f66699c1876 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -494,7 +494,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { if place_ty.variant_index.is_none() { if place_ty.ty.references_error() { assert!(self.errors_reported); - return PlaceTy::from_ty(self.tcx().types.err); + return PlaceTy::from_ty(self.tcx().err()); } } place_ty = self.sanitize_projection(place_ty, elem, place, location) @@ -721,7 +721,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { fn error(&mut self) -> Ty<'tcx> { self.errors_reported = true; - self.tcx().types.err + self.tcx().err() } fn field_ty( diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index 2ce2627987a01..74b5c7e3578f3 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -687,7 +687,7 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t let tcx = hir.tcx(); let owner_id = tcx.hir().body_owner(body_id); let span = tcx.hir().span(owner_id); - let ty = tcx.types.err; + let ty = tcx.err(); let num_params = match hir.body_owner_kind { hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len(), hir::BodyOwnerKind::Closure => { diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index de3ae2e961f42..6ddadf3b4f1e1 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -894,12 +894,12 @@ impl<'tcx> Constructor<'tcx> { match (is_visible, is_non_exhaustive, is_uninhabited) { // Treat all uninhabited types in non-exhaustive variants as // `TyErr`. - (_, true, true) => cx.tcx.types.err, + (_, true, true) => cx.tcx.err(), // Treat all non-visible fields as `TyErr`. They can't appear // in any other pattern from this match (because they are // private), so their type does not matter - but we don't want // to know they are uninhabited. - (false, ..) => cx.tcx.types.err, + (false, ..) => cx.tcx.err(), (true, ..) => { let ty = field.ty(cx.tcx, substs); match ty.kind { @@ -910,7 +910,7 @@ impl<'tcx> Constructor<'tcx> { .try_eval_usize(cx.tcx, cx.param_env) .is_none() => { - cx.tcx.types.err + cx.tcx.err() } _ => ty, } diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 4f8075b0171d3..f0cc9806bb4ed 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -939,7 +939,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { ) .emit(); - self.tcx().types.err + self.tcx().err() } } } @@ -972,7 +972,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { ) .emit(); - self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: ct.ty }) + self.tcx().err_const(ct.ty) } } } @@ -1000,7 +1000,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { tcx, ty_op: |ty| { if ty.references_error() { - return tcx.types.err; + return tcx.err(); } else if let ty::Opaque(def_id, substs) = ty.kind { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 2b4a0409fd1e2..6e419a5acbf2f 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -773,7 +773,7 @@ struct Progress<'tcx> { impl<'tcx> Progress<'tcx> { fn error(tcx: TyCtxt<'tcx>) -> Self { - Progress { ty: tcx.types.err, obligations: vec![] } + Progress { ty: tcx.err(), obligations: vec![] } } fn with_addl_obligations(mut self, mut obligations: Vec>) -> Self { @@ -1356,7 +1356,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( ); debug!("confirm_param_env_candidate: {}", msg); infcx.tcx.sess.delay_span_bug(obligation.cause.span, &msg); - Progress { ty: infcx.tcx.types.err, obligations: vec![] } + Progress { ty: infcx.tcx.err(), obligations: vec![] } } } } @@ -1375,7 +1375,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let param_env = obligation.param_env; let assoc_ty = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) { Ok(assoc_ty) => assoc_ty, - Err(ErrorReported) => return Progress { ty: tcx.types.err, obligations: nested }, + Err(ErrorReported) => return Progress { ty: tcx.err(), obligations: nested }, }; if !assoc_ty.item.defaultness.has_value() { @@ -1387,7 +1387,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( "confirm_impl_candidate: no associated type {:?} for {:?}", assoc_ty.item.ident, obligation.predicate ); - return Progress { ty: tcx.types.err, obligations: nested }; + return Progress { ty: tcx.err(), obligations: nested }; } let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); let substs = @@ -1401,7 +1401,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { tcx.sess .delay_span_bug(DUMMY_SP, "impl item and trait item have different parameter counts"); - Progress { ty: tcx.types.err, obligations: nested } + Progress { ty: tcx.err(), obligations: nested } } else { Progress { ty: ty.subst(tcx, substs), obligations: nested } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index cd6cd94b14356..43cff98a04eb8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -780,7 +780,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { inferred_params.push(ty.span); - tcx.types.err.into() + tcx.err().into() } else { self.ast_ty_to_ty(&ty).into() } @@ -806,7 +806,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // careful! if default_needs_object_self(param) { missing_type_params.push(param.name.to_string()); - tcx.types.err.into() + tcx.err().into() } else { // This is a default type parameter. self.normalize_ty( @@ -826,7 +826,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ty_infer(param, span).into() } else { // We've already errored above about the mismatch. - tcx.types.err.into() + tcx.err().into() } } GenericParamDefKind::Const => { @@ -837,7 +837,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ct_infer(ty, Some(param), span).into() } else { // We've already errored above about the mismatch. - tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty }).into() + tcx.err_const(ty).into() } } } @@ -1564,7 +1564,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "at least one trait is required for an object type" ) .emit(); - return tcx.types.err; + return tcx.err(); } // Check that there are no gross object safety violations; @@ -1581,7 +1581,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &object_safety_violations[..], ) .emit(); - return tcx.types.err; + return tcx.err(); } } @@ -2391,7 +2391,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &path_str, item_segment.ident.name, ); - return tcx.types.err; + return tcx.err(); }; debug!("qpath_to_ty: self_type={:?}", self_ty); @@ -2708,7 +2708,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } Res::Err => { self.set_tainted_by_errors(); - self.tcx().types.err + self.tcx().err() } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } @@ -2769,7 +2769,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false) .map(|(ty, _, _)| ty) - .unwrap_or(tcx.types.err) + .unwrap_or(tcx.err()) } hir::TyKind::Array(ref ty, ref length) => { let length_def_id = tcx.hir().local_def_id(length.hir_id); @@ -2787,7 +2787,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .span_label(ast_ty.span, "reserved keyword") .emit(); - tcx.types.err + tcx.err() } hir::TyKind::Infer => { // Infer also appears as the type of arguments or return @@ -2796,7 +2796,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // handled specially and will not descend into this routine. self.ty_infer(None, ast_ty.span) } - hir::TyKind::Err => tcx.types.err, + hir::TyKind::Err => tcx.err(), }; debug!("ast_ty_to_ty: result_ty={:?}", result_ty); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 16af168ce1af9..8ddecc1061642 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -105,7 +105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && i != 0 && self.if_fallback_coercion(expr.span, &arms[0].body, &mut coercion) { - tcx.types.err + tcx.err() } else { // Only call this if this is not an `if` expr with an expected type and no `else` // clause to avoid duplicated type errors. (#60254) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 0d254412203aa..22d298f5337c9 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -363,7 +363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ( ty::Binder::bind(self.tcx.mk_fn_sig( self.err_args(arg_exprs.len()).into_iter(), - self.tcx.types.err, + self.tcx.err(), false, hir::Unsafety::Normal, abi::Abi::Rust, diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 1acbcc038891d..8566bbaf6cdad 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match expected_ty.kind { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { - let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); + let pb = pb.with_self_ty(self.tcx, self.tcx.err()); self.deduce_sig_from_projection(None, &pb) }); let kind = object_type @@ -714,7 +714,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let supplied_arguments = decl.inputs.iter().map(|a| { // Convert the types that the user supplied (if any), but ignore them. astconv.ast_ty_to_ty(a); - self.tcx.types.err + self.tcx.err() }); if let hir::FnRetTy::Return(ref output) = decl.output { @@ -723,7 +723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let result = ty::Binder::bind(self.tcx.mk_fn_sig( supplied_arguments, - self.tcx.types.err, + self.tcx.err(), decl.c_variadic, hir::Unsafety::Normal, Abi::RustCall, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 86cafa0b8ca25..0b65b0ff61aaa 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -162,7 +162,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Just ignore error types. if a.references_error() || b.references_error() { - return success(vec![], self.fcx.tcx.types.err, vec![]); + return success(vec![], self.fcx.tcx.err(), vec![]); } if a.is_never() { @@ -827,7 +827,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (adjustments, _) = self.register_infer_ok_obligations(ok); self.apply_adjustments(expr, adjustments); - Ok(if expr_ty.references_error() { self.tcx.types.err } else { target }) + Ok(if expr_ty.references_error() { self.tcx.err() } else { target }) } /// Same as `try_coerce()`, but without side-effects. @@ -1156,7 +1156,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // If we see any error types, just propagate that error // upwards. if expression_ty.references_error() || self.merged_ty().references_error() { - self.final_ty = Some(fcx.tcx.types.err); + self.final_ty = Some(fcx.tcx.err()); return; } @@ -1313,7 +1313,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { err.emit_unless(assign_to_bool || unsized_return); - self.final_ty = Some(fcx.tcx.types.err); + self.final_ty = Some(fcx.tcx.err()); } } } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 92ddfbff824cd..74a3c2bc1036f 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -246,7 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.types.never } else { // There was an error; make type-check fail. - tcx.types.err + tcx.err() } } ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr), @@ -282,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Field(ref base, field) => self.check_field(expr, needs, &base, field), ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, needs, expr), ExprKind::Yield(ref value, ref src) => self.check_expr_yield(value, expr, src), - hir::ExprKind::Err => tcx.types.err, + hir::ExprKind::Err => tcx.err(), } } @@ -358,7 +358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp, None); } err.emit(); - oprnd_t = tcx.types.err; + oprnd_t = tcx.err(); } } hir::UnOp::UnNot => { @@ -408,7 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tm = ty::TypeAndMut { ty, mutbl }; match kind { - _ if tm.ty.references_error() => self.tcx.types.err, + _ if tm.ty.references_error() => self.tcx.err(), hir::BorrowKind::Raw => { self.check_named_place_expr(oprnd); self.tcx.mk_ptr(tm) @@ -474,11 +474,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match res { Res::Err => { self.set_tainted_by_errors(); - tcx.types.err + tcx.err() } Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => { report_unexpected_variant_res(tcx, res, expr.span); - tcx.types.err + tcx.err() } _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; @@ -562,7 +562,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.span, "break was outside loop, but no error was emitted", ); - return tcx.types.err; + return tcx.err(); } } }; @@ -570,7 +570,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the loop context is not a `loop { }`, then break with // a value is illegal, and `opt_coerce_to` will be `None`. // Just set expectation to error in that case. - let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err); + let coerce_to = opt_coerce_to.unwrap_or(tcx.err()); // Recurse without `enclosing_breakables` borrowed. e_ty = self.check_expr_with_hint(e, coerce_to); @@ -594,7 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.span, "break was outside loop, but no error was emitted", ); - return tcx.types.err; + return tcx.err(); } }; @@ -654,7 +654,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We still need to assign a type to the inner expression to // prevent the ICE in #43162. if let Some(ref e) = expr_opt { - self.check_expr_with_hint(e, tcx.types.err); + self.check_expr_with_hint(e, tcx.err()); // ... except when we try to 'break rust;'. // ICE this expression in particular (see #43162). @@ -665,7 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } // There was an error; make type-check fail. - tcx.types.err + tcx.err() } } @@ -801,7 +801,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); if lhs_ty.references_error() || rhs_ty.references_error() { - self.tcx.types.err + self.tcx.err() } else { self.tcx.mk_unit() } @@ -955,7 +955,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { - self.tcx.types.err + self.tcx.err() } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); @@ -964,7 +964,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_cast_checks.push(cast_check); t_cast } - Err(ErrorReported) => self.tcx.types.err, + Err(ErrorReported) => self.tcx.err(), } } } @@ -1039,7 +1039,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if element_ty.references_error() { - return tcx.types.err; + return tcx.err(); } tcx.mk_ty(ty::Array(t, count)) @@ -1069,7 +1069,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let tuple = self.tcx.mk_tup(elt_ts_iter); if tuple.references_error() { - self.tcx.types.err + self.tcx.err() } else { self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized); tuple @@ -1090,7 +1090,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant_ty } else { self.check_struct_fields_on_error(fields, base_expr); - return self.tcx.types.err; + return self.tcx.err(); }; let path_span = match *qpath { @@ -1231,7 +1231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span); } - tcx.types.err + tcx.err() }; // Make sure to give a type to the field even if there's @@ -1517,7 +1517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit(); } - self.tcx().types.err + self.tcx().err() } fn ban_nonexisting_field( @@ -1773,7 +1773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } err.emit(); - self.tcx.types.err + self.tcx.err() } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 64dc34ab3b0a7..a52d8ad020b94 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { rustc_span::DUMMY_SP, &format!("failed autoderef {}", pick.autoderefs), ); - return self.tcx.types.err; + return self.tcx.err(); } }; assert_eq!(n, pick.autoderefs); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 03e32c21a54ac..fdd1ed6fa2e00 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -400,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .probe_instantiate_query_response(span, &orig_values, ty) .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); let ty = self.structurally_resolved_type(span, ty.value); - assert_eq!(ty, self.tcx.types.err); + assert_eq!(ty, self.tcx.err()); return Err(MethodError::NoMatch(NoMatchData::new( Vec::new(), Vec::new(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bff1ca2433a83..5d505274b6ee0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -982,7 +982,7 @@ fn diagnostic_only_typeck_tables_of<'tcx>( let fallback = move || { let span = tcx.hir().span(tcx.hir().as_local_hir_id(def_id)); tcx.sess.delay_span_bug(span, "diagnostic only typeck table used"); - tcx.types.err + tcx.err() }; typeck_tables_of_with_fallback(tcx, def_id, fallback) } @@ -3400,7 +3400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { match self.tables.borrow().node_types().get(id) { Some(&t) => t, - None if self.is_tainted_by_errors() => self.tcx.types.err, + None if self.is_tainted_by_errors() => self.tcx.err(), None => { bug!( "no type for node {}: {} in fcx {}", @@ -3515,7 +3515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert!(ty.is_ty_infer()); let fallback = match self.type_is_unconstrained_numeric(ty) { - _ if self.is_tainted_by_errors() => self.tcx().types.err, + _ if self.is_tainted_by_errors() => self.tcx().err(), UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), @@ -3788,7 +3788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tuple_arguments, None, ); - return self.tcx.types.err; + return self.tcx.err(); } let method = method.unwrap(); @@ -4172,7 +4172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn err_args(&self, len: usize) -> Vec> { - vec![self.tcx.types.err; len] + vec![self.tcx.err(); len] } /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk @@ -4314,7 +4314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_ty.unwrap_or_else(|| self.next_float_var()) } ast::LitKind::Bool(_) => tcx.types.bool, - ast::LitKind::Err(_) => tcx.types.err, + ast::LitKind::Err(_) => tcx.err(), } } @@ -4451,7 +4451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let result = AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); - let ty = result.map(|(ty, _, _)| ty).unwrap_or(self.tcx().types.err); + let ty = result.map(|(ty, _, _)| ty).unwrap_or(self.tcx().err()); let result = result.map(|(_, kind, def_id)| (kind, def_id)); // Write back the new resolution. @@ -4579,7 +4579,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) { if ty.references_error() { - // Override the types everywhere with `types.err` to avoid knock on errors. + // Override the types everywhere with `err()` to avoid knock on errors. self.write_ty(local.hir_id, ty); self.write_ty(local.pat.hir_id, ty); let local_ty = LocalTy { decl_ty, revealed_ty: ty }; @@ -4799,7 +4799,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut ty = ctxt.coerce.unwrap().complete(self); if self.has_errors.get() || ty.references_error() { - ty = self.tcx.types.err + ty = self.tcx.err() } self.write_ty(blk.hir_id, ty); @@ -5546,7 +5546,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err.emit(); - return (tcx.types.err, res); + return (tcx.err(), res); } } } else { @@ -5730,8 +5730,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .note("type must be known at this point") .emit(); } - self.demand_suptype(sp, self.tcx.types.err, ty); - self.tcx.types.err + self.demand_suptype(sp, self.tcx.err(), ty); + self.tcx.err() } } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 23004cf364725..9d0bab70fef41 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -473,7 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - self.tcx.types.err + self.tcx.err() } }; @@ -685,7 +685,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err.emit(); } - self.tcx.types.err + self.tcx.err() } } } diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 8e109efbcb576..5cb557ad97182 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -441,7 +441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // There exists a side that didn't meet our criteria that the end-point // be of a numeric or char type, as checked in `calc_side` above. self.emit_err_pat_range(span, lhs, rhs); - return self.tcx.types.err; + return self.tcx.err(); } // Now that we know the types can be unified we find the unified type @@ -674,9 +674,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { for field in fields { let ti = TopInfo { parent_pat: Some(&pat), ..ti }; - self.check_pat(&field.pat, self.tcx.types.err, def_bm, ti); + self.check_pat(&field.pat, self.tcx.err(), def_bm, ti); } - return self.tcx.types.err; + return self.tcx.err(); }; // Type-check the path. @@ -686,7 +686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, etc, def_bm, ti) { pat_ty } else { - self.tcx.types.err + self.tcx.err() } } @@ -704,11 +704,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match res { Res::Err => { self.set_tainted_by_errors(); - return tcx.types.err; + return tcx.err(); } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => { report_unexpected_variant_res(tcx, res, pat.span); - return tcx.types.err; + return tcx.err(); } Res::SelfCtor(..) | Res::Def( @@ -787,7 +787,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let on_error = || { let parent_pat = Some(pat); for pat in subpats { - self.check_pat(&pat, tcx.types.err, def_bm, TopInfo { parent_pat, ..ti }); + self.check_pat(&pat, tcx.err(), def_bm, TopInfo { parent_pat, ..ti }); } }; let report_unexpected_res = |res: Res| { @@ -823,7 +823,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if res == Res::Err { self.set_tainted_by_errors(); on_error(); - return self.tcx.types.err; + return self.tcx.err(); } // Type-check the path. @@ -831,18 +831,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); if !pat_ty.is_fn() { report_unexpected_res(res); - return tcx.types.err; + return tcx.err(); } let variant = match res { Res::Err => { self.set_tainted_by_errors(); on_error(); - return tcx.types.err; + return tcx.err(); } Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { report_unexpected_res(res); - return tcx.types.err; + return tcx.err(); } Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res), _ => bug!("unexpected pattern resolution: {:?}", res), @@ -879,7 +879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Pattern has wrong number of fields. self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err); on_error(); - return tcx.types.err; + return tcx.err(); } pat_ty } @@ -1000,9 +1000,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 - let element_tys_iter = (0..max_len).map(|_| tcx.types.err); + let element_tys_iter = (0..max_len).map(|_| tcx.err()); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, &tcx.types.err, def_bm, ti); + self.check_pat(elem, &tcx.err(), def_bm, ti); } tcx.mk_tup(element_tys_iter) } else { @@ -1051,7 +1051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Occupied(occupied) => { self.error_field_already_bound(span, field.ident, *occupied.get()); no_field_errors = false; - tcx.types.err + tcx.err() } Vacant(vacant) => { vacant.insert(span); @@ -1065,7 +1065,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or_else(|| { inexistent_fields.push(field.ident); no_field_errors = false; - tcx.types.err + tcx.err() }) } }; @@ -1280,7 +1280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype_pat(span, expected, box_ty, ti); (box_ty, inner_ty) } else { - (tcx.types.err, tcx.types.err) + (tcx.err(), tcx.err()) }; self.check_pat(&inner, inner_ty, def_bm, ti); box_ty @@ -1326,7 +1326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } else { - (tcx.types.err, tcx.types.err) + (tcx.err(), tcx.err()) }; self.check_pat(&inner, inner_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); rptr_ty @@ -1377,7 +1377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !expected.references_error() { self.error_expected_array_or_slice(span, expected); } - let err = self.tcx.types.err; + let err = self.tcx.err(); (err, Some(err), err) } }; @@ -1444,7 +1444,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If we get here, we must have emitted an error. - (Some(self.tcx.types.err), arr_ty) + (Some(self.tcx.err()), arr_ty) } fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index c5bf151bc1e11..fa89dbe60b3d9 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -212,7 +212,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { e.span, &format!("bad index {:?} for base: `{:?}`", index, base), ); - self.fcx.tcx.types.err + self.fcx.tcx.err() }); let index_ty = self.fcx.resolve_vars_if_possible(&index_ty); @@ -668,7 +668,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); self.report_error(t); self.replaced_with_error = true; - self.tcx().types.err + self.tcx().err() } } } @@ -686,7 +686,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { // FIXME: we'd like to use `self.report_error`, but it doesn't yet // accept a &'tcx ty::Const. self.replaced_with_error = true; - self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: ct.ty }) + self.tcx().err_const(ct.ty) } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0fad328459890..a71501ea18a42 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -308,7 +308,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { self.tcx().sess.delay_span_bug(span, "bad placeholder type"); - self.tcx().types.err + self.tcx().err() } fn ct_infer( @@ -318,8 +318,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { span: Span, ) -> &'tcx Const<'tcx> { bad_placeholder_type(self.tcx(), vec![span]).emit(); - - self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty }) + self.tcx().err_const(ty) } fn projected_ty_from_poly_trait_ref( @@ -419,7 +418,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { _ => {} } err.emit(); - self.tcx().types.err + self.tcx().err() } } @@ -1473,7 +1472,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { visitor.visit_ty(ty); let mut diag = bad_placeholder_type(tcx, visitor.0); let ret_ty = fn_sig.output(); - if ret_ty != tcx.types.err { + if ret_ty != tcx.err() { diag.span_suggestion( ty.span, "replace with the correct return type", @@ -2032,12 +2031,11 @@ fn associated_item_predicates( // once they are handled by the trait system. ty::GenericParamDefKind::Type { .. } => { unimplemented_error("type"); - tcx.types.err.into() + tcx.err().into() } ty::GenericParamDefKind::Const => { unimplemented_error("const"); - tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: tcx.type_of(param.def_id) }) - .into() + tcx.err_const(tcx.type_of(param.def_id)).into() } } }; diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs index cf0e3f9cdf592..03ce83afa8250 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/src/librustc_typeck/collect/type_of.rs @@ -143,7 +143,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { // Some error in the // owner fn prevented us from populating // the `concrete_opaque_types` table. - tcx.types.err + tcx.err() } else { // We failed to resolve the opaque type or it // resolves to itself. Return the non-revealed @@ -244,7 +244,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { DUMMY_SP, &format!("unexpected const parent path {:?}", parent_node), ); - return tcx.types.err; + return tcx.err(); } }; @@ -284,7 +284,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { res, path, ), ); - return tcx.types.err; + return tcx.err(); } }; @@ -313,7 +313,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { parent_node, res ), ); - tcx.types.err + tcx.err() } } @@ -322,7 +322,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { DUMMY_SP, &format!("unexpected const parent in type_of_def_id(): {:?}", x), ); - tcx.types.err + tcx.err() } } } @@ -591,7 +591,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { None => { let span = tcx.def_span(def_id); tcx.sess.span_err(span, "could not find defining uses"); - tcx.types.err + tcx.err() } } } @@ -624,7 +624,7 @@ fn infer_placeholder_type( } None => { let mut diag = bad_placeholder_type(tcx, vec![span]); - if ty != tcx.types.err { + if ty != tcx.err() { diag.span_suggestion( span, "replace `_` with the correct type", From b9ec308ce33214e882fe57ff708a142dcea35cd1 Mon Sep 17 00:00:00 2001 From: mark Date: Tue, 5 May 2020 23:36:51 -0500 Subject: [PATCH 02/23] lazily construct errors --- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/expr.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 43cff98a04eb8..6eccb2ab0d275 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -2769,7 +2769,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false) .map(|(ty, _, _)| ty) - .unwrap_or(tcx.err()) + .unwrap_or_else(|_| tcx.err()) } hir::TyKind::Array(ref ty, ref length) => { let length_def_id = tcx.hir().local_def_id(length.hir_id); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 74a3c2bc1036f..e4fa990e16d27 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -570,7 +570,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the loop context is not a `loop { }`, then break with // a value is illegal, and `opt_coerce_to` will be `None`. // Just set expectation to error in that case. - let coerce_to = opt_coerce_to.unwrap_or(tcx.err()); + let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.err()); // Recurse without `enclosing_breakables` borrowed. e_ty = self.check_expr_with_hint(e, coerce_to); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5d505274b6ee0..c6d941c9bde21 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4451,7 +4451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let result = AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); - let ty = result.map(|(ty, _, _)| ty).unwrap_or(self.tcx().err()); + let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().err()); let result = result.map(|(_, kind, def_id)| (kind, def_id)); // Write back the new resolution. From 363383263e823042e021273e19e6c859766beb89 Mon Sep 17 00:00:00 2001 From: mark Date: Tue, 5 May 2020 21:32:08 -0500 Subject: [PATCH 03/23] use trait_object_dummy_self instead of err --- src/librustc_typeck/check/closure.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 8566bbaf6cdad..c97d2174a8953 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match expected_ty.kind { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { - let pb = pb.with_self_ty(self.tcx, self.tcx.err()); + let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); self.deduce_sig_from_projection(None, &pb) }); let kind = object_type From 2218f59beeac48eb61dc1578f09cd805ec5ef5f0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 13 Apr 2020 15:16:43 +0100 Subject: [PATCH 04/23] Factor the code that generates TyErrs --- src/librustc_mir_build/hair/pattern/_match.rs | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 6ddadf3b4f1e1..5e194786eda40 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -888,36 +888,37 @@ impl<'tcx> Constructor<'tcx> { .fields .iter() .map(|field| { + let ty = field.ty(cx.tcx, substs); let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs)); - match (is_visible, is_non_exhaustive, is_uninhabited) { - // Treat all uninhabited types in non-exhaustive variants as - // `TyErr`. - (_, true, true) => cx.tcx.err(), - // Treat all non-visible fields as `TyErr`. They can't appear - // in any other pattern from this match (because they are - // private), so their type does not matter - but we don't want - // to know they are uninhabited. - (false, ..) => cx.tcx.err(), - (true, ..) => { - let ty = field.ty(cx.tcx, substs); - match ty.kind { - // If the field type returned is an array of an unknown - // size return an TyErr. - ty::Array(_, len) - if len + let is_uninhabited = cx.is_uninhabited(ty); + // Treat all non-visible fields as `TyErr`. They can't appear + // in any other pattern from this match (because they are + // private), so their type does not matter - but we don't want + // to know they are uninhabited. + let allowed_to_inspect = is_visible + && match (is_non_exhaustive, is_uninhabited) { + // Treat all uninhabited types in non-exhaustive variants as + // `TyErr`. + (true, true) => false, + (_, _) => { + match ty.kind { + // If the field type returned is an array of an unknown + // size return an TyErr. + ty::Array(_, len) => len .try_eval_usize(cx.tcx, cx.param_env) - .is_none() => - { - cx.tcx.err() + .is_some(), + _ => true, } - _ => ty, } - } + }; + + if allowed_to_inspect { + Pat::wildcard_from_ty(ty) + } else { + Pat::wildcard_from_ty(cx.tcx.types.err) } }) - .map(Pat::wildcard_from_ty) .collect() } } From 7037bcc016d62d55f5876afc569a3d4eb0c95b86 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 13 Apr 2020 16:23:39 +0100 Subject: [PATCH 05/23] We already handle arrays of unknown length correctly --- src/librustc_mir_build/hair/pattern/_match.rs | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 5e194786eda40..746fba0925f36 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -896,22 +896,10 @@ impl<'tcx> Constructor<'tcx> { // in any other pattern from this match (because they are // private), so their type does not matter - but we don't want // to know they are uninhabited. - let allowed_to_inspect = is_visible - && match (is_non_exhaustive, is_uninhabited) { - // Treat all uninhabited types in non-exhaustive variants as - // `TyErr`. - (true, true) => false, - (_, _) => { - match ty.kind { - // If the field type returned is an array of an unknown - // size return an TyErr. - ty::Array(_, len) => len - .try_eval_usize(cx.tcx, cx.param_env) - .is_some(), - _ => true, - } - } - }; + // Also treat all uninhabited types in non-exhaustive variants as + // `TyErr`. + let allowed_to_inspect = + is_visible && !(is_non_exhaustive && is_uninhabited); if allowed_to_inspect { Pat::wildcard_from_ty(ty) From 40553dcfcc80fdf8c6388cc59ce0e53f70451d39 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 13 Apr 2020 17:45:12 +0100 Subject: [PATCH 06/23] Only need TyErr for uninhabited types --- src/librustc_mir_build/hair/pattern/_match.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 746fba0925f36..fd1ff7a6bd98b 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -891,15 +891,15 @@ impl<'tcx> Constructor<'tcx> { let ty = field.ty(cx.tcx, substs); let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(ty); - // Treat all non-visible fields as `TyErr`. They can't appear - // in any other pattern from this match (because they are + let is_inhabited = !cx.is_uninhabited(ty); + // Treat all uninhabited non-visible fields as `TyErr`. They can't + // appear in any other pattern from this match (because they are // private), so their type does not matter - but we don't want // to know they are uninhabited. // Also treat all uninhabited types in non-exhaustive variants as // `TyErr`. let allowed_to_inspect = - is_visible && !(is_non_exhaustive && is_uninhabited); + is_inhabited || (is_visible && !is_non_exhaustive); if allowed_to_inspect { Pat::wildcard_from_ty(ty) From 31acfb93ab26082b170503e6321a3ffa3900dd34 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 13 Apr 2020 18:35:46 +0100 Subject: [PATCH 07/23] Small tweaks --- src/librustc_mir_build/hair/pattern/_match.rs | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index fd1ff7a6bd98b..ae0030acdedbb 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -604,7 +604,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } - // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. + /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. crate fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.kind { ty::Adt(def, ..) => { @@ -614,8 +614,8 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } - // Returns whether the given variant is from another crate and has its fields declared - // `#[non_exhaustive]`. + /// Returns whether the given variant is from another crate and has its fields declared + /// `#[non_exhaustive]`. fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool { match ty.kind { ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(), @@ -735,8 +735,8 @@ impl Slice { #[derive(Clone, Debug, PartialEq)] enum Constructor<'tcx> { - /// The constructor of all patterns that don't vary by constructor, - /// e.g., struct patterns and fixed-length arrays. + /// The constructor for patterns that have a single constructor, like tuples, struct patterns + /// and fixed-length arrays. Single, /// Enum variants. Variant(DefId), @@ -2351,12 +2351,17 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let variant = &adt_def.variants[variant_index]; - let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant); - Some(Variant(variant.def_id)) - .filter(|variant_constructor| variant_constructor == constructor) - .map(|_| { - patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, is_non_exhaustive) - }) + if constructor == &Variant(variant.def_id) { + let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant); + Some(patterns_for_variant( + cx, + subpatterns, + ctor_wild_subpatterns, + is_non_exhaustive, + )) + } else { + None + } } PatKind::Leaf { ref subpatterns } => { From e73b84a6654f3e75788ab7e30989ea451e7f2930 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 13 Apr 2020 18:36:05 +0100 Subject: [PATCH 08/23] Factor out the condition for hiding fields --- src/librustc_mir_build/hair/pattern/_match.rs | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index ae0030acdedbb..c353f51b40158 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -242,7 +242,7 @@ use rustc_hir::{HirId, RangeEnd}; use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef}; +use rustc_middle::ty::{self, Const, FieldDef, Ty, TyCtxt, TypeFoldable, VariantDef}; use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; @@ -622,6 +622,27 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { _ => false, } } + + /// In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide + /// uninhabited fields in order not to reveal the uninhabitedness of the whole variant. + fn hide_uninhabited_field( + &self, + adt_ty: Ty<'tcx>, + variant: &VariantDef, + field: &FieldDef, + ) -> bool { + match adt_ty.kind { + ty::Adt(adt, substs) => { + let is_non_exhaustive = self.is_foreign_non_exhaustive_variant(adt_ty, variant); + let field_ty = field.ty(self.tcx, substs); + let is_visible = + adt.is_enum() || field.vis.is_accessible_from(self.module, self.tcx); + let is_uninhabited = self.is_uninhabited(field_ty); + is_uninhabited && (!is_visible || is_non_exhaustive) + } + _ => false, + } + } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -883,30 +904,19 @@ impl<'tcx> Constructor<'tcx> { vec![Pat::wildcard_from_ty(substs.type_at(0))] } else { let variant = &adt.variants[self.variant_index_for_adt(cx, adt)]; - let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(ty, variant); variant .fields .iter() .map(|field| { - let ty = field.ty(cx.tcx, substs); - let is_visible = adt.is_enum() - || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_inhabited = !cx.is_uninhabited(ty); - // Treat all uninhabited non-visible fields as `TyErr`. They can't - // appear in any other pattern from this match (because they are - // private), so their type does not matter - but we don't want - // to know they are uninhabited. - // Also treat all uninhabited types in non-exhaustive variants as - // `TyErr`. - let allowed_to_inspect = - is_inhabited || (is_visible && !is_non_exhaustive); - - if allowed_to_inspect { - Pat::wildcard_from_ty(ty) + // Treat hidden fields as TyErr so we don't know they are + // uninhabited. + if cx.hide_uninhabited_field(ty, variant, field) { + cx.tcx.types.err } else { - Pat::wildcard_from_ty(cx.tcx.types.err) + field.ty(cx.tcx, substs) } }) + .map(Pat::wildcard_from_ty) .collect() } } From 76df2f48394b39d5b4a0d4dff86769aa4037d403 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 4 May 2020 13:54:30 +0100 Subject: [PATCH 09/23] Remove caching of wildcard_subpatterns Main reason is to simplify the code for what's to come, but also I don't know if that ever made a noticeable perf difference. The caching was introduced in 9c5e86d0cd0185bb1030b95196394adb6c2c7a7a. --- src/librustc_mir_build/hair/pattern/_match.rs | 72 +++++++++---------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index c353f51b40158..3f863463530a6 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -441,9 +441,8 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, constructor: &Constructor<'tcx>, - ctor_wild_subpatterns: &'p [Pat<'tcx>], ) -> Option> { - let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns); + let new_heads = specialize_one_pattern(cx, self.head(), constructor); new_heads.map(|mut new_head| { new_head.0.extend_from_slice(&self.0[1..]); new_head @@ -503,12 +502,8 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, constructor: &Constructor<'tcx>, - ctor_wild_subpatterns: &'p [Pat<'tcx>], ) -> Matrix<'p, 'tcx> { - self.0 - .iter() - .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns)) - .collect() + self.0.iter().filter_map(|r| r.specialize_constructor(cx, constructor)).collect() } } @@ -922,9 +917,9 @@ impl<'tcx> Constructor<'tcx> { } _ => vec![], }, - Slice(_) => match ty.kind { + Slice(slice) => match ty.kind { ty::Slice(ty) | ty::Array(ty, _) => { - let arity = self.arity(cx, ty); + let arity = slice.arity(); (0..arity).map(|_| Pat::wildcard_from_ty(ty)).collect() } _ => bug!("bad slice pattern {:?} {:?}", self, ty), @@ -1844,10 +1839,8 @@ fn is_useful_specialized<'p, 'tcx>( ) -> Usefulness<'tcx, 'p> { debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty); - let ctor_wild_subpatterns = - cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty)); - let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns); - v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns) + let matrix = matrix.specialize_constructor(cx, &ctor); + v.specialize_constructor(cx, &ctor) .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)) .map(|u| u.apply_constructor(cx, &ctor, lty)) .unwrap_or(NotUseful) @@ -2316,9 +2309,12 @@ fn constructor_covered_by_range<'tcx>( fn patterns_for_variant<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, subpatterns: &'p [FieldPat<'tcx>], - ctor_wild_subpatterns: &'p [Pat<'tcx>], + constructor: &Constructor<'tcx>, + ty: Ty<'tcx>, is_non_exhaustive: bool, ) -> PatStack<'p, 'tcx> { + let ctor_wild_subpatterns = + cx.pattern_arena.alloc_from_iter(constructor.wildcard_subpatterns(cx, ty)); let mut result: SmallVec<_> = ctor_wild_subpatterns.iter().collect(); for subpat in subpatterns { @@ -2327,10 +2323,7 @@ fn patterns_for_variant<'p, 'tcx>( } } - debug!( - "patterns_for_variant({:#?}, {:#?}) = {:#?}", - subpatterns, ctor_wild_subpatterns, result - ); + debug!("patterns_for_variant({:#?}) = {:#?}", subpatterns, result); PatStack::from_vec(result) } @@ -2347,7 +2340,6 @@ fn specialize_one_pattern<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>, constructor: &Constructor<'tcx>, - ctor_wild_subpatterns: &'p [Pat<'tcx>], ) -> Option> { if let NonExhaustive = constructor { // Only a wildcard pattern can match the special extra constructor @@ -2357,30 +2349,31 @@ fn specialize_one_pattern<'p, 'tcx>( let result = match *pat.kind { PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` - PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_subpatterns.iter().collect()), + PatKind::Binding { .. } | PatKind::Wild => { + let ctor_wild_subpatterns = + cx.pattern_arena.alloc_from_iter(constructor.wildcard_subpatterns(cx, pat.ty)); + Some(ctor_wild_subpatterns.iter().collect()) + } PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let variant = &adt_def.variants[variant_index]; if constructor == &Variant(variant.def_id) { let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant); - Some(patterns_for_variant( - cx, - subpatterns, - ctor_wild_subpatterns, - is_non_exhaustive, - )) + Some(patterns_for_variant(cx, subpatterns, constructor, pat.ty, is_non_exhaustive)) } else { None } } PatKind::Leaf { ref subpatterns } => { - Some(patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, false)) + Some(patterns_for_variant(cx, subpatterns, constructor, pat.ty, false)) } PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)), PatKind::Constant { value } if constructor.is_slice() => { + let arity = constructor.arity(cx, pat.ty); + // We extract an `Option` for the pointer because slices of zero // elements don't necessarily point to memory, they are usually // just integers. The only time they should be pointing to memory @@ -2391,7 +2384,7 @@ fn specialize_one_pattern<'p, 'tcx>( // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce, // the result would be exactly what we early return here. if n == 0 { - if ctor_wild_subpatterns.len() as u64 == 0 { + if arity == 0 { return Some(PatStack::from_slice(&[])); } else { return None; @@ -2429,7 +2422,7 @@ fn specialize_one_pattern<'p, 'tcx>( constructor, ), }; - if ctor_wild_subpatterns.len() as u64 == n { + if arity == n { // convert a constant slice/array pattern to a list of patterns. let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?; let ptr = Pointer::new(AllocId(0), offset); @@ -2476,20 +2469,21 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Array { ref prefix, ref slice, ref suffix } | PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor { - Slice(_) => { + Slice(slice_ctor) => { let pat_len = prefix.len() + suffix.len(); - if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) { + if let Some(slice_count) = (slice_ctor.arity() as usize).checked_sub(pat_len) { if slice_count == 0 || slice.is_some() { + let item_ty = match pat.ty.kind { + ty::Slice(ty) | ty::Array(ty, _) => ty, + _ => bug!("bad slice pattern {:?} {:?}", constructor, pat.ty), + }; + let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(item_ty)); + Some( prefix .iter() - .chain( - ctor_wild_subpatterns - .iter() - .skip(prefix.len()) - .take(slice_count) - .chain(suffix.iter()), - ) + .chain((0..slice_count).map(|_| wild)) + .chain(suffix.iter()) .collect(), ) } else { @@ -2519,7 +2513,7 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."), }; - debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result); + debug!("specialize({:#?}) = {:#?}", pat, result); result } From 72beeae8defd37912552a44bd0bd97ad2703830d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 4 May 2020 18:59:25 +0100 Subject: [PATCH 10/23] Factor out a struct holding the fields of a variant --- src/librustc_mir_build/hair/pattern/_match.rs | 109 +++++++++++++----- 1 file changed, 78 insertions(+), 31 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 3f863463530a6..bfaf526fa53d0 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -978,9 +978,8 @@ impl<'tcx> Constructor<'tcx> { let pat = match self { Single | Variant(_) => match ty.kind { ty::Adt(..) | ty::Tuple(..) => { - let subpatterns = subpatterns - .enumerate() - .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) + let subpatterns = VariantFields::from_patterns(cx, self, ty, subpatterns) + .into_fieldpats() .collect(); if let ty::Adt(adt, substs) = ty.kind { @@ -1043,6 +1042,70 @@ impl<'tcx> Constructor<'tcx> { } } +/// The fields of a variant, like `Option::Some` or `(,)`. This handles uninhabited fields and +/// `non_exhaustive` pragmas under the hood. +#[derive(Debug)] +struct VariantFields<'p, 'tcx> { + fields: SmallVec<[&'p Pat<'tcx>; 2]>, + is_non_exhaustive: bool, +} + +impl<'p, 'tcx> VariantFields<'p, 'tcx> { + fn from_patterns( + cx: &MatchCheckCtxt<'p, 'tcx>, + constructor: &Constructor<'tcx>, + ty: Ty<'tcx>, + pats: impl IntoIterator>, + ) -> Self { + let fields = cx.pattern_arena.alloc_from_iter(pats); + let fields: SmallVec<_> = fields.iter().collect(); + let is_non_exhaustive = match ty.kind { + ty::Adt(adt, _) => { + let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; + cx.is_foreign_non_exhaustive_variant(ty, variant) + } + _ => false, + }; + VariantFields { fields, is_non_exhaustive } + } + + /// Creates a new list of wildcard fields for a given constructor. `constructor` + /// must be `Variant` or `Single`. + fn wildcards( + cx: &MatchCheckCtxt<'p, 'tcx>, + constructor: &Constructor<'tcx>, + ty: Ty<'tcx>, + ) -> Self { + Self::from_patterns(cx, constructor, ty, constructor.wildcard_subpatterns(cx, ty)) + } + + /// Overrides some of the fields with the provided patterns + fn override_patterns( + mut self, + cx: &mut MatchCheckCtxt<'p, 'tcx>, + pats: impl IntoIterator>, + ) -> Self { + for pat in pats { + if !self.is_non_exhaustive || !cx.is_uninhabited(pat.pattern.ty) { + self.fields[pat.field.index()] = &pat.pattern; + } + } + self + } + + fn into_patstack(self) -> PatStack<'p, 'tcx> { + PatStack::from_vec(self.fields) + } + + fn into_fieldpats(self) -> impl Iterator> + 'p { + self.fields + .into_iter() + .cloned() + .enumerate() + .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) + } +} + #[derive(Clone, Debug)] crate enum Usefulness<'tcx, 'p> { /// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns. @@ -2306,27 +2369,6 @@ fn constructor_covered_by_range<'tcx>( if intersects { Some(()) } else { None } } -fn patterns_for_variant<'p, 'tcx>( - cx: &mut MatchCheckCtxt<'p, 'tcx>, - subpatterns: &'p [FieldPat<'tcx>], - constructor: &Constructor<'tcx>, - ty: Ty<'tcx>, - is_non_exhaustive: bool, -) -> PatStack<'p, 'tcx> { - let ctor_wild_subpatterns = - cx.pattern_arena.alloc_from_iter(constructor.wildcard_subpatterns(cx, ty)); - let mut result: SmallVec<_> = ctor_wild_subpatterns.iter().collect(); - - for subpat in subpatterns { - if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) { - result[subpat.field.index()] = &subpat.pattern; - } - } - - debug!("patterns_for_variant({:#?}) = {:#?}", subpatterns, result); - PatStack::from_vec(result) -} - /// This is the main specialization step. It expands the pattern /// into `arity` patterns based on the constructor. For most patterns, the step is trivial, /// for instance tuple patterns are flattened and box patterns expand into their inner pattern. @@ -2356,18 +2398,23 @@ fn specialize_one_pattern<'p, 'tcx>( } PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { - let variant = &adt_def.variants[variant_index]; - if constructor == &Variant(variant.def_id) { - let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant); - Some(patterns_for_variant(cx, subpatterns, constructor, pat.ty, is_non_exhaustive)) + let pat_ctor = Variant(adt_def.variants[variant_index].def_id); + if constructor == &pat_ctor { + Some( + VariantFields::wildcards(cx, constructor, pat.ty) + .override_patterns(cx, subpatterns) + .into_patstack(), + ) } else { None } } - PatKind::Leaf { ref subpatterns } => { - Some(patterns_for_variant(cx, subpatterns, constructor, pat.ty, false)) - } + PatKind::Leaf { ref subpatterns } => Some( + VariantFields::wildcards(cx, constructor, pat.ty) + .override_patterns(cx, subpatterns) + .into_patstack(), + ), PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)), From 710fc8a836246a5d3572e9953880edaa081d9f77 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 4 May 2020 19:14:45 +0100 Subject: [PATCH 11/23] Swap responsibility for generating wildcard fields --- src/librustc_mir_build/hair/pattern/_match.rs | 71 ++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index bfaf526fa53d0..ff67036382c4e 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -888,35 +888,7 @@ impl<'tcx> Constructor<'tcx> { debug!("wildcard_subpatterns({:#?}, {:?})", self, ty); match self { - Single | Variant(_) => match ty.kind { - ty::Tuple(ref fs) => { - fs.into_iter().map(|t| t.expect_ty()).map(Pat::wildcard_from_ty).collect() - } - ty::Ref(_, rty, _) => vec![Pat::wildcard_from_ty(rty)], - ty::Adt(adt, substs) => { - if adt.is_box() { - // Use T as the sub pattern type of Box. - vec![Pat::wildcard_from_ty(substs.type_at(0))] - } else { - let variant = &adt.variants[self.variant_index_for_adt(cx, adt)]; - variant - .fields - .iter() - .map(|field| { - // Treat hidden fields as TyErr so we don't know they are - // uninhabited. - if cx.hide_uninhabited_field(ty, variant, field) { - cx.tcx.types.err - } else { - field.ty(cx.tcx, substs) - } - }) - .map(Pat::wildcard_from_ty) - .collect() - } - } - _ => vec![], - }, + Single | Variant(_) => VariantFields::wildcards(cx, self, ty).into_vec(), Slice(slice) => match ty.kind { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); @@ -1076,11 +1048,40 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { constructor: &Constructor<'tcx>, ty: Ty<'tcx>, ) -> Self { - Self::from_patterns(cx, constructor, ty, constructor.wildcard_subpatterns(cx, ty)) + let subpatterns = match ty.kind { + ty::Tuple(ref fs) => { + fs.into_iter().map(|t| t.expect_ty()).map(Pat::wildcard_from_ty).collect() + } + ty::Ref(_, rty, _) => vec![Pat::wildcard_from_ty(rty)], + ty::Adt(adt, substs) => { + if adt.is_box() { + // Use T as the sub pattern type of Box. + vec![Pat::wildcard_from_ty(substs.type_at(0))] + } else { + let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; + variant + .fields + .iter() + .map(|field| { + // Treat hidden fields as TyErr so we don't know they are + // uninhabited. + if cx.hide_uninhabited_field(ty, variant, field) { + cx.tcx.types.err + } else { + field.ty(cx.tcx, substs) + } + }) + .map(Pat::wildcard_from_ty) + .collect() + } + } + _ => vec![], + }; + Self::from_patterns(cx, constructor, ty, subpatterns) } /// Overrides some of the fields with the provided patterns - fn override_patterns( + fn override_fieldpatterns( mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pats: impl IntoIterator>, @@ -1097,6 +1098,10 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { PatStack::from_vec(self.fields) } + fn into_vec(self) -> Vec> { + self.fields.into_iter().cloned().collect() + } + fn into_fieldpats(self) -> impl Iterator> + 'p { self.fields .into_iter() @@ -2402,7 +2407,7 @@ fn specialize_one_pattern<'p, 'tcx>( if constructor == &pat_ctor { Some( VariantFields::wildcards(cx, constructor, pat.ty) - .override_patterns(cx, subpatterns) + .override_fieldpatterns(cx, subpatterns) .into_patstack(), ) } else { @@ -2412,7 +2417,7 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Leaf { ref subpatterns } => Some( VariantFields::wildcards(cx, constructor, pat.ty) - .override_patterns(cx, subpatterns) + .override_fieldpatterns(cx, subpatterns) .into_patstack(), ), From d49fda90eef86559b3dda4b928122c6c97f1fa3f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 4 May 2020 19:26:26 +0100 Subject: [PATCH 12/23] `wildcards_subpatterns` returns PatStack This is to clarify the API of VariantFields in preparation for filtering. --- src/librustc_mir_build/hair/pattern/_match.rs | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index ff67036382c4e..80296fbcc1c41 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -408,7 +408,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { PatStack::from_slice(&self.0[1..]) } - fn iter(&self) -> impl Iterator> { + fn iter(&self) -> impl Iterator> + DoubleEndedIterator { self.0.iter().copied() } @@ -880,23 +880,26 @@ impl<'tcx> Constructor<'tcx> { /// This returns one wildcard pattern for each argument to this constructor. /// /// This must be consistent with `apply`, `specialize_one_pattern`, and `arity`. - fn wildcard_subpatterns<'a>( + fn wildcard_subpatterns<'p>( &self, - cx: &MatchCheckCtxt<'a, 'tcx>, + cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>, - ) -> Vec> { + ) -> PatStack<'p, 'tcx> { debug!("wildcard_subpatterns({:#?}, {:?})", self, ty); match self { - Single | Variant(_) => VariantFields::wildcards(cx, self, ty).into_vec(), + Single | Variant(_) => VariantFields::wildcards(cx, self, ty).into_patstack(), Slice(slice) => match ty.kind { ty::Slice(ty) | ty::Array(ty, _) => { + let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); let arity = slice.arity(); - (0..arity).map(|_| Pat::wildcard_from_ty(ty)).collect() + (0..arity).map(|_| wild).collect() } _ => bug!("bad slice pattern {:?} {:?}", self, ty), }, - ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => vec![], + ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => { + PatStack::default() + } } } @@ -1009,8 +1012,8 @@ impl<'tcx> Constructor<'tcx> { /// Like `apply`, but where all the subpatterns are wildcards `_`. fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { - let subpatterns = self.wildcard_subpatterns(cx, ty).into_iter().rev(); - self.apply(cx, ty, subpatterns) + let subpatterns = self.wildcard_subpatterns(cx, ty); + self.apply(cx, ty, subpatterns.iter().cloned().rev()) } } @@ -1098,10 +1101,6 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { PatStack::from_vec(self.fields) } - fn into_vec(self) -> Vec> { - self.fields.into_iter().cloned().collect() - } - fn into_fieldpats(self) -> impl Iterator> + 'p { self.fields .into_iter() @@ -2397,9 +2396,7 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` PatKind::Binding { .. } | PatKind::Wild => { - let ctor_wild_subpatterns = - cx.pattern_arena.alloc_from_iter(constructor.wildcard_subpatterns(cx, pat.ty)); - Some(ctor_wild_subpatterns.iter().collect()) + Some(constructor.wildcard_subpatterns(cx, pat.ty)) } PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { From 05623fda04da733164c2bbae165c1bf1ec38de12 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 4 May 2020 20:54:15 +0100 Subject: [PATCH 13/23] Prepare VariantsFields for filtering --- src/librustc_mir_build/hair/pattern/_match.rs | 128 +++++++++++++----- 1 file changed, 94 insertions(+), 34 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 80296fbcc1c41..bdddd3c9dfacf 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -776,6 +776,21 @@ impl<'tcx> Constructor<'tcx> { } } + /// Returns whether the fields of this constructor should be treated as `non_exhaustive`. + fn is_field_list_non_exhaustive<'a>( + &self, + cx: &MatchCheckCtxt<'a, 'tcx>, + ty: Ty<'tcx>, + ) -> bool { + match ty.kind { + ty::Adt(adt, _) => { + let variant = &adt.variants[self.variant_index_for_adt(cx, adt)]; + cx.is_foreign_non_exhaustive_variant(ty, variant) + } + _ => false, + } + } + fn variant_index_for_adt<'a>( &self, cx: &MatchCheckCtxt<'a, 'tcx>, @@ -913,15 +928,7 @@ impl<'tcx> Constructor<'tcx> { fn arity<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> u64 { debug!("Constructor::arity({:#?}, {:?})", self, ty); match self { - Single | Variant(_) => match ty.kind { - ty::Tuple(ref fs) => fs.len() as u64, - ty::Slice(..) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty), - ty::Ref(..) => 1, - ty::Adt(adt, _) => { - adt.variants[self.variant_index_for_adt(cx, adt)].fields.len() as u64 - } - _ => 0, - }, + Single | Variant(_) => VariantFields::ctor_arity(cx, self, ty), Slice(slice) => slice.arity(), ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => 0, } @@ -1018,30 +1025,60 @@ impl<'tcx> Constructor<'tcx> { } /// The fields of a variant, like `Option::Some` or `(,)`. This handles uninhabited fields and -/// `non_exhaustive` pragmas under the hood. -#[derive(Debug)] +/// `non_exhaustive` field lists under the hood. +#[derive(Debug, Clone)] struct VariantFields<'p, 'tcx> { - fields: SmallVec<[&'p Pat<'tcx>; 2]>, + fields: SmallVec<[VariantField<'p, 'tcx>; 2]>, is_non_exhaustive: bool, } +#[derive(Debug, Clone)] +enum VariantField<'p, 'tcx> { + Kept(&'p Pat<'tcx>), + // Hidden(Ty<'tcx>), +} + +impl<'p, 'tcx> VariantField<'p, 'tcx> { + fn wildcard_from_ty(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self { + let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); + VariantField::Kept(wild) + } + + fn kept(&self) -> Option<&'p Pat<'tcx>> { + match self { + VariantField::Kept(p) => Some(p), + // VariantField::Hidden(_) => None, + } + } + + fn into_pattern(self) -> Pat<'tcx> { + match self { + VariantField::Kept(p) => p.clone(), + // VariantField::Hidden(ty) => Pat::wildcard_from_ty(ty), + } + } +} + impl<'p, 'tcx> VariantFields<'p, 'tcx> { + // Takes an already filtered list of patterns, e.g. taken from the matrix. fn from_patterns( cx: &MatchCheckCtxt<'p, 'tcx>, constructor: &Constructor<'tcx>, ty: Ty<'tcx>, pats: impl IntoIterator>, ) -> Self { - let fields = cx.pattern_arena.alloc_from_iter(pats); - let fields: SmallVec<_> = fields.iter().collect(); - let is_non_exhaustive = match ty.kind { - ty::Adt(adt, _) => { - let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; - cx.is_foreign_non_exhaustive_variant(ty, variant) + // There are `arity()` patterns in there. + let mut pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); + + let mut fields = Self::wildcards(cx, constructor, ty); + for f in &mut fields.fields { + if let VariantField::Kept(p) = f { + let (pat, rest) = pats.split_first().unwrap(); + *p = pat; + pats = rest; } - _ => false, - }; - VariantFields { fields, is_non_exhaustive } + } + fields } /// Creates a new list of wildcard fields for a given constructor. `constructor` @@ -1051,15 +1088,17 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { constructor: &Constructor<'tcx>, ty: Ty<'tcx>, ) -> Self { - let subpatterns = match ty.kind { - ty::Tuple(ref fs) => { - fs.into_iter().map(|t| t.expect_ty()).map(Pat::wildcard_from_ty).collect() - } - ty::Ref(_, rty, _) => vec![Pat::wildcard_from_ty(rty)], + let fields = match ty.kind { + ty::Tuple(ref fs) => fs + .into_iter() + .map(|t| t.expect_ty()) + .map(|ty| VariantField::wildcard_from_ty(cx, ty)) + .collect(), + ty::Ref(_, rty, _) => smallvec![VariantField::wildcard_from_ty(cx, rty)], ty::Adt(adt, substs) => { if adt.is_box() { // Use T as the sub pattern type of Box. - vec![Pat::wildcard_from_ty(substs.type_at(0))] + smallvec![VariantField::wildcard_from_ty(cx, substs.type_at(0))] } else { let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; variant @@ -1074,37 +1113,58 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { field.ty(cx.tcx, substs) } }) - .map(Pat::wildcard_from_ty) + .map(|ty| VariantField::wildcard_from_ty(cx, ty)) .collect() } } - _ => vec![], + _ => smallvec![], }; - Self::from_patterns(cx, constructor, ty, subpatterns) + let is_non_exhaustive = constructor.is_field_list_non_exhaustive(cx, ty); + VariantFields { fields, is_non_exhaustive } + } + + /// Calculates the number of fields of a given constructor. `constructor` must be `Variant` or + /// `Single`. + fn ctor_arity( + cx: &MatchCheckCtxt<'p, 'tcx>, + constructor: &Constructor<'tcx>, + ty: Ty<'tcx>, + ) -> u64 { + match ty.kind { + ty::Tuple(ref fs) => fs.len() as u64, + ty::Ref(..) => 1, + ty::Adt(adt, _) => { + adt.variants[constructor.variant_index_for_adt(cx, adt)].fields.len() as u64 + } + ty::Slice(..) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", constructor, ty), + _ => 0, + } } /// Overrides some of the fields with the provided patterns fn override_fieldpatterns( mut self, - cx: &mut MatchCheckCtxt<'p, 'tcx>, + cx: &MatchCheckCtxt<'p, 'tcx>, pats: impl IntoIterator>, ) -> Self { for pat in pats { if !self.is_non_exhaustive || !cx.is_uninhabited(pat.pattern.ty) { - self.fields[pat.field.index()] = &pat.pattern; + self.fields[pat.field.index()] = VariantField::Kept(&pat.pattern); } } self } + /// Returns a filtered list of patterns, to be stored in the matrix. fn into_patstack(self) -> PatStack<'p, 'tcx> { - PatStack::from_vec(self.fields) + PatStack::from_vec(self.fields.into_iter().filter_map(|p| p.kept()).collect()) } + /// Returns an exhaustive list of patterns, to be stored into the relevant `PatKind`. fn into_fieldpats(self) -> impl Iterator> + 'p { self.fields .into_iter() - .cloned() + .map(|p| p.into_pattern()) .enumerate() .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) } From 0c55f7fec53febb9e2f2f71305fe3462f2d57757 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 4 May 2020 21:37:57 +0100 Subject: [PATCH 14/23] Filter out fields that should not be seen. This was previously done by using tyerr as a fake type. That was hacky. --- src/librustc_mir_build/hair/pattern/_match.rs | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index bdddd3c9dfacf..fca0d881cd76b 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -1025,7 +1025,8 @@ impl<'tcx> Constructor<'tcx> { } /// The fields of a variant, like `Option::Some` or `(,)`. This handles uninhabited fields and -/// `non_exhaustive` field lists under the hood. +/// `non_exhaustive` field lists under the hood. This in particular filters out fields whose +/// uninhabitedness should not be visible to the user. #[derive(Debug, Clone)] struct VariantFields<'p, 'tcx> { fields: SmallVec<[VariantField<'p, 'tcx>; 2]>, @@ -1035,7 +1036,7 @@ struct VariantFields<'p, 'tcx> { #[derive(Debug, Clone)] enum VariantField<'p, 'tcx> { Kept(&'p Pat<'tcx>), - // Hidden(Ty<'tcx>), + Hidden(Ty<'tcx>), } impl<'p, 'tcx> VariantField<'p, 'tcx> { @@ -1047,14 +1048,14 @@ impl<'p, 'tcx> VariantField<'p, 'tcx> { fn kept(&self) -> Option<&'p Pat<'tcx>> { match self { VariantField::Kept(p) => Some(p), - // VariantField::Hidden(_) => None, + VariantField::Hidden(_) => None, } } fn into_pattern(self) -> Pat<'tcx> { match self { VariantField::Kept(p) => p.clone(), - // VariantField::Hidden(ty) => Pat::wildcard_from_ty(ty), + VariantField::Hidden(ty) => Pat::wildcard_from_ty(ty), } } } @@ -1067,15 +1068,16 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { ty: Ty<'tcx>, pats: impl IntoIterator>, ) -> Self { - // There are `arity()` patterns in there. - let mut pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); + // There should be `arity()` patterns in there. + let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); + let mut pats_iter = pats.iter(); let mut fields = Self::wildcards(cx, constructor, ty); for f in &mut fields.fields { if let VariantField::Kept(p) = f { - let (pat, rest) = pats.split_first().unwrap(); + // We take one input pattern for each `Kept` field, in order. + let pat = pats_iter.next().unwrap(); *p = pat; - pats = rest; } } fields @@ -1105,15 +1107,14 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { .fields .iter() .map(|field| { - // Treat hidden fields as TyErr so we don't know they are - // uninhabited. + let field_ty = field.ty(cx.tcx, substs); + // Filter out hidden fields so we don't know they are uninhabited. if cx.hide_uninhabited_field(ty, variant, field) { - cx.tcx.types.err + VariantField::Hidden(field_ty) } else { - field.ty(cx.tcx, substs) + VariantField::wildcard_from_ty(cx, field_ty) } }) - .map(|ty| VariantField::wildcard_from_ty(cx, ty)) .collect() } } @@ -1134,7 +1135,12 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { ty::Tuple(ref fs) => fs.len() as u64, ty::Ref(..) => 1, ty::Adt(adt, _) => { - adt.variants[constructor.variant_index_for_adt(cx, adt)].fields.len() as u64 + let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; + variant + .fields + .iter() + .filter(|field| !cx.hide_uninhabited_field(ty, variant, field)) + .count() as u64 } ty::Slice(..) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", constructor, ty), _ => 0, @@ -1144,12 +1150,11 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { /// Overrides some of the fields with the provided patterns fn override_fieldpatterns( mut self, - cx: &MatchCheckCtxt<'p, 'tcx>, pats: impl IntoIterator>, ) -> Self { for pat in pats { - if !self.is_non_exhaustive || !cx.is_uninhabited(pat.pattern.ty) { - self.fields[pat.field.index()] = VariantField::Kept(&pat.pattern); + if let VariantField::Kept(p) = &mut self.fields[pat.field.index()] { + *p = &pat.pattern } } self @@ -2464,7 +2469,7 @@ fn specialize_one_pattern<'p, 'tcx>( if constructor == &pat_ctor { Some( VariantFields::wildcards(cx, constructor, pat.ty) - .override_fieldpatterns(cx, subpatterns) + .override_fieldpatterns(subpatterns) .into_patstack(), ) } else { @@ -2474,7 +2479,7 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Leaf { ref subpatterns } => Some( VariantFields::wildcards(cx, constructor, pat.ty) - .override_fieldpatterns(cx, subpatterns) + .override_fieldpatterns(subpatterns) .into_patstack(), ), From f6a90453d9efd6320e0dfb175bd08f6701876212 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 5 May 2020 10:52:42 +0100 Subject: [PATCH 15/23] Rename VariantFields to StructFields --- src/librustc_mir_build/hair/pattern/_match.rs | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index fca0d881cd76b..e48575d215252 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -903,7 +903,7 @@ impl<'tcx> Constructor<'tcx> { debug!("wildcard_subpatterns({:#?}, {:?})", self, ty); match self { - Single | Variant(_) => VariantFields::wildcards(cx, self, ty).into_patstack(), + Single | Variant(_) => StructFields::wildcards(cx, self, ty).into_patstack(), Slice(slice) => match ty.kind { ty::Slice(ty) | ty::Array(ty, _) => { let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); @@ -928,7 +928,7 @@ impl<'tcx> Constructor<'tcx> { fn arity<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> u64 { debug!("Constructor::arity({:#?}, {:?})", self, ty); match self { - Single | Variant(_) => VariantFields::ctor_arity(cx, self, ty), + Single | Variant(_) => StructFields::ctor_arity(cx, self, ty), Slice(slice) => slice.arity(), ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => 0, } @@ -960,7 +960,7 @@ impl<'tcx> Constructor<'tcx> { let pat = match self { Single | Variant(_) => match ty.kind { ty::Adt(..) | ty::Tuple(..) => { - let subpatterns = VariantFields::from_patterns(cx, self, ty, subpatterns) + let subpatterns = StructFields::from_patterns(cx, self, ty, subpatterns) .into_fieldpats() .collect(); @@ -1024,43 +1024,42 @@ impl<'tcx> Constructor<'tcx> { } } -/// The fields of a variant, like `Option::Some` or `(,)`. This handles uninhabited fields and -/// `non_exhaustive` field lists under the hood. This in particular filters out fields whose +/// The fields of a struct, a tuple, or an enum variant. This hides away fields whose /// uninhabitedness should not be visible to the user. #[derive(Debug, Clone)] -struct VariantFields<'p, 'tcx> { - fields: SmallVec<[VariantField<'p, 'tcx>; 2]>, +struct StructFields<'p, 'tcx> { + fields: SmallVec<[StructField<'p, 'tcx>; 2]>, is_non_exhaustive: bool, } #[derive(Debug, Clone)] -enum VariantField<'p, 'tcx> { +enum StructField<'p, 'tcx> { Kept(&'p Pat<'tcx>), Hidden(Ty<'tcx>), } -impl<'p, 'tcx> VariantField<'p, 'tcx> { +impl<'p, 'tcx> StructField<'p, 'tcx> { fn wildcard_from_ty(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self { let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); - VariantField::Kept(wild) + StructField::Kept(wild) } fn kept(&self) -> Option<&'p Pat<'tcx>> { match self { - VariantField::Kept(p) => Some(p), - VariantField::Hidden(_) => None, + StructField::Kept(p) => Some(p), + StructField::Hidden(_) => None, } } fn into_pattern(self) -> Pat<'tcx> { match self { - VariantField::Kept(p) => p.clone(), - VariantField::Hidden(ty) => Pat::wildcard_from_ty(ty), + StructField::Kept(p) => p.clone(), + StructField::Hidden(ty) => Pat::wildcard_from_ty(ty), } } } -impl<'p, 'tcx> VariantFields<'p, 'tcx> { +impl<'p, 'tcx> StructFields<'p, 'tcx> { // Takes an already filtered list of patterns, e.g. taken from the matrix. fn from_patterns( cx: &MatchCheckCtxt<'p, 'tcx>, @@ -1074,7 +1073,7 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { let mut pats_iter = pats.iter(); let mut fields = Self::wildcards(cx, constructor, ty); for f in &mut fields.fields { - if let VariantField::Kept(p) = f { + if let StructField::Kept(p) = f { // We take one input pattern for each `Kept` field, in order. let pat = pats_iter.next().unwrap(); *p = pat; @@ -1094,13 +1093,13 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { ty::Tuple(ref fs) => fs .into_iter() .map(|t| t.expect_ty()) - .map(|ty| VariantField::wildcard_from_ty(cx, ty)) + .map(|ty| StructField::wildcard_from_ty(cx, ty)) .collect(), - ty::Ref(_, rty, _) => smallvec![VariantField::wildcard_from_ty(cx, rty)], + ty::Ref(_, rty, _) => smallvec![StructField::wildcard_from_ty(cx, rty)], ty::Adt(adt, substs) => { if adt.is_box() { // Use T as the sub pattern type of Box. - smallvec![VariantField::wildcard_from_ty(cx, substs.type_at(0))] + smallvec![StructField::wildcard_from_ty(cx, substs.type_at(0))] } else { let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; variant @@ -1110,9 +1109,9 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { let field_ty = field.ty(cx.tcx, substs); // Filter out hidden fields so we don't know they are uninhabited. if cx.hide_uninhabited_field(ty, variant, field) { - VariantField::Hidden(field_ty) + StructField::Hidden(field_ty) } else { - VariantField::wildcard_from_ty(cx, field_ty) + StructField::wildcard_from_ty(cx, field_ty) } }) .collect() @@ -1121,7 +1120,7 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { _ => smallvec![], }; let is_non_exhaustive = constructor.is_field_list_non_exhaustive(cx, ty); - VariantFields { fields, is_non_exhaustive } + StructFields { fields, is_non_exhaustive } } /// Calculates the number of fields of a given constructor. `constructor` must be `Variant` or @@ -1153,7 +1152,7 @@ impl<'p, 'tcx> VariantFields<'p, 'tcx> { pats: impl IntoIterator>, ) -> Self { for pat in pats { - if let VariantField::Kept(p) = &mut self.fields[pat.field.index()] { + if let StructField::Kept(p) = &mut self.fields[pat.field.index()] { *p = &pat.pattern } } @@ -2468,7 +2467,7 @@ fn specialize_one_pattern<'p, 'tcx>( let pat_ctor = Variant(adt_def.variants[variant_index].def_id); if constructor == &pat_ctor { Some( - VariantFields::wildcards(cx, constructor, pat.ty) + StructFields::wildcards(cx, constructor, pat.ty) .override_fieldpatterns(subpatterns) .into_patstack(), ) @@ -2478,7 +2477,7 @@ fn specialize_one_pattern<'p, 'tcx>( } PatKind::Leaf { ref subpatterns } => Some( - VariantFields::wildcards(cx, constructor, pat.ty) + StructFields::wildcards(cx, constructor, pat.ty) .override_fieldpatterns(subpatterns) .into_patstack(), ), From b879567f767ed05e1b85cd550e8783b54a4431b5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 5 May 2020 18:15:58 +0100 Subject: [PATCH 16/23] Restore caching of wildcard subfields I had removed it a few commits ago to ease refactoring. --- src/librustc_mir_build/hair/pattern/_match.rs | 148 +++++++++++------- 1 file changed, 88 insertions(+), 60 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index e48575d215252..361f928acd1fb 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -441,8 +441,9 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, constructor: &Constructor<'tcx>, + ctor_wild_fields: &Fields<'p, 'tcx>, ) -> Option> { - let new_heads = specialize_one_pattern(cx, self.head(), constructor); + let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_fields); new_heads.map(|mut new_head| { new_head.0.extend_from_slice(&self.0[1..]); new_head @@ -502,8 +503,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, constructor: &Constructor<'tcx>, + ctor_wild_fields: &Fields<'p, 'tcx>, ) -> Matrix<'p, 'tcx> { - self.0.iter().filter_map(|r| r.specialize_constructor(cx, constructor)).collect() + self.0 + .iter() + .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_fields)) + .collect() } } @@ -892,32 +897,6 @@ impl<'tcx> Constructor<'tcx> { } } - /// This returns one wildcard pattern for each argument to this constructor. - /// - /// This must be consistent with `apply`, `specialize_one_pattern`, and `arity`. - fn wildcard_subpatterns<'p>( - &self, - cx: &MatchCheckCtxt<'p, 'tcx>, - ty: Ty<'tcx>, - ) -> PatStack<'p, 'tcx> { - debug!("wildcard_subpatterns({:#?}, {:?})", self, ty); - - match self { - Single | Variant(_) => StructFields::wildcards(cx, self, ty).into_patstack(), - Slice(slice) => match ty.kind { - ty::Slice(ty) | ty::Array(ty, _) => { - let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); - let arity = slice.arity(); - (0..arity).map(|_| wild).collect() - } - _ => bug!("bad slice pattern {:?} {:?}", self, ty), - }, - ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => { - PatStack::default() - } - } - } - /// This computes the arity of a constructor. The arity of a constructor /// is how many subpattern patterns of that constructor should be expanded to. /// @@ -1019,7 +998,7 @@ impl<'tcx> Constructor<'tcx> { /// Like `apply`, but where all the subpatterns are wildcards `_`. fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { - let subpatterns = self.wildcard_subpatterns(cx, ty); + let subpatterns = Fields::wildcards(cx, self, ty).to_patstack(); self.apply(cx, ty, subpatterns.iter().cloned().rev()) } } @@ -1032,7 +1011,7 @@ struct StructFields<'p, 'tcx> { is_non_exhaustive: bool, } -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] enum StructField<'p, 'tcx> { Kept(&'p Pat<'tcx>), Hidden(Ty<'tcx>), @@ -1146,22 +1125,20 @@ impl<'p, 'tcx> StructFields<'p, 'tcx> { } } - /// Overrides some of the fields with the provided patterns - fn override_fieldpatterns( - mut self, - pats: impl IntoIterator>, - ) -> Self { + /// Overrides some of the fields with the provided patterns. Clones the input. + fn override_fieldpatterns(&self, pats: impl IntoIterator>) -> Self { + let mut res = self.clone(); for pat in pats { - if let StructField::Kept(p) = &mut self.fields[pat.field.index()] { + if let StructField::Kept(p) = &mut res.fields[pat.field.index()] { *p = &pat.pattern } } - self + res } /// Returns a filtered list of patterns, to be stored in the matrix. - fn into_patstack(self) -> PatStack<'p, 'tcx> { - PatStack::from_vec(self.fields.into_iter().filter_map(|p| p.kept()).collect()) + fn to_patstack(&self) -> PatStack<'p, 'tcx> { + PatStack::from_vec(self.fields.iter().filter_map(|p| p.kept()).collect()) } /// Returns an exhaustive list of patterns, to be stored into the relevant `PatKind`. @@ -1174,6 +1151,54 @@ impl<'p, 'tcx> StructFields<'p, 'tcx> { } } +/// A value can be decomposed into a Constructor applied to some Fields. This struct represents +/// those fields, generalized to allow patterns in each field. +#[derive(Debug, Clone)] +enum Fields<'p, 'tcx> { + Struct(StructFields<'p, 'tcx>), + WildcardSlice { arity: u64, wild: &'p Pat<'tcx> }, + Empty, +} + +impl<'p, 'tcx> Fields<'p, 'tcx> { + /// Creates a new list of wildcard fields for a given constructor. + fn wildcards( + cx: &MatchCheckCtxt<'p, 'tcx>, + constructor: &Constructor<'tcx>, + ty: Ty<'tcx>, + ) -> Self { + debug!("Fields::wildcards({:#?}, {:?})", constructor, ty); + + match constructor { + Single | Variant(_) => Fields::Struct(StructFields::wildcards(cx, constructor, ty)), + Slice(slice) => match ty.kind { + ty::Slice(ty) | ty::Array(ty, _) => { + let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); + let arity = slice.arity(); + Fields::WildcardSlice { arity, wild } + } + _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), + }, + ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => Fields::Empty, + } + } + + fn as_structfields(&self) -> Option<&StructFields<'p, 'tcx>> { + match self { + Fields::Struct(sf) => Some(sf), + _ => None, + } + } + + fn to_patstack(&self) -> PatStack<'p, 'tcx> { + match self { + Fields::Struct(sf) => sf.to_patstack(), + &Fields::WildcardSlice { arity, wild } => (0..arity).map(|_| wild).collect(), + Fields::Empty => PatStack::default(), + } + } +} + #[derive(Clone, Debug)] crate enum Usefulness<'tcx, 'p> { /// Carries a list of unreachable subpatterns. Used only in the presence of or-patterns. @@ -1963,17 +1988,19 @@ fn is_useful_specialized<'p, 'tcx>( matrix: &Matrix<'p, 'tcx>, v: &PatStack<'p, 'tcx>, ctor: Constructor<'tcx>, - lty: Ty<'tcx>, + ty: Ty<'tcx>, witness_preference: WitnessPreference, hir_id: HirId, is_under_guard: bool, ) -> Usefulness<'tcx, 'p> { - debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty); + debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, ty); - let matrix = matrix.specialize_constructor(cx, &ctor); - v.specialize_constructor(cx, &ctor) + // We cache the result of `Fields::wildcards` because it is used a lot. + let ctor_wild_fields = Fields::wildcards(cx, &ctor, ty); + let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_fields); + v.specialize_constructor(cx, &ctor, &ctor_wild_fields) .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)) - .map(|u| u.apply_constructor(cx, &ctor, lty)) + .map(|u| u.apply_constructor(cx, &ctor, ty)) .unwrap_or(NotUseful) } @@ -2450,6 +2477,7 @@ fn specialize_one_pattern<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>, constructor: &Constructor<'tcx>, + ctor_wild_fields: &Fields<'p, 'tcx>, ) -> Option> { if let NonExhaustive = constructor { // Only a wildcard pattern can match the special extra constructor @@ -2459,17 +2487,17 @@ fn specialize_one_pattern<'p, 'tcx>( let result = match *pat.kind { PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` - PatKind::Binding { .. } | PatKind::Wild => { - Some(constructor.wildcard_subpatterns(cx, pat.ty)) - } + PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_fields.to_patstack()), PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let pat_ctor = Variant(adt_def.variants[variant_index].def_id); if constructor == &pat_ctor { Some( - StructFields::wildcards(cx, constructor, pat.ty) + ctor_wild_fields + .as_structfields() + .unwrap() .override_fieldpatterns(subpatterns) - .into_patstack(), + .to_patstack(), ) } else { None @@ -2477,9 +2505,11 @@ fn specialize_one_pattern<'p, 'tcx>( } PatKind::Leaf { ref subpatterns } => Some( - StructFields::wildcards(cx, constructor, pat.ty) + ctor_wild_fields + .as_structfields() + .unwrap() .override_fieldpatterns(subpatterns) - .into_patstack(), + .to_patstack(), ), PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)), @@ -2582,20 +2612,18 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Array { ref prefix, ref slice, ref suffix } | PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor { - Slice(slice_ctor) => { + Slice(_) => { + let (arity, wild_pat) = match *ctor_wild_fields { + Fields::WildcardSlice { arity, wild } => (arity as usize, wild), + _ => bug!("bad slice pattern {:?} {:?}", ctor_wild_fields, pat.ty), + }; let pat_len = prefix.len() + suffix.len(); - if let Some(slice_count) = (slice_ctor.arity() as usize).checked_sub(pat_len) { + if let Some(slice_count) = arity.checked_sub(pat_len) { if slice_count == 0 || slice.is_some() { - let item_ty = match pat.ty.kind { - ty::Slice(ty) | ty::Array(ty, _) => ty, - _ => bug!("bad slice pattern {:?} {:?}", constructor, pat.ty), - }; - let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(item_ty)); - Some( prefix .iter() - .chain((0..slice_count).map(|_| wild)) + .chain((0..slice_count).map(|_| wild_pat)) .chain(suffix.iter()) .collect(), ) From 7ad17a5d6637aa5a8ef982bd7565c505b6bfc059 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 5 May 2020 18:55:07 +0100 Subject: [PATCH 17/23] Fix incorrect ordering I introduced this mistake in 175976e2a2b03c3f347d4eff28661445c3c58372 and I can't quite remember what the reasoning was back then. --- src/librustc_mir_build/hair/pattern/_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 361f928acd1fb..13ed7d9f63c48 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -999,7 +999,7 @@ impl<'tcx> Constructor<'tcx> { /// Like `apply`, but where all the subpatterns are wildcards `_`. fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { let subpatterns = Fields::wildcards(cx, self, ty).to_patstack(); - self.apply(cx, ty, subpatterns.iter().cloned().rev()) + self.apply(cx, ty, subpatterns.iter().cloned()) } } From c8e36a266259d2b1c86cdc405e1f1c0563e150ce Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 5 May 2020 20:37:39 +0100 Subject: [PATCH 18/23] Use `Fields` everywhere relevant The idea is that `PatStack` is mostly used in the Matrix, and `Fields` is used whenever we're close to a relevant constructor. That way, we have a bunch of functions to go back and forth between a `Pat` and a `Constructor` along a `Fields`. That's a simpler mental model and better abstraction. --- src/librustc_mir_build/hair/pattern/_match.rs | 259 +++++++++--------- 1 file changed, 132 insertions(+), 127 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 13ed7d9f63c48..7553d8a76ecf3 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -444,9 +444,10 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { ctor_wild_fields: &Fields<'p, 'tcx>, ) -> Option> { let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_fields); - new_heads.map(|mut new_head| { - new_head.0.extend_from_slice(&self.0[1..]); - new_head + new_heads.map(|fields| { + let mut new_head = fields.filtered_patterns(); + new_head.extend_from_slice(&self.0[1..]); + PatStack::from_vec(new_head) }) } } @@ -897,26 +898,10 @@ impl<'tcx> Constructor<'tcx> { } } - /// This computes the arity of a constructor. The arity of a constructor - /// is how many subpattern patterns of that constructor should be expanded to. - /// - /// For instance, a tuple pattern `(_, 42, Some([]))` has the arity of 3. - /// A struct pattern's arity is the number of fields it contains, etc. - /// - /// This must be consistent with `wildcard_subpatterns`, `specialize_one_pattern`, and `apply`. - fn arity<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> u64 { - debug!("Constructor::arity({:#?}, {:?})", self, ty); - match self { - Single | Variant(_) => StructFields::ctor_arity(cx, self, ty), - Slice(slice) => slice.arity(), - ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => 0, - } - } - /// Apply a constructor to a list of patterns, yielding a new pattern. `pats` /// must have as many elements as this constructor's arity. /// - /// This must be consistent with `wildcard_subpatterns`, `specialize_one_pattern`, and `arity`. + /// This is morally the inverse of `specialize_one_pattern`. /// /// Examples: /// `self`: `Constructor::Single` @@ -928,19 +913,20 @@ impl<'tcx> Constructor<'tcx> { /// `ty`: `Option` /// `pats`: `[false]` /// returns `Some(false)` - fn apply<'a>( + fn apply<'p>( &self, - cx: &MatchCheckCtxt<'a, 'tcx>, + cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>, - pats: impl IntoIterator>, + fields: Fields<'p, 'tcx>, ) -> Pat<'tcx> { - let mut subpatterns = pats.into_iter(); + let mut subpatterns = fields.all_patterns().into_iter(); let pat = match self { Single | Variant(_) => match ty.kind { ty::Adt(..) | ty::Tuple(..) => { - let subpatterns = StructFields::from_patterns(cx, self, ty, subpatterns) - .into_fieldpats() + let subpatterns = subpatterns + .enumerate() + .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) .collect(); if let ty::Adt(adt, substs) = ty.kind { @@ -998,8 +984,7 @@ impl<'tcx> Constructor<'tcx> { /// Like `apply`, but where all the subpatterns are wildcards `_`. fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { - let subpatterns = Fields::wildcards(cx, self, ty).to_patstack(); - self.apply(cx, ty, subpatterns.iter().cloned()) + self.apply(cx, ty, Fields::wildcards(cx, self, ty)) } } @@ -1023,14 +1008,14 @@ impl<'p, 'tcx> StructField<'p, 'tcx> { StructField::Kept(wild) } - fn kept(&self) -> Option<&'p Pat<'tcx>> { + fn kept(self) -> Option<&'p Pat<'tcx>> { match self { StructField::Kept(p) => Some(p), StructField::Hidden(_) => None, } } - fn into_pattern(self) -> Pat<'tcx> { + fn to_pattern(self) -> Pat<'tcx> { match self { StructField::Kept(p) => p.clone(), StructField::Hidden(ty) => Pat::wildcard_from_ty(ty), @@ -1039,28 +1024,6 @@ impl<'p, 'tcx> StructField<'p, 'tcx> { } impl<'p, 'tcx> StructFields<'p, 'tcx> { - // Takes an already filtered list of patterns, e.g. taken from the matrix. - fn from_patterns( - cx: &MatchCheckCtxt<'p, 'tcx>, - constructor: &Constructor<'tcx>, - ty: Ty<'tcx>, - pats: impl IntoIterator>, - ) -> Self { - // There should be `arity()` patterns in there. - let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); - - let mut pats_iter = pats.iter(); - let mut fields = Self::wildcards(cx, constructor, ty); - for f in &mut fields.fields { - if let StructField::Kept(p) = f { - // We take one input pattern for each `Kept` field, in order. - let pat = pats_iter.next().unwrap(); - *p = pat; - } - } - fields - } - /// Creates a new list of wildcard fields for a given constructor. `constructor` /// must be `Variant` or `Single`. fn wildcards( @@ -1102,31 +1065,28 @@ impl<'p, 'tcx> StructFields<'p, 'tcx> { StructFields { fields, is_non_exhaustive } } - /// Calculates the number of fields of a given constructor. `constructor` must be `Variant` or - /// `Single`. - fn ctor_arity( - cx: &MatchCheckCtxt<'p, 'tcx>, - constructor: &Constructor<'tcx>, - ty: Ty<'tcx>, - ) -> u64 { - match ty.kind { - ty::Tuple(ref fs) => fs.len() as u64, - ty::Ref(..) => 1, - ty::Adt(adt, _) => { - let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; - variant - .fields - .iter() - .filter(|field| !cx.hide_uninhabited_field(ty, variant, field)) - .count() as u64 + /// Number of (filtered) patterns contained. + fn arity(&self) -> usize { + self.fields.iter().filter(|p| p.kept().is_some()).count() + } + + /// Overrides some of the fields with the provided patterns in the order provided. + fn replace_fields(&self, pats: impl IntoIterator>) -> Self { + // There should be `arity()` patterns in there. + let mut pats_iter = pats.into_iter(); + let mut fields = self.clone(); + for f in &mut fields.fields { + if let StructField::Kept(p) = f { + // We take one input pattern for each `Kept` field, in order. + let pat = pats_iter.next().unwrap(); + *p = pat; } - ty::Slice(..) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", constructor, ty), - _ => 0, } + fields } - /// Overrides some of the fields with the provided patterns. Clones the input. - fn override_fieldpatterns(&self, pats: impl IntoIterator>) -> Self { + /// Overrides some of the fields with the provided patterns. + fn replace_fields_indexed(&self, pats: impl IntoIterator>) -> Self { let mut res = self.clone(); for pat in pats { if let StructField::Kept(p) = &mut res.fields[pat.field.index()] { @@ -1136,18 +1096,14 @@ impl<'p, 'tcx> StructFields<'p, 'tcx> { res } - /// Returns a filtered list of patterns, to be stored in the matrix. - fn to_patstack(&self) -> PatStack<'p, 'tcx> { - PatStack::from_vec(self.fields.iter().filter_map(|p| p.kept()).collect()) + /// Iterate over the exhaustive list of patterns. + fn iter_all_patterns<'a>(&'a self) -> impl Iterator> + Captures<'a> { + self.fields.iter().map(|p| p.to_pattern()) } - /// Returns an exhaustive list of patterns, to be stored into the relevant `PatKind`. - fn into_fieldpats(self) -> impl Iterator> + 'p { - self.fields - .into_iter() - .map(|p| p.into_pattern()) - .enumerate() - .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) + /// Returns the filtered list of patterns, to be stored in the matrix. + fn filtered_patterns(&self) -> SmallVec<[&'p Pat<'tcx>; 2]> { + self.fields.iter().filter_map(|p| p.kept()).collect() } } @@ -1155,12 +1111,25 @@ impl<'p, 'tcx> StructFields<'p, 'tcx> { /// those fields, generalized to allow patterns in each field. #[derive(Debug, Clone)] enum Fields<'p, 'tcx> { + /// Fields of a struct, with special handling of uninhabited types. Struct(StructFields<'p, 'tcx>), - WildcardSlice { arity: u64, wild: &'p Pat<'tcx> }, - Empty, + /// Non-struct list of patterns + Other(SmallVec<[&'p Pat<'tcx>; 2]>), + /// Optimization for slices + WildcardSlice { arity: usize, wild: &'p Pat<'tcx> }, } impl<'p, 'tcx> Fields<'p, 'tcx> { + fn empty() -> Self { + Fields::Other(smallvec![]) + } + + /// Construct a new `Fields` from the given patterns. Must not be used if the patterns are + /// fields of a struct/tuple/variant. + fn from_patterns_not_struct(pats: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self { + Fields::Other(pats) + } + /// Creates a new list of wildcard fields for a given constructor. fn wildcards( cx: &MatchCheckCtxt<'p, 'tcx>, @@ -1174,12 +1143,40 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { Slice(slice) => match ty.kind { ty::Slice(ty) | ty::Array(ty, _) => { let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); - let arity = slice.arity(); + let arity = slice.arity() as usize; Fields::WildcardSlice { arity, wild } } _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), }, - ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => Fields::Empty, + ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => Fields::empty(), + } + } + + /// Overrides some of the fields with the provided patterns. Panics if `self` is not `Struct`. + fn replace_fields_indexed(&self, pats: impl IntoIterator>) -> Self { + Fields::Struct(self.as_structfields().unwrap().replace_fields_indexed(pats)) + } + + /// Replaces contained fields with the given filtered list of patterns, e.g. taken from the + /// matrix. + fn replace_fields( + &self, + cx: &MatchCheckCtxt<'p, 'tcx>, + pats: impl IntoIterator>, + ) -> Self { + let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); + match self { + Fields::Struct(sf) => Fields::Struct(sf.replace_fields(pats)), + _ => Fields::Other(pats.iter().collect()), + } + } + + /// Number of (filtered) patterns contained. + fn arity(&self) -> usize { + match self { + Fields::Struct(sf) => sf.arity(), + Fields::Other(pats) => pats.len(), + &Fields::WildcardSlice { arity, .. } => arity, } } @@ -1190,11 +1187,21 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { } } - fn to_patstack(&self) -> PatStack<'p, 'tcx> { + /// Returns the exhaustive list of patterns. + fn all_patterns(&self) -> SmallVec<[Pat<'tcx>; 2]> { + match self { + Fields::Struct(sf) => sf.iter_all_patterns().collect(), + Fields::Other(pats) => pats.iter().copied().cloned().collect(), + &Fields::WildcardSlice { arity, wild } => (0..arity).map(|_| wild).cloned().collect(), + } + } + + /// Returns the filtered list of patterns, to be stored in the matrix. + fn filtered_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> { match self { - Fields::Struct(sf) => sf.to_patstack(), - &Fields::WildcardSlice { arity, wild } => (0..arity).map(|_| wild).collect(), - Fields::Empty => PatStack::default(), + Fields::Struct(sf) => sf.filtered_patterns(), + Fields::Other(pats) => pats, + Fields::WildcardSlice { arity, wild } => (0..arity).map(|_| wild).collect(), } } } @@ -1225,15 +1232,16 @@ impl<'tcx, 'p> Usefulness<'tcx, 'p> { fn apply_constructor( self, - cx: &MatchCheckCtxt<'_, 'tcx>, + cx: &MatchCheckCtxt<'p, 'tcx>, ctor: &Constructor<'tcx>, ty: Ty<'tcx>, + ctor_wild_fields: &Fields<'p, 'tcx>, ) -> Self { match self { UsefulWithWitness(witnesses) => UsefulWithWitness( witnesses .into_iter() - .map(|witness| witness.apply_constructor(cx, &ctor, ty)) + .map(|witness| witness.apply_constructor(cx, &ctor, ty, ctor_wild_fields)) .collect(), ), x => x, @@ -1353,17 +1361,19 @@ impl<'tcx> Witness<'tcx> { /// /// left_ty: struct X { a: (bool, &'static str), b: usize} /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } - fn apply_constructor<'a>( + fn apply_constructor<'p>( mut self, - cx: &MatchCheckCtxt<'a, 'tcx>, + cx: &MatchCheckCtxt<'p, 'tcx>, ctor: &Constructor<'tcx>, ty: Ty<'tcx>, + ctor_wild_fields: &Fields<'p, 'tcx>, ) -> Self { - let arity = ctor.arity(cx, ty); let pat = { - let len = self.0.len() as u64; - let pats = self.0.drain((len - arity) as usize..).rev(); - ctor.apply(cx, ty, pats) + let len = self.0.len(); + let arity = ctor_wild_fields.arity(); + let pats = self.0.drain((len - arity)..).rev(); + let fields = ctor_wild_fields.replace_fields(cx, pats); + ctor.apply(cx, ty, fields) }; self.0.push(pat); @@ -2000,7 +2010,7 @@ fn is_useful_specialized<'p, 'tcx>( let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_fields); v.specialize_constructor(cx, &ctor, &ctor_wild_fields) .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)) - .map(|u| u.apply_constructor(cx, &ctor, ty)) + .map(|u| u.apply_constructor(cx, &ctor, ty, &ctor_wild_fields)) .unwrap_or(NotUseful) } @@ -2473,49 +2483,43 @@ fn constructor_covered_by_range<'tcx>( /// different patterns. /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing /// fields filled with wild patterns. +/// +/// This is morally the inverse of `Constructor::apply`. fn specialize_one_pattern<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>, constructor: &Constructor<'tcx>, ctor_wild_fields: &Fields<'p, 'tcx>, -) -> Option> { +) -> Option> { if let NonExhaustive = constructor { // Only a wildcard pattern can match the special extra constructor - return if pat.is_wildcard() { Some(PatStack::default()) } else { None }; + return if pat.is_wildcard() { Some(Fields::empty()) } else { None }; } let result = match *pat.kind { PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` - PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_fields.to_patstack()), + PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_fields.clone()), PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let pat_ctor = Variant(adt_def.variants[variant_index].def_id); if constructor == &pat_ctor { - Some( - ctor_wild_fields - .as_structfields() - .unwrap() - .override_fieldpatterns(subpatterns) - .to_patstack(), - ) + Some(ctor_wild_fields.replace_fields_indexed(subpatterns)) } else { None } } - PatKind::Leaf { ref subpatterns } => Some( - ctor_wild_fields - .as_structfields() - .unwrap() - .override_fieldpatterns(subpatterns) - .to_patstack(), - ), + PatKind::Leaf { ref subpatterns } => { + Some(ctor_wild_fields.replace_fields_indexed(subpatterns)) + } - PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)), + PatKind::Deref { ref subpattern } => { + Some(Fields::from_patterns_not_struct(smallvec![subpattern])) + } PatKind::Constant { value } if constructor.is_slice() => { - let arity = constructor.arity(cx, pat.ty); + let arity = ctor_wild_fields.arity() as u64; // We extract an `Option` for the pointer because slices of zero // elements don't necessarily point to memory, they are usually @@ -2528,7 +2532,7 @@ fn specialize_one_pattern<'p, 'tcx>( // the result would be exactly what we early return here. if n == 0 { if arity == 0 { - return Some(PatStack::from_slice(&[])); + return Some(Fields::empty()); } else { return None; } @@ -2579,7 +2583,8 @@ fn specialize_one_pattern<'p, 'tcx>( Pat { ty, span: pat.span, kind: box PatKind::Constant { value } }; Some(&*cx.pattern_arena.alloc(pattern)) }) - .collect() + .collect::>() + .map(Fields::from_patterns_not_struct) } else { None } @@ -2595,7 +2600,7 @@ fn specialize_one_pattern<'p, 'tcx>( // Constructor splitting should ensure that all intersections we encounter // are actually inclusions. assert!(ctor.is_subrange(&pat)); - PatStack::default() + Fields::empty() }), _ => None, } @@ -2606,7 +2611,7 @@ fn specialize_one_pattern<'p, 'tcx>( // range so intersection actually devolves into being covered // by the pattern. constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat) - .map(|()| PatStack::default()) + .map(|()| Fields::empty()) } } @@ -2614,19 +2619,19 @@ fn specialize_one_pattern<'p, 'tcx>( | PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor { Slice(_) => { let (arity, wild_pat) = match *ctor_wild_fields { - Fields::WildcardSlice { arity, wild } => (arity as usize, wild), + Fields::WildcardSlice { arity, wild } => (arity, wild), _ => bug!("bad slice pattern {:?} {:?}", ctor_wild_fields, pat.ty), }; let pat_len = prefix.len() + suffix.len(); if let Some(slice_count) = arity.checked_sub(pat_len) { if slice_count == 0 || slice.is_some() { - Some( + Some(Fields::from_patterns_not_struct( prefix .iter() .chain((0..slice_count).map(|_| wild_pat)) .chain(suffix.iter()) .collect(), - ) + )) } else { None } @@ -2644,7 +2649,7 @@ fn specialize_one_pattern<'p, 'tcx>( suffix, cx.param_env, ) { - Ok(true) => Some(PatStack::default()), + Ok(true) => Some(Fields::empty()), Ok(false) => None, Err(ErrorReported) => None, } From 9d9d3c9b8db1753a74decd3d696ce0adde05d32d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 5 May 2020 21:02:01 +0100 Subject: [PATCH 19/23] We don't use TyErr anymore --- src/librustc_mir_build/hair/pattern/_match.rs | 37 ++----------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 7553d8a76ecf3..7c870f69e07d8 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -242,7 +242,7 @@ use rustc_hir::{HirId, RangeEnd}; use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Const, FieldDef, Ty, TyCtxt, TypeFoldable, VariantDef}; +use rustc_middle::ty::{self, Const, FieldDef, Ty, TyCtxt, VariantDef}; use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; @@ -1771,11 +1771,7 @@ impl<'tcx> fmt::Debug for MissingConstructors<'tcx> { /// to a set of such vectors `m` - this is defined as there being a set of /// inputs that will match `v` but not any of the sets in `m`. /// -/// All the patterns at each column of the `matrix ++ v` matrix must -/// have the same type, except that wildcard (PatKind::Wild) patterns -/// with type `TyErr` are also allowed, even if the "type of the column" -/// is not `TyErr`. That is used to represent private fields, as using their -/// real type would assert that they are inhabited. +/// All the patterns at each column of the `matrix ++ v` matrix must have the same type. /// /// This is used both for reachability checking (if a pattern isn't useful in /// relation to preceding patterns, it is not reachable) and exhaustiveness @@ -1839,34 +1835,7 @@ crate fn is_useful<'p, 'tcx>( return if any_is_useful { Useful(unreachable_pats) } else { NotUseful }; } - let (ty, span) = matrix - .heads() - .map(|r| (r.ty, r.span)) - .find(|(ty, _)| !ty.references_error()) - .unwrap_or((v.head().ty, v.head().span)); - let pcx = PatCtxt { - // TyErr is used to represent the type of wildcard patterns matching - // against inaccessible (private) fields of structs, so that we won't - // be able to observe whether the types of the struct's fields are - // inhabited. - // - // If the field is truly inaccessible, then all the patterns - // matching against it must be wildcard patterns, so its type - // does not matter. - // - // However, if we are matching against non-wildcard patterns, we - // need to know the real type of the field so we can specialize - // against it. This primarily occurs through constants - they - // can include contents for fields that are inaccessible at the - // location of the match. In that case, the field's type is - // inhabited - by the constant - so we can just use it. - // - // FIXME: this might lead to "unstable" behavior with macro hygiene - // introducing uninhabited patterns for inaccessible fields. We - // need to figure out how to model that. - ty, - span, - }; + let pcx = PatCtxt { ty: v.head().ty, span: v.head().span }; debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head()); From af175e001094af61ff7e4045dddc96a05ad2cb12 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 5 May 2020 21:20:59 +0100 Subject: [PATCH 20/23] Document Fields a bit --- src/librustc_mir_build/hair/pattern/_match.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 7c870f69e07d8..caa24e5dba3ac 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -755,6 +755,13 @@ impl Slice { } } +/// A value can be decomposed into a constructor applied to some fields. This struct represents +/// the constructor. See also `Fields`. +/// +/// `pat_constructor` retrieves the constructor corresponding to a pattern. +/// `specialize_one_pattern` returns the list of fields corresponding to a pattern, given a +/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and +/// `Fields`. #[derive(Clone, Debug, PartialEq)] enum Constructor<'tcx> { /// The constructor for patterns that have a single constructor, like tuples, struct patterns @@ -1107,8 +1114,14 @@ impl<'p, 'tcx> StructFields<'p, 'tcx> { } } -/// A value can be decomposed into a Constructor applied to some Fields. This struct represents -/// those fields, generalized to allow patterns in each field. +/// A value can be decomposed into a constructor applied to some fields. This struct represents +/// those fields, generalized to allow patterns in each field. See also `Constructor`. +/// +/// In some special cases of uninhabited types, we filter out those fields in the matrix so that +/// the code can't observe they are uninhabited. But we do need to handle the full list of fields +/// when going to/from a `Pat`, hence the distinction between filtered and unfiltered fields. As a +/// rule, when going to/from the matrix, use the filtered fields; when going to/from `Pat`, use the +/// full fields. #[derive(Debug, Clone)] enum Fields<'p, 'tcx> { /// Fields of a struct, with special handling of uninhabited types. From f95cbacbc561f8872555f9c9ea770267dd58f25b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 5 May 2020 21:41:41 +0100 Subject: [PATCH 21/23] Inline cx methods used only once --- src/librustc_mir_build/hair/pattern/_match.rs | 63 ++++--------------- 1 file changed, 12 insertions(+), 51 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index caa24e5dba3ac..70523dfb4cb64 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -242,7 +242,7 @@ use rustc_hir::{HirId, RangeEnd}; use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Const, FieldDef, Ty, TyCtxt, VariantDef}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; @@ -614,36 +614,6 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { _ => false, } } - - /// Returns whether the given variant is from another crate and has its fields declared - /// `#[non_exhaustive]`. - fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool { - match ty.kind { - ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(), - _ => false, - } - } - - /// In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide - /// uninhabited fields in order not to reveal the uninhabitedness of the whole variant. - fn hide_uninhabited_field( - &self, - adt_ty: Ty<'tcx>, - variant: &VariantDef, - field: &FieldDef, - ) -> bool { - match adt_ty.kind { - ty::Adt(adt, substs) => { - let is_non_exhaustive = self.is_foreign_non_exhaustive_variant(adt_ty, variant); - let field_ty = field.ty(self.tcx, substs); - let is_visible = - adt.is_enum() || field.vis.is_accessible_from(self.module, self.tcx); - let is_uninhabited = self.is_uninhabited(field_ty); - is_uninhabited && (!is_visible || is_non_exhaustive) - } - _ => false, - } - } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -789,21 +759,6 @@ impl<'tcx> Constructor<'tcx> { } } - /// Returns whether the fields of this constructor should be treated as `non_exhaustive`. - fn is_field_list_non_exhaustive<'a>( - &self, - cx: &MatchCheckCtxt<'a, 'tcx>, - ty: Ty<'tcx>, - ) -> bool { - match ty.kind { - ty::Adt(adt, _) => { - let variant = &adt.variants[self.variant_index_for_adt(cx, adt)]; - cx.is_foreign_non_exhaustive_variant(ty, variant) - } - _ => false, - } - } - fn variant_index_for_adt<'a>( &self, cx: &MatchCheckCtxt<'a, 'tcx>, @@ -1000,7 +955,6 @@ impl<'tcx> Constructor<'tcx> { #[derive(Debug, Clone)] struct StructFields<'p, 'tcx> { fields: SmallVec<[StructField<'p, 'tcx>; 2]>, - is_non_exhaustive: bool, } #[derive(Debug, Copy, Clone)] @@ -1051,13 +1005,21 @@ impl<'p, 'tcx> StructFields<'p, 'tcx> { smallvec![StructField::wildcard_from_ty(cx, substs.type_at(0))] } else { let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; + // Whether we must not match the fields of this variant exhaustively. + let is_non_exhaustive = + variant.is_field_list_non_exhaustive() && !adt.did.is_local(); variant .fields .iter() .map(|field| { let field_ty = field.ty(cx.tcx, substs); - // Filter out hidden fields so we don't know they are uninhabited. - if cx.hide_uninhabited_field(ty, variant, field) { + let is_visible = + adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(field_ty); + + // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide + // uninhabited fields in order not to reveal the uninhabitedness of the whole variant. + if is_uninhabited && (!is_visible || is_non_exhaustive) { StructField::Hidden(field_ty) } else { StructField::wildcard_from_ty(cx, field_ty) @@ -1068,8 +1030,7 @@ impl<'p, 'tcx> StructFields<'p, 'tcx> { } _ => smallvec![], }; - let is_non_exhaustive = constructor.is_field_list_non_exhaustive(cx, ty); - StructFields { fields, is_non_exhaustive } + StructFields { fields } } /// Number of (filtered) patterns contained. From b12aab55a986648c6a138d63595435ca3f518cfa Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 5 May 2020 21:55:26 +0100 Subject: [PATCH 22/23] Inline StructFields into Fields --- src/librustc_mir_build/hair/pattern/_match.rs | 185 +++++++----------- 1 file changed, 70 insertions(+), 115 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 70523dfb4cb64..4f93e1d5133d0 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -950,13 +950,6 @@ impl<'tcx> Constructor<'tcx> { } } -/// The fields of a struct, a tuple, or an enum variant. This hides away fields whose -/// uninhabitedness should not be visible to the user. -#[derive(Debug, Clone)] -struct StructFields<'p, 'tcx> { - fields: SmallVec<[StructField<'p, 'tcx>; 2]>, -} - #[derive(Debug, Copy, Clone)] enum StructField<'p, 'tcx> { Kept(&'p Pat<'tcx>), @@ -984,97 +977,6 @@ impl<'p, 'tcx> StructField<'p, 'tcx> { } } -impl<'p, 'tcx> StructFields<'p, 'tcx> { - /// Creates a new list of wildcard fields for a given constructor. `constructor` - /// must be `Variant` or `Single`. - fn wildcards( - cx: &MatchCheckCtxt<'p, 'tcx>, - constructor: &Constructor<'tcx>, - ty: Ty<'tcx>, - ) -> Self { - let fields = match ty.kind { - ty::Tuple(ref fs) => fs - .into_iter() - .map(|t| t.expect_ty()) - .map(|ty| StructField::wildcard_from_ty(cx, ty)) - .collect(), - ty::Ref(_, rty, _) => smallvec![StructField::wildcard_from_ty(cx, rty)], - ty::Adt(adt, substs) => { - if adt.is_box() { - // Use T as the sub pattern type of Box. - smallvec![StructField::wildcard_from_ty(cx, substs.type_at(0))] - } else { - let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; - // Whether we must not match the fields of this variant exhaustively. - let is_non_exhaustive = - variant.is_field_list_non_exhaustive() && !adt.did.is_local(); - variant - .fields - .iter() - .map(|field| { - let field_ty = field.ty(cx.tcx, substs); - let is_visible = - adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(field_ty); - - // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide - // uninhabited fields in order not to reveal the uninhabitedness of the whole variant. - if is_uninhabited && (!is_visible || is_non_exhaustive) { - StructField::Hidden(field_ty) - } else { - StructField::wildcard_from_ty(cx, field_ty) - } - }) - .collect() - } - } - _ => smallvec![], - }; - StructFields { fields } - } - - /// Number of (filtered) patterns contained. - fn arity(&self) -> usize { - self.fields.iter().filter(|p| p.kept().is_some()).count() - } - - /// Overrides some of the fields with the provided patterns in the order provided. - fn replace_fields(&self, pats: impl IntoIterator>) -> Self { - // There should be `arity()` patterns in there. - let mut pats_iter = pats.into_iter(); - let mut fields = self.clone(); - for f in &mut fields.fields { - if let StructField::Kept(p) = f { - // We take one input pattern for each `Kept` field, in order. - let pat = pats_iter.next().unwrap(); - *p = pat; - } - } - fields - } - - /// Overrides some of the fields with the provided patterns. - fn replace_fields_indexed(&self, pats: impl IntoIterator>) -> Self { - let mut res = self.clone(); - for pat in pats { - if let StructField::Kept(p) = &mut res.fields[pat.field.index()] { - *p = &pat.pattern - } - } - res - } - - /// Iterate over the exhaustive list of patterns. - fn iter_all_patterns<'a>(&'a self) -> impl Iterator> + Captures<'a> { - self.fields.iter().map(|p| p.to_pattern()) - } - - /// Returns the filtered list of patterns, to be stored in the matrix. - fn filtered_patterns(&self) -> SmallVec<[&'p Pat<'tcx>; 2]> { - self.fields.iter().filter_map(|p| p.kept()).collect() - } -} - /// A value can be decomposed into a constructor applied to some fields. This struct represents /// those fields, generalized to allow patterns in each field. See also `Constructor`. /// @@ -1085,11 +987,11 @@ impl<'p, 'tcx> StructFields<'p, 'tcx> { /// full fields. #[derive(Debug, Clone)] enum Fields<'p, 'tcx> { - /// Fields of a struct, with special handling of uninhabited types. - Struct(StructFields<'p, 'tcx>), + /// Fields of a struct/tuple/variant, with special handling of uninhabited types. + Struct(SmallVec<[StructField<'p, 'tcx>; 2]>), /// Non-struct list of patterns Other(SmallVec<[&'p Pat<'tcx>; 2]>), - /// Optimization for slices + /// Optimization for slices of wildcards WildcardSlice { arity: usize, wild: &'p Pat<'tcx> }, } @@ -1113,7 +1015,44 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { debug!("Fields::wildcards({:#?}, {:?})", constructor, ty); match constructor { - Single | Variant(_) => Fields::Struct(StructFields::wildcards(cx, constructor, ty)), + Single | Variant(_) => Fields::Struct(match ty.kind { + ty::Tuple(ref fs) => fs + .into_iter() + .map(|t| t.expect_ty()) + .map(|ty| StructField::wildcard_from_ty(cx, ty)) + .collect(), + ty::Ref(_, rty, _) => smallvec![StructField::wildcard_from_ty(cx, rty)], + ty::Adt(adt, substs) => { + if adt.is_box() { + // Use T as the sub pattern type of Box. + smallvec![StructField::wildcard_from_ty(cx, substs.type_at(0))] + } else { + let variant = &adt.variants[constructor.variant_index_for_adt(cx, adt)]; + // Whether we must not match the fields of this variant exhaustively. + let is_non_exhaustive = + variant.is_field_list_non_exhaustive() && !adt.did.is_local(); + variant + .fields + .iter() + .map(|field| { + let field_ty = field.ty(cx.tcx, substs); + let is_visible = adt.is_enum() + || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(field_ty); + + // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide + // uninhabited fields in order not to reveal the uninhabitedness of the whole variant. + if is_uninhabited && (!is_visible || is_non_exhaustive) { + StructField::Hidden(field_ty) + } else { + StructField::wildcard_from_ty(cx, field_ty) + } + }) + .collect() + } + } + _ => smallvec![], + }), Slice(slice) => match ty.kind { ty::Slice(ty) | ty::Array(ty, _) => { let wild = &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); @@ -1128,7 +1067,18 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { /// Overrides some of the fields with the provided patterns. Panics if `self` is not `Struct`. fn replace_fields_indexed(&self, pats: impl IntoIterator>) -> Self { - Fields::Struct(self.as_structfields().unwrap().replace_fields_indexed(pats)) + match self { + Fields::Struct(fields) => { + let mut fields = fields.clone(); + for pat in pats { + if let StructField::Kept(p) = &mut fields[pat.field.index()] { + *p = &pat.pattern + } + } + Fields::Struct(fields) + } + _ => bug!("`replace_fields_indexed` called on the wrong kind of `Fields`"), + } } /// Replaces contained fields with the given filtered list of patterns, e.g. taken from the @@ -1138,33 +1088,38 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { cx: &MatchCheckCtxt<'p, 'tcx>, pats: impl IntoIterator>, ) -> Self { + // There should be `arity()` patterns in there. let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); + let mut pats = pats.iter(); + match self { - Fields::Struct(sf) => Fields::Struct(sf.replace_fields(pats)), - _ => Fields::Other(pats.iter().collect()), + Fields::Struct(fields) => { + let mut fields = fields.clone(); + for f in &mut fields { + if let StructField::Kept(p) = f { + // We take one input pattern for each `Kept` field, in order. + *p = pats.next().unwrap(); + } + } + Fields::Struct(fields) + } + _ => Fields::Other(pats.collect()), } } /// Number of (filtered) patterns contained. fn arity(&self) -> usize { match self { - Fields::Struct(sf) => sf.arity(), + Fields::Struct(fields) => fields.iter().filter(|p| p.kept().is_some()).count(), Fields::Other(pats) => pats.len(), &Fields::WildcardSlice { arity, .. } => arity, } } - fn as_structfields(&self) -> Option<&StructFields<'p, 'tcx>> { - match self { - Fields::Struct(sf) => Some(sf), - _ => None, - } - } - /// Returns the exhaustive list of patterns. fn all_patterns(&self) -> SmallVec<[Pat<'tcx>; 2]> { match self { - Fields::Struct(sf) => sf.iter_all_patterns().collect(), + Fields::Struct(fields) => fields.iter().map(|p| p.to_pattern()).collect(), Fields::Other(pats) => pats.iter().copied().cloned().collect(), &Fields::WildcardSlice { arity, wild } => (0..arity).map(|_| wild).cloned().collect(), } @@ -1173,7 +1128,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { /// Returns the filtered list of patterns, to be stored in the matrix. fn filtered_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> { match self { - Fields::Struct(sf) => sf.filtered_patterns(), + Fields::Struct(fields) => fields.into_iter().filter_map(|p| p.kept()).collect(), Fields::Other(pats) => pats, Fields::WildcardSlice { arity, wild } => (0..arity).map(|_| wild).collect(), } From c67da3071c72c74554288e4a07763ad86050a78e Mon Sep 17 00:00:00 2001 From: mark Date: Wed, 6 May 2020 09:35:36 -0500 Subject: [PATCH 23/23] Revert "We don't use TyErr anymore" This reverts commit 9d9d3c9b8db1753a74decd3d696ce0adde05d32d. --- src/librustc_mir_build/hair/pattern/_match.rs | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 4f93e1d5133d0..ec44e3d193a19 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -242,7 +242,7 @@ use rustc_hir::{HirId, RangeEnd}; use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; @@ -1700,7 +1700,11 @@ impl<'tcx> fmt::Debug for MissingConstructors<'tcx> { /// to a set of such vectors `m` - this is defined as there being a set of /// inputs that will match `v` but not any of the sets in `m`. /// -/// All the patterns at each column of the `matrix ++ v` matrix must have the same type. +/// All the patterns at each column of the `matrix ++ v` matrix must +/// have the same type, except that wildcard (PatKind::Wild) patterns +/// with type `TyErr` are also allowed, even if the "type of the column" +/// is not `TyErr`. That is used to represent private fields, as using their +/// real type would assert that they are inhabited. /// /// This is used both for reachability checking (if a pattern isn't useful in /// relation to preceding patterns, it is not reachable) and exhaustiveness @@ -1764,7 +1768,34 @@ crate fn is_useful<'p, 'tcx>( return if any_is_useful { Useful(unreachable_pats) } else { NotUseful }; } - let pcx = PatCtxt { ty: v.head().ty, span: v.head().span }; + let (ty, span) = matrix + .heads() + .map(|r| (r.ty, r.span)) + .find(|(ty, _)| !ty.references_error()) + .unwrap_or((v.head().ty, v.head().span)); + let pcx = PatCtxt { + // TyErr is used to represent the type of wildcard patterns matching + // against inaccessible (private) fields of structs, so that we won't + // be able to observe whether the types of the struct's fields are + // inhabited. + // + // If the field is truly inaccessible, then all the patterns + // matching against it must be wildcard patterns, so its type + // does not matter. + // + // However, if we are matching against non-wildcard patterns, we + // need to know the real type of the field so we can specialize + // against it. This primarily occurs through constants - they + // can include contents for fields that are inaccessible at the + // location of the match. In that case, the field's type is + // inhabited - by the constant - so we can just use it. + // + // FIXME: this might lead to "unstable" behavior with macro hygiene + // introducing uninhabited patterns for inaccessible fields. We + // need to figure out how to model that. + ty, + span, + }; debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());