Auto merge of #120466 - Dylan-DPC:rollup-v0or19a, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #116677 (References refer to allocated objects) - #118625 (Improve handling of expressions in patterns) - #120266 (Improve documentation for [A]Rc::into_inner) - #120373 (Adjust Behaviour of `read_dir` and `ReadDir` in Windows Implementation: Check Whether Path to Search In Exists) - #120390 (Borrow check inline const patterns) - #120420 (Stop using derivative in rustc_pattern_analysis) - #120428 (hir: Two preparatory changes for #120206) - #120453 (Fix incorrect comment in normalize_newlines) - #120462 (Clean dead code) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5518eaa946
62 changed files with 1281 additions and 159 deletions
|
@ -4342,7 +4342,6 @@ dependencies = [
|
||||||
name = "rustc_pattern_analysis"
|
name = "rustc_pattern_analysis"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derivative",
|
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustc_apfloat",
|
"rustc_apfloat",
|
||||||
"rustc_arena",
|
"rustc_arena",
|
||||||
|
|
|
@ -153,7 +153,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
ExprKind::Let(pat, scrutinee, span, is_recovered) => {
|
ExprKind::Let(pat, scrutinee, span, is_recovered) => {
|
||||||
hir::ExprKind::Let(self.arena.alloc(hir::Let {
|
hir::ExprKind::Let(self.arena.alloc(hir::Let {
|
||||||
hir_id: self.next_id(),
|
|
||||||
span: self.lower_span(*span),
|
span: self.lower_span(*span),
|
||||||
pat: self.lower_pat(pat),
|
pat: self.lower_pat(pat),
|
||||||
ty: None,
|
ty: None,
|
||||||
|
|
|
@ -2305,7 +2305,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
match c.value.kind {
|
match c.value.kind {
|
||||||
ExprKind::Underscore => {
|
ExprKind::Underscore => {
|
||||||
if self.tcx.features().generic_arg_infer {
|
if self.tcx.features().generic_arg_infer {
|
||||||
hir::ArrayLen::Infer(self.lower_node_id(c.id), self.lower_span(c.value.span))
|
hir::ArrayLen::Infer(hir::InferArg {
|
||||||
|
hir_id: self.lower_node_id(c.id),
|
||||||
|
span: self.lower_span(c.value.span),
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
feature_err(
|
feature_err(
|
||||||
&self.tcx.sess,
|
&self.tcx.sess,
|
||||||
|
|
|
@ -1099,12 +1099,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn check_user_type_annotations(&mut self) {
|
fn check_user_type_annotations(&mut self) {
|
||||||
debug!(?self.user_type_annotations);
|
debug!(?self.user_type_annotations);
|
||||||
|
let tcx = self.tcx();
|
||||||
for user_annotation in self.user_type_annotations {
|
for user_annotation in self.user_type_annotations {
|
||||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||||
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
|
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
|
||||||
|
if let ty::UserType::TypeOf(def, args) = annotation
|
||||||
|
&& let DefKind::InlineConst = tcx.def_kind(def)
|
||||||
|
{
|
||||||
|
self.check_inline_const(inferred_ty, def.expect_local(), args, span);
|
||||||
|
} else {
|
||||||
self.ascribe_user_type(inferred_ty, annotation, span);
|
self.ascribe_user_type(inferred_ty, annotation, span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, data), level = "debug")]
|
#[instrument(skip(self, data), level = "debug")]
|
||||||
fn push_region_constraints(
|
fn push_region_constraints(
|
||||||
|
@ -1195,6 +1202,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_inline_const(
|
||||||
|
&mut self,
|
||||||
|
inferred_ty: Ty<'tcx>,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
args: UserArgs<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
|
assert!(args.user_self_ty.is_none());
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args);
|
||||||
|
if let Err(terr) =
|
||||||
|
self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring)
|
||||||
|
{
|
||||||
|
span_bug!(
|
||||||
|
span,
|
||||||
|
"bad inline const pattern: ({:?} = {:?}) {:?}",
|
||||||
|
const_ty,
|
||||||
|
inferred_ty,
|
||||||
|
terr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let args = self.infcx.resolve_vars_if_possible(args.args);
|
||||||
|
let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span));
|
||||||
|
self.normalize_and_prove_instantiated_predicates(
|
||||||
|
def_id.to_def_id(),
|
||||||
|
predicates,
|
||||||
|
Locations::All(span),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
self.infcx.tcx
|
self.infcx.tcx
|
||||||
}
|
}
|
||||||
|
@ -1851,7 +1888,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
let def_id = uv.def;
|
let def_id = uv.def;
|
||||||
if tcx.def_kind(def_id) == DefKind::InlineConst {
|
if tcx.def_kind(def_id) == DefKind::InlineConst {
|
||||||
let def_id = def_id.expect_local();
|
let def_id = def_id.expect_local();
|
||||||
let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location);
|
let predicates = self.prove_closure_bounds(
|
||||||
|
tcx,
|
||||||
|
def_id,
|
||||||
|
uv.args,
|
||||||
|
location.to_locations(),
|
||||||
|
);
|
||||||
self.normalize_and_prove_instantiated_predicates(
|
self.normalize_and_prove_instantiated_predicates(
|
||||||
def_id.to_def_id(),
|
def_id.to_def_id(),
|
||||||
predicates,
|
predicates,
|
||||||
|
@ -2654,9 +2696,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// desugaring. A closure gets desugared to a struct, and
|
// desugaring. A closure gets desugared to a struct, and
|
||||||
// these extra requirements are basically like where
|
// these extra requirements are basically like where
|
||||||
// clauses on the struct.
|
// clauses on the struct.
|
||||||
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => {
|
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
|
||||||
(def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
|
def_id,
|
||||||
}
|
self.prove_closure_bounds(
|
||||||
|
tcx,
|
||||||
|
def_id.expect_local(),
|
||||||
|
args,
|
||||||
|
location.to_locations(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
AggregateKind::Array(_) | AggregateKind::Tuple => {
|
AggregateKind::Array(_) | AggregateKind::Tuple => {
|
||||||
(CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
|
(CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
|
||||||
|
@ -2675,7 +2723,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
def_id: LocalDefId,
|
def_id: LocalDefId,
|
||||||
args: GenericArgsRef<'tcx>,
|
args: GenericArgsRef<'tcx>,
|
||||||
location: Location,
|
locations: Locations,
|
||||||
) -> ty::InstantiatedPredicates<'tcx> {
|
) -> ty::InstantiatedPredicates<'tcx> {
|
||||||
if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
|
if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
|
||||||
constraint_conversion::ConstraintConversion::new(
|
constraint_conversion::ConstraintConversion::new(
|
||||||
|
@ -2684,7 +2732,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
self.region_bound_pairs,
|
self.region_bound_pairs,
|
||||||
self.implicit_region_bound,
|
self.implicit_region_bound,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
location.to_locations(),
|
locations,
|
||||||
DUMMY_SP, // irrelevant; will be overridden.
|
DUMMY_SP, // irrelevant; will be overridden.
|
||||||
ConstraintCategory::Boring, // same as above.
|
ConstraintCategory::Boring, // same as above.
|
||||||
self.borrowck_context.constraints,
|
self.borrowck_context.constraints,
|
||||||
|
@ -2710,7 +2758,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
if let Err(_) = self.eq_args(
|
if let Err(_) = self.eq_args(
|
||||||
typeck_root_args,
|
typeck_root_args,
|
||||||
parent_args,
|
parent_args,
|
||||||
location.to_locations(),
|
locations,
|
||||||
ConstraintCategory::BoringNoLocation,
|
ConstraintCategory::BoringNoLocation,
|
||||||
) {
|
) {
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
|
|
|
@ -1273,7 +1273,6 @@ pub struct Arm<'hir> {
|
||||||
/// desugaring to if-let. Only let-else supports the type annotation at present.
|
/// desugaring to if-let. Only let-else supports the type annotation at present.
|
||||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
pub struct Let<'hir> {
|
pub struct Let<'hir> {
|
||||||
pub hir_id: HirId,
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub pat: &'hir Pat<'hir>,
|
pub pat: &'hir Pat<'hir>,
|
||||||
pub ty: Option<&'hir Ty<'hir>>,
|
pub ty: Option<&'hir Ty<'hir>>,
|
||||||
|
@ -1532,14 +1531,16 @@ pub type Lit = Spanned<LitKind>;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
||||||
pub enum ArrayLen {
|
pub enum ArrayLen {
|
||||||
Infer(HirId, Span),
|
Infer(InferArg),
|
||||||
Body(AnonConst),
|
Body(AnonConst),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArrayLen {
|
impl ArrayLen {
|
||||||
pub fn hir_id(&self) -> HirId {
|
pub fn hir_id(&self) -> HirId {
|
||||||
match self {
|
match self {
|
||||||
&ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, .. }) => hir_id,
|
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => {
|
||||||
|
*hir_id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2424,7 +2425,7 @@ impl<'hir> Ty<'hir> {
|
||||||
TyKind::Infer => true,
|
TyKind::Infer => true,
|
||||||
TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
|
TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
|
||||||
TyKind::Array(ty, length) => {
|
TyKind::Array(ty, length) => {
|
||||||
ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(_, _))
|
ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(..))
|
||||||
}
|
}
|
||||||
TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty),
|
TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty),
|
||||||
TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(),
|
TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(),
|
||||||
|
|
|
@ -341,9 +341,6 @@ pub trait Visitor<'v>: Sized {
|
||||||
fn visit_expr(&mut self, ex: &'v Expr<'v>) {
|
fn visit_expr(&mut self, ex: &'v Expr<'v>) {
|
||||||
walk_expr(self, ex)
|
walk_expr(self, ex)
|
||||||
}
|
}
|
||||||
fn visit_let_expr(&mut self, lex: &'v Let<'v>) {
|
|
||||||
walk_let_expr(self, lex)
|
|
||||||
}
|
|
||||||
fn visit_expr_field(&mut self, field: &'v ExprField<'v>) {
|
fn visit_expr_field(&mut self, field: &'v ExprField<'v>) {
|
||||||
walk_expr_field(self, field)
|
walk_expr_field(self, field)
|
||||||
}
|
}
|
||||||
|
@ -672,7 +669,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
|
||||||
|
|
||||||
pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
|
pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
|
||||||
match len {
|
match len {
|
||||||
&ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
|
ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id),
|
||||||
ArrayLen::Body(c) => visitor.visit_anon_const(c),
|
ArrayLen::Body(c) => visitor.visit_anon_const(c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -729,7 +726,12 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||||
ExprKind::DropTemps(ref subexpression) => {
|
ExprKind::DropTemps(ref subexpression) => {
|
||||||
visitor.visit_expr(subexpression);
|
visitor.visit_expr(subexpression);
|
||||||
}
|
}
|
||||||
ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr),
|
ExprKind::Let(Let { span: _, pat, ty, init, is_recovered: _ }) => {
|
||||||
|
// match the visit order in walk_local
|
||||||
|
visitor.visit_expr(init);
|
||||||
|
visitor.visit_pat(pat);
|
||||||
|
walk_list!(visitor, visit_ty, ty);
|
||||||
|
}
|
||||||
ExprKind::If(ref cond, ref then, ref else_opt) => {
|
ExprKind::If(ref cond, ref then, ref else_opt) => {
|
||||||
visitor.visit_expr(cond);
|
visitor.visit_expr(cond);
|
||||||
visitor.visit_expr(then);
|
visitor.visit_expr(then);
|
||||||
|
@ -806,14 +808,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) {
|
|
||||||
// match the visit order in walk_local
|
|
||||||
visitor.visit_expr(let_expr.init);
|
|
||||||
visitor.visit_id(let_expr.hir_id);
|
|
||||||
visitor.visit_pat(let_expr.pat);
|
|
||||||
walk_list!(visitor, visit_ty, let_expr.ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) {
|
pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) {
|
||||||
visitor.visit_id(field.hir_id);
|
visitor.visit_id(field.hir_id);
|
||||||
visitor.visit_ident(field.ident);
|
visitor.visit_ident(field.ident);
|
||||||
|
|
|
@ -2529,7 +2529,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
}
|
}
|
||||||
hir::TyKind::Array(ty, length) => {
|
hir::TyKind::Array(ty, length) => {
|
||||||
let length = match length {
|
let length = match length {
|
||||||
&hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
|
hir::ArrayLen::Infer(inf) => self.ct_infer(tcx.types.usize, None, inf.span),
|
||||||
hir::ArrayLen::Body(constant) => {
|
hir::ArrayLen::Body(constant) => {
|
||||||
ty::Const::from_anon_const(tcx, constant.def_id)
|
ty::Const::from_anon_const(tcx, constant.def_id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,8 +146,8 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn visit_array_length(&mut self, length: &'v hir::ArrayLen) {
|
fn visit_array_length(&mut self, length: &'v hir::ArrayLen) {
|
||||||
if let &hir::ArrayLen::Infer(_, span) = length {
|
if let hir::ArrayLen::Infer(inf) = length {
|
||||||
self.0.push(span);
|
self.0.push(inf.span);
|
||||||
}
|
}
|
||||||
intravisit::walk_array_len(self, length)
|
intravisit::walk_array_len(self, length)
|
||||||
}
|
}
|
||||||
|
|
|
@ -956,7 +956,7 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
fn print_array_length(&mut self, len: &hir::ArrayLen) {
|
fn print_array_length(&mut self, len: &hir::ArrayLen) {
|
||||||
match len {
|
match len {
|
||||||
hir::ArrayLen::Infer(_, _) => self.word("_"),
|
hir::ArrayLen::Infer(..) => self.word("_"),
|
||||||
hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
|
hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,7 +320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
|
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
|
||||||
ExprKind::Become(call) => self.check_expr_become(call, expr),
|
ExprKind::Become(call) => self.check_expr_become(call, expr),
|
||||||
ExprKind::Let(let_expr) => self.check_expr_let(let_expr),
|
ExprKind::Let(let_expr) => self.check_expr_let(let_expr, expr.hir_id),
|
||||||
ExprKind::Loop(body, _, source, _) => {
|
ExprKind::Loop(body, _, source, _) => {
|
||||||
self.check_expr_loop(body, source, expected, expr)
|
self.check_expr_loop(body, source, expected, expr)
|
||||||
}
|
}
|
||||||
|
@ -1259,12 +1259,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> {
|
pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>, hir_id: HirId) -> Ty<'tcx> {
|
||||||
// for let statements, this is done in check_stmt
|
// for let statements, this is done in check_stmt
|
||||||
let init = let_expr.init;
|
let init = let_expr.init;
|
||||||
self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
|
self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
|
||||||
// otherwise check exactly as a let statement
|
// otherwise check exactly as a let statement
|
||||||
self.check_decl(let_expr.into());
|
self.check_decl((let_expr, hir_id).into());
|
||||||
// but return a bool, for this is a boolean expression
|
// but return a bool, for this is a boolean expression
|
||||||
if let Some(error_guaranteed) = let_expr.is_recovered {
|
if let Some(error_guaranteed) = let_expr.is_recovered {
|
||||||
self.set_tainted_by_errors(error_guaranteed);
|
self.set_tainted_by_errors(error_guaranteed);
|
||||||
|
|
|
@ -405,7 +405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
|
pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
|
||||||
match length {
|
match length {
|
||||||
&hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
|
hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span),
|
||||||
hir::ArrayLen::Body(anon_const) => {
|
hir::ArrayLen::Body(anon_const) => {
|
||||||
let span = self.tcx.def_span(anon_const.def_id);
|
let span = self.tcx.def_span(anon_const.def_id);
|
||||||
let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id);
|
let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id);
|
||||||
|
|
|
@ -48,9 +48,9 @@ impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
|
impl<'a> From<(&'a hir::Let<'a>, hir::HirId)> for Declaration<'a> {
|
||||||
fn from(let_expr: &'a hir::Let<'a>) -> Self {
|
fn from((let_expr, hir_id): (&'a hir::Let<'a>, hir::HirId)) -> Self {
|
||||||
let hir::Let { hir_id, pat, ty, span, init, is_recovered: _ } = *let_expr;
|
let hir::Let { pat, ty, span, init, is_recovered: _ } = *let_expr;
|
||||||
Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr }
|
Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,9 +125,11 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
||||||
intravisit::walk_local(self, local)
|
intravisit::walk_local(self, local)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) {
|
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||||
self.declare(let_expr.into());
|
if let hir::ExprKind::Let(let_expr) = expr.kind {
|
||||||
intravisit::walk_let_expr(self, let_expr);
|
self.declare((let_expr, expr.hir_id).into());
|
||||||
|
}
|
||||||
|
intravisit::walk_expr(self, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
use crate::build::expr::as_place::PlaceBuilder;
|
use crate::build::expr::as_place::PlaceBuilder;
|
||||||
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
|
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
|
||||||
use crate::build::Builder;
|
use crate::build::Builder;
|
||||||
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_middle::thir::{self, *};
|
use rustc_middle::thir::{self, *};
|
||||||
|
use rustc_middle::ty;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
@ -149,7 +151,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
ref subpattern,
|
ref subpattern,
|
||||||
ascription: thir::Ascription { ref annotation, variance },
|
ascription: thir::Ascription { ref annotation, variance },
|
||||||
} => {
|
} => {
|
||||||
// Apply the type ascription to the value at `match_pair.place`, which is the
|
// Apply the type ascription to the value at `match_pair.place`
|
||||||
if let Some(source) = match_pair.place.try_to_place(self) {
|
if let Some(source) = match_pair.place.try_to_place(self) {
|
||||||
candidate.ascriptions.push(Ascription {
|
candidate.ascriptions.push(Ascription {
|
||||||
annotation: annotation.clone(),
|
annotation: annotation.clone(),
|
||||||
|
@ -205,7 +207,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
Err(match_pair)
|
Err(match_pair)
|
||||||
}
|
}
|
||||||
|
|
||||||
PatKind::InlineConstant { subpattern: ref pattern, def: _ } => {
|
PatKind::InlineConstant { subpattern: ref pattern, def } => {
|
||||||
|
// Apply a type ascription for the inline constant to the value at `match_pair.place`
|
||||||
|
if let Some(source) = match_pair.place.try_to_place(self) {
|
||||||
|
let span = match_pair.pattern.span;
|
||||||
|
let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id());
|
||||||
|
let args = ty::InlineConstArgs::new(
|
||||||
|
self.tcx,
|
||||||
|
ty::InlineConstArgsParts {
|
||||||
|
parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id),
|
||||||
|
ty: self.infcx.next_ty_var(TypeVariableOrigin {
|
||||||
|
kind: TypeVariableOriginKind::MiscVariable,
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.args;
|
||||||
|
let user_ty =
|
||||||
|
self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
|
||||||
|
def.to_def_id(),
|
||||||
|
ty::UserArgs { args, user_self_ty: None },
|
||||||
|
));
|
||||||
|
let annotation = ty::CanonicalUserTypeAnnotation {
|
||||||
|
inferred_ty: pattern.ty,
|
||||||
|
span,
|
||||||
|
user_ty: Box::new(user_ty),
|
||||||
|
};
|
||||||
|
candidate.ascriptions.push(Ascription {
|
||||||
|
annotation,
|
||||||
|
source,
|
||||||
|
variance: ty::Contravariant,
|
||||||
|
});
|
||||||
|
}
|
||||||
candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
|
candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -772,6 +772,20 @@ parse_unexpected_const_param_declaration = unexpected `const` parameter declarat
|
||||||
parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
|
parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
|
||||||
.label = lifetime parameters cannot have default values
|
.label = lifetime parameters cannot have default values
|
||||||
|
|
||||||
|
parse_unexpected_expr_in_pat =
|
||||||
|
expected {$is_bound ->
|
||||||
|
[true] a pattern range bound
|
||||||
|
*[false] a pattern
|
||||||
|
}, found {$is_method_call ->
|
||||||
|
[true] a method call
|
||||||
|
*[false] an expression
|
||||||
|
}
|
||||||
|
|
||||||
|
.label = {$is_method_call ->
|
||||||
|
[true] method calls
|
||||||
|
*[false] arbitrary expressions
|
||||||
|
} are not allowed in patterns
|
||||||
|
|
||||||
parse_unexpected_if_with_if = unexpected `if` in the condition expression
|
parse_unexpected_if_with_if = unexpected `if` in the condition expression
|
||||||
.suggestion = remove the `if`
|
.suggestion = remove the `if`
|
||||||
|
|
||||||
|
|
|
@ -2415,6 +2415,18 @@ pub(crate) struct ExpectedCommaAfterPatternField {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_unexpected_expr_in_pat)]
|
||||||
|
pub(crate) struct UnexpectedExpressionInPattern {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
/// Was a `RangePatternBound` expected?
|
||||||
|
pub is_bound: bool,
|
||||||
|
/// Was the unexpected expression a `MethodCallExpression`?
|
||||||
|
pub is_method_call: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_unexpected_paren_in_range_pat)]
|
#[diag(parse_unexpected_paren_in_range_pat)]
|
||||||
pub(crate) struct UnexpectedParenInRangePat {
|
pub(crate) struct UnexpectedParenInRangePat {
|
||||||
|
|
|
@ -444,6 +444,19 @@ impl<'a> Parser<'a> {
|
||||||
) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
|
) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
// When recovering patterns as expressions, stop parsing when encountering an assignment `=`, an alternative `|`, or a range `..`.
|
||||||
|
(
|
||||||
|
Some(
|
||||||
|
AssocOp::Assign
|
||||||
|
| AssocOp::AssignOp(_)
|
||||||
|
| AssocOp::BitOr
|
||||||
|
| AssocOp::DotDot
|
||||||
|
| AssocOp::DotDotEq,
|
||||||
|
),
|
||||||
|
_,
|
||||||
|
) if self.restrictions.contains(Restrictions::IS_PAT) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
(Some(op), _) => (op, self.token.span),
|
(Some(op), _) => (op, self.token.span),
|
||||||
(None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => {
|
(None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => {
|
||||||
self.dcx().emit_err(errors::InvalidLogicalOperator {
|
self.dcx().emit_err(errors::InvalidLogicalOperator {
|
||||||
|
|
|
@ -53,6 +53,7 @@ bitflags::bitflags! {
|
||||||
const CONST_EXPR = 1 << 2;
|
const CONST_EXPR = 1 << 2;
|
||||||
const ALLOW_LET = 1 << 3;
|
const ALLOW_LET = 1 << 3;
|
||||||
const IN_IF_GUARD = 1 << 4;
|
const IN_IF_GUARD = 1 << 4;
|
||||||
|
const IS_PAT = 1 << 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
|
use super::{ForceCollect, Parser, PathStyle, Restrictions, TrailingToken};
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
|
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
|
||||||
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
|
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
|
||||||
|
@ -6,14 +6,14 @@ use crate::errors::{
|
||||||
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
|
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
|
||||||
PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
|
PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
|
||||||
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
|
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
|
||||||
TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
|
TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern,
|
||||||
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
|
UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
|
||||||
UnexpectedVertVertInPattern,
|
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern,
|
||||||
};
|
};
|
||||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||||
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Delimiter};
|
use rustc_ast::token::{self, BinOpToken, Delimiter, Token};
|
||||||
use rustc_ast::{
|
use rustc_ast::{
|
||||||
self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat,
|
self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat,
|
||||||
PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
|
PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
|
||||||
|
@ -23,7 +23,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
|
||||||
use rustc_session::errors::ExprParenthesesNeeded;
|
use rustc_session::errors::ExprParenthesesNeeded;
|
||||||
use rustc_span::source_map::{respan, Spanned};
|
use rustc_span::source_map::{respan, Spanned};
|
||||||
use rustc_span::symbol::{kw, sym, Ident};
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::{ErrorGuaranteed, Span};
|
||||||
use thin_vec::{thin_vec, ThinVec};
|
use thin_vec::{thin_vec, ThinVec};
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
|
@ -336,6 +336,95 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensures that the last parsed pattern (or pattern range bound) is not followed by a method call or an operator.
|
||||||
|
///
|
||||||
|
/// `is_end_bound` indicates whether the last parsed thing was the end bound of a range pattern (see [`parse_pat_range_end`](Self::parse_pat_range_end))
|
||||||
|
/// in order to say "expected a pattern range bound" instead of "expected a pattern";
|
||||||
|
/// ```text
|
||||||
|
/// 0..=1 + 2
|
||||||
|
/// ^^^^^
|
||||||
|
/// ```
|
||||||
|
/// Only the end bound is spanned, and this function have no idea if there were a `..=` before `pat_span`, hence the parameter.
|
||||||
|
#[must_use = "the pattern must be discarded as `PatKind::Err` if this function returns Some"]
|
||||||
|
fn maybe_recover_trailing_expr(
|
||||||
|
&mut self,
|
||||||
|
pat_span: Span,
|
||||||
|
is_end_bound: bool,
|
||||||
|
) -> Option<ErrorGuaranteed> {
|
||||||
|
if self.prev_token.is_keyword(kw::Underscore) || !self.may_recover() {
|
||||||
|
// Don't recover anything after an `_` or if recovery is disabled.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for `.hello()`, but allow `.Hello()` to be recovered as `, Hello()` in `parse_seq_to_before_tokens()`.
|
||||||
|
let has_trailing_method = self.check_noexpect(&token::Dot)
|
||||||
|
&& self.look_ahead(1, |tok| {
|
||||||
|
tok.ident()
|
||||||
|
.and_then(|(ident, _)| ident.name.as_str().chars().next())
|
||||||
|
.is_some_and(char::is_lowercase)
|
||||||
|
})
|
||||||
|
&& self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis));
|
||||||
|
|
||||||
|
// Check for operators.
|
||||||
|
// `|` is excluded as it is used in pattern alternatives and lambdas,
|
||||||
|
// `?` is included for error propagation,
|
||||||
|
// `[` is included for indexing operations,
|
||||||
|
// `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`)
|
||||||
|
let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or)
|
||||||
|
|| self.token.kind == token::Question
|
||||||
|
|| (self.token.kind == token::OpenDelim(Delimiter::Bracket)
|
||||||
|
&& self.look_ahead(1, |tok| tok.kind != token::CloseDelim(Delimiter::Bracket)));
|
||||||
|
|
||||||
|
if !has_trailing_method && !has_trailing_operator {
|
||||||
|
// Nothing to recover here.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's try to parse an expression to emit a better diagnostic.
|
||||||
|
let mut snapshot = self.create_snapshot_for_diagnostic();
|
||||||
|
snapshot.restrictions.insert(Restrictions::IS_PAT);
|
||||||
|
|
||||||
|
// Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten.
|
||||||
|
if let Ok(expr) = snapshot
|
||||||
|
.parse_expr_dot_or_call_with(
|
||||||
|
self.mk_expr_err(pat_span), // equivalent to transforming the parsed pattern into an `Expr`
|
||||||
|
pat_span,
|
||||||
|
AttrVec::new(),
|
||||||
|
)
|
||||||
|
.map_err(|err| err.cancel())
|
||||||
|
{
|
||||||
|
let non_assoc_span = expr.span;
|
||||||
|
|
||||||
|
// Parse an associative expression such as `+ expr`, `% expr`, ...
|
||||||
|
// Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
|
||||||
|
if let Ok(expr) =
|
||||||
|
snapshot.parse_expr_assoc_with(0, expr.into()).map_err(|err| err.cancel())
|
||||||
|
{
|
||||||
|
// We got a valid expression.
|
||||||
|
self.restore_snapshot(snapshot);
|
||||||
|
self.restrictions.remove(Restrictions::IS_PAT);
|
||||||
|
|
||||||
|
let is_bound = is_end_bound
|
||||||
|
// is_start_bound: either `..` or `)..`
|
||||||
|
|| self.token.is_range_separator()
|
||||||
|
|| self.token.kind == token::CloseDelim(Delimiter::Parenthesis)
|
||||||
|
&& self.look_ahead(1, Token::is_range_separator);
|
||||||
|
|
||||||
|
// Check that `parse_expr_assoc_with` didn't eat a rhs.
|
||||||
|
let is_method_call = has_trailing_method && non_assoc_span == expr.span;
|
||||||
|
|
||||||
|
return Some(self.dcx().emit_err(UnexpectedExpressionInPattern {
|
||||||
|
span: expr.span,
|
||||||
|
is_bound,
|
||||||
|
is_method_call,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We got a trailing method/operator, but we couldn't parse an expression.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
|
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
|
||||||
/// allowed).
|
/// allowed).
|
||||||
fn parse_pat_with_range_pat(
|
fn parse_pat_with_range_pat(
|
||||||
|
@ -441,7 +530,10 @@ impl<'a> Parser<'a> {
|
||||||
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
||||||
self.parse_pat_tuple_struct(qself, path)?
|
self.parse_pat_tuple_struct(qself, path)?
|
||||||
} else {
|
} else {
|
||||||
PatKind::Path(qself, path)
|
match self.maybe_recover_trailing_expr(span, false) {
|
||||||
|
Some(guar) => PatKind::Err(guar),
|
||||||
|
None => PatKind::Path(qself, path),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if matches!(self.token.kind, token::Lifetime(_))
|
} else if matches!(self.token.kind, token::Lifetime(_))
|
||||||
// In pattern position, we're totally fine with using "next token isn't colon"
|
// In pattern position, we're totally fine with using "next token isn't colon"
|
||||||
|
@ -470,10 +562,17 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
// Try to parse everything else as literal with optional minus
|
// Try to parse everything else as literal with optional minus
|
||||||
match self.parse_literal_maybe_minus() {
|
match self.parse_literal_maybe_minus() {
|
||||||
Ok(begin) => match self.parse_range_end() {
|
Ok(begin) => {
|
||||||
|
let begin = match self.maybe_recover_trailing_expr(begin.span, false) {
|
||||||
|
Some(_) => self.mk_expr_err(begin.span),
|
||||||
|
None => begin,
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.parse_range_end() {
|
||||||
Some(form) => self.parse_pat_range_begin_with(begin, form)?,
|
Some(form) => self.parse_pat_range_begin_with(begin, form)?,
|
||||||
None => PatKind::Lit(begin),
|
None => PatKind::Lit(begin),
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Err(err) => return self.fatal_unexpected_non_pat(err, expected),
|
Err(err) => return self.fatal_unexpected_non_pat(err, expected),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -615,6 +714,21 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
self.parse_pat_range_begin_with(begin.clone(), form)?
|
self.parse_pat_range_begin_with(begin.clone(), form)?
|
||||||
}
|
}
|
||||||
|
// recover ranges with parentheses around the `(start)..`
|
||||||
|
PatKind::Err(_)
|
||||||
|
if self.may_recover()
|
||||||
|
&& let Some(form) = self.parse_range_end() =>
|
||||||
|
{
|
||||||
|
self.dcx().emit_err(UnexpectedParenInRangePat {
|
||||||
|
span: vec![open_paren, close_paren],
|
||||||
|
sugg: UnexpectedParenInRangePatSugg {
|
||||||
|
start_span: open_paren,
|
||||||
|
end_span: close_paren,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form)?
|
||||||
|
}
|
||||||
|
|
||||||
// (pat) with optional parentheses
|
// (pat) with optional parentheses
|
||||||
_ => PatKind::Paren(pat),
|
_ => PatKind::Paren(pat),
|
||||||
|
@ -853,6 +967,8 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_literal_maybe_minus()
|
self.parse_literal_maybe_minus()
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
let recovered = self.maybe_recover_trailing_expr(bound.span, true);
|
||||||
|
|
||||||
// recover trailing `)`
|
// recover trailing `)`
|
||||||
if let Some(open_paren) = open_paren {
|
if let Some(open_paren) = open_paren {
|
||||||
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
|
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
|
||||||
|
@ -866,7 +982,10 @@ impl<'a> Parser<'a> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(bound)
|
Ok(match recovered {
|
||||||
|
Some(_) => self.mk_expr_err(bound.span),
|
||||||
|
None => bound,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this the start of a pattern beginning with a path?
|
/// Is this the start of a pattern beginning with a path?
|
||||||
|
@ -929,7 +1048,17 @@ impl<'a> Parser<'a> {
|
||||||
.create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span }));
|
.create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span }));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(PatKind::Ident(binding_annotation, ident, sub))
|
// Check for method calls after the `ident`,
|
||||||
|
// but not `ident @ subpat` as `subpat` was already checked and `ident` continues with `@`.
|
||||||
|
|
||||||
|
let pat = if sub.is_none()
|
||||||
|
&& let Some(guar) = self.maybe_recover_trailing_expr(ident.span, false)
|
||||||
|
{
|
||||||
|
PatKind::Err(guar)
|
||||||
|
} else {
|
||||||
|
PatKind::Ident(binding_annotation, ident, sub)
|
||||||
|
};
|
||||||
|
Ok(pat)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
|
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
|
||||||
|
|
|
@ -328,11 +328,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
hir_visit::walk_expr(self, e)
|
hir_visit::walk_expr(self, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_let_expr(&mut self, lex: &'v hir::Let<'v>) {
|
|
||||||
self.record("Let", Id::Node(lex.hir_id), lex);
|
|
||||||
hir_visit::walk_let_expr(self, lex)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) {
|
fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) {
|
||||||
self.record("ExprField", Id::Node(f.hir_id), f);
|
self.record("ExprField", Id::Node(f.hir_id), f);
|
||||||
hir_visit::walk_expr_field(self, f)
|
hir_visit::walk_expr_field(self, f)
|
||||||
|
|
|
@ -5,7 +5,6 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# tidy-alphabetical-start
|
# tidy-alphabetical-start
|
||||||
derivative = "2.2.0"
|
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
rustc_apfloat = "0.2.0"
|
rustc_apfloat = "0.2.0"
|
||||||
rustc_arena = { path = "../rustc_arena", optional = true }
|
rustc_arena = { path = "../rustc_arena", optional = true }
|
||||||
|
|
|
@ -151,6 +151,7 @@
|
||||||
use std::cmp::{self, max, min, Ordering};
|
use std::cmp::{self, max, min, Ordering};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
@ -648,8 +649,6 @@ impl OpaqueId {
|
||||||
/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a
|
/// `specialize_constructor` returns the list of fields corresponding to a pattern, given a
|
||||||
/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
|
/// constructor. `Constructor::apply` reconstructs the pattern from a pair of `Constructor` and
|
||||||
/// `Fields`.
|
/// `Fields`.
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derivative(Debug(bound = ""), Clone(bound = ""), PartialEq(bound = ""))]
|
|
||||||
pub enum Constructor<Cx: TypeCx> {
|
pub enum Constructor<Cx: TypeCx> {
|
||||||
/// Tuples and structs.
|
/// Tuples and structs.
|
||||||
Struct,
|
Struct,
|
||||||
|
@ -692,6 +691,101 @@ pub enum Constructor<Cx: TypeCx> {
|
||||||
Missing,
|
Missing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Cx: TypeCx> Clone for Constructor<Cx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Constructor::Struct => Constructor::Struct,
|
||||||
|
Constructor::Variant(idx) => Constructor::Variant(idx.clone()),
|
||||||
|
Constructor::Ref => Constructor::Ref,
|
||||||
|
Constructor::Slice(slice) => Constructor::Slice(slice.clone()),
|
||||||
|
Constructor::UnionField => Constructor::UnionField,
|
||||||
|
Constructor::Bool(b) => Constructor::Bool(b.clone()),
|
||||||
|
Constructor::IntRange(range) => Constructor::IntRange(range.clone()),
|
||||||
|
Constructor::F32Range(lo, hi, end) => {
|
||||||
|
Constructor::F32Range(lo.clone(), hi.clone(), end.clone())
|
||||||
|
}
|
||||||
|
Constructor::F64Range(lo, hi, end) => {
|
||||||
|
Constructor::F64Range(lo.clone(), hi.clone(), end.clone())
|
||||||
|
}
|
||||||
|
Constructor::Str(value) => Constructor::Str(value.clone()),
|
||||||
|
Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()),
|
||||||
|
Constructor::Or => Constructor::Or,
|
||||||
|
Constructor::Wildcard => Constructor::Wildcard,
|
||||||
|
Constructor::NonExhaustive => Constructor::NonExhaustive,
|
||||||
|
Constructor::Hidden => Constructor::Hidden,
|
||||||
|
Constructor::Missing => Constructor::Missing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Cx: TypeCx> fmt::Debug for Constructor<Cx> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Constructor::Struct => f.debug_tuple("Struct").finish(),
|
||||||
|
Constructor::Variant(idx) => f.debug_tuple("Variant").field(idx).finish(),
|
||||||
|
Constructor::Ref => f.debug_tuple("Ref").finish(),
|
||||||
|
Constructor::Slice(slice) => f.debug_tuple("Slice").field(slice).finish(),
|
||||||
|
Constructor::UnionField => f.debug_tuple("UnionField").finish(),
|
||||||
|
Constructor::Bool(b) => f.debug_tuple("Bool").field(b).finish(),
|
||||||
|
Constructor::IntRange(range) => f.debug_tuple("IntRange").field(range).finish(),
|
||||||
|
Constructor::F32Range(lo, hi, end) => {
|
||||||
|
f.debug_tuple("F32Range").field(lo).field(hi).field(end).finish()
|
||||||
|
}
|
||||||
|
Constructor::F64Range(lo, hi, end) => {
|
||||||
|
f.debug_tuple("F64Range").field(lo).field(hi).field(end).finish()
|
||||||
|
}
|
||||||
|
Constructor::Str(value) => f.debug_tuple("Str").field(value).finish(),
|
||||||
|
Constructor::Opaque(inner) => f.debug_tuple("Opaque").field(inner).finish(),
|
||||||
|
Constructor::Or => f.debug_tuple("Or").finish(),
|
||||||
|
Constructor::Wildcard => f.debug_tuple("Wildcard").finish(),
|
||||||
|
Constructor::NonExhaustive => f.debug_tuple("NonExhaustive").finish(),
|
||||||
|
Constructor::Hidden => f.debug_tuple("Hidden").finish(),
|
||||||
|
Constructor::Missing => f.debug_tuple("Missing").finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Cx: TypeCx> PartialEq for Constructor<Cx> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
(mem::discriminant(self) == mem::discriminant(other))
|
||||||
|
&& match (self, other) {
|
||||||
|
(Constructor::Struct, Constructor::Struct) => true,
|
||||||
|
(Constructor::Variant(self_variant), Constructor::Variant(other_variant)) => {
|
||||||
|
self_variant == other_variant
|
||||||
|
}
|
||||||
|
(Constructor::Ref, Constructor::Ref) => true,
|
||||||
|
(Constructor::Slice(self_slice), Constructor::Slice(other_slice)) => {
|
||||||
|
self_slice == other_slice
|
||||||
|
}
|
||||||
|
(Constructor::UnionField, Constructor::UnionField) => true,
|
||||||
|
(Constructor::Bool(self_b), Constructor::Bool(other_b)) => self_b == other_b,
|
||||||
|
(Constructor::IntRange(self_range), Constructor::IntRange(other_range)) => {
|
||||||
|
self_range == other_range
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Constructor::F32Range(self_lo, self_hi, self_end),
|
||||||
|
Constructor::F32Range(other_lo, other_hi, other_end),
|
||||||
|
) => self_lo == other_lo && self_hi == other_hi && self_end == other_end,
|
||||||
|
(
|
||||||
|
Constructor::F64Range(self_lo, self_hi, self_end),
|
||||||
|
Constructor::F64Range(other_lo, other_hi, other_end),
|
||||||
|
) => self_lo == other_lo && self_hi == other_hi && self_end == other_end,
|
||||||
|
(Constructor::Str(self_value), Constructor::Str(other_value)) => {
|
||||||
|
self_value == other_value
|
||||||
|
}
|
||||||
|
(Constructor::Opaque(self_inner), Constructor::Opaque(other_inner)) => {
|
||||||
|
self_inner == other_inner
|
||||||
|
}
|
||||||
|
(Constructor::Or, Constructor::Or) => true,
|
||||||
|
(Constructor::Wildcard, Constructor::Wildcard) => true,
|
||||||
|
(Constructor::NonExhaustive, Constructor::NonExhaustive) => true,
|
||||||
|
(Constructor::Hidden, Constructor::Hidden) => true,
|
||||||
|
(Constructor::Missing, Constructor::Missing) => true,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Cx: TypeCx> Constructor<Cx> {
|
impl<Cx: TypeCx> Constructor<Cx> {
|
||||||
pub(crate) fn is_non_exhaustive(&self) -> bool {
|
pub(crate) fn is_non_exhaustive(&self) -> bool {
|
||||||
matches!(self, NonExhaustive)
|
matches!(self, NonExhaustive)
|
||||||
|
|
|
@ -136,23 +136,35 @@ pub trait TypeCx: Sized + fmt::Debug {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Context that provides information global to a match.
|
/// Context that provides information global to a match.
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derivative(Clone(bound = ""), Copy(bound = ""))]
|
|
||||||
pub struct MatchCtxt<'a, Cx: TypeCx> {
|
pub struct MatchCtxt<'a, Cx: TypeCx> {
|
||||||
/// The context for type information.
|
/// The context for type information.
|
||||||
pub tycx: &'a Cx,
|
pub tycx: &'a Cx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, Cx: TypeCx> Clone for MatchCtxt<'a, Cx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { tycx: self.tycx }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Cx: TypeCx> Copy for MatchCtxt<'a, Cx> {}
|
||||||
|
|
||||||
/// The arm of a match expression.
|
/// The arm of a match expression.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derivative(Clone(bound = ""), Copy(bound = ""))]
|
|
||||||
pub struct MatchArm<'p, Cx: TypeCx> {
|
pub struct MatchArm<'p, Cx: TypeCx> {
|
||||||
pub pat: &'p DeconstructedPat<'p, Cx>,
|
pub pat: &'p DeconstructedPat<'p, Cx>,
|
||||||
pub has_guard: bool,
|
pub has_guard: bool,
|
||||||
pub arm_data: Cx::ArmData,
|
pub arm_data: Cx::ArmData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'p, Cx: TypeCx> Clone for MatchArm<'p, Cx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { pat: self.pat, has_guard: self.has_guard, arm_data: self.arm_data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, Cx: TypeCx> Copy for MatchArm<'p, Cx> {}
|
||||||
|
|
||||||
/// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are
|
/// The entrypoint for this crate. Computes whether a match is exhaustive and which of its arms are
|
||||||
/// useful, and runs some lints.
|
/// useful, and runs some lints.
|
||||||
#[cfg(feature = "rustc")]
|
#[cfg(feature = "rustc")]
|
||||||
|
|
|
@ -218,8 +218,6 @@ impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
|
||||||
/// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input.
|
/// algorithm. Do not use `Wild` to represent a wildcard pattern comping from user input.
|
||||||
///
|
///
|
||||||
/// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard.
|
/// This is morally `Option<&'p DeconstructedPat>` where `None` is interpreted as a wildcard.
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derivative(Clone(bound = ""), Copy(bound = ""))]
|
|
||||||
pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
|
pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
|
||||||
/// A non-user-provided wildcard, created during specialization.
|
/// A non-user-provided wildcard, created during specialization.
|
||||||
Wild,
|
Wild,
|
||||||
|
@ -227,6 +225,17 @@ pub(crate) enum PatOrWild<'p, Cx: TypeCx> {
|
||||||
Pat(&'p DeconstructedPat<'p, Cx>),
|
Pat(&'p DeconstructedPat<'p, Cx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'p, Cx: TypeCx> Clone for PatOrWild<'p, Cx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
PatOrWild::Wild => PatOrWild::Wild,
|
||||||
|
PatOrWild::Pat(pat) => PatOrWild::Pat(pat),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, Cx: TypeCx> Copy for PatOrWild<'p, Cx> {}
|
||||||
|
|
||||||
impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
|
impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
|
||||||
pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> {
|
pub(crate) fn as_pat(&self) -> Option<&'p DeconstructedPat<'p, Cx>> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -289,14 +298,28 @@ impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> {
|
||||||
|
|
||||||
/// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
|
/// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
|
||||||
/// purposes. As such they don't use interning and can be cloned.
|
/// purposes. As such they don't use interning and can be cloned.
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derivative(Debug(bound = ""), Clone(bound = ""))]
|
|
||||||
pub struct WitnessPat<Cx: TypeCx> {
|
pub struct WitnessPat<Cx: TypeCx> {
|
||||||
ctor: Constructor<Cx>,
|
ctor: Constructor<Cx>,
|
||||||
pub(crate) fields: Vec<WitnessPat<Cx>>,
|
pub(crate) fields: Vec<WitnessPat<Cx>>,
|
||||||
ty: Cx::Ty,
|
ty: Cx::Ty,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Cx: TypeCx> Clone for WitnessPat<Cx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { ctor: self.ctor.clone(), fields: self.fields.clone(), ty: self.ty.clone() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Cx: TypeCx> fmt::Debug for WitnessPat<Cx> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt.debug_struct("WitnessPat")
|
||||||
|
.field("ctor", &self.ctor)
|
||||||
|
.field("fields", &self.fields)
|
||||||
|
.field("ty", &self.ty)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Cx: TypeCx> WitnessPat<Cx> {
|
impl<Cx: TypeCx> WitnessPat<Cx> {
|
||||||
pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
|
pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
|
||||||
Self { ctor, fields, ty }
|
Self { ctor, fields, ty }
|
||||||
|
|
|
@ -46,11 +46,15 @@ pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcMatchCheckCtxt<'p, '
|
||||||
///
|
///
|
||||||
/// Use `.inner()` or deref to get to the `Ty<'tcx>`.
|
/// Use `.inner()` or deref to get to the `Ty<'tcx>`.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[derivative(Debug = "transparent")]
|
|
||||||
pub struct RevealedTy<'tcx>(Ty<'tcx>);
|
pub struct RevealedTy<'tcx>(Ty<'tcx>);
|
||||||
|
|
||||||
|
impl<'tcx> fmt::Debug for RevealedTy<'tcx> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.0.fmt(fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> std::ops::Deref for RevealedTy<'tcx> {
|
impl<'tcx> std::ops::Deref for RevealedTy<'tcx> {
|
||||||
type Target = Ty<'tcx>;
|
type Target = Ty<'tcx>;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
|
|
@ -731,16 +731,26 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Context that provides information local to a place under investigation.
|
/// Context that provides information local to a place under investigation.
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derivative(Debug(bound = ""), Clone(bound = ""), Copy(bound = ""))]
|
|
||||||
pub(crate) struct PlaceCtxt<'a, Cx: TypeCx> {
|
pub(crate) struct PlaceCtxt<'a, Cx: TypeCx> {
|
||||||
#[derivative(Debug = "ignore")]
|
|
||||||
pub(crate) mcx: MatchCtxt<'a, Cx>,
|
pub(crate) mcx: MatchCtxt<'a, Cx>,
|
||||||
/// Type of the place under investigation.
|
/// Type of the place under investigation.
|
||||||
#[derivative(Clone(clone_with = "Clone::clone"))] // See rust-derivative#90
|
|
||||||
pub(crate) ty: &'a Cx::Ty,
|
pub(crate) ty: &'a Cx::Ty,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, Cx: TypeCx> Clone for PlaceCtxt<'a, Cx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { mcx: self.mcx, ty: self.ty }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Cx: TypeCx> Copy for PlaceCtxt<'a, Cx> {}
|
||||||
|
|
||||||
|
impl<'a, Cx: TypeCx> fmt::Debug for PlaceCtxt<'a, Cx> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt.debug_struct("PlaceCtxt").field("ty", self.ty).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
|
impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
|
||||||
/// A `PlaceCtxt` when code other than `is_useful` needs one.
|
/// A `PlaceCtxt` when code other than `is_useful` needs one.
|
||||||
#[cfg_attr(not(feature = "rustc"), allow(dead_code))]
|
#[cfg_attr(not(feature = "rustc"), allow(dead_code))]
|
||||||
|
@ -813,8 +823,6 @@ impl fmt::Display for ValidityConstraint {
|
||||||
// The three lifetimes are:
|
// The three lifetimes are:
|
||||||
// - 'p coming from the input
|
// - 'p coming from the input
|
||||||
// - Cx global compilation context
|
// - Cx global compilation context
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derivative(Clone(bound = ""))]
|
|
||||||
struct PatStack<'p, Cx: TypeCx> {
|
struct PatStack<'p, Cx: TypeCx> {
|
||||||
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
|
// Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well.
|
||||||
pats: SmallVec<[PatOrWild<'p, Cx>; 2]>,
|
pats: SmallVec<[PatOrWild<'p, Cx>; 2]>,
|
||||||
|
@ -824,6 +832,12 @@ struct PatStack<'p, Cx: TypeCx> {
|
||||||
relevant: bool,
|
relevant: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'p, Cx: TypeCx> Clone for PatStack<'p, Cx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { pats: self.pats.clone(), relevant: self.relevant }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
|
impl<'p, Cx: TypeCx> PatStack<'p, Cx> {
|
||||||
fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self {
|
fn from_pattern(pat: &'p DeconstructedPat<'p, Cx>) -> Self {
|
||||||
PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true }
|
PatStack { pats: smallvec![PatOrWild::Pat(pat)], relevant: true }
|
||||||
|
@ -1184,10 +1198,20 @@ impl<'p, Cx: TypeCx> fmt::Debug for Matrix<'p, Cx> {
|
||||||
/// The final `Pair(Some(_), true)` is then the resulting witness.
|
/// The final `Pair(Some(_), true)` is then the resulting witness.
|
||||||
///
|
///
|
||||||
/// See the top of the file for more detailed explanations and examples.
|
/// See the top of the file for more detailed explanations and examples.
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derivative(Debug(bound = ""), Clone(bound = ""))]
|
|
||||||
struct WitnessStack<Cx: TypeCx>(Vec<WitnessPat<Cx>>);
|
struct WitnessStack<Cx: TypeCx>(Vec<WitnessPat<Cx>>);
|
||||||
|
|
||||||
|
impl<Cx: TypeCx> Clone for WitnessStack<Cx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Cx: TypeCx> fmt::Debug for WitnessStack<Cx> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt.debug_tuple("WitnessStack").field(&self.0).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Cx: TypeCx> WitnessStack<Cx> {
|
impl<Cx: TypeCx> WitnessStack<Cx> {
|
||||||
/// Asserts that the witness contains a single pattern, and returns it.
|
/// Asserts that the witness contains a single pattern, and returns it.
|
||||||
fn single_pattern(self) -> WitnessPat<Cx> {
|
fn single_pattern(self) -> WitnessPat<Cx> {
|
||||||
|
@ -1232,18 +1256,28 @@ impl<Cx: TypeCx> WitnessStack<Cx> {
|
||||||
///
|
///
|
||||||
/// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single
|
/// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single
|
||||||
/// column, which contains the patterns that are missing for the match to be exhaustive.
|
/// column, which contains the patterns that are missing for the match to be exhaustive.
|
||||||
#[derive(derivative::Derivative)]
|
|
||||||
#[derivative(Debug(bound = ""), Clone(bound = ""))]
|
|
||||||
struct WitnessMatrix<Cx: TypeCx>(Vec<WitnessStack<Cx>>);
|
struct WitnessMatrix<Cx: TypeCx>(Vec<WitnessStack<Cx>>);
|
||||||
|
|
||||||
|
impl<Cx: TypeCx> Clone for WitnessMatrix<Cx> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Cx: TypeCx> fmt::Debug for WitnessMatrix<Cx> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt.debug_tuple("WitnessMatrix").field(&self.0).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Cx: TypeCx> WitnessMatrix<Cx> {
|
impl<Cx: TypeCx> WitnessMatrix<Cx> {
|
||||||
/// New matrix with no witnesses.
|
/// New matrix with no witnesses.
|
||||||
fn empty() -> Self {
|
fn empty() -> Self {
|
||||||
WitnessMatrix(vec![])
|
WitnessMatrix(Vec::new())
|
||||||
}
|
}
|
||||||
/// New matrix with one `()` witness, i.e. with no columns.
|
/// New matrix with one `()` witness, i.e. with no columns.
|
||||||
fn unit_witness() -> Self {
|
fn unit_witness() -> Self {
|
||||||
WitnessMatrix(vec![WitnessStack(vec![])])
|
WitnessMatrix(vec![WitnessStack(Vec::new())])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this has any witnesses.
|
/// Whether this has any witnesses.
|
||||||
|
|
|
@ -2105,7 +2105,7 @@ fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
|
||||||
|
|
||||||
/// Replaces `\r\n` with `\n` in-place in `src`.
|
/// Replaces `\r\n` with `\n` in-place in `src`.
|
||||||
///
|
///
|
||||||
/// Returns error if there's a lone `\r` in the string.
|
/// Leaves any occurrences of lone `\r` unchanged.
|
||||||
fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
|
fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
|
||||||
if !src.as_bytes().contains(&b'\r') {
|
if !src.as_bytes().contains(&b'\r') {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -939,8 +939,11 @@ impl<T, A: Allocator> Rc<T, A> {
|
||||||
/// it is guaranteed that exactly one of the calls returns the inner value.
|
/// it is guaranteed that exactly one of the calls returns the inner value.
|
||||||
/// This means in particular that the inner value is not dropped.
|
/// This means in particular that the inner value is not dropped.
|
||||||
///
|
///
|
||||||
/// This is equivalent to `Rc::try_unwrap(this).ok()`. (Note that these are not equivalent for
|
/// [`Rc::try_unwrap`] is conceptually similar to `Rc::into_inner`.
|
||||||
/// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`.)
|
/// And while they are meant for different use-cases, `Rc::into_inner(this)`
|
||||||
|
/// is in fact equivalent to <code>[Rc::try_unwrap]\(this).[ok][Result::ok]()</code>.
|
||||||
|
/// (Note that the same kind of equivalence does **not** hold true for
|
||||||
|
/// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`!)
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rc_into_inner", since = "1.70.0")]
|
#[stable(feature = "rc_into_inner", since = "1.70.0")]
|
||||||
pub fn into_inner(this: Self) -> Option<T> {
|
pub fn into_inner(this: Self) -> Option<T> {
|
||||||
|
|
|
@ -983,9 +983,13 @@ impl<T, A: Allocator> Arc<T, A> {
|
||||||
/// it is guaranteed that exactly one of the calls returns the inner value.
|
/// it is guaranteed that exactly one of the calls returns the inner value.
|
||||||
/// This means in particular that the inner value is not dropped.
|
/// This means in particular that the inner value is not dropped.
|
||||||
///
|
///
|
||||||
/// The similar expression `Arc::try_unwrap(this).ok()` does not
|
/// [`Arc::try_unwrap`] is conceptually similar to `Arc::into_inner`, but it
|
||||||
/// offer such a guarantee. See the last example below
|
/// is meant for different use-cases. If used as a direct replacement
|
||||||
/// and the documentation of [`Arc::try_unwrap`].
|
/// for `Arc::into_inner` anyway, such as with the expression
|
||||||
|
/// <code>[Arc::try_unwrap]\(this).[ok][Result::ok]()</code>, then it does
|
||||||
|
/// **not** give the same guarantee as described in the previous paragraph.
|
||||||
|
/// For more information, see the examples below and read the documentation
|
||||||
|
/// of [`Arc::try_unwrap`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|
|
@ -1384,6 +1384,30 @@ mod prim_usize {}
|
||||||
/// work on references as well as they do on owned values! The implementations described here are
|
/// work on references as well as they do on owned values! The implementations described here are
|
||||||
/// meant for generic contexts, where the final type `T` is a type parameter or otherwise not
|
/// meant for generic contexts, where the final type `T` is a type parameter or otherwise not
|
||||||
/// locally known.
|
/// locally known.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, when such values cross an API
|
||||||
|
/// boundary, the following invariants must generally be upheld:
|
||||||
|
///
|
||||||
|
/// * `t` is aligned to `align_of_val(t)`
|
||||||
|
/// * `t` is dereferenceable for `size_of_val(t)` many bytes
|
||||||
|
///
|
||||||
|
/// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range
|
||||||
|
/// `[a, a + N)` is all contained within a single [allocated object].
|
||||||
|
///
|
||||||
|
/// For instance, this means that unsafe code in a safe function may assume these invariants are
|
||||||
|
/// ensured of arguments passed by the caller, and it may assume that these invariants are ensured
|
||||||
|
/// of return values from any safe functions it calls. In most cases, the inverse is also true:
|
||||||
|
/// unsafe code must not violate these invariants when passing arguments to safe functions or
|
||||||
|
/// returning values from safe functions; such violations may result in undefined behavior. Where
|
||||||
|
/// exceptions to this latter requirement exist, they will be called out explicitly in documentation.
|
||||||
|
///
|
||||||
|
/// It is not decided yet whether unsafe code may violate these invariants temporarily on internal
|
||||||
|
/// data. As a consequence, unsafe code which violates these invariants temporarily on internal data
|
||||||
|
/// may become unsound in future versions of Rust depending on how this question is decided.
|
||||||
|
///
|
||||||
|
/// [allocated object]: ptr#allocated-object
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
mod prim_ref {}
|
mod prim_ref {}
|
||||||
|
|
||||||
|
|
|
@ -538,7 +538,4 @@ pub mod netc {
|
||||||
pub sin6_flowinfo: u32,
|
pub sin6_flowinfo: u32,
|
||||||
pub sin6_scope_id: u32,
|
pub sin6_scope_id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct sockaddr {}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,13 @@ impl fmt::Debug for ReadDir {
|
||||||
impl Iterator for ReadDir {
|
impl Iterator for ReadDir {
|
||||||
type Item = io::Result<DirEntry>;
|
type Item = io::Result<DirEntry>;
|
||||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||||
|
if self.handle.0 == c::INVALID_HANDLE_VALUE {
|
||||||
|
// This iterator was initialized with an `INVALID_HANDLE_VALUE` as its handle.
|
||||||
|
// Simply return `None` because this is only the case when `FindFirstFileW` in
|
||||||
|
// the construction of this iterator returns `ERROR_FILE_NOT_FOUND` which means
|
||||||
|
// no matchhing files can be found.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
if let Some(first) = self.first.take() {
|
if let Some(first) = self.first.take() {
|
||||||
if let Some(e) = DirEntry::new(&self.root, &first) {
|
if let Some(e) = DirEntry::new(&self.root, &first) {
|
||||||
return Some(Ok(e));
|
return Some(Ok(e));
|
||||||
|
@ -1068,6 +1075,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut wfd = mem::zeroed();
|
let mut wfd = mem::zeroed();
|
||||||
let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd);
|
let find_handle = c::FindFirstFileW(path.as_ptr(), &mut wfd);
|
||||||
|
|
||||||
if find_handle != c::INVALID_HANDLE_VALUE {
|
if find_handle != c::INVALID_HANDLE_VALUE {
|
||||||
Ok(ReadDir {
|
Ok(ReadDir {
|
||||||
handle: FindNextFileHandle(find_handle),
|
handle: FindNextFileHandle(find_handle),
|
||||||
|
@ -1075,7 +1083,31 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
|
||||||
first: Some(wfd),
|
first: Some(wfd),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::last_os_error())
|
// The status `ERROR_FILE_NOT_FOUND` is returned by the `FindFirstFileW` function
|
||||||
|
// if no matching files can be found, but not necessarily that the path to find the
|
||||||
|
// files in does not exist.
|
||||||
|
//
|
||||||
|
// Hence, a check for whether the path to search in exists is added when the last
|
||||||
|
// os error returned by Windows is `ERROR_FILE_NOT_FOUND` to handle this scenario.
|
||||||
|
// If that is the case, an empty `ReadDir` iterator is returned as it returns `None`
|
||||||
|
// in the initial `.next()` invocation because `ERROR_NO_MORE_FILES` would have been
|
||||||
|
// returned by the `FindNextFileW` function.
|
||||||
|
//
|
||||||
|
// See issue #120040: https://github.com/rust-lang/rust/issues/120040.
|
||||||
|
let last_error = api::get_last_error();
|
||||||
|
if last_error.code == c::ERROR_FILE_NOT_FOUND {
|
||||||
|
return Ok(ReadDir {
|
||||||
|
handle: FindNextFileHandle(find_handle),
|
||||||
|
root: Arc::new(root),
|
||||||
|
first: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just return the error constructed from the raw OS error if the above is not the case.
|
||||||
|
//
|
||||||
|
// Note: `ERROR_PATH_NOT_FOUND` would have been returned by the `FindFirstFileW` function
|
||||||
|
// when the path to search in does not exist in the first place.
|
||||||
|
Err(Error::from_raw_os_error(last_error.code as i32))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1836,7 +1836,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
||||||
TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
|
TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
|
||||||
TyKind::Array(ty, ref length) => {
|
TyKind::Array(ty, ref length) => {
|
||||||
let length = match length {
|
let length = match length {
|
||||||
hir::ArrayLen::Infer(_, _) => "_".to_string(),
|
hir::ArrayLen::Infer(..) => "_".to_string(),
|
||||||
hir::ArrayLen::Body(anon_const) => {
|
hir::ArrayLen::Body(anon_const) => {
|
||||||
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
|
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
|
||||||
// as we currently do not supply the parent generics to anonymous constants
|
// as we currently do not supply the parent generics to anonymous constants
|
||||||
|
|
|
@ -17,12 +17,18 @@ fn main() {
|
||||||
}
|
}
|
||||||
match x as i32 {
|
match x as i32 {
|
||||||
0..5+1 => errors_only.push(x),
|
0..5+1 => errors_only.push(x),
|
||||||
//~^ error: expected one of `=>`, `if`, or `|`, found `+`
|
//~^ error: expected a pattern range bound, found an expression
|
||||||
|
//~| error: exclusive range pattern syntax is experimental
|
||||||
1 | -3..0 => first_or.push(x),
|
1 | -3..0 => first_or.push(x),
|
||||||
|
//~^ error: exclusive range pattern syntax is experimental
|
||||||
y @ (0..5 | 6) => or_two.push(y),
|
y @ (0..5 | 6) => or_two.push(y),
|
||||||
|
//~^ error: exclusive range pattern syntax is experimental
|
||||||
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
|
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
|
||||||
|
//~^ error: exclusive range pattern syntax is experimental
|
||||||
|
//~| error: inline-const in pattern position is experimental
|
||||||
y @ -5.. => range_from.push(y),
|
y @ -5.. => range_from.push(y),
|
||||||
y @ ..-7 => assert_eq!(y, -8),
|
y @ ..-7 => assert_eq!(y, -8),
|
||||||
|
//~^ error: exclusive range pattern syntax is experimental
|
||||||
y => bottom.push(y),
|
y => bottom.push(y),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `=>`, `if`, or `|`, found `+`
|
error: expected a pattern range bound, found an expression
|
||||||
--> $DIR/range_pat_interactions1.rs:19:17
|
--> $DIR/range_pat_interactions1.rs:19:16
|
||||||
|
|
|
|
||||||
LL | 0..5+1 => errors_only.push(x),
|
LL | 0..5+1 => errors_only.push(x),
|
||||||
| ^ expected one of `=>`, `if`, or `|`
|
| ^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
error[E0408]: variable `n` is not bound in all patterns
|
error[E0408]: variable `n` is not bound in all patterns
|
||||||
--> $DIR/range_pat_interactions1.rs:10:25
|
--> $DIR/range_pat_interactions1.rs:10:25
|
||||||
|
@ -12,6 +12,16 @@ LL | if let n @ 2..3|4 = x {
|
||||||
| |
|
| |
|
||||||
| variable not in all patterns
|
| variable not in all patterns
|
||||||
|
|
||||||
|
error[E0658]: inline-const in pattern position is experimental
|
||||||
|
--> $DIR/range_pat_interactions1.rs:26:20
|
||||||
|
|
|
||||||
|
LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
|
||||||
|
= help: add `#![feature(inline_const_pat)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
error[E0658]: exclusive range pattern syntax is experimental
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
--> $DIR/range_pat_interactions1.rs:10:20
|
--> $DIR/range_pat_interactions1.rs:10:20
|
||||||
|
|
|
|
||||||
|
@ -34,7 +44,62 @@ LL | } else if let 2..3 | 4 = x {
|
||||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
= help: use an inclusive range pattern, like N..=M
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
|
--> $DIR/range_pat_interactions1.rs:19:13
|
||||||
|
|
|
||||||
|
LL | 0..5+1 => errors_only.push(x),
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
|
||||||
|
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
|
--> $DIR/range_pat_interactions1.rs:22:17
|
||||||
|
|
|
||||||
|
LL | 1 | -3..0 => first_or.push(x),
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
|
||||||
|
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
|
--> $DIR/range_pat_interactions1.rs:24:18
|
||||||
|
|
|
||||||
|
LL | y @ (0..5 | 6) => or_two.push(y),
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
|
||||||
|
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
|
--> $DIR/range_pat_interactions1.rs:26:17
|
||||||
|
|
|
||||||
|
LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
|
||||||
|
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
|
--> $DIR/range_pat_interactions1.rs:30:17
|
||||||
|
|
|
||||||
|
LL | y @ ..-7 => assert_eq!(y, -8),
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
|
||||||
|
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
|
error: aborting due to 10 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0408, E0658.
|
Some errors have detailed explanations: E0408, E0658.
|
||||||
For more information about an error, try `rustc --explain E0408`.
|
For more information about an error, try `rustc --explain E0408`.
|
||||||
|
|
|
@ -8,12 +8,18 @@ fn main() {
|
||||||
for x in -9 + 1..=(9 - 2) {
|
for x in -9 + 1..=(9 - 2) {
|
||||||
match x as i32 {
|
match x as i32 {
|
||||||
0..=(5+1) => errors_only.push(x),
|
0..=(5+1) => errors_only.push(x),
|
||||||
//~^ error: expected `)`, found `+`
|
//~^ error: expected a pattern range bound, found an expression
|
||||||
|
//~| error: range pattern bounds cannot have parentheses
|
||||||
1 | -3..0 => first_or.push(x),
|
1 | -3..0 => first_or.push(x),
|
||||||
|
//~^ error: exclusive range pattern syntax is experimental
|
||||||
y @ (0..5 | 6) => or_two.push(y),
|
y @ (0..5 | 6) => or_two.push(y),
|
||||||
|
//~^ error: exclusive range pattern syntax is experimental
|
||||||
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
|
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
|
||||||
|
//~^ error: inline-const in pattern position is experimental
|
||||||
|
//~| error: exclusive range pattern syntax is experimental
|
||||||
y @ -5.. => range_from.push(y),
|
y @ -5.. => range_from.push(y),
|
||||||
y @ ..-7 => assert_eq!(y, -8),
|
y @ ..-7 => assert_eq!(y, -8),
|
||||||
|
//~^ error: exclusive range pattern syntax is experimental
|
||||||
y => bottom.push(y),
|
y => bottom.push(y),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,75 @@
|
||||||
error: expected `)`, found `+`
|
error: expected a pattern range bound, found an expression
|
||||||
--> $DIR/range_pat_interactions2.rs:10:19
|
--> $DIR/range_pat_interactions2.rs:10:18
|
||||||
|
|
|
|
||||||
LL | 0..=(5+1) => errors_only.push(x),
|
LL | 0..=(5+1) => errors_only.push(x),
|
||||||
| ^ expected `)`
|
| ^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: range pattern bounds cannot have parentheses
|
||||||
|
--> $DIR/range_pat_interactions2.rs:10:17
|
||||||
|
|
|
||||||
|
LL | 0..=(5+1) => errors_only.push(x),
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
help: remove these parentheses
|
||||||
|
|
|
||||||
|
LL - 0..=(5+1) => errors_only.push(x),
|
||||||
|
LL + 0..=5+1 => errors_only.push(x),
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0658]: inline-const in pattern position is experimental
|
||||||
|
--> $DIR/range_pat_interactions2.rs:17:20
|
||||||
|
|
|
||||||
|
LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
|
||||||
|
= help: add `#![feature(inline_const_pat)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
|
--> $DIR/range_pat_interactions2.rs:13:17
|
||||||
|
|
|
||||||
|
LL | 1 | -3..0 => first_or.push(x),
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
|
||||||
|
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
|
--> $DIR/range_pat_interactions2.rs:15:18
|
||||||
|
|
|
||||||
|
LL | y @ (0..5 | 6) => or_two.push(y),
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
|
||||||
|
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
|
--> $DIR/range_pat_interactions2.rs:17:17
|
||||||
|
|
|
||||||
|
LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
|
||||||
|
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
|
error[E0658]: exclusive range pattern syntax is experimental
|
||||||
|
--> $DIR/range_pat_interactions2.rs:21:17
|
||||||
|
|
|
||||||
|
LL | y @ ..-7 => assert_eq!(y, -8),
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
|
||||||
|
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
= help: use an inclusive range pattern, like N..=M
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// ignore-test (This is currently broken)
|
|
||||||
|
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![feature(const_mut_refs)]
|
#![feature(const_mut_refs)]
|
||||||
#![feature(inline_const_pat)]
|
#![feature(inline_const_pat)]
|
||||||
|
@ -9,6 +7,9 @@ use std::marker::PhantomData;
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct CovariantRef<'a, T: ?Sized>(&'a T);
|
||||||
|
|
||||||
impl<'a, T: ?Sized> InvariantRef<'a, T> {
|
impl<'a, T: ?Sized> InvariantRef<'a, T> {
|
||||||
pub const fn new(r: &'a T) -> Self {
|
pub const fn new(r: &'a T) -> Self {
|
||||||
InvariantRef(r, PhantomData)
|
InvariantRef(r, PhantomData)
|
||||||
|
@ -19,16 +20,30 @@ impl<'a> InvariantRef<'a, ()> {
|
||||||
pub const NEW: Self = InvariantRef::new(&());
|
pub const NEW: Self = InvariantRef::new(&());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> CovariantRef<'a, ()> {
|
||||||
|
pub const NEW: Self = CovariantRef(&());
|
||||||
|
}
|
||||||
|
|
||||||
fn match_invariant_ref<'a>() {
|
fn match_invariant_ref<'a>() {
|
||||||
let y = ();
|
let y = ();
|
||||||
match InvariantRef::new(&y) {
|
match InvariantRef::new(&y) {
|
||||||
//~^ ERROR `y` does not live long enough [E0597]
|
//~^ ERROR `y` does not live long enough [E0597]
|
||||||
// FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
|
|
||||||
// const block)
|
|
||||||
const { InvariantRef::<'a>::NEW } => (),
|
const { InvariantRef::<'a>::NEW } => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn match_covariant_ref<'a>() {
|
||||||
|
// Unclear if we should error here (should we be able to subtype the type of
|
||||||
|
// `y.0`), but using the associated const directly in the pattern also
|
||||||
|
// errors.
|
||||||
|
let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
|
||||||
|
//~^ ERROR lifetime may not live long enough
|
||||||
|
match y.0 {
|
||||||
|
const { CovariantRef::<'a>::NEW } => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match_invariant_ref();
|
match_invariant_ref();
|
||||||
|
match_covariant_ref();
|
||||||
}
|
}
|
||||||
|
|
28
tests/ui/inline-const/const-match-pat-lifetime-err.stderr
Normal file
28
tests/ui/inline-const/const-match-pat-lifetime-err.stderr
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
error[E0597]: `y` does not live long enough
|
||||||
|
--> $DIR/const-match-pat-lifetime-err.rs:29:29
|
||||||
|
|
|
||||||
|
LL | fn match_invariant_ref<'a>() {
|
||||||
|
| -- lifetime `'a` defined here
|
||||||
|
LL | let y = ();
|
||||||
|
| - binding `y` declared here
|
||||||
|
LL | match InvariantRef::new(&y) {
|
||||||
|
| ^^ borrowed value does not live long enough
|
||||||
|
LL |
|
||||||
|
LL | const { InvariantRef::<'a>::NEW } => (),
|
||||||
|
| --------------------------------- type annotation requires that `y` is borrowed for `'a`
|
||||||
|
LL | }
|
||||||
|
LL | }
|
||||||
|
| - `y` dropped here while still borrowed
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/const-match-pat-lifetime-err.rs:39:12
|
||||||
|
|
|
||||||
|
LL | fn match_covariant_ref<'a>() {
|
||||||
|
| -- lifetime `'a` defined here
|
||||||
|
...
|
||||||
|
LL | let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0597`.
|
|
@ -1,5 +1,3 @@
|
||||||
// ignore-test This is currently broken
|
|
||||||
|
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![feature(inline_const_pat)]
|
#![feature(inline_const_pat)]
|
||||||
|
|
||||||
|
|
19
tests/ui/inline-const/pat-unsafe-err.stderr
Normal file
19
tests/ui/inline-const/pat-unsafe-err.stderr
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
|
||||||
|
--> $DIR/pat-unsafe-err.rs:11:13
|
||||||
|
|
|
||||||
|
LL | require_unsafe();
|
||||||
|
| ^^^^^^^^^^^^^^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
|
error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
|
||||||
|
--> $DIR/pat-unsafe-err.rs:18:13
|
||||||
|
|
|
||||||
|
LL | require_unsafe()
|
||||||
|
| ^^^^^^^^^^^^^^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0133`.
|
|
@ -1,5 +1,4 @@
|
||||||
// check-pass
|
// check-pass
|
||||||
// ignore-test This is currently broken
|
|
||||||
|
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
#![warn(unused_unsafe)]
|
#![warn(unused_unsafe)]
|
||||||
|
|
20
tests/ui/inline-const/pat-unsafe.stderr
Normal file
20
tests/ui/inline-const/pat-unsafe.stderr
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
warning: unnecessary `unsafe` block
|
||||||
|
--> $DIR/pat-unsafe.rs:16:17
|
||||||
|
|
|
||||||
|
LL | unsafe {}
|
||||||
|
| ^^^^^^ unnecessary `unsafe` block
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/pat-unsafe.rs:4:9
|
||||||
|
|
|
||||||
|
LL | #![warn(unused_unsafe)]
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: unnecessary `unsafe` block
|
||||||
|
--> $DIR/pat-unsafe.rs:23:17
|
||||||
|
|
|
||||||
|
LL | unsafe {}
|
||||||
|
| ^^^^^^ unnecessary `unsafe` block
|
||||||
|
|
||||||
|
warning: 2 warnings emitted
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
|
let buf[0] = 0; //~ error: expected a pattern, found an expression
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
|
error: expected a pattern, found an expression
|
||||||
--> $DIR/issue-24197.rs:2:12
|
--> $DIR/issue-24197.rs:2:9
|
||||||
|
|
|
|
||||||
LL | let buf[0] = 0;
|
LL | let buf[0] = 0;
|
||||||
| ^ expected one of `:`, `;`, `=`, `@`, or `|`
|
| ^^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ static tmp : [&'static str; 2] = ["hello", "he"];
|
||||||
fn main() {
|
fn main() {
|
||||||
let z = "hello";
|
let z = "hello";
|
||||||
match z {
|
match z {
|
||||||
tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[`
|
tmp[0] => {} //~ error: expected a pattern, found an expression
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `=>`, `@`, `if`, or `|`, found `[`
|
error: expected a pattern, found an expression
|
||||||
--> $DIR/issue-24375.rs:6:12
|
--> $DIR/issue-24375.rs:6:9
|
||||||
|
|
|
|
||||||
LL | tmp[0] => {}
|
LL | tmp[0] => {}
|
||||||
| ^ expected one of `=>`, `@`, `if`, or `|`
|
| ^^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
|
let v[0] = v[1];
|
||||||
|
//~^ error: expected a pattern, found an expression
|
||||||
|
//~| error: cannot find value `v` in this scope
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[`
|
error: expected a pattern, found an expression
|
||||||
--> $DIR/pat-lt-bracket-5.rs:2:10
|
--> $DIR/pat-lt-bracket-5.rs:2:9
|
||||||
|
|
|
|
||||||
LL | let v[0] = v[1];
|
LL | let v[0] = v[1];
|
||||||
| ^ expected one of `:`, `;`, `=`, `@`, or `|`
|
| ^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0425]: cannot find value `v` in this scope
|
||||||
|
--> $DIR/pat-lt-bracket-5.rs:2:16
|
||||||
|
|
|
||||||
|
LL | let v[0] = v[1];
|
||||||
|
| ^ not found in this scope
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0425`.
|
||||||
|
|
|
@ -3,7 +3,8 @@ fn main() {
|
||||||
let x = Test(&0, []);
|
let x = Test(&0, []);
|
||||||
|
|
||||||
let Test(&desc[..]) = x;
|
let Test(&desc[..]) = x;
|
||||||
//~^ ERROR: expected one of `)`, `,`, `@`, or `|`, found `[`
|
//~^ error: expected a pattern, found an expression
|
||||||
|
//~| error: this pattern has 1 field, but the corresponding tuple struct has 2 fields
|
||||||
}
|
}
|
||||||
|
|
||||||
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
|
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
|
||||||
|
|
|
@ -1,18 +1,30 @@
|
||||||
error: expected one of `)`, `,`, `@`, or `|`, found `[`
|
error: expected a pattern, found an expression
|
||||||
--> $DIR/pat-lt-bracket-6.rs:5:19
|
--> $DIR/pat-lt-bracket-6.rs:5:15
|
||||||
|
|
|
|
||||||
LL | let Test(&desc[..]) = x;
|
LL | let Test(&desc[..]) = x;
|
||||||
| ^
|
| ^^^^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
| |
|
|
||||||
| expected one of `)`, `,`, `@`, or `|`
|
|
||||||
| help: missing `,`
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/pat-lt-bracket-6.rs:9:30
|
--> $DIR/pat-lt-bracket-6.rs:10:30
|
||||||
|
|
|
|
||||||
LL | const RECOVERY_WITNESS: () = 0;
|
LL | const RECOVERY_WITNESS: () = 0;
|
||||||
| ^ expected `()`, found integer
|
| ^ expected `()`, found integer
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
|
||||||
|
--> $DIR/pat-lt-bracket-6.rs:5:14
|
||||||
|
|
|
||||||
|
LL | struct Test(&'static u8, [u8; 0]);
|
||||||
|
| ----------- ------- tuple struct has 2 fields
|
||||||
|
...
|
||||||
|
LL | let Test(&desc[..]) = x;
|
||||||
|
| ^^^^^^^^^ expected 2 fields, found 1
|
||||||
|
|
|
||||||
|
help: use `_` to explicitly ignore each field
|
||||||
|
|
|
||||||
|
LL | let Test(&desc[..], _) = x;
|
||||||
|
| +++
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0023, E0308.
|
||||||
|
For more information about an error, try `rustc --explain E0023`.
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
// Parsing of range patterns
|
// Parsing of range patterns
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+`
|
let 10 ..= 10 + 3 = 12;
|
||||||
|
//~^ error: expected a pattern range bound, found an expression
|
||||||
|
|
||||||
|
let 10 - 3 ..= 10 = 8;
|
||||||
|
//~^ error: expected a pattern range bound, found an expression
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
error: expected one of `:`, `;`, `=`, or `|`, found `+`
|
error: expected a pattern range bound, found an expression
|
||||||
--> $DIR/pat-ranges-3.rs:4:19
|
--> $DIR/pat-ranges-3.rs:4:16
|
||||||
|
|
|
|
||||||
LL | let 10 ..= 10 + 3 = 12;
|
LL | let 10 ..= 10 + 3 = 12;
|
||||||
| ^ expected one of `:`, `;`, `=`, or `|`
|
| ^^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: expected a pattern range bound, found an expression
|
||||||
|
--> $DIR/pat-ranges-3.rs:7:9
|
||||||
|
|
|
||||||
|
LL | let 10 - 3 ..= 10 = 8;
|
||||||
|
| ^^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
// Parsing of range patterns
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let 10 - 3 ..= 10 = 8;
|
|
||||||
//~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-`
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-`
|
|
||||||
--> $DIR/pat-ranges-4.rs:4:12
|
|
||||||
|
|
|
||||||
LL | let 10 - 3 ..= 10 = 8;
|
|
||||||
| ^ expected one of 7 possible tokens
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
28
tests/ui/parser/pat-recover-exprs.rs
Normal file
28
tests/ui/parser/pat-recover-exprs.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
fn main() {
|
||||||
|
match u8::MAX {
|
||||||
|
u8::MAX.abs() => (),
|
||||||
|
//~^ error: expected a pattern, found a method call
|
||||||
|
x.sqrt() @ .. => (),
|
||||||
|
//~^ error: expected a pattern, found a method call
|
||||||
|
//~| error: left-hand side of `@` must be a binding
|
||||||
|
z @ w @ v.u() => (),
|
||||||
|
//~^ error: expected a pattern, found a method call
|
||||||
|
y.ilog(3) => (),
|
||||||
|
//~^ error: expected a pattern, found a method call
|
||||||
|
n + 1 => (),
|
||||||
|
//~^ error: expected a pattern, found an expression
|
||||||
|
("".f() + 14 * 8) => (),
|
||||||
|
//~^ error: expected a pattern, found an expression
|
||||||
|
0 | ((1) | 2) | 3 => (),
|
||||||
|
f?() => (),
|
||||||
|
//~^ error: expected a pattern, found an expression
|
||||||
|
(_ + 1) => (),
|
||||||
|
//~^ error: expected one of `)`, `,`, or `|`, found `+`
|
||||||
|
}
|
||||||
|
|
||||||
|
let 1 + 1 = 2;
|
||||||
|
//~^ error: expected a pattern, found an expression
|
||||||
|
|
||||||
|
let b = matches!(x, (x * x | x.f()) | x[0]);
|
||||||
|
//~^ error: expected one of `)`, `,`, `@`, or `|`, found `*`
|
||||||
|
}
|
76
tests/ui/parser/pat-recover-exprs.stderr
Normal file
76
tests/ui/parser/pat-recover-exprs.stderr
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
error: expected a pattern, found a method call
|
||||||
|
--> $DIR/pat-recover-exprs.rs:3:9
|
||||||
|
|
|
||||||
|
LL | u8::MAX.abs() => (),
|
||||||
|
| ^^^^^^^^^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern, found a method call
|
||||||
|
--> $DIR/pat-recover-exprs.rs:5:9
|
||||||
|
|
|
||||||
|
LL | x.sqrt() @ .. => (),
|
||||||
|
| ^^^^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
error: left-hand side of `@` must be a binding
|
||||||
|
--> $DIR/pat-recover-exprs.rs:5:9
|
||||||
|
|
|
||||||
|
LL | x.sqrt() @ .. => (),
|
||||||
|
| --------^^^--
|
||||||
|
| | |
|
||||||
|
| | also a pattern
|
||||||
|
| interpreted as a pattern, not a binding
|
||||||
|
|
|
||||||
|
= note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
|
||||||
|
|
||||||
|
error: expected a pattern, found a method call
|
||||||
|
--> $DIR/pat-recover-exprs.rs:8:17
|
||||||
|
|
|
||||||
|
LL | z @ w @ v.u() => (),
|
||||||
|
| ^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern, found a method call
|
||||||
|
--> $DIR/pat-recover-exprs.rs:10:9
|
||||||
|
|
|
||||||
|
LL | y.ilog(3) => (),
|
||||||
|
| ^^^^^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern, found an expression
|
||||||
|
--> $DIR/pat-recover-exprs.rs:12:9
|
||||||
|
|
|
||||||
|
LL | n + 1 => (),
|
||||||
|
| ^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern, found an expression
|
||||||
|
--> $DIR/pat-recover-exprs.rs:14:10
|
||||||
|
|
|
||||||
|
LL | ("".f() + 14 * 8) => (),
|
||||||
|
| ^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern, found an expression
|
||||||
|
--> $DIR/pat-recover-exprs.rs:17:9
|
||||||
|
|
|
||||||
|
LL | f?() => (),
|
||||||
|
| ^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected one of `)`, `,`, or `|`, found `+`
|
||||||
|
--> $DIR/pat-recover-exprs.rs:19:12
|
||||||
|
|
|
||||||
|
LL | (_ + 1) => (),
|
||||||
|
| ^ expected one of `)`, `,`, or `|`
|
||||||
|
|
||||||
|
error: expected a pattern, found an expression
|
||||||
|
--> $DIR/pat-recover-exprs.rs:23:9
|
||||||
|
|
|
||||||
|
LL | let 1 + 1 = 2;
|
||||||
|
| ^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected one of `)`, `,`, `@`, or `|`, found `*`
|
||||||
|
--> $DIR/pat-recover-exprs.rs:26:28
|
||||||
|
|
|
||||||
|
LL | let b = matches!(x, (x * x | x.f()) | x[0]);
|
||||||
|
| ^ expected one of `)`, `,`, `@`, or `|`
|
||||||
|
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||||
|
|
|
||||||
|
= note: while parsing argument for this `pat` macro fragment
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
37
tests/ui/parser/pat-recover-methodcalls.rs
Normal file
37
tests/ui/parser/pat-recover-methodcalls.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
struct Foo(String);
|
||||||
|
struct Bar { baz: String }
|
||||||
|
|
||||||
|
fn foo(foo: Foo) -> bool {
|
||||||
|
match foo {
|
||||||
|
Foo("hi".to_owned()) => true,
|
||||||
|
//~^ error: expected a pattern, found a method call
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(bar: Bar) -> bool {
|
||||||
|
match bar {
|
||||||
|
Bar { baz: "hi".to_owned() } => true,
|
||||||
|
//~^ error: expected a pattern, found a method call
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn baz() { // issue #90121
|
||||||
|
let foo = vec!["foo".to_string()];
|
||||||
|
|
||||||
|
match foo.as_slice() {
|
||||||
|
&["foo".to_string()] => {}
|
||||||
|
//~^ error: expected a pattern, found a method call
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if let (-1.some(4)) = (0, Some(4)) {}
|
||||||
|
//~^ error: expected a pattern, found a method call
|
||||||
|
|
||||||
|
if let (-1.Some(4)) = (0, Some(4)) {}
|
||||||
|
//~^ error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.`
|
||||||
|
//~| help: missing `,`
|
||||||
|
}
|
35
tests/ui/parser/pat-recover-methodcalls.stderr
Normal file
35
tests/ui/parser/pat-recover-methodcalls.stderr
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
error: expected a pattern, found a method call
|
||||||
|
--> $DIR/pat-recover-methodcalls.rs:6:13
|
||||||
|
|
|
||||||
|
LL | Foo("hi".to_owned()) => true,
|
||||||
|
| ^^^^^^^^^^^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern, found a method call
|
||||||
|
--> $DIR/pat-recover-methodcalls.rs:14:20
|
||||||
|
|
|
||||||
|
LL | Bar { baz: "hi".to_owned() } => true,
|
||||||
|
| ^^^^^^^^^^^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern, found a method call
|
||||||
|
--> $DIR/pat-recover-methodcalls.rs:24:11
|
||||||
|
|
|
||||||
|
LL | &["foo".to_string()] => {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern, found a method call
|
||||||
|
--> $DIR/pat-recover-methodcalls.rs:31:13
|
||||||
|
|
|
||||||
|
LL | if let (-1.some(4)) = (0, Some(4)) {}
|
||||||
|
| ^^^^^^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found `.`
|
||||||
|
--> $DIR/pat-recover-methodcalls.rs:34:15
|
||||||
|
|
|
||||||
|
LL | if let (-1.Some(4)) = (0, Some(4)) {}
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
| expected one of `)`, `,`, `...`, `..=`, `..`, or `|`
|
||||||
|
| help: missing `,`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
|
@ -8,6 +8,22 @@ fn main() {
|
||||||
(0)..=(-4) => (),
|
(0)..=(-4) => (),
|
||||||
//~^ error: range pattern bounds cannot have parentheses
|
//~^ error: range pattern bounds cannot have parentheses
|
||||||
//~| error: range pattern bounds cannot have parentheses
|
//~| error: range pattern bounds cannot have parentheses
|
||||||
|
..=1 + 2 => (),
|
||||||
|
//~^ error: expected a pattern range bound, found an expression
|
||||||
|
(4).. => (),
|
||||||
|
//~^ error: range pattern bounds cannot have parentheses
|
||||||
|
(-4 + 0).. => (),
|
||||||
|
//~^ error: expected a pattern range bound, found an expression
|
||||||
|
//~| error: range pattern bounds cannot have parentheses
|
||||||
|
(1 + 4)...1 * 2 => (),
|
||||||
|
//~^ error: expected a pattern range bound, found an expression
|
||||||
|
//~| error: expected a pattern range bound, found an expression
|
||||||
|
//~| error: range pattern bounds cannot have parentheses
|
||||||
|
//~| warning: `...` range patterns are deprecated
|
||||||
|
//~| warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||||
|
0.x()..="y".z() => (),
|
||||||
|
//~^ error: expected a pattern range bound, found a method call
|
||||||
|
//~| error: expected a pattern range bound, found a method call
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,5 +46,87 @@ LL - (0)..=(-4) => (),
|
||||||
LL + (0)..=-4 => (),
|
LL + (0)..=-4 => (),
|
||||||
|
|
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: expected a pattern range bound, found an expression
|
||||||
|
--> $DIR/pat-recover-ranges.rs:11:12
|
||||||
|
|
|
||||||
|
LL | ..=1 + 2 => (),
|
||||||
|
| ^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: range pattern bounds cannot have parentheses
|
||||||
|
--> $DIR/pat-recover-ranges.rs:13:9
|
||||||
|
|
|
||||||
|
LL | (4).. => (),
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
help: remove these parentheses
|
||||||
|
|
|
||||||
|
LL - (4).. => (),
|
||||||
|
LL + 4.. => (),
|
||||||
|
|
|
||||||
|
|
||||||
|
error: expected a pattern range bound, found an expression
|
||||||
|
--> $DIR/pat-recover-ranges.rs:15:10
|
||||||
|
|
|
||||||
|
LL | (-4 + 0).. => (),
|
||||||
|
| ^^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: range pattern bounds cannot have parentheses
|
||||||
|
--> $DIR/pat-recover-ranges.rs:15:9
|
||||||
|
|
|
||||||
|
LL | (-4 + 0).. => (),
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
help: remove these parentheses
|
||||||
|
|
|
||||||
|
LL - (-4 + 0).. => (),
|
||||||
|
LL + -4 + 0.. => (),
|
||||||
|
|
|
||||||
|
|
||||||
|
error: expected a pattern range bound, found an expression
|
||||||
|
--> $DIR/pat-recover-ranges.rs:18:10
|
||||||
|
|
|
||||||
|
LL | (1 + 4)...1 * 2 => (),
|
||||||
|
| ^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: range pattern bounds cannot have parentheses
|
||||||
|
--> $DIR/pat-recover-ranges.rs:18:9
|
||||||
|
|
|
||||||
|
LL | (1 + 4)...1 * 2 => (),
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
help: remove these parentheses
|
||||||
|
|
|
||||||
|
LL - (1 + 4)...1 * 2 => (),
|
||||||
|
LL + 1 + 4...1 * 2 => (),
|
||||||
|
|
|
||||||
|
|
||||||
|
error: expected a pattern range bound, found an expression
|
||||||
|
--> $DIR/pat-recover-ranges.rs:18:19
|
||||||
|
|
|
||||||
|
LL | (1 + 4)...1 * 2 => (),
|
||||||
|
| ^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern range bound, found a method call
|
||||||
|
--> $DIR/pat-recover-ranges.rs:24:9
|
||||||
|
|
|
||||||
|
LL | 0.x()..="y".z() => (),
|
||||||
|
| ^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
error: expected a pattern range bound, found a method call
|
||||||
|
--> $DIR/pat-recover-ranges.rs:24:17
|
||||||
|
|
|
||||||
|
LL | 0.x()..="y".z() => (),
|
||||||
|
| ^^^^^^^ method calls are not allowed in patterns
|
||||||
|
|
||||||
|
warning: `...` range patterns are deprecated
|
||||||
|
--> $DIR/pat-recover-ranges.rs:18:16
|
||||||
|
|
|
||||||
|
LL | (1 + 4)...1 * 2 => (),
|
||||||
|
| ^^^ help: use `..=` for an inclusive range
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
|
||||||
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
|
||||||
|
= note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default
|
||||||
|
|
||||||
|
error: aborting due to 13 previous errors; 1 warning emitted
|
||||||
|
|
||||||
|
|
61
tests/ui/parser/pat-recover-wildcards.rs
Normal file
61
tests/ui/parser/pat-recover-wildcards.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// check that we can't do funny things with wildcards.
|
||||||
|
|
||||||
|
fn a() {
|
||||||
|
match 1 {
|
||||||
|
_ + 1 => () //~ error: expected one of `=>`, `if`, or `|`, found `+`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() {
|
||||||
|
match 2 {
|
||||||
|
(_ % 4) => () //~ error: expected one of `)`, `,`, or `|`, found `%`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() {
|
||||||
|
match 3 {
|
||||||
|
_.x() => () //~ error: expected one of `=>`, `if`, or `|`, found `.`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn d() {
|
||||||
|
match 4 {
|
||||||
|
_..=4 => () //~ error: expected one of `=>`, `if`, or `|`, found `..=`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn e() {
|
||||||
|
match 5 {
|
||||||
|
.._ => () //~ error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
match 6 {
|
||||||
|
0..._ => ()
|
||||||
|
//~^ error: inclusive range with no end
|
||||||
|
//~| error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn g() {
|
||||||
|
match 7 {
|
||||||
|
(_ * 0)..5 => () //~ error: expected one of `)`, `,`, or `|`, found `*`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn h() {
|
||||||
|
match 8 {
|
||||||
|
..(_) => () //~ error: expected one of `=>`, `if`, or `|`, found `(`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn i() {
|
||||||
|
match 9 {
|
||||||
|
4..=(2 + _) => ()
|
||||||
|
//~^ error: expected a pattern range bound, found an expression
|
||||||
|
//~| error: range pattern bounds cannot have parentheses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
77
tests/ui/parser/pat-recover-wildcards.stderr
Normal file
77
tests/ui/parser/pat-recover-wildcards.stderr
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
error: expected one of `=>`, `if`, or `|`, found `+`
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:5:11
|
||||||
|
|
|
||||||
|
LL | _ + 1 => ()
|
||||||
|
| ^ expected one of `=>`, `if`, or `|`
|
||||||
|
|
||||||
|
error: expected one of `)`, `,`, or `|`, found `%`
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:11:12
|
||||||
|
|
|
||||||
|
LL | (_ % 4) => ()
|
||||||
|
| ^ expected one of `)`, `,`, or `|`
|
||||||
|
|
||||||
|
error: expected one of `=>`, `if`, or `|`, found `.`
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:17:10
|
||||||
|
|
|
||||||
|
LL | _.x() => ()
|
||||||
|
| ^ expected one of `=>`, `if`, or `|`
|
||||||
|
|
||||||
|
error: expected one of `=>`, `if`, or `|`, found `..=`
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:23:10
|
||||||
|
|
|
||||||
|
LL | _..=4 => ()
|
||||||
|
| ^^^ expected one of `=>`, `if`, or `|`
|
||||||
|
|
||||||
|
error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:29:11
|
||||||
|
|
|
||||||
|
LL | .._ => ()
|
||||||
|
| ^ expected one of `=>`, `if`, or `|`
|
||||||
|
|
||||||
|
error[E0586]: inclusive range with no end
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:35:10
|
||||||
|
|
|
||||||
|
LL | 0..._ => ()
|
||||||
|
| ^^^ help: use `..` instead
|
||||||
|
|
|
||||||
|
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
|
||||||
|
|
||||||
|
error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:35:13
|
||||||
|
|
|
||||||
|
LL | 0..._ => ()
|
||||||
|
| ^ expected one of `=>`, `if`, or `|`
|
||||||
|
|
||||||
|
error: expected one of `)`, `,`, or `|`, found `*`
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:43:12
|
||||||
|
|
|
||||||
|
LL | (_ * 0)..5 => ()
|
||||||
|
| ^ expected one of `)`, `,`, or `|`
|
||||||
|
|
||||||
|
error: expected one of `=>`, `if`, or `|`, found `(`
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:49:11
|
||||||
|
|
|
||||||
|
LL | ..(_) => ()
|
||||||
|
| ^ expected one of `=>`, `if`, or `|`
|
||||||
|
|
||||||
|
error: expected a pattern range bound, found an expression
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:55:14
|
||||||
|
|
|
||||||
|
LL | 4..=(2 + _) => ()
|
||||||
|
| ^^^^^ arbitrary expressions are not allowed in patterns
|
||||||
|
|
||||||
|
error: range pattern bounds cannot have parentheses
|
||||||
|
--> $DIR/pat-recover-wildcards.rs:55:13
|
||||||
|
|
|
||||||
|
LL | 4..=(2 + _) => ()
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
help: remove these parentheses
|
||||||
|
|
|
||||||
|
LL - 4..=(2 + _) => ()
|
||||||
|
LL + 4..=2 + _ => ()
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0586`.
|
Loading…
Add table
Reference in a new issue