summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/thir/pattern/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build/src/thir/pattern/mod.rs')
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs127
1 files changed, 73 insertions, 54 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index a13748a2d..0edf6a983 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:
//
@@ -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,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
}
- fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+ 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 +233,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 +263,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 +331,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 +349,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))
}
@@ -436,12 +448,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 +465,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 +481,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 +522,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 +536,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// `variance` field documentation for details.
variance: ty::Variance::Contravariant,
},
- }),
+ },
ty: const_.ty(),
- }
+ })
} else {
pattern
}
@@ -553,23 +570,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 +593,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 +611,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 +628,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 +636,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 +659,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))
@@ -732,7 +751,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),