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:
bors 2024-01-29 21:53:39 +00:00
commit 5518eaa946
62 changed files with 1281 additions and 159 deletions

View file

@ -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",

View file

@ -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,

View file

@ -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,

View file

@ -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!(

View file

@ -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(),

View file

@ -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);

View file

@ -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)
} }

View file

@ -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)
} }

View file

@ -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),
} }
} }

View file

@ -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);

View file

@ -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);

View file

@ -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>) {

View file

@ -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(())

View file

@ -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`

View file

@ -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 {

View file

@ -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 {

View file

@ -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;
} }
} }

View file

@ -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 { ... }`).

View file

@ -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)

View file

@ -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 }

View file

@ -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)

View file

@ -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")]

View file

@ -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 }

View file

@ -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 {

View file

@ -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.

View file

@ -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;

View file

@ -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> {

View file

@ -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
/// ///

View file

@ -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 {}

View file

@ -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 {}
} }

View file

@ -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))
} }
} }
} }

View file

@ -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

View file

@ -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),
} }
} }

View file

@ -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`.

View file

@ -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),
} }
} }

View file

@ -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`.

View file

@ -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();
} }

View 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`.

View file

@ -1,5 +1,3 @@
// ignore-test This is currently broken
#![allow(incomplete_features)] #![allow(incomplete_features)]
#![feature(inline_const_pat)] #![feature(inline_const_pat)]

View 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`.

View file

@ -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)]

View 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

View file

@ -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
} }

View file

@ -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

View file

@ -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
_ => {} _ => {}
} }
} }

View file

@ -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

View file

@ -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
} }

View file

@ -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`.

View file

@ -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

View file

@ -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`.

View file

@ -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
} }

View file

@ -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

View file

@ -1,6 +0,0 @@
// Parsing of range patterns
fn main() {
let 10 - 3 ..= 10 = 8;
//~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-`
}

View file

@ -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

View 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 `*`
}

View 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

View 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 `,`
}

View 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

View file

@ -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
}; };
} }

View file

@ -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

View 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() {}

View 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`.