summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/thir
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/block.rs18
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs79
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs114
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs149
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs101
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs67
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs135
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs47
9 files changed, 455 insertions, 257 deletions
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index a7e4403a2..f626571b5 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -44,7 +44,7 @@ pub(crate) fn lit_to_const<'tcx>(
}
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
- (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
+ (ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
_ => return Err(LitToConstError::TypeError),
};
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index dccaa61ed..321353ca2 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -9,13 +9,13 @@ use rustc_index::vec::Idx;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
impl<'tcx> Cx<'tcx> {
- pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block {
+ pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> BlockId {
// We have to eagerly lower the "spine" of the statements
// in order to get the lexical scoping correctly.
let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts);
let opt_destruction_scope =
self.region_scope_tree.opt_destruction_scope(block.hir_id.local_id);
- Block {
+ let block = Block {
targeted_by_break: block.targeted_by_break,
region_scope: region::Scope {
id: block.hir_id.local_id,
@@ -34,7 +34,9 @@ impl<'tcx> Cx<'tcx> {
BlockSafety::ExplicitUnsafe(block.hir_id)
}
},
- }
+ };
+
+ self.thir.blocks.push(block)
}
fn mirror_stmts(
@@ -85,21 +87,21 @@ impl<'tcx> Cx<'tcx> {
{
debug!("mirror_stmts: user_ty={:?}", user_ty);
let annotation = CanonicalUserTypeAnnotation {
- user_ty,
+ user_ty: Box::new(user_ty),
span: ty.span,
inferred_ty: self.typeck_results.node_type(ty.hir_id),
};
- pattern = Pat {
+ pattern = Box::new(Pat {
ty: pattern.ty,
span: pattern.span,
- kind: Box::new(PatKind::AscribeUserType {
+ kind: PatKind::AscribeUserType {
ascription: Ascription {
annotation,
variance: ty::Variance::Covariant,
},
subpattern: pattern,
- }),
- };
+ },
+ });
}
}
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 985601712..c7a7c3e3f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -48,6 +48,8 @@ impl<'tcx> Cx<'tcx> {
_ => None,
};
+ trace!(?expr.ty);
+
// Now apply adjustments, if any.
for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
trace!(?expr, ?adjustment);
@@ -56,6 +58,8 @@ impl<'tcx> Cx<'tcx> {
self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
}
+ trace!(?expr.ty, "after adjustments");
+
// Next, wrap this up in the expr's scope.
expr = Expr {
temp_lifetime,
@@ -108,8 +112,8 @@ impl<'tcx> Cx<'tcx> {
// // ^ error message points at this expression.
// }
let mut adjust_span = |expr: &mut Expr<'tcx>| {
- if let ExprKind::Block { body } = &expr.kind {
- if let Some(last_expr) = body.expr {
+ if let ExprKind::Block { block } = expr.kind {
+ if let Some(last_expr) = self.thir[block].expr {
span = self.thir[last_expr].span;
expr.span = span;
}
@@ -155,6 +159,7 @@ impl<'tcx> Cx<'tcx> {
Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) }
}
+ Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
};
Expr { temp_lifetime, ty: adjustment.target, span, kind }
@@ -261,15 +266,19 @@ impl<'tcx> Cx<'tcx> {
let kind = match expr.kind {
// Here comes the interesting stuff:
- hir::ExprKind::MethodCall(segment, ref args, fn_span) => {
+ hir::ExprKind::MethodCall(segment, receiver, ref args, fn_span) => {
// Rewrite a.b(c) into UFCS form like Trait::b(a, c)
let expr = self.method_callee(expr, segment.ident.span, None);
// When we apply adjustments to the receiver, use the span of
// the overall method call for better diagnostics. args[0]
// is guaranteed to exist, since a method call always has a receiver.
- let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span));
- tracing::info!("Using method span: {:?}", expr.span);
- let args = self.mirror_exprs(args);
+ let old_adjustment_span =
+ self.adjustment_span.replace((receiver.hir_id, expr_span));
+ info!("Using method span: {:?}", expr.span);
+ let args = std::iter::once(receiver)
+ .chain(args.iter())
+ .map(|expr| self.mirror_expr(expr))
+ .collect();
self.adjustment_span = old_adjustment_span;
ExprKind::Call {
ty: expr.ty,
@@ -329,7 +338,7 @@ impl<'tcx> Cx<'tcx> {
if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value {
*did = adt_def.did();
}
- u_ty
+ Box::new(u_ty)
});
debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
@@ -341,7 +350,7 @@ impl<'tcx> Cx<'tcx> {
expr: self.mirror_expr(e),
})
.collect();
- ExprKind::Adt(Box::new(Adt {
+ ExprKind::Adt(Box::new(AdtExpr {
adt_def,
substs,
variant_index: index,
@@ -369,7 +378,7 @@ impl<'tcx> Cx<'tcx> {
ExprKind::AddressOf { mutability, arg: self.mirror_expr(arg) }
}
- hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: self.mirror_block(blk) },
+ hir::ExprKind::Block(ref blk, _) => ExprKind::Block { block: self.mirror_block(blk) },
hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) }
@@ -464,9 +473,9 @@ impl<'tcx> Cx<'tcx> {
ty::Adt(adt, substs) => match adt.adt_kind() {
AdtKind::Struct | AdtKind::Union => {
let user_provided_types = self.typeck_results().user_provided_types();
- let user_ty = user_provided_types.get(expr.hir_id).copied();
+ let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new);
debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
- ExprKind::Adt(Box::new(Adt {
+ ExprKind::Adt(Box::new(AdtExpr {
adt_def: *adt,
variant_index: VariantIdx::new(0),
substs,
@@ -490,9 +499,10 @@ impl<'tcx> Cx<'tcx> {
let index = adt.variant_index_with_id(variant_id);
let user_provided_types =
self.typeck_results().user_provided_types();
- let user_ty = user_provided_types.get(expr.hir_id).copied();
+ let user_ty =
+ user_provided_types.get(expr.hir_id).copied().map(Box::new);
debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
- ExprKind::Adt(Box::new(Adt {
+ ExprKind::Adt(Box::new(AdtExpr {
adt_def: *adt,
variant_index: index,
substs,
@@ -547,7 +557,13 @@ impl<'tcx> Cx<'tcx> {
None => Vec::new(),
};
- ExprKind::Closure { closure_id: def_id, substs, upvars, movability, fake_reads }
+ ExprKind::Closure(Box::new(ClosureExpr {
+ closure_id: def_id,
+ substs,
+ upvars,
+ movability,
+ fake_reads,
+ }))
}
hir::ExprKind::Path(ref qpath) => {
@@ -555,7 +571,7 @@ impl<'tcx> Cx<'tcx> {
self.convert_path_expr(expr, res)
}
- hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm {
+ hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm(Box::new(InlineAsmExpr {
template: asm.template,
operands: asm
.operands
@@ -614,7 +630,7 @@ impl<'tcx> Cx<'tcx> {
.collect(),
options: asm.options,
line_spans: asm.line_spans,
- },
+ })),
hir::ExprKind::ConstBlock(ref anon_const) => {
let ty = self.typeck_results().node_type(anon_const.hir_id);
@@ -679,8 +695,8 @@ impl<'tcx> Cx<'tcx> {
let body = self.thir.exprs.push(Expr {
ty: block_ty,
temp_lifetime,
- span: block.span,
- kind: ExprKind::Block { body: block },
+ span: self.thir[block].span,
+ kind: ExprKind::Block { block },
});
ExprKind::Loop { body }
}
@@ -712,14 +728,17 @@ impl<'tcx> Cx<'tcx> {
});
debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
- ExprKind::ValueTypeAscription { source: cast_expr, user_ty: Some(*user_ty) }
+ ExprKind::ValueTypeAscription {
+ source: cast_expr,
+ user_ty: Some(Box::new(*user_ty)),
+ }
} else {
cast
}
}
hir::ExprKind::Type(ref source, ref ty) => {
let user_provided_types = self.typeck_results.user_provided_types();
- let user_ty = user_provided_types.get(ty.hir_id).copied();
+ let user_ty = user_provided_types.get(ty.hir_id).copied().map(Box::new);
debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
let mirrored = self.mirror_expr(source);
if source.is_syntactic_place_expr() {
@@ -748,7 +767,7 @@ impl<'tcx> Cx<'tcx> {
&mut self,
hir_id: hir::HirId,
res: Res,
- ) -> Option<ty::CanonicalUserType<'tcx>> {
+ ) -> Option<Box<ty::CanonicalUserType<'tcx>>> {
debug!("user_substs_applied_to_res: res={:?}", res);
let user_provided_type = match res {
// A reference to something callable -- e.g., a fn, method, or
@@ -759,7 +778,7 @@ impl<'tcx> Cx<'tcx> {
| Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
| Res::Def(DefKind::Const, _)
| Res::Def(DefKind::AssocConst, _) => {
- self.typeck_results().user_provided_types().get(hir_id).copied()
+ self.typeck_results().user_provided_types().get(hir_id).copied().map(Box::new)
}
// A unit struct/variant which is used as a value (e.g.,
@@ -767,11 +786,11 @@ impl<'tcx> Cx<'tcx> {
// this variant -- but with the substitutions given by the
// user.
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => {
- self.user_substs_applied_to_ty_of_hir_id(hir_id)
+ self.user_substs_applied_to_ty_of_hir_id(hir_id).map(Box::new)
}
// `Self` is used in expression as a tuple struct constructor or a unit struct constructor
- Res::SelfCtor(_) => self.user_substs_applied_to_ty_of_hir_id(hir_id),
+ Res::SelfCtor(_) => self.user_substs_applied_to_ty_of_hir_id(hir_id).map(Box::new),
_ => bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id),
};
@@ -846,22 +865,22 @@ impl<'tcx> Cx<'tcx> {
Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
let user_ty = self.user_substs_applied_to_res(expr.hir_id, res);
- ExprKind::NamedConst { def_id, substs, user_ty: user_ty }
+ ExprKind::NamedConst { def_id, substs, user_ty }
}
Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => {
let user_provided_types = self.typeck_results.user_provided_types();
- let user_provided_type = user_provided_types.get(expr.hir_id).copied();
- debug!("convert_path_expr: user_provided_type={:?}", user_provided_type);
+ let user_ty = user_provided_types.get(expr.hir_id).copied().map(Box::new);
+ debug!("convert_path_expr: user_ty={:?}", user_ty);
let ty = self.typeck_results().node_type(expr.hir_id);
match ty.kind() {
// A unit struct/variant which is used as a value.
// We return a completely different ExprKind here to account for this special case.
- ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(Adt {
+ ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(AdtExpr {
adt_def: *adt_def,
variant_index: adt_def.variant_index_with_ctor_id(def_id),
substs,
- user_ty: user_provided_type,
+ user_ty,
fields: Box::new([]),
base: None,
})),
@@ -980,7 +999,7 @@ impl<'tcx> Cx<'tcx> {
.temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
let var_ty = place.base_ty;
- // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
+ // The result of capture analysis in `rustc_hir_analysis/check/upvar.rs`represents a captured path
// as it's seen for use within the closure and not at the time of closure creation.
//
// That is we see expect to see it start from a captured upvar and not something that is local
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index f7351a4ca..1d95d6b53 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -8,7 +8,9 @@ use crate::thir::util::UserAnnotatedTyHelpers;
use rustc_data_structures::steal::Steal;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::lang_items::LangItem;
use rustc_hir::HirId;
use rustc_hir::Node;
use rustc_middle::middle::region;
@@ -27,6 +29,26 @@ pub(crate) fn thir_body<'tcx>(
return Err(reported);
}
let expr = cx.mirror_expr(&body.value);
+
+ let owner_id = hir.local_def_id_to_hir_id(owner_def.did);
+ if let Some(ref fn_decl) = hir.fn_decl_by_hir_id(owner_id) {
+ let closure_env_param = cx.closure_env_param(owner_def.did, owner_id);
+ let explicit_params = cx.explicit_params(owner_id, fn_decl, body);
+ cx.thir.params = closure_env_param.into_iter().chain(explicit_params).collect();
+
+ // The resume argument may be missing, in that case we need to provide it here.
+ // It will always be `()` in this case.
+ if tcx.def_kind(owner_def.did) == DefKind::Generator && body.params.is_empty() {
+ cx.thir.params.push(Param {
+ ty: tcx.mk_unit(),
+ pat: None,
+ ty_span: None,
+ self_kind: None,
+ hir_id: None,
+ });
+ }
+ }
+
Ok((tcx.alloc_steal_thir(cx.thir), expr))
}
@@ -44,11 +66,11 @@ struct Cx<'tcx> {
tcx: TyCtxt<'tcx>,
thir: Thir<'tcx>,
- pub(crate) param_env: ty::ParamEnv<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
- pub(crate) region_scope_tree: &'tcx region::ScopeTree,
- pub(crate) typeck_results: &'tcx ty::TypeckResults<'tcx>,
- pub(crate) rvalue_scopes: &'tcx RvalueScopes,
+ region_scope_tree: &'tcx region::ScopeTree,
+ typeck_results: &'tcx ty::TypeckResults<'tcx>,
+ rvalue_scopes: &'tcx RvalueScopes,
/// When applying adjustments to the expression
/// with the given `HirId`, use the given `Span`,
@@ -77,14 +99,94 @@ impl<'tcx> Cx<'tcx> {
}
}
- #[tracing::instrument(level = "debug", skip(self))]
- pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
+ #[instrument(level = "debug", skip(self))]
+ fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Box<Pat<'tcx>> {
let p = match self.tcx.hir().get(p.hir_id) {
Node::Pat(p) => p,
node => bug!("pattern became {:?}", node),
};
pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
}
+
+ fn closure_env_param(&self, owner_def: LocalDefId, owner_id: HirId) -> Option<Param<'tcx>> {
+ match self.tcx.def_kind(owner_def) {
+ DefKind::Closure => {
+ let closure_ty = self.typeck_results.node_type(owner_id);
+
+ let ty::Closure(closure_def_id, closure_substs) = *closure_ty.kind() else {
+ bug!("closure expr does not have closure type: {:?}", closure_ty);
+ };
+
+ let bound_vars = self.tcx.mk_bound_variable_kinds(std::iter::once(
+ ty::BoundVariableKind::Region(ty::BrEnv),
+ ));
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+ kind: ty::BrEnv,
+ };
+ let env_region = ty::ReLateBound(ty::INNERMOST, br);
+ let closure_env_ty =
+ self.tcx.closure_env_ty(closure_def_id, closure_substs, env_region).unwrap();
+ let liberated_closure_env_ty = self.tcx.erase_late_bound_regions(
+ ty::Binder::bind_with_vars(closure_env_ty, bound_vars),
+ );
+ let env_param = Param {
+ ty: liberated_closure_env_ty,
+ pat: None,
+ ty_span: None,
+ self_kind: None,
+ hir_id: None,
+ };
+
+ Some(env_param)
+ }
+ DefKind::Generator => {
+ let gen_ty = self.typeck_results.node_type(owner_id);
+ let gen_param =
+ Param { ty: gen_ty, pat: None, ty_span: None, self_kind: None, hir_id: None };
+ Some(gen_param)
+ }
+ _ => None,
+ }
+ }
+
+ fn explicit_params<'a>(
+ &'a mut self,
+ owner_id: HirId,
+ fn_decl: &'tcx hir::FnDecl<'tcx>,
+ body: &'tcx hir::Body<'tcx>,
+ ) -> impl Iterator<Item = Param<'tcx>> + 'a {
+ let fn_sig = self.typeck_results.liberated_fn_sigs()[owner_id];
+
+ body.params.iter().enumerate().map(move |(index, param)| {
+ let ty_span = fn_decl
+ .inputs
+ .get(index)
+ // Make sure that inferred closure args have no type span
+ .and_then(|ty| if param.pat.span != ty.span { Some(ty.span) } else { None });
+
+ let self_kind = if index == 0 && fn_decl.implicit_self.has_implicit_self() {
+ Some(fn_decl.implicit_self)
+ } else {
+ None
+ };
+
+ // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+ // (as it's created inside the body itself, not passed in from outside).
+ let ty = if fn_decl.c_variadic && index == fn_decl.inputs.len() {
+ let va_list_did = self.tcx.require_lang_item(LangItem::VaList, Some(param.span));
+
+ self.tcx
+ .bound_type_of(va_list_did)
+ .subst(self.tcx, &[self.tcx.lifetimes.re_erased.into()])
+ } else {
+ fn_sig.inputs()[index]
+ };
+
+ let pat = self.pattern_from_hir(param.pat);
+ Param { pat: Some(pat), ty, ty_span, self_kind, hir_id: Some(param.hir_id) }
+ })
+ }
}
impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'tcx> {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 063c07647..858129c74 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -7,7 +7,7 @@ use super::{PatCtxt, PatternError};
use rustc_arena::TypedArena;
use rustc_ast::Mutability;
use rustc_errors::{
- error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
+ error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
@@ -347,27 +347,35 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let span_end = affix.last().unwrap().unwrap().0;
let span = span_start.to(span_end);
let cnt = affix.len();
- cx.tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, top, span, |lint| {
- let s = pluralize!(cnt);
- let mut diag = lint.build(&format!("{kind} irrefutable pattern{s} in let chain"));
- diag.note(&format!(
- "{these} pattern{s} will always match",
- these = pluralize!("this", cnt),
- ));
- diag.help(&format!(
- "consider moving {} {suggestion}",
- if cnt > 1 { "them" } else { "it" }
- ));
- diag.emit()
- });
+ let s = pluralize!(cnt);
+ cx.tcx.struct_span_lint_hir(
+ IRREFUTABLE_LET_PATTERNS,
+ top,
+ span,
+ format!("{kind} irrefutable pattern{s} in let chain"),
+ |lint| {
+ lint.note(format!(
+ "{these} pattern{s} will always match",
+ these = pluralize!("this", cnt),
+ ))
+ .help(format!(
+ "consider moving {} {suggestion}",
+ if cnt > 1 { "them" } else { "it" }
+ ))
+ },
+ );
};
if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
// The chain has a non-zero prefix of irrefutable `let` statements.
// Check if the let source is while, for there is no alternative place to put a prefix,
// and we shouldn't lint.
+ // For let guards inside a match, prefixes might use bindings of the match pattern,
+ // so can't always be moved out.
+ // FIXME: Add checking whether the bindings are actually used in the prefix,
+ // and lint if they are not.
let let_source = let_source_parent(self.tcx, top, None);
- if !matches!(let_source, LetSource::WhileLet) {
+ if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
// Emit the lint
let prefix = &chain_refutabilities[..until];
lint_affix(prefix, "leading", "outside of the construct");
@@ -487,12 +495,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
],
Applicability::HasPlaceholders,
);
- if !bindings.is_empty() && cx.tcx.sess.is_nightly_build() {
+ if !bindings.is_empty() {
err.span_suggestion_verbose(
semi_span.shrink_to_lo(),
&format!(
- "alternatively, on nightly, you might want to use \
- `#![feature(let_else)]` to handle the variant{} that {} matched",
+ "alternatively, you might want to use \
+ let else to handle the variant{} that {} matched",
pluralize!(witnesses.len()),
match witnesses.len() {
1 => "isn't",
@@ -561,26 +569,28 @@ fn check_for_bindings_named_same_as_variants(
BINDINGS_WITH_VARIANT_NAME,
p.hir_id,
p.span,
+ DelayDm(|| format!(
+ "pattern binding `{}` is named the same as one \
+ of the variants of the type `{}`",
+ ident, cx.tcx.def_path_str(edef.did())
+ )),
|lint| {
let ty_path = cx.tcx.def_path_str(edef.did());
- let mut err = lint.build(&format!(
- "pattern binding `{}` is named the same as one \
- of the variants of the type `{}`",
- ident, ty_path
- ));
- err.code(error_code!(E0170));
+ lint.code(error_code!(E0170));
+
// If this is an irrefutable pattern, and there's > 1 variant,
// then we can't actually match on this. Applying the below
// suggestion would produce code that breaks on `check_irrefutable`.
if rf == Refutable || variant_count == 1 {
- err.span_suggestion(
+ lint.span_suggestion(
p.span,
"to match on the variant, qualify the path",
format!("{}::{}", ty_path, ident),
Applicability::MachineApplicable,
);
}
- err.emit();
+
+ lint
},
)
}
@@ -598,14 +608,13 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
}
fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
- tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, |lint| {
- let mut err = lint.build("unreachable pattern");
+ tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
if let Some(catchall) = catchall {
// We had a catchall pattern, hint at that.
- err.span_label(span, "unreachable pattern");
- err.span_label(catchall, "matches any value");
+ lint.span_label(span, "unreachable pattern");
+ lint.span_label(catchall, "matches any value");
}
- err.emit();
+ lint
});
}
@@ -621,6 +630,11 @@ fn irrefutable_let_patterns(
count: usize,
span: Span,
) {
+ let span = match source {
+ LetSource::LetElse(span) => span,
+ _ => span,
+ };
+
macro_rules! emit_diag {
(
$lint:expr,
@@ -630,18 +644,23 @@ fn irrefutable_let_patterns(
) => {{
let s = pluralize!(count);
let these = pluralize!("this", count);
- let mut diag = $lint.build(&format!("irrefutable {} pattern{s}", $source_name));
- diag.note(&format!("{these} pattern{s} will always match, so the {}", $note_sufix));
- diag.help(concat!("consider ", $help_sufix));
- diag.emit()
+ tcx.struct_span_lint_hir(
+ IRREFUTABLE_LET_PATTERNS,
+ id,
+ span,
+ format!("irrefutable {} pattern{s}", $source_name),
+ |lint| {
+ lint.note(&format!(
+ "{these} pattern{s} will always match, so the {}",
+ $note_sufix
+ ))
+ .help(concat!("consider ", $help_sufix))
+ },
+ )
}};
}
- let span = match source {
- LetSource::LetElse(span) => span,
- _ => span,
- };
- tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
+ match source {
LetSource::GenericLet => {
emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
}
@@ -677,7 +696,7 @@ fn irrefutable_let_patterns(
"instead using a `loop { ... }` with a `let` inside it"
);
}
- });
+ };
}
fn is_let_irrefutable<'p, 'tcx>(
@@ -849,22 +868,22 @@ fn non_exhaustive_match<'p, 'tcx>(
));
}
[.., prev, last] if prev.span.eq_ctxt(last.span) => {
- if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
- let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
- && last.span.eq_ctxt(last.body.span)
- {
- ""
- } else {
- ","
- };
+ let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
+ && last.span.eq_ctxt(last.body.span)
+ {
+ ""
+ } else {
+ ","
+ };
+ let spacing = if sm.is_multiline(prev.span.between(last.span)) {
+ sm.indentation_before(last.span).map(|indent| format!("\n{indent}"))
+ } else {
+ Some(" ".to_string())
+ };
+ if let Some(spacing) = spacing {
suggestion = Some((
last.span.shrink_to_hi(),
- format!(
- "{}{}{} => todo!()",
- comma,
- snippet.strip_prefix(',').unwrap_or(&snippet),
- pattern
- ),
+ format!("{}{}{} => todo!()", comma, spacing, pattern),
));
}
}
@@ -985,8 +1004,8 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
}
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
-fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId, span: Span) -> bool {
- !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
+fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool {
+ !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env)
}
/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
@@ -1012,7 +1031,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
// Get the binding move, extract the mutability if by-ref.
let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) {
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id, pat.span) => {
+ Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => {
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
let mut conflicts_ref = Vec::new();
sub.each_binding(|_, hir_id, span, _| {
@@ -1051,7 +1070,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
(Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`.
_ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction.
},
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id, span) => {
+ Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => {
conflicts_move.push((span, name)) // `ref mut?` + by-move conflict.
}
Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine.
@@ -1136,10 +1155,14 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
let parent_parent = hir.get_parent_node(parent);
let parent_parent_node = hir.get(parent_parent);
- if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) =
- parent_parent_node
- {
- return LetSource::LetElse(*span);
+ match parent_parent_node {
+ hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) => {
+ return LetSource::LetElse(*span);
+ }
+ hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => {
+ return LetSource::IfLetGuard;
+ }
+ _ => {}
}
let parent_parent_parent = hir.get_parent_node(parent_parent);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index d6dd0f017..ad12e0116 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,3 +1,4 @@
+use rustc_errors::DelayDm;
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -19,25 +20,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// Converts an evaluated constant to a pattern (if possible).
/// This means aggregate values (like structs and enums) are converted
/// to a pattern that matches the value (as if you'd compared via structural equality).
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self), ret)]
pub(super) fn const_to_pat(
&self,
cv: mir::ConstantKind<'tcx>,
id: hir::HirId,
span: Span,
mir_structural_match_violation: bool,
- ) -> Pat<'tcx> {
- let pat = self.tcx.infer_ctxt().enter(|infcx| {
- let mut convert = ConstToPat::new(self, id, span, infcx);
- convert.to_pat(cv, mir_structural_match_violation)
- });
-
- debug!(?pat);
- pat
+ ) -> Box<Pat<'tcx>> {
+ let infcx = self.tcx.infer_ctxt().build();
+ let mut convert = ConstToPat::new(self, id, span, infcx);
+ convert.to_pat(cv, mir_structural_match_violation)
}
}
-struct ConstToPat<'a, 'tcx> {
+struct ConstToPat<'tcx> {
id: hir::HirId,
span: Span,
param_env: ty::ParamEnv<'tcx>,
@@ -57,7 +54,7 @@ struct ConstToPat<'a, 'tcx> {
behind_reference: Cell<bool>,
// inference context used for checking `T: Structural` bounds.
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
include_lint_checks: bool,
@@ -73,21 +70,19 @@ mod fallback_to_const_ref {
/// hoops to get a reference to the value.
pub(super) struct FallbackToConstRef(());
- pub(super) fn fallback_to_const_ref<'a, 'tcx>(
- c2p: &super::ConstToPat<'a, 'tcx>,
- ) -> FallbackToConstRef {
+ pub(super) fn fallback_to_const_ref<'tcx>(c2p: &super::ConstToPat<'tcx>) -> FallbackToConstRef {
assert!(c2p.behind_reference.get());
FallbackToConstRef(())
}
}
use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef};
-impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
+impl<'tcx> ConstToPat<'tcx> {
fn new(
pat_ctxt: &PatCtxt<'_, 'tcx>,
id: hir::HirId,
span: Span,
- infcx: InferCtxt<'a, 'tcx>,
+ infcx: InferCtxt<'tcx>,
) -> Self {
trace!(?pat_ctxt.typeck_results.hir_owner);
ConstToPat {
@@ -159,7 +154,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
&mut self,
cv: mir::ConstantKind<'tcx>,
mir_structural_match_violation: bool,
- ) -> Pat<'tcx> {
+ ) -> Box<Pat<'tcx>> {
trace!(self.treat_byte_string_as_slice);
// This method is just a wrapper handling a validity check; the heavy lifting is
// performed by the recursive `recur` method, which is not meant to be
@@ -168,7 +163,14 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// once indirect_structural_match is a full fledged error, this
// level of indirection can be eliminated
- let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap();
+ let inlined_const_as_pat =
+ self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| {
+ Box::new(Pat {
+ span: self.span,
+ ty: cv.ty(),
+ kind: PatKind::Constant { value: cv },
+ })
+ });
if self.include_lint_checks && !self.saw_const_match_error.get() {
// If we were able to successfully convert the const to some pat,
@@ -201,9 +203,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id,
self.span,
- |lint| {
- lint.build(&msg).emit();
- },
+ msg,
+ |lint| lint,
);
} else {
debug!(
@@ -269,7 +270,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
&self,
cv: mir::ConstantKind<'tcx>,
mir_structural_match_violation: bool,
- ) -> Result<Pat<'tcx>, FallbackToConstRef> {
+ ) -> Result<Box<Pat<'tcx>>, FallbackToConstRef> {
let id = self.id;
let span = self.span;
let tcx = self.tcx();
@@ -282,9 +283,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
id,
span,
- |lint| {
- lint.build("floating-point types cannot be used in patterns").emit();
- },
+ "floating-point types cannot be used in patterns",
+ |lint| lint,
);
}
PatKind::Constant { value: cv }
@@ -336,15 +336,15 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
id,
span,
- |lint| {
- let msg = format!(
+ DelayDm(|| {
+ format!(
"to use a constant of type `{}` in a pattern, \
`{}` must be annotated with `#[derive(PartialEq, Eq)]`",
cv.ty(),
cv.ty(),
- );
- lint.build(&msg).emit();
- },
+ )
+ }),
+ |lint| lint,
);
}
// Since we are behind a reference, we can just bubble the error up so we get a
@@ -396,7 +396,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
.map(|val| self.recur(*val, false))
.collect::<Result<_, _>>()?,
slice: None,
- suffix: Vec::new(),
+ suffix: Box::new([]),
},
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
// These are not allowed and will error elsewhere anyway.
@@ -423,8 +423,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
let old = self.behind_reference.replace(true);
let array = tcx.deref_mir_constant(self.param_env.and(cv));
let val = PatKind::Deref {
- subpattern: Pat {
- kind: Box::new(PatKind::Array {
+ subpattern: Box::new(Pat {
+ kind: PatKind::Array {
prefix: tcx
.destructure_mir_constant(param_env, array)
.fields
@@ -432,11 +432,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
.map(|val| self.recur(*val, false))
.collect::<Result<_, _>>()?,
slice: None,
- suffix: vec![],
- }),
+ suffix: Box::new([]),
+ },
span,
ty: *pointee_ty,
- },
+ }),
};
self.behind_reference.set(old);
val
@@ -449,8 +449,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
let old = self.behind_reference.replace(true);
let array = tcx.deref_mir_constant(self.param_env.and(cv));
let val = PatKind::Deref {
- subpattern: Pat {
- kind: Box::new(PatKind::Slice {
+ subpattern: Box::new(Pat {
+ kind: PatKind::Slice {
prefix: tcx
.destructure_mir_constant(param_env, array)
.fields
@@ -458,11 +458,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
.map(|val| self.recur(*val, false))
.collect::<Result<_, _>>()?,
slice: None,
- suffix: vec![],
- }),
+ suffix: Box::new([]),
+ },
span,
ty: tcx.mk_slice(elem_ty),
- },
+ }),
};
self.behind_reference.set(old);
val
@@ -484,7 +484,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id,
self.span,
- |lint| {lint.build(&msg).emit();},
+ msg,
+ |lint| lint,
);
}
PatKind::Constant { value: cv }
@@ -505,7 +506,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// convert the dereferenced constant to a pattern that is the sub-pattern of the
// deref pattern.
_ => {
- if !pointee_ty.is_sized(tcx.at(span), param_env) {
+ if !pointee_ty.is_sized(tcx, param_env) {
// `tcx.deref_mir_constant()` below will ICE with an unsized type
// (except slices, which are handled in a separate arm above).
let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
@@ -533,7 +534,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
PatKind::Constant { value: cv }
}
- ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => {
+ ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
PatKind::Constant { value: cv }
}
// FIXME: these can have very surprising behaviour where optimization levels or other
@@ -552,9 +553,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::POINTER_STRUCTURAL_MATCH,
id,
span,
- |lint| {
- lint.build(msg).emit();
- },
+ msg,
+ |lint| lint,
);
}
PatKind::Constant { value: cv }
@@ -590,12 +590,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
id,
span,
- |lint| {
- lint.build(&msg).emit();
- },
+ msg,
+ |lint| lint,
);
}
- Ok(Pat { span, ty: cv.ty(), kind: Box::new(kind) })
+ Ok(Box::new(Pat { span, ty: cv.ty(), kind }))
}
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 8d6f8efb6..595abc8f6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -71,9 +71,9 @@ use std::ops::RangeInclusive;
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
- if let PatKind::Or { pats } = pat.kind.as_ref() {
- for pat in pats {
- expand(pat, vec);
+ if let PatKind::Or { pats } = &pat.kind {
+ for pat in pats.iter() {
+ expand(&pat, vec);
}
} else {
vec.push(pat)
@@ -252,10 +252,14 @@ impl IntRange {
let kind = if lo == hi {
PatKind::Constant { value: lo_const }
} else {
- PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
+ PatKind::Range(Box::new(PatRange {
+ lo: lo_const,
+ hi: hi_const,
+ end: RangeEnd::Included,
+ }))
};
- Pat { ty, span: DUMMY_SP, kind: Box::new(kind) }
+ Pat { ty, span: DUMMY_SP, kind }
}
/// Lint on likely incorrect range patterns (#63987)
@@ -295,10 +299,10 @@ impl IntRange {
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
hir_id,
pcx.span,
+ "multiple patterns overlap on their endpoints",
|lint| {
- let mut err = lint.build("multiple patterns overlap on their endpoints");
for (int_range, span) in overlaps {
- err.span_label(
+ lint.span_label(
span,
&format!(
"this range overlaps on `{}`...",
@@ -306,9 +310,9 @@ impl IntRange {
),
);
}
- err.span_label(pcx.span, "... with this range");
- err.note("you likely meant to write mutually exclusive ranges");
- err.emit();
+ lint.span_label(pcx.span, "... with this range");
+ lint.note("you likely meant to write mutually exclusive ranges");
+ lint
},
);
}
@@ -984,10 +988,12 @@ impl<'tcx> SplitWildcard<'tcx> {
.filter(|(_, v)| {
// If `exhaustive_patterns` is enabled, we exclude variants known to be
// uninhabited.
- let is_uninhabited = is_exhaustive_pat_feature
- && v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
- .contains(cx.tcx, cx.module);
- !is_uninhabited
+ !is_exhaustive_pat_feature
+ || v.inhabited_predicate(cx.tcx, *def).subst(cx.tcx, substs).apply(
+ cx.tcx,
+ cx.param_env,
+ cx.module,
+ )
})
.map(|(idx, _)| Variant(idx))
.collect();
@@ -1297,7 +1303,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
let mkpat = |pat| DeconstructedPat::from_pat(cx, pat);
let ctor;
let fields;
- match pat.kind.as_ref() {
+ match &pat.kind {
PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern),
PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
@@ -1342,9 +1348,9 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
fields = Fields::singleton(cx, pat);
}
ty::Adt(adt, _) => {
- ctor = match pat.kind.as_ref() {
+ ctor = match pat.kind {
PatKind::Leaf { .. } => Single,
- PatKind::Variant { variant_index, .. } => Variant(*variant_index),
+ PatKind::Variant { variant_index, .. } => Variant(variant_index),
_ => bug!(),
};
let variant = &adt.variant(ctor.variant_index_for_adt(*adt));
@@ -1402,7 +1408,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
}
}
}
- &PatKind::Range(PatRange { lo, hi, end }) => {
+ &PatKind::Range(box PatRange { lo, hi, end }) => {
let ty = lo.ty();
ctor = if let Some(int_range) = IntRange::from_range(
cx.tcx,
@@ -1429,7 +1435,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
FixedLen(prefix.len() + suffix.len())
};
ctor = Slice(Slice::new(array_len, kind));
- fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(mkpat));
+ fields =
+ Fields::from_iter(cx, prefix.iter().chain(suffix.iter()).map(|p| mkpat(&*p)));
}
PatKind::Or { .. } => {
ctor = Or;
@@ -1442,15 +1449,15 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
let is_wildcard = |pat: &Pat<'_>| {
- matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
+ matches!(pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
};
- let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx));
- let pat = match &self.ctor {
+ let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx)));
+ let kind = match &self.ctor {
Single | Variant(_) => match self.ty.kind() {
ty::Tuple(..) => PatKind::Leaf {
subpatterns: subpatterns
.enumerate()
- .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
+ .map(|(i, pattern)| FieldPat { field: Field::new(i), pattern })
.collect(),
},
ty::Adt(adt_def, _) if adt_def.is_box() => {
@@ -1485,7 +1492,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
FixedLen(_) => PatKind::Slice {
prefix: subpatterns.collect(),
slice: None,
- suffix: vec![],
+ suffix: Box::new([]),
},
VarLen(prefix, _) => {
let mut subpatterns = subpatterns.peekable();
@@ -1504,14 +1511,18 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
subpatterns.next();
}
}
- let suffix: Vec<_> = subpatterns.collect();
+ let suffix: Box<[_]> = subpatterns.collect();
let wild = Pat::wildcard_from_ty(self.ty);
- PatKind::Slice { prefix, slice: Some(wild), suffix }
+ PatKind::Slice {
+ prefix: prefix.into_boxed_slice(),
+ slice: Some(Box::new(wild)),
+ suffix,
+ }
}
}
}
&Str(value) => PatKind::Constant { value },
- &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
+ &FloatRange(lo, hi, end) => PatKind::Range(Box::new(PatRange { lo, hi, end })),
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
Wildcard | NonExhaustive => PatKind::Wild,
Missing { .. } => bug!(
@@ -1523,7 +1534,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
}
};
- Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(pat) }
+ Pat { ty: self.ty, span: DUMMY_SP, kind }
}
pub(super) fn is_or_pat(&self) -> bool {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index a13748a2d..2526522a2 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -29,27 +29,27 @@ use rustc_span::{Span, Symbol};
use std::cmp::Ordering;
#[derive(Clone, Debug)]
-pub(crate) enum PatternError {
+enum PatternError {
AssocConstInPattern(Span),
ConstParamInPattern(Span),
StaticInPattern(Span),
NonConstPath(Span),
}
-pub(crate) struct PatCtxt<'a, 'tcx> {
- pub(crate) tcx: TyCtxt<'tcx>,
- pub(crate) param_env: ty::ParamEnv<'tcx>,
- pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>,
- pub(crate) errors: Vec<PatternError>,
+struct PatCtxt<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ typeck_results: &'a ty::TypeckResults<'tcx>,
+ errors: Vec<PatternError>,
include_lint_checks: bool,
}
-pub(crate) fn pat_from_hir<'a, 'tcx>(
+pub(super) fn pat_from_hir<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
pat: &'tcx hir::Pat<'tcx>,
-) -> Pat<'tcx> {
+) -> Box<Pat<'tcx>> {
let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
let result = pcx.lower_pattern(pat);
if !pcx.errors.is_empty() {
@@ -61,7 +61,7 @@ pub(crate) fn pat_from_hir<'a, 'tcx>(
}
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
- pub(crate) fn new(
+ fn new(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -69,12 +69,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
PatCtxt { tcx, param_env, typeck_results, errors: vec![], include_lint_checks: false }
}
- pub(crate) fn include_lint_checks(&mut self) -> &mut Self {
+ fn include_lint_checks(&mut self) -> &mut Self {
self.include_lint_checks = true;
self
}
- pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+ fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
// When implicit dereferences have been inserted in this pattern, the unadjusted lowered
// pattern has the type that results *after* dereferencing. For example, in this code:
//
@@ -86,7 +86,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// ```
//
// the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
- // determined in rustc_typeck::check::match). The adjustments would be
+ // determined in rustc_hir_analysis::check::match). The adjustments would be
//
// `vec![&&Option<i32>, &Option<i32>]`.
//
@@ -97,13 +97,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let unadjusted_pat = self.lower_pattern_unadjusted(pat);
self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
unadjusted_pat,
- |pat, ref_ty| {
+ |pat: Box<_>, ref_ty| {
debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
- Pat {
+ Box::new(Pat {
span: pat.span,
ty: *ref_ty,
- kind: Box::new(PatKind::Deref { subpattern: pat }),
- }
+ kind: PatKind::Deref { subpattern: pat },
+ })
},
)
}
@@ -113,7 +113,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
expr: &'tcx hir::Expr<'tcx>,
) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) {
match self.lower_lit(expr) {
- PatKind::AscribeUserType { ascription, subpattern: Pat { kind: box kind, .. } } => {
+ PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
(kind, Some(ascription))
}
kind => (kind, None),
@@ -134,7 +134,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
match (end, cmp) {
// `x..y` where `x < y`.
// Non-empty because the range includes at least `x`.
- (RangeEnd::Excluded, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+ (RangeEnd::Excluded, Some(Ordering::Less)) => {
+ PatKind::Range(Box::new(PatRange { lo, hi, end }))
+ }
// `x..y` where `x >= y`. The range is empty => error.
(RangeEnd::Excluded, _) => {
struct_span_err!(
@@ -149,7 +151,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// `x..=y` where `x == y`.
(RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo },
// `x..=y` where `x < y`.
- (RangeEnd::Included, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
+ (RangeEnd::Included, Some(Ordering::Less)) => {
+ PatKind::Range(Box::new(PatRange { lo, hi, end }))
+ }
// `x..=y` where `x > y` hence the range is empty => error.
(RangeEnd::Included, _) => {
let mut err = struct_span_err!(
@@ -196,8 +200,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
}
- fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+ #[instrument(skip(self), level = "debug")]
+ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
let mut ty = self.typeck_results.node_type(pat.hir_id);
+ let mut span = pat.span;
let kind = match pat.kind {
hir::PatKind::Wild => PatKind::Wild,
@@ -228,7 +234,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// constants somewhere. Have them on the range pattern.
for end in &[lo, hi] {
if let Some((_, Some(ascription))) = end {
- let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) };
+ let subpattern = Box::new(Pat { span: pat.span, ty, kind });
kind =
PatKind::AscribeUserType { ascription: ascription.clone(), subpattern };
}
@@ -258,6 +264,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
hir::PatKind::Binding(_, id, ident, ref sub) => {
+ if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
+ span = span.with_hi(ident_span.hi());
+ }
+
let bm = *self
.typeck_results
.pat_binding_modes()
@@ -322,14 +332,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
};
- Pat { span: pat.span, ty, kind: Box::new(kind) }
+ Box::new(Pat { span, ty, kind })
}
fn lower_tuple_subpats(
&mut self,
pats: &'tcx [hir::Pat<'tcx>],
expected_len: usize,
- gap_pos: Option<usize>,
+ gap_pos: hir::DotDotPos,
) -> Vec<FieldPat<'tcx>> {
pats.iter()
.enumerate_and_adjust(expected_len, gap_pos)
@@ -340,11 +350,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
.collect()
}
- fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Vec<Pat<'tcx>> {
+ fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box<Pat<'tcx>>]> {
pats.iter().map(|p| self.lower_pattern(p)).collect()
}
- fn lower_opt_pattern(&mut self, pat: &'tcx Option<&'tcx hir::Pat<'tcx>>) -> Option<Pat<'tcx>> {
+ fn lower_opt_pattern(
+ &mut self,
+ pat: &'tcx Option<&'tcx hir::Pat<'tcx>>,
+ ) -> Option<Box<Pat<'tcx>>> {
pat.as_ref().map(|p| self.lower_pattern(p))
}
@@ -420,7 +433,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
| DefKind::AssocTy,
_,
)
- | Res::SelfTy { .. }
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
_ => {
let pattern_error = match res {
@@ -436,12 +450,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
let annotation = CanonicalUserTypeAnnotation {
- user_ty,
+ user_ty: Box::new(user_ty),
span,
inferred_ty: self.typeck_results.node_type(hir_id),
};
kind = PatKind::AscribeUserType {
- subpattern: Pat { span, ty, kind: Box::new(kind) },
+ subpattern: Box::new(Pat { span, ty, kind }),
ascription: Ascription { annotation, variance: ty::Variance::Covariant },
};
}
@@ -453,11 +467,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// it to `const_to_pat`. Any other path (like enum variants without fields)
/// is converted to the corresponding pattern via `lower_variant_or_leaf`.
#[instrument(skip(self), level = "debug")]
- fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> {
+ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> {
let ty = self.typeck_results.node_type(id);
let res = self.typeck_results.qpath_res(qpath, id);
- let pat_from_kind = |kind| Pat { span, ty, kind: Box::new(kind) };
+ let pat_from_kind = |kind| Box::new(Pat { span, ty, kind });
let (def_id, is_associated_const) = match res {
Res::Def(DefKind::Const, def_id) => (def_id, false),
@@ -469,7 +483,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// Use `Reveal::All` here because patterns are always monomorphic even if their function
// isn't.
let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx);
- let substs = self.typeck_results.node_substs(id);
+ // N.B. There is no guarantee that substs collected in typeck results are fully normalized,
+ // so they need to be normalized in order to pass to `Instance::resolve`, which will ICE
+ // if given unnormalized types.
+ let substs = self
+ .tcx
+ .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_substs(id));
let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) {
Ok(Some(i)) => i,
Ok(None) => {
@@ -505,13 +524,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let user_provided_types = self.typeck_results().user_provided_types();
if let Some(&user_ty) = user_provided_types.get(id) {
let annotation = CanonicalUserTypeAnnotation {
- user_ty,
+ user_ty: Box::new(user_ty),
span,
inferred_ty: self.typeck_results().node_type(id),
};
- Pat {
+ Box::new(Pat {
span,
- kind: Box::new(PatKind::AscribeUserType {
+ kind: PatKind::AscribeUserType {
subpattern: pattern,
ascription: Ascription {
annotation,
@@ -519,9 +538,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// `variance` field documentation for details.
variance: ty::Variance::Contravariant,
},
- }),
+ },
ty: const_.ty(),
- }
+ })
} else {
pattern
}
@@ -553,23 +572,19 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let value = value.eval(self.tcx, self.param_env);
match value {
- mir::ConstantKind::Ty(c) => {
- match c.kind() {
- ConstKind::Param(_) => {
- self.errors.push(PatternError::ConstParamInPattern(span));
- return PatKind::Wild;
- }
- ConstKind::Unevaluated(_) => {
- // If we land here it means the const can't be evaluated because it's `TooGeneric`.
- self.tcx
- .sess
- .span_err(span, "constant pattern depends on a generic parameter");
- return PatKind::Wild;
- }
- _ => bug!("Expected either ConstKind::Param or ConstKind::Unevaluated"),
+ mir::ConstantKind::Ty(c) => match c.kind() {
+ ConstKind::Param(_) => {
+ self.errors.push(PatternError::ConstParamInPattern(span));
+ return PatKind::Wild;
}
+ _ => bug!("Expected ConstKind::Param"),
+ },
+ mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
+ mir::ConstantKind::Unevaluated(..) => {
+ // If we land here it means the const can't be evaluated because it's `TooGeneric`.
+ self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+ return PatKind::Wild;
}
- mir::ConstantKind::Val(_, _) => *self.const_to_pat(value, id, span, false).kind,
}
}
@@ -580,7 +595,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
let (lit, neg) = match expr.kind {
hir::ExprKind::Path(ref qpath) => {
- return *self.lower_path(qpath, expr.hir_id, expr.span).kind;
+ return self.lower_path(qpath, expr.hir_id, expr.span).kind;
}
hir::ExprKind::ConstBlock(ref anon_const) => {
return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
@@ -598,7 +613,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let lit_input =
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
- Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
+ Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
Err(LitToConstError::Reported) => PatKind::Wild,
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
}
@@ -615,7 +630,7 @@ impl<'tcx> UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> {
}
}
-pub(crate) trait PatternFoldable<'tcx>: Sized {
+trait PatternFoldable<'tcx>: Sized {
fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
self.super_fold_with(folder)
}
@@ -623,7 +638,7 @@ pub(crate) trait PatternFoldable<'tcx>: Sized {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
}
-pub(crate) trait PatternFolder<'tcx>: Sized {
+trait PatternFolder<'tcx>: Sized {
fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> {
pattern.super_fold_with(self)
}
@@ -646,6 +661,12 @@ impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec<T> {
}
}
+impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<[T]> {
+ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
+ self.iter().map(|t| t.fold_with(folder)).collect()
+ }
+}
+
impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
self.as_ref().map(|t| t.fold_with(folder))
@@ -665,7 +686,7 @@ macro_rules! ClonePatternFoldableImpls {
}
ClonePatternFoldableImpls! { <'tcx>
- Span, Field, Mutability, Symbol, LocalVarId, usize, ty::Const<'tcx>,
+ Span, Field, Mutability, Symbol, LocalVarId, usize,
Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
UserTypeProjection, CanonicalUserTypeAnnotation<'tcx>
@@ -732,7 +753,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
PatKind::Deref { subpattern: subpattern.fold_with(folder) }
}
PatKind::Constant { value } => PatKind::Constant { value },
- PatKind::Range(range) => PatKind::Range(range),
+ PatKind::Range(ref range) => PatKind::Range(range.clone()),
PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
prefix: prefix.fold_with(folder),
slice: slice.fold_with(folder),
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 0a660ef30..8dc9976ea 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -364,8 +364,8 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
/// works well.
#[derive(Clone)]
-struct PatStack<'p, 'tcx> {
- pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
+pub(crate) struct PatStack<'p, 'tcx> {
+ pub(crate) pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
}
impl<'p, 'tcx> PatStack<'p, 'tcx> {
@@ -403,6 +403,21 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
})
}
+ // Recursively expand all patterns into their subpatterns and push each `PatStack` to matrix.
+ fn expand_and_extend<'a>(&'a self, matrix: &mut Matrix<'p, 'tcx>) {
+ if !self.is_empty() && self.head().is_or_pat() {
+ for pat in self.head().iter_fields() {
+ let mut new_patstack = PatStack::from_pattern(pat);
+ new_patstack.pats.extend_from_slice(&self.pats[1..]);
+ if !new_patstack.is_empty() && new_patstack.head().is_or_pat() {
+ new_patstack.expand_and_extend(matrix);
+ } else if !new_patstack.is_empty() {
+ matrix.push(new_patstack);
+ }
+ }
+ }
+ }
+
/// This computes `S(self.head().ctor(), self)`. See top of the file for explanations.
///
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
@@ -436,7 +451,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
/// A 2D matrix.
#[derive(Clone)]
pub(super) struct Matrix<'p, 'tcx> {
- patterns: Vec<PatStack<'p, 'tcx>>,
+ pub patterns: Vec<PatStack<'p, 'tcx>>,
}
impl<'p, 'tcx> Matrix<'p, 'tcx> {
@@ -453,7 +468,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
/// expands it.
fn push(&mut self, row: PatStack<'p, 'tcx>) {
if !row.is_empty() && row.head().is_or_pat() {
- self.patterns.extend(row.expand_or_pat());
+ row.expand_and_extend(self);
} else {
self.patterns.push(row);
}
@@ -731,7 +746,7 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
/// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
/// is not exhaustive enough.
///
-/// NB: The partner lint for structs lives in `compiler/rustc_typeck/src/check/pat.rs`.
+/// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
scrut_ty: Ty<'tcx>,
@@ -739,9 +754,8 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
hir_id: HirId,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
) {
- let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
- cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| {
- let mut lint = build.build("some variants are not matched explicitly");
+ cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, "some variants are not matched explicitly", |lint| {
+ let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
lint.help(
"ensure that all variants are matched explicitly by adding the suggested match arms",
@@ -750,7 +764,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
"the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
scrut_ty,
));
- lint.emit();
+ lint
});
}
@@ -776,7 +790,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
/// `is_under_guard` is used to inform if the pattern has a guard. If it
/// has one it must not be inserted into the matrix. This shouldn't be
/// relied on for soundness.
-#[instrument(level = "debug", skip(cx, matrix, hir_id))]
+#[instrument(level = "debug", skip(cx, matrix, hir_id), ret)]
fn is_useful<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
@@ -827,7 +841,15 @@ fn is_useful<'p, 'tcx>(
}
}
} else {
- let ty = v.head().ty();
+ let mut ty = v.head().ty();
+
+ // Opaque types can't get destructured/split, but the patterns can
+ // actually hint at hidden types, so we use the patterns' types instead.
+ if let ty::Opaque(..) = ty.kind() {
+ if let Some(row) = rows.first() {
+ ty = row.head().ty();
+ }
+ }
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
@@ -863,7 +885,7 @@ fn is_useful<'p, 'tcx>(
// that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
// To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
if is_non_exhaustive_and_wild
- // We check that the match has a wildcard pattern and that that wildcard is useful,
+ // We check that the match has a wildcard pattern and that wildcard is useful,
// meaning there are variants that are covered by the wildcard. Without the check
// for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
&& usefulness.is_useful() && matches!(witness_preference, RealArm)
@@ -902,7 +924,6 @@ fn is_useful<'p, 'tcx>(
v.head().set_reachable();
}
- debug!(?ret);
ret
}