diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 470e9114217c6..6c172d59f837b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -392,14 +392,20 @@ impl<'hir> LoweringContext<'_, 'hir> { // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond` // in a temporary block. fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> { - match cond.kind { - hir::ExprKind::Let(..) => cond, - _ => { - let span_block = - self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None); - self.expr_drop_temps(span_block, cond, AttrVec::new()) + fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool { + match expr.kind { + hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), + hir::ExprKind::Let(..) => true, + _ => false, } } + if has_let_expr(cond) { + cond + } else { + let reason = DesugaringKind::CondTemporary; + let span_block = self.mark_span_with_reason(reason, cond.span, None); + self.expr_drop_temps(span_block, cond, AttrVec::new()) + } } // We desugar: `'label: while $cond $body` into: diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 89671788255a9..a6ecfa4520608 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -707,11 +707,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { "`if let` guards are experimental", "you can write `if matches!(, )` instead of `if let = `" ); - gate_all!( - let_chains, - "`let` expressions in this position are experimental", - "you can write `matches!(, )` instead of `let = `" - ); + gate_all!(let_chains, "`let` expressions in this position are unstable"); gate_all!( async_closure, "async closures are unstable", diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 17941058ed6f0..487451466f1f0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1,3 +1,6 @@ +mod expr; +mod item; + use crate::pp::Breaks::{Consistent, Inconsistent}; use crate::pp::{self, Breaks}; @@ -6,10 +9,10 @@ use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, T use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; -use rustc_ast::util::parser::{self, AssocOp, Fixity}; +use rustc_ast::util::parser; use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use rustc_ast::{attr, Term}; -use rustc_ast::{GenericArg, MacArgs, ModKind}; +use rustc_ast::{GenericArg, MacArgs}; use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; @@ -210,10 +213,6 @@ pub fn literal_to_string(lit: token::Lit) -> String { out } -fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { - format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s) -} - impl std::ops::Deref for State<'_> { type Target = pp::Printer; fn deref(&self) -> &Self::Target { @@ -938,13 +937,6 @@ impl<'a> State<'a> { self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span) } - crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) { - self.print_inner_attributes(attrs); - for item in &nmod.items { - self.print_foreign_item(item); - } - } - pub fn print_opt_lifetime(&mut self, lifetime: &Option) { if let Some(lt) = *lifetime { self.print_lifetime(lt); @@ -1057,343 +1049,6 @@ impl<'a> State<'a> { self.end(); } - crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) { - let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; - self.ann.pre(self, AnnNode::SubItem(id)); - self.hardbreak_if_not_bol(); - self.maybe_print_comment(span.lo()); - self.print_outer_attributes(attrs); - match kind { - ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { - self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); - } - ast::ForeignItemKind::Static(ty, mutbl, body) => { - let def = ast::Defaultness::Final; - self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def); - } - ast::ForeignItemKind::TyAlias(box ast::TyAlias { - defaultness, - generics, - bounds, - ty, - }) => { - self.print_associated_type( - ident, - generics, - bounds, - ty.as_deref(), - vis, - *defaultness, - ); - } - ast::ForeignItemKind::MacCall(m) => { - self.print_mac(m); - if m.args.need_semicolon() { - self.word(";"); - } - } - } - self.ann.post(self, AnnNode::SubItem(id)) - } - - fn print_item_const( - &mut self, - ident: Ident, - mutbl: Option, - ty: &ast::Ty, - body: Option<&ast::Expr>, - vis: &ast::Visibility, - defaultness: ast::Defaultness, - ) { - self.head(""); - self.print_visibility(vis); - self.print_defaultness(defaultness); - let leading = match mutbl { - None => "const", - Some(ast::Mutability::Not) => "static", - Some(ast::Mutability::Mut) => "static mut", - }; - self.word_space(leading); - self.print_ident(ident); - self.word_space(":"); - self.print_type(ty); - if body.is_some() { - self.space(); - } - self.end(); // end the head-ibox - if let Some(body) = body { - self.word_space("="); - self.print_expr(body); - } - self.word(";"); - self.end(); // end the outer cbox - } - - fn print_associated_type( - &mut self, - ident: Ident, - generics: &ast::Generics, - bounds: &ast::GenericBounds, - ty: Option<&ast::Ty>, - vis: &ast::Visibility, - defaultness: ast::Defaultness, - ) { - self.head(""); - self.print_visibility(vis); - self.print_defaultness(defaultness); - self.word_space("type"); - self.print_ident(ident); - self.print_generic_params(&generics.params); - self.print_type_bounds(":", bounds); - self.print_where_clause(&generics.where_clause); - if let Some(ty) = ty { - self.space(); - self.word_space("="); - self.print_type(ty); - } - self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block - } - - /// Pretty-prints an item. - crate fn print_item(&mut self, item: &ast::Item) { - self.hardbreak_if_not_bol(); - self.maybe_print_comment(item.span.lo()); - self.print_outer_attributes(&item.attrs); - self.ann.pre(self, AnnNode::Item(item)); - match item.kind { - ast::ItemKind::ExternCrate(orig_name) => { - self.head(visibility_qualified(&item.vis, "extern crate")); - if let Some(orig_name) = orig_name { - self.print_name(orig_name); - self.space(); - self.word("as"); - self.space(); - } - self.print_ident(item.ident); - self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block - } - ast::ItemKind::Use(ref tree) => { - self.head(visibility_qualified(&item.vis, "use")); - self.print_use_tree(tree); - self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block - } - ast::ItemKind::Static(ref ty, mutbl, ref body) => { - let def = ast::Defaultness::Final; - self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def); - } - ast::ItemKind::Const(def, ref ty, ref body) => { - self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def); - } - ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => { - let body = body.as_deref(); - self.print_fn_full( - sig, - item.ident, - generics, - &item.vis, - defaultness, - body, - &item.attrs, - ); - } - ast::ItemKind::Mod(unsafety, ref mod_kind) => { - self.head(Self::to_string(|s| { - s.print_visibility(&item.vis); - s.print_unsafety(unsafety); - s.word("mod"); - })); - self.print_ident(item.ident); - - match mod_kind { - ModKind::Loaded(items, ..) => { - self.nbsp(); - self.bopen(); - self.print_inner_attributes(&item.attrs); - for item in items { - self.print_item(item); - } - let empty = item.attrs.is_empty() && items.is_empty(); - self.bclose(item.span, empty); - } - ModKind::Unloaded => { - self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block - } - } - } - ast::ItemKind::ForeignMod(ref nmod) => { - self.head(Self::to_string(|s| { - s.print_unsafety(nmod.unsafety); - s.word("extern"); - })); - if let Some(abi) = nmod.abi { - self.print_literal(&abi.as_lit()); - self.nbsp(); - } - self.bopen(); - self.print_foreign_mod(nmod, &item.attrs); - let empty = item.attrs.is_empty() && nmod.items.is_empty(); - self.bclose(item.span, empty); - } - ast::ItemKind::GlobalAsm(ref asm) => { - self.head(visibility_qualified(&item.vis, "global_asm!")); - self.print_inline_asm(asm); - self.end(); - } - ast::ItemKind::TyAlias(box ast::TyAlias { - defaultness, - ref generics, - ref bounds, - ref ty, - }) => { - let ty = ty.as_deref(); - self.print_associated_type( - item.ident, - generics, - bounds, - ty, - &item.vis, - defaultness, - ); - } - ast::ItemKind::Enum(ref enum_definition, ref params) => { - self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis); - } - ast::ItemKind::Struct(ref struct_def, ref generics) => { - self.head(visibility_qualified(&item.vis, "struct")); - self.print_struct(struct_def, generics, item.ident, item.span, true); - } - ast::ItemKind::Union(ref struct_def, ref generics) => { - self.head(visibility_qualified(&item.vis, "union")); - self.print_struct(struct_def, generics, item.ident, item.span, true); - } - ast::ItemKind::Impl(box ast::Impl { - unsafety, - polarity, - defaultness, - constness, - ref generics, - ref of_trait, - ref self_ty, - ref items, - }) => { - self.head(""); - self.print_visibility(&item.vis); - self.print_defaultness(defaultness); - self.print_unsafety(unsafety); - self.word("impl"); - - if generics.params.is_empty() { - self.nbsp(); - } else { - self.print_generic_params(&generics.params); - self.space(); - } - - self.print_constness(constness); - - if let ast::ImplPolarity::Negative(_) = polarity { - self.word("!"); - } - - if let Some(ref t) = *of_trait { - self.print_trait_ref(t); - self.space(); - self.word_space("for"); - } - - self.print_type(self_ty); - self.print_where_clause(&generics.where_clause); - - self.space(); - self.bopen(); - self.print_inner_attributes(&item.attrs); - for impl_item in items { - self.print_assoc_item(impl_item); - } - let empty = item.attrs.is_empty() && items.is_empty(); - self.bclose(item.span, empty); - } - ast::ItemKind::Trait(box ast::Trait { - is_auto, - unsafety, - ref generics, - ref bounds, - ref items, - .. - }) => { - self.head(""); - self.print_visibility(&item.vis); - self.print_unsafety(unsafety); - self.print_is_auto(is_auto); - self.word_nbsp("trait"); - self.print_ident(item.ident); - self.print_generic_params(&generics.params); - let mut real_bounds = Vec::with_capacity(bounds.len()); - for b in bounds.iter() { - if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b { - self.space(); - self.word_space("for ?"); - self.print_trait_ref(&ptr.trait_ref); - } else { - real_bounds.push(b.clone()); - } - } - self.print_type_bounds(":", &real_bounds); - self.print_where_clause(&generics.where_clause); - self.word(" "); - self.bopen(); - self.print_inner_attributes(&item.attrs); - for trait_item in items { - self.print_assoc_item(trait_item); - } - let empty = item.attrs.is_empty() && items.is_empty(); - self.bclose(item.span, empty); - } - ast::ItemKind::TraitAlias(ref generics, ref bounds) => { - self.head(visibility_qualified(&item.vis, "trait")); - self.print_ident(item.ident); - self.print_generic_params(&generics.params); - let mut real_bounds = Vec::with_capacity(bounds.len()); - // FIXME(durka) this seems to be some quite outdated syntax - for b in bounds.iter() { - if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b { - self.space(); - self.word_space("for ?"); - self.print_trait_ref(&ptr.trait_ref); - } else { - real_bounds.push(b.clone()); - } - } - self.nbsp(); - self.print_type_bounds("=", &real_bounds); - self.print_where_clause(&generics.where_clause); - self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block - } - ast::ItemKind::MacCall(ref mac) => { - self.print_mac(mac); - if mac.args.need_semicolon() { - self.word(";"); - } - } - ast::ItemKind::MacroDef(ref macro_def) => { - self.print_mac_def(macro_def, &item.ident, &item.span, |state| { - state.print_visibility(&item.vis) - }); - } - } - self.ann.post(self, AnnNode::Item(item)) - } - fn print_trait_ref(&mut self, t: &ast::TraitRef) { self.print_path(&t.path, false, 0) } @@ -1411,167 +1066,6 @@ impl<'a> State<'a> { self.print_trait_ref(&t.trait_ref) } - crate fn print_enum_def( - &mut self, - enum_definition: &ast::EnumDef, - generics: &ast::Generics, - ident: Ident, - span: rustc_span::Span, - visibility: &ast::Visibility, - ) { - self.head(visibility_qualified(visibility, "enum")); - self.print_ident(ident); - self.print_generic_params(&generics.params); - self.print_where_clause(&generics.where_clause); - self.space(); - self.print_variants(&enum_definition.variants, span) - } - - crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) { - self.bopen(); - for v in variants { - self.space_if_not_bol(); - self.maybe_print_comment(v.span.lo()); - self.print_outer_attributes(&v.attrs); - self.ibox(INDENT_UNIT); - self.print_variant(v); - self.word(","); - self.end(); - self.maybe_print_trailing_comment(v.span, None); - } - let empty = variants.is_empty(); - self.bclose(span, empty) - } - - crate fn print_visibility(&mut self, vis: &ast::Visibility) { - match vis.kind { - ast::VisibilityKind::Public => self.word_nbsp("pub"), - ast::VisibilityKind::Crate(sugar) => match sugar { - ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"), - ast::CrateSugar::JustCrate => self.word_nbsp("crate"), - }, - ast::VisibilityKind::Restricted { ref path, .. } => { - let path = Self::to_string(|s| s.print_path(path, false, 0)); - if path == "self" || path == "super" { - self.word_nbsp(format!("pub({})", path)) - } else { - self.word_nbsp(format!("pub(in {})", path)) - } - } - ast::VisibilityKind::Inherited => {} - } - } - - crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) { - if let ast::Defaultness::Default(_) = defaultness { - self.word_nbsp("default"); - } - } - - crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) { - self.nbsp(); - self.bopen(); - - let empty = fields.is_empty(); - if !empty { - self.hardbreak_if_not_bol(); - - for field in fields { - self.hardbreak_if_not_bol(); - self.maybe_print_comment(field.span.lo()); - self.print_outer_attributes(&field.attrs); - self.print_visibility(&field.vis); - self.print_ident(field.ident.unwrap()); - self.word_nbsp(":"); - self.print_type(&field.ty); - self.word(","); - } - } - - self.bclose(span, empty); - } - - crate fn print_struct( - &mut self, - struct_def: &ast::VariantData, - generics: &ast::Generics, - ident: Ident, - span: rustc_span::Span, - print_finalizer: bool, - ) { - self.print_ident(ident); - self.print_generic_params(&generics.params); - match struct_def { - ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => { - if let ast::VariantData::Tuple(..) = struct_def { - self.popen(); - self.commasep(Inconsistent, struct_def.fields(), |s, field| { - s.maybe_print_comment(field.span.lo()); - s.print_outer_attributes(&field.attrs); - s.print_visibility(&field.vis); - s.print_type(&field.ty) - }); - self.pclose(); - } - self.print_where_clause(&generics.where_clause); - if print_finalizer { - self.word(";"); - } - self.end(); - self.end(); // Close the outer-box. - } - ast::VariantData::Struct(ref fields, ..) => { - self.print_where_clause(&generics.where_clause); - self.print_record_struct_body(fields, span); - } - } - } - - crate fn print_variant(&mut self, v: &ast::Variant) { - self.head(""); - self.print_visibility(&v.vis); - let generics = ast::Generics::default(); - self.print_struct(&v.data, &generics, v.ident, v.span, false); - if let Some(ref d) = v.disr_expr { - self.space(); - self.word_space("="); - self.print_expr(&d.value) - } - } - - crate fn print_assoc_item(&mut self, item: &ast::AssocItem) { - let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; - self.ann.pre(self, AnnNode::SubItem(id)); - self.hardbreak_if_not_bol(); - self.maybe_print_comment(span.lo()); - self.print_outer_attributes(attrs); - match kind { - ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { - self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); - } - ast::AssocItemKind::Const(def, ty, body) => { - self.print_item_const(ident, None, ty, body.as_deref(), vis, *def); - } - ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => { - self.print_associated_type( - ident, - generics, - bounds, - ty.as_deref(), - vis, - *defaultness, - ); - } - ast::AssocItemKind::MacCall(m) => { - self.print_mac(m); - if m.args.need_semicolon() { - self.word(";"); - } - } - } - self.ann.post(self, AnnNode::SubItem(id)) - } - crate fn print_stmt(&mut self, st: &ast::Stmt) { self.maybe_print_comment(st.span.lo()); match st.kind { @@ -1682,42 +1176,6 @@ impl<'a> State<'a> { self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals()) } - fn print_else(&mut self, els: Option<&ast::Expr>) { - if let Some(_else) = els { - match _else.kind { - // Another `else if` block. - ast::ExprKind::If(ref i, ref then, ref e) => { - self.cbox(INDENT_UNIT - 1); - self.ibox(0); - self.word(" else if "); - self.print_expr_as_cond(i); - self.space(); - self.print_block(then); - self.print_else(e.as_deref()) - } - // Final `else` block. - ast::ExprKind::Block(ref b, _) => { - self.cbox(INDENT_UNIT - 1); - self.ibox(0); - self.word(" else "); - self.print_block(b) - } - // Constraints would be great here! - _ => { - panic!("print_if saw if with weird alternative"); - } - } - } - } - - crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) { - self.head("if"); - self.print_expr_as_cond(test); - self.space(); - self.print_block(blk); - self.print_else(elseopt) - } - crate fn print_mac(&mut self, m: &ast::MacCall) { self.print_mac_common( Some(MacHeader::Path(&m.path)), @@ -1730,477 +1188,6 @@ impl<'a> State<'a> { ); } - fn print_call_post(&mut self, args: &[P]) { - self.popen(); - self.commasep_exprs(Inconsistent, args); - self.pclose() - } - - crate fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) { - self.print_expr_cond_paren(expr, expr.precedence().order() < prec) - } - - /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in - /// `if cond { ... }`. - crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) { - self.print_expr_cond_paren(expr, Self::cond_needs_par(expr)) - } - - // Does `expr` need parentheses when printed in a condition position? - // - // These cases need parens due to the parse error observed in #26461: `if return {}` - // parses as the erroneous construct `if (return {})`, not `if (return) {}`. - fn cond_needs_par(expr: &ast::Expr) -> bool { - match expr.kind { - ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true, - _ => parser::contains_exterior_struct_lit(expr), - } - } - - /// Prints `expr` or `(expr)` when `needs_par` holds. - fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) { - if needs_par { - self.popen(); - } - self.print_expr(expr); - if needs_par { - self.pclose(); - } - } - - fn print_expr_vec(&mut self, exprs: &[P]) { - self.ibox(INDENT_UNIT); - self.word("["); - self.commasep_exprs(Inconsistent, exprs); - self.word("]"); - self.end(); - } - - fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) { - self.ibox(INDENT_UNIT); - self.word("const"); - self.print_expr(&expr.value); - self.end(); - } - - fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) { - self.ibox(INDENT_UNIT); - self.word("["); - self.print_expr(element); - self.word_space(";"); - self.print_expr(&count.value); - self.word("]"); - self.end(); - } - - fn print_expr_struct( - &mut self, - qself: &Option, - path: &ast::Path, - fields: &[ast::ExprField], - rest: &ast::StructRest, - ) { - if let Some(qself) = qself { - self.print_qpath(path, qself, true); - } else { - self.print_path(path, true, 0); - } - self.word("{"); - self.commasep_cmnt( - Consistent, - fields, - |s, field| { - s.print_outer_attributes(&field.attrs); - s.ibox(INDENT_UNIT); - if !field.is_shorthand { - s.print_ident(field.ident); - s.word_space(":"); - } - s.print_expr(&field.expr); - s.end(); - }, - |f| f.span, - ); - match rest { - ast::StructRest::Base(_) | ast::StructRest::Rest(_) => { - self.ibox(INDENT_UNIT); - if !fields.is_empty() { - self.word(","); - self.space(); - } - self.word(".."); - if let ast::StructRest::Base(ref expr) = *rest { - self.print_expr(expr); - } - self.end(); - } - ast::StructRest::None if !fields.is_empty() => self.word(","), - _ => {} - } - self.word("}"); - } - - fn print_expr_tup(&mut self, exprs: &[P]) { - self.popen(); - self.commasep_exprs(Inconsistent, exprs); - if exprs.len() == 1 { - self.word(","); - } - self.pclose() - } - - fn print_expr_call(&mut self, func: &ast::Expr, args: &[P]) { - let prec = match func.kind { - ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, - _ => parser::PREC_POSTFIX, - }; - - self.print_expr_maybe_paren(func, prec); - self.print_call_post(args) - } - - fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P]) { - let base_args = &args[1..]; - self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX); - self.word("."); - self.print_ident(segment.ident); - if let Some(ref args) = segment.args { - self.print_generic_args(args, true); - } - self.print_call_post(base_args) - } - - fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) { - let assoc_op = AssocOp::from_ast_binop(op.node); - let prec = assoc_op.precedence() as i8; - let fixity = assoc_op.fixity(); - - let (left_prec, right_prec) = match fixity { - Fixity::Left => (prec, prec + 1), - Fixity::Right => (prec + 1, prec), - Fixity::None => (prec + 1, prec + 1), - }; - - let left_prec = match (&lhs.kind, op.node) { - // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is - // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead - // of `(x as i32) < ...`. We need to convince it _not_ to do that. - (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => { - parser::PREC_FORCE_PAREN - } - // We are given `(let _ = a) OP b`. - // - // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens - // as the parser will interpret this as `(let _ = a) OP b`. - // - // - Otherwise, e.g. when we have `(let a = b) < c` in AST, - // parens are required since the parser would interpret `let a = b < c` as - // `let a = (b < c)`. To achieve this, we force parens. - (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => { - parser::PREC_FORCE_PAREN - } - _ => left_prec, - }; - - self.print_expr_maybe_paren(lhs, left_prec); - self.space(); - self.word_space(op.node.to_string()); - self.print_expr_maybe_paren(rhs, right_prec) - } - - fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) { - self.word(ast::UnOp::to_string(op)); - self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) - } - - fn print_expr_addr_of( - &mut self, - kind: ast::BorrowKind, - mutability: ast::Mutability, - expr: &ast::Expr, - ) { - self.word("&"); - match kind { - ast::BorrowKind::Ref => self.print_mutability(mutability, false), - ast::BorrowKind::Raw => { - self.word_nbsp("raw"); - self.print_mutability(mutability, true); - } - } - self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) - } - - pub fn print_expr(&mut self, expr: &ast::Expr) { - self.print_expr_outer_attr_style(expr, true) - } - - fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) { - self.maybe_print_comment(expr.span.lo()); - - let attrs = &expr.attrs; - if is_inline { - self.print_outer_attributes_inline(attrs); - } else { - self.print_outer_attributes(attrs); - } - - self.ibox(INDENT_UNIT); - self.ann.pre(self, AnnNode::Expr(expr)); - match expr.kind { - ast::ExprKind::Box(ref expr) => { - self.word_space("box"); - self.print_expr_maybe_paren(expr, parser::PREC_PREFIX); - } - ast::ExprKind::Array(ref exprs) => { - self.print_expr_vec(exprs); - } - ast::ExprKind::ConstBlock(ref anon_const) => { - self.print_expr_anon_const(anon_const); - } - ast::ExprKind::Repeat(ref element, ref count) => { - self.print_expr_repeat(element, count); - } - ast::ExprKind::Struct(ref se) => { - self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest); - } - ast::ExprKind::Tup(ref exprs) => { - self.print_expr_tup(exprs); - } - ast::ExprKind::Call(ref func, ref args) => { - self.print_expr_call(func, &args); - } - ast::ExprKind::MethodCall(ref segment, ref args, _) => { - self.print_expr_method_call(segment, &args); - } - ast::ExprKind::Binary(op, ref lhs, ref rhs) => { - self.print_expr_binary(op, lhs, rhs); - } - ast::ExprKind::Unary(op, ref expr) => { - self.print_expr_unary(op, expr); - } - ast::ExprKind::AddrOf(k, m, ref expr) => { - self.print_expr_addr_of(k, m, expr); - } - ast::ExprKind::Lit(ref lit) => { - self.print_literal(lit); - } - ast::ExprKind::Cast(ref expr, ref ty) => { - let prec = AssocOp::As.precedence() as i8; - self.print_expr_maybe_paren(expr, prec); - self.space(); - self.word_space("as"); - self.print_type(ty); - } - ast::ExprKind::Type(ref expr, ref ty) => { - let prec = AssocOp::Colon.precedence() as i8; - self.print_expr_maybe_paren(expr, prec); - self.word_space(":"); - self.print_type(ty); - } - ast::ExprKind::Let(ref pat, ref scrutinee, _) => { - self.print_let(pat, scrutinee); - } - ast::ExprKind::If(ref test, ref blk, ref elseopt) => { - self.print_if(test, blk, elseopt.as_deref()) - } - ast::ExprKind::While(ref test, ref blk, opt_label) => { - if let Some(label) = opt_label { - self.print_ident(label.ident); - self.word_space(":"); - } - self.head("while"); - self.print_expr_as_cond(test); - self.space(); - self.print_block_with_attrs(blk, attrs); - } - ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => { - if let Some(label) = opt_label { - self.print_ident(label.ident); - self.word_space(":"); - } - self.head("for"); - self.print_pat(pat); - self.space(); - self.word_space("in"); - self.print_expr_as_cond(iter); - self.space(); - self.print_block_with_attrs(blk, attrs); - } - ast::ExprKind::Loop(ref blk, opt_label) => { - if let Some(label) = opt_label { - self.print_ident(label.ident); - self.word_space(":"); - } - self.head("loop"); - self.print_block_with_attrs(blk, attrs); - } - ast::ExprKind::Match(ref expr, ref arms) => { - self.cbox(INDENT_UNIT); - self.ibox(INDENT_UNIT); - self.word_nbsp("match"); - self.print_expr_as_cond(expr); - self.space(); - self.bopen(); - self.print_inner_attributes_no_trailing_hardbreak(attrs); - for arm in arms { - self.print_arm(arm); - } - let empty = attrs.is_empty() && arms.is_empty(); - self.bclose(expr.span, empty); - } - ast::ExprKind::Closure( - capture_clause, - asyncness, - movability, - ref decl, - ref body, - _, - ) => { - self.print_movability(movability); - self.print_asyncness(asyncness); - self.print_capture_clause(capture_clause); - - self.print_fn_params_and_ret(decl, true); - self.space(); - self.print_expr(body); - self.end(); // need to close a box - - // a box will be closed by print_expr, but we didn't want an overall - // wrapper so we closed the corresponding opening. so create an - // empty box to satisfy the close. - self.ibox(0); - } - ast::ExprKind::Block(ref blk, opt_label) => { - if let Some(label) = opt_label { - self.print_ident(label.ident); - self.word_space(":"); - } - // containing cbox, will be closed by print-block at } - self.cbox(INDENT_UNIT); - // head-box, will be closed by print-block after { - self.ibox(0); - self.print_block_with_attrs(blk, attrs); - } - ast::ExprKind::Async(capture_clause, _, ref blk) => { - self.word_nbsp("async"); - self.print_capture_clause(capture_clause); - // cbox/ibox in analogy to the `ExprKind::Block` arm above - self.cbox(INDENT_UNIT); - self.ibox(0); - self.print_block_with_attrs(blk, attrs); - } - ast::ExprKind::Await(ref expr) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); - self.word(".await"); - } - ast::ExprKind::Assign(ref lhs, ref rhs, _) => { - let prec = AssocOp::Assign.precedence() as i8; - self.print_expr_maybe_paren(lhs, prec + 1); - self.space(); - self.word_space("="); - self.print_expr_maybe_paren(rhs, prec); - } - ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => { - let prec = AssocOp::Assign.precedence() as i8; - self.print_expr_maybe_paren(lhs, prec + 1); - self.space(); - self.word(op.node.to_string()); - self.word_space("="); - self.print_expr_maybe_paren(rhs, prec); - } - ast::ExprKind::Field(ref expr, ident) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); - self.word("."); - self.print_ident(ident); - } - ast::ExprKind::Index(ref expr, ref index) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); - self.word("["); - self.print_expr(index); - self.word("]"); - } - ast::ExprKind::Range(ref start, ref end, limits) => { - // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence - // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`. - // Here we use a fake precedence value so that any child with lower precedence than - // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.) - let fake_prec = AssocOp::LOr.precedence() as i8; - if let Some(ref e) = *start { - self.print_expr_maybe_paren(e, fake_prec); - } - if limits == ast::RangeLimits::HalfOpen { - self.word(".."); - } else { - self.word("..="); - } - if let Some(ref e) = *end { - self.print_expr_maybe_paren(e, fake_prec); - } - } - ast::ExprKind::Underscore => self.word("_"), - ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0), - ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true), - ast::ExprKind::Break(opt_label, ref opt_expr) => { - self.word("break"); - if let Some(label) = opt_label { - self.space(); - self.print_ident(label.ident); - } - if let Some(ref expr) = *opt_expr { - self.space(); - self.print_expr_maybe_paren(expr, parser::PREC_JUMP); - } - } - ast::ExprKind::Continue(opt_label) => { - self.word("continue"); - if let Some(label) = opt_label { - self.space(); - self.print_ident(label.ident); - } - } - ast::ExprKind::Ret(ref result) => { - self.word("return"); - if let Some(ref expr) = *result { - self.word(" "); - self.print_expr_maybe_paren(expr, parser::PREC_JUMP); - } - } - ast::ExprKind::InlineAsm(ref a) => { - self.word("asm!"); - self.print_inline_asm(a); - } - ast::ExprKind::MacCall(ref m) => self.print_mac(m), - ast::ExprKind::Paren(ref e) => { - self.popen(); - self.print_expr(e); - self.pclose(); - } - ast::ExprKind::Yield(ref e) => { - self.word("yield"); - - if let Some(ref expr) = *e { - self.space(); - self.print_expr_maybe_paren(expr, parser::PREC_JUMP); - } - } - ast::ExprKind::Try(ref e) => { - self.print_expr_maybe_paren(e, parser::PREC_POSTFIX); - self.word("?") - } - ast::ExprKind::TryBlock(ref blk) => { - self.head("try"); - self.print_block_with_attrs(blk, attrs) - } - ast::ExprKind::Err => { - self.popen(); - self.word("/*ERROR*/"); - self.pclose() - } - } - self.ann.post(self, AnnNode::Expr(expr)); - self.end(); - } - fn print_inline_asm(&mut self, asm: &ast::InlineAsm) { enum AsmArg<'a> { Template(String), @@ -2496,48 +1483,6 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } - fn print_arm(&mut self, arm: &ast::Arm) { - // Note, I have no idea why this check is necessary, but here it is. - if arm.attrs.is_empty() { - self.space(); - } - self.cbox(INDENT_UNIT); - self.ibox(0); - self.maybe_print_comment(arm.pat.span.lo()); - self.print_outer_attributes(&arm.attrs); - self.print_pat(&arm.pat); - self.space(); - if let Some(ref e) = arm.guard { - self.word_space("if"); - self.print_expr(e); - self.space(); - } - self.word_space("=>"); - - match arm.body.kind { - ast::ExprKind::Block(ref blk, opt_label) => { - if let Some(label) = opt_label { - self.print_ident(label.ident); - self.word_space(":"); - } - - // The block will close the pattern's ibox. - self.print_block_unclosed_indent(blk); - - // If it is a user-provided unsafe block, print a comma after it. - if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules { - self.word(","); - } - } - _ => { - self.end(); // Close the ibox for the pattern. - self.print_expr(&arm.body); - self.word(","); - } - } - self.end(); // Close enclosing cbox. - } - fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) { match explicit_self.node { SelfKind::Value(m) => { @@ -2559,75 +1504,12 @@ impl<'a> State<'a> { } } - fn print_fn_full( - &mut self, - sig: &ast::FnSig, - name: Ident, - generics: &ast::Generics, - vis: &ast::Visibility, - defaultness: ast::Defaultness, - body: Option<&ast::Block>, - attrs: &[ast::Attribute], - ) { - if body.is_some() { - self.head(""); - } - self.print_visibility(vis); - self.print_defaultness(defaultness); - self.print_fn(&sig.decl, sig.header, Some(name), generics); - if let Some(body) = body { - self.nbsp(); - self.print_block_with_attrs(body, attrs); - } else { - self.word(";"); - } - } - - crate fn print_fn( - &mut self, - decl: &ast::FnDecl, - header: ast::FnHeader, - name: Option, - generics: &ast::Generics, - ) { - self.print_fn_header_info(header); - if let Some(name) = name { - self.nbsp(); - self.print_ident(name); - } - self.print_generic_params(&generics.params); - self.print_fn_params_and_ret(decl, false); - self.print_where_clause(&generics.where_clause) - } - - crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) { - let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") }; - self.word(open); - self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure)); - self.word(close); - self.print_fn_ret_ty(&decl.output) - } - - crate fn print_movability(&mut self, movability: ast::Movability) { - match movability { - ast::Movability::Static => self.word_space("static"), - ast::Movability::Movable => {} - } - } - crate fn print_asyncness(&mut self, asyncness: ast::Async) { if asyncness.is_async() { self.word_nbsp("async"); } } - crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { - match capture_clause { - ast::CaptureBy::Value => self.word_space("move"), - ast::CaptureBy::Ref => {} - } - } - pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) { if !bounds.is_empty() { self.word(prefix); @@ -2722,83 +1604,6 @@ impl<'a> State<'a> { self.word(">"); } - crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) { - if where_clause.predicates.is_empty() && !where_clause.has_where_token { - return; - } - - self.space(); - self.word_space("where"); - - for (i, predicate) in where_clause.predicates.iter().enumerate() { - if i != 0 { - self.word_space(","); - } - - self.print_where_predicate(predicate); - } - } - - pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) { - match predicate { - ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { - bound_generic_params, - bounded_ty, - bounds, - .. - }) => { - self.print_formal_generic_params(bound_generic_params); - self.print_type(bounded_ty); - self.print_type_bounds(":", bounds); - } - ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { - lifetime, - bounds, - .. - }) => { - self.print_lifetime_bounds(*lifetime, bounds); - } - ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { - self.print_type(lhs_ty); - self.space(); - self.word_space("="); - self.print_type(rhs_ty); - } - } - } - - crate fn print_use_tree(&mut self, tree: &ast::UseTree) { - match tree.kind { - ast::UseTreeKind::Simple(rename, ..) => { - self.print_path(&tree.prefix, false, 0); - if let Some(rename) = rename { - self.space(); - self.word_space("as"); - self.print_ident(rename); - } - } - ast::UseTreeKind::Glob => { - if !tree.prefix.segments.is_empty() { - self.print_path(&tree.prefix, false, 0); - self.word("::"); - } - self.word("*"); - } - ast::UseTreeKind::Nested(ref items) => { - if tree.prefix.segments.is_empty() { - self.word("{"); - } else { - self.print_path(&tree.prefix, false, 0); - self.word("::{"); - } - self.commasep(Inconsistent, &items, |this, &(ref tree, _)| { - this.print_use_tree(tree) - }); - self.word("}"); - } - } - } - pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) { match mutbl { ast::Mutability::Mut => self.word_nbsp("mut"), diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs new file mode 100644 index 0000000000000..956200d60f507 --- /dev/null +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -0,0 +1,571 @@ +use crate::pp::Breaks::{Consistent, Inconsistent}; +use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; + +use rustc_ast::ptr::P; +use rustc_ast::util::parser::{self, AssocOp, Fixity}; +use rustc_ast::{self as ast, BlockCheckMode}; + +impl<'a> State<'a> { + fn print_else(&mut self, els: Option<&ast::Expr>) { + if let Some(_else) = els { + match _else.kind { + // Another `else if` block. + ast::ExprKind::If(ref i, ref then, ref e) => { + self.cbox(INDENT_UNIT - 1); + self.ibox(0); + self.word(" else if "); + self.print_expr_as_cond(i); + self.space(); + self.print_block(then); + self.print_else(e.as_deref()) + } + // Final `else` block. + ast::ExprKind::Block(ref b, _) => { + self.cbox(INDENT_UNIT - 1); + self.ibox(0); + self.word(" else "); + self.print_block(b) + } + // Constraints would be great here! + _ => { + panic!("print_if saw if with weird alternative"); + } + } + } + } + + fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) { + self.head("if"); + self.print_expr_as_cond(test); + self.space(); + self.print_block(blk); + self.print_else(elseopt) + } + + fn print_call_post(&mut self, args: &[P]) { + self.popen(); + self.commasep_exprs(Inconsistent, args); + self.pclose() + } + + fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) { + self.print_expr_cond_paren(expr, expr.precedence().order() < prec) + } + + /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in + /// `if cond { ... }`. + fn print_expr_as_cond(&mut self, expr: &ast::Expr) { + self.print_expr_cond_paren(expr, Self::cond_needs_par(expr)) + } + + // Does `expr` need parentheses when printed in a condition position? + // + // These cases need parens due to the parse error observed in #26461: `if return {}` + // parses as the erroneous construct `if (return {})`, not `if (return) {}`. + pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool { + match expr.kind { + ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true, + _ => parser::contains_exterior_struct_lit(expr), + } + } + + /// Prints `expr` or `(expr)` when `needs_par` holds. + pub(super) fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) { + if needs_par { + self.popen(); + } + self.print_expr(expr); + if needs_par { + self.pclose(); + } + } + + fn print_expr_vec(&mut self, exprs: &[P]) { + self.ibox(INDENT_UNIT); + self.word("["); + self.commasep_exprs(Inconsistent, exprs); + self.word("]"); + self.end(); + } + + pub(super) fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) { + self.ibox(INDENT_UNIT); + self.word("const"); + self.print_expr(&expr.value); + self.end(); + } + + fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) { + self.ibox(INDENT_UNIT); + self.word("["); + self.print_expr(element); + self.word_space(";"); + self.print_expr(&count.value); + self.word("]"); + self.end(); + } + + fn print_expr_struct( + &mut self, + qself: &Option, + path: &ast::Path, + fields: &[ast::ExprField], + rest: &ast::StructRest, + ) { + if let Some(qself) = qself { + self.print_qpath(path, qself, true); + } else { + self.print_path(path, true, 0); + } + self.word("{"); + self.commasep_cmnt( + Consistent, + fields, + |s, field| { + s.print_outer_attributes(&field.attrs); + s.ibox(INDENT_UNIT); + if !field.is_shorthand { + s.print_ident(field.ident); + s.word_space(":"); + } + s.print_expr(&field.expr); + s.end(); + }, + |f| f.span, + ); + match rest { + ast::StructRest::Base(_) | ast::StructRest::Rest(_) => { + self.ibox(INDENT_UNIT); + if !fields.is_empty() { + self.word(","); + self.space(); + } + self.word(".."); + if let ast::StructRest::Base(ref expr) = *rest { + self.print_expr(expr); + } + self.end(); + } + ast::StructRest::None if !fields.is_empty() => self.word(","), + _ => {} + } + self.word("}"); + } + + fn print_expr_tup(&mut self, exprs: &[P]) { + self.popen(); + self.commasep_exprs(Inconsistent, exprs); + if exprs.len() == 1 { + self.word(","); + } + self.pclose() + } + + fn print_expr_call(&mut self, func: &ast::Expr, args: &[P]) { + let prec = match func.kind { + ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, + _ => parser::PREC_POSTFIX, + }; + + self.print_expr_maybe_paren(func, prec); + self.print_call_post(args) + } + + fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P]) { + let base_args = &args[1..]; + self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX); + self.word("."); + self.print_ident(segment.ident); + if let Some(ref args) = segment.args { + self.print_generic_args(args, true); + } + self.print_call_post(base_args) + } + + fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) { + let assoc_op = AssocOp::from_ast_binop(op.node); + let prec = assoc_op.precedence() as i8; + let fixity = assoc_op.fixity(); + + let (left_prec, right_prec) = match fixity { + Fixity::Left => (prec, prec + 1), + Fixity::Right => (prec + 1, prec), + Fixity::None => (prec + 1, prec + 1), + }; + + let left_prec = match (&lhs.kind, op.node) { + // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is + // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead + // of `(x as i32) < ...`. We need to convince it _not_ to do that. + (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => { + parser::PREC_FORCE_PAREN + } + // We are given `(let _ = a) OP b`. + // + // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens + // as the parser will interpret this as `(let _ = a) OP b`. + // + // - Otherwise, e.g. when we have `(let a = b) < c` in AST, + // parens are required since the parser would interpret `let a = b < c` as + // `let a = (b < c)`. To achieve this, we force parens. + (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => { + parser::PREC_FORCE_PAREN + } + _ => left_prec, + }; + + self.print_expr_maybe_paren(lhs, left_prec); + self.space(); + self.word_space(op.node.to_string()); + self.print_expr_maybe_paren(rhs, right_prec) + } + + fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) { + self.word(ast::UnOp::to_string(op)); + self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) + } + + fn print_expr_addr_of( + &mut self, + kind: ast::BorrowKind, + mutability: ast::Mutability, + expr: &ast::Expr, + ) { + self.word("&"); + match kind { + ast::BorrowKind::Ref => self.print_mutability(mutability, false), + ast::BorrowKind::Raw => { + self.word_nbsp("raw"); + self.print_mutability(mutability, true); + } + } + self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) + } + + pub fn print_expr(&mut self, expr: &ast::Expr) { + self.print_expr_outer_attr_style(expr, true) + } + + pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) { + self.maybe_print_comment(expr.span.lo()); + + let attrs = &expr.attrs; + if is_inline { + self.print_outer_attributes_inline(attrs); + } else { + self.print_outer_attributes(attrs); + } + + self.ibox(INDENT_UNIT); + self.ann.pre(self, AnnNode::Expr(expr)); + match expr.kind { + ast::ExprKind::Box(ref expr) => { + self.word_space("box"); + self.print_expr_maybe_paren(expr, parser::PREC_PREFIX); + } + ast::ExprKind::Array(ref exprs) => { + self.print_expr_vec(exprs); + } + ast::ExprKind::ConstBlock(ref anon_const) => { + self.print_expr_anon_const(anon_const); + } + ast::ExprKind::Repeat(ref element, ref count) => { + self.print_expr_repeat(element, count); + } + ast::ExprKind::Struct(ref se) => { + self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest); + } + ast::ExprKind::Tup(ref exprs) => { + self.print_expr_tup(exprs); + } + ast::ExprKind::Call(ref func, ref args) => { + self.print_expr_call(func, &args); + } + ast::ExprKind::MethodCall(ref segment, ref args, _) => { + self.print_expr_method_call(segment, &args); + } + ast::ExprKind::Binary(op, ref lhs, ref rhs) => { + self.print_expr_binary(op, lhs, rhs); + } + ast::ExprKind::Unary(op, ref expr) => { + self.print_expr_unary(op, expr); + } + ast::ExprKind::AddrOf(k, m, ref expr) => { + self.print_expr_addr_of(k, m, expr); + } + ast::ExprKind::Lit(ref lit) => { + self.print_literal(lit); + } + ast::ExprKind::Cast(ref expr, ref ty) => { + let prec = AssocOp::As.precedence() as i8; + self.print_expr_maybe_paren(expr, prec); + self.space(); + self.word_space("as"); + self.print_type(ty); + } + ast::ExprKind::Type(ref expr, ref ty) => { + let prec = AssocOp::Colon.precedence() as i8; + self.print_expr_maybe_paren(expr, prec); + self.word_space(":"); + self.print_type(ty); + } + ast::ExprKind::Let(ref pat, ref scrutinee, _) => { + self.print_let(pat, scrutinee); + } + ast::ExprKind::If(ref test, ref blk, ref elseopt) => { + self.print_if(test, blk, elseopt.as_deref()) + } + ast::ExprKind::While(ref test, ref blk, opt_label) => { + if let Some(label) = opt_label { + self.print_ident(label.ident); + self.word_space(":"); + } + self.head("while"); + self.print_expr_as_cond(test); + self.space(); + self.print_block_with_attrs(blk, attrs); + } + ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => { + if let Some(label) = opt_label { + self.print_ident(label.ident); + self.word_space(":"); + } + self.head("for"); + self.print_pat(pat); + self.space(); + self.word_space("in"); + self.print_expr_as_cond(iter); + self.space(); + self.print_block_with_attrs(blk, attrs); + } + ast::ExprKind::Loop(ref blk, opt_label) => { + if let Some(label) = opt_label { + self.print_ident(label.ident); + self.word_space(":"); + } + self.head("loop"); + self.print_block_with_attrs(blk, attrs); + } + ast::ExprKind::Match(ref expr, ref arms) => { + self.cbox(INDENT_UNIT); + self.ibox(INDENT_UNIT); + self.word_nbsp("match"); + self.print_expr_as_cond(expr); + self.space(); + self.bopen(); + self.print_inner_attributes_no_trailing_hardbreak(attrs); + for arm in arms { + self.print_arm(arm); + } + let empty = attrs.is_empty() && arms.is_empty(); + self.bclose(expr.span, empty); + } + ast::ExprKind::Closure( + capture_clause, + asyncness, + movability, + ref decl, + ref body, + _, + ) => { + self.print_movability(movability); + self.print_asyncness(asyncness); + self.print_capture_clause(capture_clause); + + self.print_fn_params_and_ret(decl, true); + self.space(); + self.print_expr(body); + self.end(); // need to close a box + + // a box will be closed by print_expr, but we didn't want an overall + // wrapper so we closed the corresponding opening. so create an + // empty box to satisfy the close. + self.ibox(0); + } + ast::ExprKind::Block(ref blk, opt_label) => { + if let Some(label) = opt_label { + self.print_ident(label.ident); + self.word_space(":"); + } + // containing cbox, will be closed by print-block at } + self.cbox(INDENT_UNIT); + // head-box, will be closed by print-block after { + self.ibox(0); + self.print_block_with_attrs(blk, attrs); + } + ast::ExprKind::Async(capture_clause, _, ref blk) => { + self.word_nbsp("async"); + self.print_capture_clause(capture_clause); + // cbox/ibox in analogy to the `ExprKind::Block` arm above + self.cbox(INDENT_UNIT); + self.ibox(0); + self.print_block_with_attrs(blk, attrs); + } + ast::ExprKind::Await(ref expr) => { + self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); + self.word(".await"); + } + ast::ExprKind::Assign(ref lhs, ref rhs, _) => { + let prec = AssocOp::Assign.precedence() as i8; + self.print_expr_maybe_paren(lhs, prec + 1); + self.space(); + self.word_space("="); + self.print_expr_maybe_paren(rhs, prec); + } + ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => { + let prec = AssocOp::Assign.precedence() as i8; + self.print_expr_maybe_paren(lhs, prec + 1); + self.space(); + self.word(op.node.to_string()); + self.word_space("="); + self.print_expr_maybe_paren(rhs, prec); + } + ast::ExprKind::Field(ref expr, ident) => { + self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); + self.word("."); + self.print_ident(ident); + } + ast::ExprKind::Index(ref expr, ref index) => { + self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); + self.word("["); + self.print_expr(index); + self.word("]"); + } + ast::ExprKind::Range(ref start, ref end, limits) => { + // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence + // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`. + // Here we use a fake precedence value so that any child with lower precedence than + // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.) + let fake_prec = AssocOp::LOr.precedence() as i8; + if let Some(ref e) = *start { + self.print_expr_maybe_paren(e, fake_prec); + } + if limits == ast::RangeLimits::HalfOpen { + self.word(".."); + } else { + self.word("..="); + } + if let Some(ref e) = *end { + self.print_expr_maybe_paren(e, fake_prec); + } + } + ast::ExprKind::Underscore => self.word("_"), + ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0), + ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true), + ast::ExprKind::Break(opt_label, ref opt_expr) => { + self.word("break"); + if let Some(label) = opt_label { + self.space(); + self.print_ident(label.ident); + } + if let Some(ref expr) = *opt_expr { + self.space(); + self.print_expr_maybe_paren(expr, parser::PREC_JUMP); + } + } + ast::ExprKind::Continue(opt_label) => { + self.word("continue"); + if let Some(label) = opt_label { + self.space(); + self.print_ident(label.ident); + } + } + ast::ExprKind::Ret(ref result) => { + self.word("return"); + if let Some(ref expr) = *result { + self.word(" "); + self.print_expr_maybe_paren(expr, parser::PREC_JUMP); + } + } + ast::ExprKind::InlineAsm(ref a) => { + self.word("asm!"); + self.print_inline_asm(a); + } + ast::ExprKind::MacCall(ref m) => self.print_mac(m), + ast::ExprKind::Paren(ref e) => { + self.popen(); + self.print_expr(e); + self.pclose(); + } + ast::ExprKind::Yield(ref e) => { + self.word("yield"); + + if let Some(ref expr) = *e { + self.space(); + self.print_expr_maybe_paren(expr, parser::PREC_JUMP); + } + } + ast::ExprKind::Try(ref e) => { + self.print_expr_maybe_paren(e, parser::PREC_POSTFIX); + self.word("?") + } + ast::ExprKind::TryBlock(ref blk) => { + self.head("try"); + self.print_block_with_attrs(blk, attrs) + } + ast::ExprKind::Err => { + self.popen(); + self.word("/*ERROR*/"); + self.pclose() + } + } + self.ann.post(self, AnnNode::Expr(expr)); + self.end(); + } + + fn print_arm(&mut self, arm: &ast::Arm) { + // Note, I have no idea why this check is necessary, but here it is. + if arm.attrs.is_empty() { + self.space(); + } + self.cbox(INDENT_UNIT); + self.ibox(0); + self.maybe_print_comment(arm.pat.span.lo()); + self.print_outer_attributes(&arm.attrs); + self.print_pat(&arm.pat); + self.space(); + if let Some(ref e) = arm.guard { + self.word_space("if"); + self.print_expr(e); + self.space(); + } + self.word_space("=>"); + + match arm.body.kind { + ast::ExprKind::Block(ref blk, opt_label) => { + if let Some(label) = opt_label { + self.print_ident(label.ident); + self.word_space(":"); + } + + // The block will close the pattern's ibox. + self.print_block_unclosed_indent(blk); + + // If it is a user-provided unsafe block, print a comma after it. + if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules { + self.word(","); + } + } + _ => { + self.end(); // Close the ibox for the pattern. + self.print_expr(&arm.body); + self.word(","); + } + } + self.end(); // Close enclosing cbox. + } + + fn print_movability(&mut self, movability: ast::Movability) { + match movability { + ast::Movability::Static => self.word_space("static"), + ast::Movability::Movable => {} + } + } + + fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { + match capture_clause { + ast::CaptureBy::Value => self.word_space("move"), + ast::CaptureBy::Ref => {} + } + } +} diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs new file mode 100644 index 0000000000000..c756b946b1e4a --- /dev/null +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -0,0 +1,644 @@ +use crate::pp::Breaks::Inconsistent; +use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; + +use rustc_ast as ast; +use rustc_ast::GenericBound; +use rustc_ast::ModKind; +use rustc_span::symbol::Ident; + +fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { + format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s) +} + +impl<'a> State<'a> { + fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) { + self.print_inner_attributes(attrs); + for item in &nmod.items { + self.print_foreign_item(item); + } + } + + fn print_foreign_item(&mut self, item: &ast::ForeignItem) { + let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; + self.ann.pre(self, AnnNode::SubItem(id)); + self.hardbreak_if_not_bol(); + self.maybe_print_comment(span.lo()); + self.print_outer_attributes(attrs); + match kind { + ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { + self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); + } + ast::ForeignItemKind::Static(ty, mutbl, body) => { + let def = ast::Defaultness::Final; + self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def); + } + ast::ForeignItemKind::TyAlias(box ast::TyAlias { + defaultness, + generics, + bounds, + ty, + }) => { + self.print_associated_type( + ident, + generics, + bounds, + ty.as_deref(), + vis, + *defaultness, + ); + } + ast::ForeignItemKind::MacCall(m) => { + self.print_mac(m); + if m.args.need_semicolon() { + self.word(";"); + } + } + } + self.ann.post(self, AnnNode::SubItem(id)) + } + + fn print_item_const( + &mut self, + ident: Ident, + mutbl: Option, + ty: &ast::Ty, + body: Option<&ast::Expr>, + vis: &ast::Visibility, + defaultness: ast::Defaultness, + ) { + self.head(""); + self.print_visibility(vis); + self.print_defaultness(defaultness); + let leading = match mutbl { + None => "const", + Some(ast::Mutability::Not) => "static", + Some(ast::Mutability::Mut) => "static mut", + }; + self.word_space(leading); + self.print_ident(ident); + self.word_space(":"); + self.print_type(ty); + if body.is_some() { + self.space(); + } + self.end(); // end the head-ibox + if let Some(body) = body { + self.word_space("="); + self.print_expr(body); + } + self.word(";"); + self.end(); // end the outer cbox + } + + fn print_associated_type( + &mut self, + ident: Ident, + generics: &ast::Generics, + bounds: &ast::GenericBounds, + ty: Option<&ast::Ty>, + vis: &ast::Visibility, + defaultness: ast::Defaultness, + ) { + self.head(""); + self.print_visibility(vis); + self.print_defaultness(defaultness); + self.word_space("type"); + self.print_ident(ident); + self.print_generic_params(&generics.params); + self.print_type_bounds(":", bounds); + self.print_where_clause(&generics.where_clause); + if let Some(ty) = ty { + self.space(); + self.word_space("="); + self.print_type(ty); + } + self.word(";"); + self.end(); // end inner head-block + self.end(); // end outer head-block + } + + /// Pretty-prints an item. + crate fn print_item(&mut self, item: &ast::Item) { + self.hardbreak_if_not_bol(); + self.maybe_print_comment(item.span.lo()); + self.print_outer_attributes(&item.attrs); + self.ann.pre(self, AnnNode::Item(item)); + match item.kind { + ast::ItemKind::ExternCrate(orig_name) => { + self.head(visibility_qualified(&item.vis, "extern crate")); + if let Some(orig_name) = orig_name { + self.print_name(orig_name); + self.space(); + self.word("as"); + self.space(); + } + self.print_ident(item.ident); + self.word(";"); + self.end(); // end inner head-block + self.end(); // end outer head-block + } + ast::ItemKind::Use(ref tree) => { + self.head(visibility_qualified(&item.vis, "use")); + self.print_use_tree(tree); + self.word(";"); + self.end(); // end inner head-block + self.end(); // end outer head-block + } + ast::ItemKind::Static(ref ty, mutbl, ref body) => { + let def = ast::Defaultness::Final; + self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def); + } + ast::ItemKind::Const(def, ref ty, ref body) => { + self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def); + } + ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => { + let body = body.as_deref(); + self.print_fn_full( + sig, + item.ident, + generics, + &item.vis, + defaultness, + body, + &item.attrs, + ); + } + ast::ItemKind::Mod(unsafety, ref mod_kind) => { + self.head(Self::to_string(|s| { + s.print_visibility(&item.vis); + s.print_unsafety(unsafety); + s.word("mod"); + })); + self.print_ident(item.ident); + + match mod_kind { + ModKind::Loaded(items, ..) => { + self.nbsp(); + self.bopen(); + self.print_inner_attributes(&item.attrs); + for item in items { + self.print_item(item); + } + let empty = item.attrs.is_empty() && items.is_empty(); + self.bclose(item.span, empty); + } + ModKind::Unloaded => { + self.word(";"); + self.end(); // end inner head-block + self.end(); // end outer head-block + } + } + } + ast::ItemKind::ForeignMod(ref nmod) => { + self.head(Self::to_string(|s| { + s.print_unsafety(nmod.unsafety); + s.word("extern"); + })); + if let Some(abi) = nmod.abi { + self.print_literal(&abi.as_lit()); + self.nbsp(); + } + self.bopen(); + self.print_foreign_mod(nmod, &item.attrs); + let empty = item.attrs.is_empty() && nmod.items.is_empty(); + self.bclose(item.span, empty); + } + ast::ItemKind::GlobalAsm(ref asm) => { + self.head(visibility_qualified(&item.vis, "global_asm!")); + self.print_inline_asm(asm); + self.end(); + } + ast::ItemKind::TyAlias(box ast::TyAlias { + defaultness, + ref generics, + ref bounds, + ref ty, + }) => { + let ty = ty.as_deref(); + self.print_associated_type( + item.ident, + generics, + bounds, + ty, + &item.vis, + defaultness, + ); + } + ast::ItemKind::Enum(ref enum_definition, ref params) => { + self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis); + } + ast::ItemKind::Struct(ref struct_def, ref generics) => { + self.head(visibility_qualified(&item.vis, "struct")); + self.print_struct(struct_def, generics, item.ident, item.span, true); + } + ast::ItemKind::Union(ref struct_def, ref generics) => { + self.head(visibility_qualified(&item.vis, "union")); + self.print_struct(struct_def, generics, item.ident, item.span, true); + } + ast::ItemKind::Impl(box ast::Impl { + unsafety, + polarity, + defaultness, + constness, + ref generics, + ref of_trait, + ref self_ty, + ref items, + }) => { + self.head(""); + self.print_visibility(&item.vis); + self.print_defaultness(defaultness); + self.print_unsafety(unsafety); + self.word("impl"); + + if generics.params.is_empty() { + self.nbsp(); + } else { + self.print_generic_params(&generics.params); + self.space(); + } + + self.print_constness(constness); + + if let ast::ImplPolarity::Negative(_) = polarity { + self.word("!"); + } + + if let Some(ref t) = *of_trait { + self.print_trait_ref(t); + self.space(); + self.word_space("for"); + } + + self.print_type(self_ty); + self.print_where_clause(&generics.where_clause); + + self.space(); + self.bopen(); + self.print_inner_attributes(&item.attrs); + for impl_item in items { + self.print_assoc_item(impl_item); + } + let empty = item.attrs.is_empty() && items.is_empty(); + self.bclose(item.span, empty); + } + ast::ItemKind::Trait(box ast::Trait { + is_auto, + unsafety, + ref generics, + ref bounds, + ref items, + .. + }) => { + self.head(""); + self.print_visibility(&item.vis); + self.print_unsafety(unsafety); + self.print_is_auto(is_auto); + self.word_nbsp("trait"); + self.print_ident(item.ident); + self.print_generic_params(&generics.params); + let mut real_bounds = Vec::with_capacity(bounds.len()); + for b in bounds.iter() { + if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b { + self.space(); + self.word_space("for ?"); + self.print_trait_ref(&ptr.trait_ref); + } else { + real_bounds.push(b.clone()); + } + } + self.print_type_bounds(":", &real_bounds); + self.print_where_clause(&generics.where_clause); + self.word(" "); + self.bopen(); + self.print_inner_attributes(&item.attrs); + for trait_item in items { + self.print_assoc_item(trait_item); + } + let empty = item.attrs.is_empty() && items.is_empty(); + self.bclose(item.span, empty); + } + ast::ItemKind::TraitAlias(ref generics, ref bounds) => { + self.head(visibility_qualified(&item.vis, "trait")); + self.print_ident(item.ident); + self.print_generic_params(&generics.params); + let mut real_bounds = Vec::with_capacity(bounds.len()); + // FIXME(durka) this seems to be some quite outdated syntax + for b in bounds.iter() { + if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b { + self.space(); + self.word_space("for ?"); + self.print_trait_ref(&ptr.trait_ref); + } else { + real_bounds.push(b.clone()); + } + } + self.nbsp(); + self.print_type_bounds("=", &real_bounds); + self.print_where_clause(&generics.where_clause); + self.word(";"); + self.end(); // end inner head-block + self.end(); // end outer head-block + } + ast::ItemKind::MacCall(ref mac) => { + self.print_mac(mac); + if mac.args.need_semicolon() { + self.word(";"); + } + } + ast::ItemKind::MacroDef(ref macro_def) => { + self.print_mac_def(macro_def, &item.ident, &item.span, |state| { + state.print_visibility(&item.vis) + }); + } + } + self.ann.post(self, AnnNode::Item(item)) + } + + fn print_enum_def( + &mut self, + enum_definition: &ast::EnumDef, + generics: &ast::Generics, + ident: Ident, + span: rustc_span::Span, + visibility: &ast::Visibility, + ) { + self.head(visibility_qualified(visibility, "enum")); + self.print_ident(ident); + self.print_generic_params(&generics.params); + self.print_where_clause(&generics.where_clause); + self.space(); + self.print_variants(&enum_definition.variants, span) + } + + fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) { + self.bopen(); + for v in variants { + self.space_if_not_bol(); + self.maybe_print_comment(v.span.lo()); + self.print_outer_attributes(&v.attrs); + self.ibox(INDENT_UNIT); + self.print_variant(v); + self.word(","); + self.end(); + self.maybe_print_trailing_comment(v.span, None); + } + let empty = variants.is_empty(); + self.bclose(span, empty) + } + + crate fn print_visibility(&mut self, vis: &ast::Visibility) { + match vis.kind { + ast::VisibilityKind::Public => self.word_nbsp("pub"), + ast::VisibilityKind::Crate(sugar) => match sugar { + ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"), + ast::CrateSugar::JustCrate => self.word_nbsp("crate"), + }, + ast::VisibilityKind::Restricted { ref path, .. } => { + let path = Self::to_string(|s| s.print_path(path, false, 0)); + if path == "self" || path == "super" { + self.word_nbsp(format!("pub({})", path)) + } else { + self.word_nbsp(format!("pub(in {})", path)) + } + } + ast::VisibilityKind::Inherited => {} + } + } + + fn print_defaultness(&mut self, defaultness: ast::Defaultness) { + if let ast::Defaultness::Default(_) = defaultness { + self.word_nbsp("default"); + } + } + + fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) { + self.nbsp(); + self.bopen(); + + let empty = fields.is_empty(); + if !empty { + self.hardbreak_if_not_bol(); + + for field in fields { + self.hardbreak_if_not_bol(); + self.maybe_print_comment(field.span.lo()); + self.print_outer_attributes(&field.attrs); + self.print_visibility(&field.vis); + self.print_ident(field.ident.unwrap()); + self.word_nbsp(":"); + self.print_type(&field.ty); + self.word(","); + } + } + + self.bclose(span, empty); + } + + fn print_struct( + &mut self, + struct_def: &ast::VariantData, + generics: &ast::Generics, + ident: Ident, + span: rustc_span::Span, + print_finalizer: bool, + ) { + self.print_ident(ident); + self.print_generic_params(&generics.params); + match struct_def { + ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => { + if let ast::VariantData::Tuple(..) = struct_def { + self.popen(); + self.commasep(Inconsistent, struct_def.fields(), |s, field| { + s.maybe_print_comment(field.span.lo()); + s.print_outer_attributes(&field.attrs); + s.print_visibility(&field.vis); + s.print_type(&field.ty) + }); + self.pclose(); + } + self.print_where_clause(&generics.where_clause); + if print_finalizer { + self.word(";"); + } + self.end(); + self.end(); // Close the outer-box. + } + ast::VariantData::Struct(ref fields, ..) => { + self.print_where_clause(&generics.where_clause); + self.print_record_struct_body(fields, span); + } + } + } + + crate fn print_variant(&mut self, v: &ast::Variant) { + self.head(""); + self.print_visibility(&v.vis); + let generics = ast::Generics::default(); + self.print_struct(&v.data, &generics, v.ident, v.span, false); + if let Some(ref d) = v.disr_expr { + self.space(); + self.word_space("="); + self.print_expr(&d.value) + } + } + + fn print_assoc_item(&mut self, item: &ast::AssocItem) { + let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; + self.ann.pre(self, AnnNode::SubItem(id)); + self.hardbreak_if_not_bol(); + self.maybe_print_comment(span.lo()); + self.print_outer_attributes(attrs); + match kind { + ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { + self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); + } + ast::AssocItemKind::Const(def, ty, body) => { + self.print_item_const(ident, None, ty, body.as_deref(), vis, *def); + } + ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => { + self.print_associated_type( + ident, + generics, + bounds, + ty.as_deref(), + vis, + *defaultness, + ); + } + ast::AssocItemKind::MacCall(m) => { + self.print_mac(m); + if m.args.need_semicolon() { + self.word(";"); + } + } + } + self.ann.post(self, AnnNode::SubItem(id)) + } + + fn print_fn_full( + &mut self, + sig: &ast::FnSig, + name: Ident, + generics: &ast::Generics, + vis: &ast::Visibility, + defaultness: ast::Defaultness, + body: Option<&ast::Block>, + attrs: &[ast::Attribute], + ) { + if body.is_some() { + self.head(""); + } + self.print_visibility(vis); + self.print_defaultness(defaultness); + self.print_fn(&sig.decl, sig.header, Some(name), generics); + if let Some(body) = body { + self.nbsp(); + self.print_block_with_attrs(body, attrs); + } else { + self.word(";"); + } + } + + crate fn print_fn( + &mut self, + decl: &ast::FnDecl, + header: ast::FnHeader, + name: Option, + generics: &ast::Generics, + ) { + self.print_fn_header_info(header); + if let Some(name) = name { + self.nbsp(); + self.print_ident(name); + } + self.print_generic_params(&generics.params); + self.print_fn_params_and_ret(decl, false); + self.print_where_clause(&generics.where_clause) + } + + crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) { + let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") }; + self.word(open); + self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure)); + self.word(close); + self.print_fn_ret_ty(&decl.output) + } + + fn print_where_clause(&mut self, where_clause: &ast::WhereClause) { + if where_clause.predicates.is_empty() && !where_clause.has_where_token { + return; + } + + self.space(); + self.word_space("where"); + + for (i, predicate) in where_clause.predicates.iter().enumerate() { + if i != 0 { + self.word_space(","); + } + + self.print_where_predicate(predicate); + } + } + + pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) { + match predicate { + ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { + bound_generic_params, + bounded_ty, + bounds, + .. + }) => { + self.print_formal_generic_params(bound_generic_params); + self.print_type(bounded_ty); + self.print_type_bounds(":", bounds); + } + ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { + lifetime, + bounds, + .. + }) => { + self.print_lifetime_bounds(*lifetime, bounds); + } + ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { + self.print_type(lhs_ty); + self.space(); + self.word_space("="); + self.print_type(rhs_ty); + } + } + } + + fn print_use_tree(&mut self, tree: &ast::UseTree) { + match tree.kind { + ast::UseTreeKind::Simple(rename, ..) => { + self.print_path(&tree.prefix, false, 0); + if let Some(rename) = rename { + self.space(); + self.word_space("as"); + self.print_ident(rename); + } + } + ast::UseTreeKind::Glob => { + if !tree.prefix.segments.is_empty() { + self.print_path(&tree.prefix, false, 0); + self.word("::"); + } + self.word("*"); + } + ast::UseTreeKind::Nested(ref items) => { + if tree.prefix.segments.is_empty() { + self.word("{"); + } else { + self.print_path(&tree.prefix, false, 0); + self.word("::{"); + } + self.commasep(Inconsistent, &items, |this, &(ref tree, _)| { + this.print_use_tree(tree) + }); + self.word("}"); + } + } + } +} diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 4b07ed1a1e6c2..c21d19a62279f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -429,87 +429,78 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cx = self.cx; let tcx = self.cx.tcx(); - let result = match place_ref { - mir::PlaceRef { local, projection: [] } => match self.locals[local] { - LocalRef::Place(place) => { - return place; - } - LocalRef::UnsizedPlace(place) => { - return bx.load_operand(place).deref(cx); - } - LocalRef::Operand(..) => { + let mut base = 0; + let mut cg_base = match self.locals[place_ref.local] { + LocalRef::Place(place) => place, + LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx), + LocalRef::Operand(..) => { + if let Some(elem) = place_ref + .projection + .iter() + .enumerate() + .find(|elem| matches!(elem.1, mir::ProjectionElem::Deref)) + { + base = elem.0 + 1; + self.codegen_consume( + bx, + mir::PlaceRef { projection: &place_ref.projection[..elem.0], ..place_ref }, + ) + .deref(bx.cx()) + } else { bug!("using operand local {:?} as place", place_ref); } - }, - mir::PlaceRef { local, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => { - // Load the pointer from its location. - self.codegen_consume(bx, mir::PlaceRef { local, projection: proj_base }) - .deref(bx.cx()) } - mir::PlaceRef { local, projection: &[ref proj_base @ .., elem] } => { - // FIXME turn this recursion into iteration - let cg_base = - self.codegen_place(bx, mir::PlaceRef { local, projection: proj_base }); - - match elem { - mir::ProjectionElem::Deref => bug!(), - mir::ProjectionElem::Field(ref field, _) => { - cg_base.project_field(bx, field.index()) - } - mir::ProjectionElem::Index(index) => { - let index = &mir::Operand::Copy(mir::Place::from(index)); - let index = self.codegen_operand(bx, index); - let llindex = index.immediate(); - cg_base.project_index(bx, llindex) - } - mir::ProjectionElem::ConstantIndex { - offset, - from_end: false, - min_length: _, - } => { - let lloffset = bx.cx().const_usize(offset as u64); - cg_base.project_index(bx, lloffset) - } - mir::ProjectionElem::ConstantIndex { - offset, - from_end: true, - min_length: _, - } => { - let lloffset = bx.cx().const_usize(offset as u64); - let lllen = cg_base.len(bx.cx()); - let llindex = bx.sub(lllen, lloffset); - cg_base.project_index(bx, llindex) - } - mir::ProjectionElem::Subslice { from, to, from_end } => { - let mut subslice = - cg_base.project_index(bx, bx.cx().const_usize(from as u64)); - let projected_ty = - PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem).ty; - subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty)); - - if subslice.layout.is_unsized() { - assert!(from_end, "slice subslices should be `from_end`"); - subslice.llextra = Some(bx.sub( - cg_base.llextra.unwrap(), - bx.cx().const_usize((from as u64) + (to as u64)), - )); - } - - // Cast the place pointer type to the new - // array or slice type (`*[%_; new_len]`). - subslice.llval = bx.pointercast( - subslice.llval, - bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)), - ); - - subslice + }; + for elem in place_ref.projection[base..].iter() { + cg_base = match elem.clone() { + mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()), + mir::ProjectionElem::Field(ref field, _) => { + cg_base.project_field(bx, field.index()) + } + mir::ProjectionElem::Index(index) => { + let index = &mir::Operand::Copy(mir::Place::from(index)); + let index = self.codegen_operand(bx, index); + let llindex = index.immediate(); + cg_base.project_index(bx, llindex) + } + mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => { + let lloffset = bx.cx().const_usize(offset as u64); + cg_base.project_index(bx, lloffset) + } + mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => { + let lloffset = bx.cx().const_usize(offset as u64); + let lllen = cg_base.len(bx.cx()); + let llindex = bx.sub(lllen, lloffset); + cg_base.project_index(bx, llindex) + } + mir::ProjectionElem::Subslice { from, to, from_end } => { + let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64)); + let projected_ty = + PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem.clone()).ty; + subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty)); + + if subslice.layout.is_unsized() { + assert!(from_end, "slice subslices should be `from_end`"); + subslice.llextra = Some(bx.sub( + cg_base.llextra.unwrap(), + bx.cx().const_usize((from as u64) + (to as u64)), + )); } - mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v), + + // Cast the place pointer type to the new + // array or slice type (`*[%_; new_len]`). + subslice.llval = bx.pointercast( + subslice.llval, + bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)), + ); + + subslice } - } - }; - debug!("codegen_place(place={:?}) => {:?}", place_ref, result); - result + mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v), + }; + } + debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base); + cg_base } pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 47010ea3ab613..0b65a5ff3ecc3 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -415,7 +415,7 @@ declare_features! ( // Allows setting the threshold for the `large_assignments` lint. (active, large_assignments, "1.52.0", Some(83518), None), /// Allows `if/while p && let q = r && ...` chains. - (incomplete, let_chains, "1.37.0", Some(53667), None), + (active, let_chains, "1.37.0", Some(53667), None), /// Allows `let...else` statements. (active, let_else, "1.56.0", Some(87335), None), /// Allows `#[link(..., cfg(..))]`. diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 3f4bbdec31545..48f39b26152cb 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -162,7 +162,7 @@ impl MirPhase { } /// Where a specific `mir::Body` comes from. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable)] pub struct MirSource<'tcx> { pub instance: InstanceDef<'tcx>, @@ -1255,17 +1255,7 @@ pub enum AssertKind { ResumedAfterPanic(GeneratorKind), } -#[derive( - Clone, - Debug, - PartialEq, - PartialOrd, - TyEncodable, - TyDecodable, - Hash, - HashStable, - TypeFoldable -)] +#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] pub enum InlineAsmOperand<'tcx> { In { reg: InlineAsmRegOrRegClass, @@ -1747,7 +1737,7 @@ pub struct CopyNonOverlapping<'tcx> { /// A path to a value; something that can be evaluated without /// changing or disturbing program state. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)] pub struct Place<'tcx> { pub local: Local, @@ -2072,7 +2062,7 @@ pub struct SourceScopeLocalData { /// These are values that can appear inside an rvalue. They are intentionally /// limited to prevent rvalues from being nested in one another. -#[derive(Clone, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum Operand<'tcx> { /// Copy: The value must be available for use afterwards. /// @@ -2500,7 +2490,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// this does not necessarily mean that they are `==` in Rust. In /// particular, one must be wary of `NaN`! -#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] pub struct Constant<'tcx> { pub span: Span, @@ -2514,7 +2504,7 @@ pub struct Constant<'tcx> { pub literal: ConstantKind<'tcx>, } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)] #[derive(Lift)] pub enum ConstantKind<'tcx> { /// This constant came from the type system diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index eef42666f2a07..11dc69ab71566 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -213,7 +213,7 @@ pub struct Expr<'tcx> { #[derive(Debug, HashStable)] pub enum ExprKind<'tcx> { - /// `Scope`s are used to explicitely mark destruction scopes, + /// `Scope`s are used to explicitly mark destruction scopes, /// and to track the `HirId` of the expressions within the scope. Scope { region_scope: region::Scope, diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 43060ecfced12..da8fbdbf3bce4 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -90,17 +90,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let join_block = this.cfg.start_new_block(); - this.cfg.terminate( - then_blk, - source_info, - TerminatorKind::Goto { target: join_block }, - ); - this.cfg.terminate( - else_blk, - source_info, - TerminatorKind::Goto { target: join_block }, - ); - + this.cfg.goto(then_blk, source_info, join_block); + this.cfg.goto(else_blk, source_info, join_block); join_block.unit() } ExprKind::Let { expr, ref pat } => { @@ -109,8 +100,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.lower_let_expr(block, &this.thir[expr], pat, scope, expr_span) }); - let join_block = this.cfg.start_new_block(); - this.cfg.push_assign_constant( true_block, source_info, @@ -133,6 +122,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); + let join_block = this.cfg.start_new_block(); this.cfg.goto(true_block, source_info, join_block); this.cfg.goto(false_block, source_info, join_block); join_block.unit() diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index e3a05e01ea8f0..85950d8241940 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -47,6 +47,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let expr_span = expr.span; match expr.kind { + ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { + let lhs_then_block = unpack!(this.then_else_break( + block, + &this.thir[lhs], + temp_scope_override, + break_scope, + variable_scope_span, + )); + + let rhs_then_block = unpack!(this.then_else_break( + lhs_then_block, + &this.thir[rhs], + temp_scope_override, + break_scope, + variable_scope_span, + )); + + rhs_then_block.unit() + } ExprKind::Scope { region_scope, lint_level, value } => { let region_scope = (region_scope, this.source_info(expr_span)); this.in_scope(region_scope, lint_level, |this| { diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index fc46c54c2fc35..84d6c1d2db87f 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -498,7 +498,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// if let Some(x) = a && let Some(y) = b && let Some(z) = c { ... } /// - /// there are three possible ways the condition can be false and we may have + /// There are three possible ways the condition can be false and we may have /// to drop `x`, `x` and `y`, or neither depending on which binding fails. /// To handle this correctly we use a `DropTree` in a similar way to a /// `loop` expression and 'break' out on all of the 'else' paths. diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 750677f161e44..a43388808cd5c 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -315,7 +315,6 @@ impl<'tcx> Cx<'tcx> { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs), }, - _ => { let op = bin_op(op.node); ExprKind::Binary { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 868dd195f3a63..34204c3852ad0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -17,6 +17,7 @@ use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; use rustc_session::Session; +use rustc_span::source_map::Spanned; use rustc_span::{DesugaringKind, ExpnKind, Span}; crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { @@ -445,6 +446,10 @@ fn check_let_reachability<'p, 'tcx>( pat: &'p DeconstructedPat<'p, 'tcx>, span: Span, ) { + if is_let_chain(cx.tcx, pat_id) { + return; + } + let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty()); @@ -764,8 +769,11 @@ pub enum LetSource { fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource { let hir = tcx.hir(); + let parent = hir.get_parent_node(pat_id); - match hir.get(parent) { + let parent_node = hir.get(parent); + + match parent_node { hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)), .. @@ -780,6 +788,7 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource { } _ => {} } + let parent_parent = hir.get_parent_node(parent); let parent_parent_node = hir.get(parent_parent); @@ -792,12 +801,30 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource { .. }) = parent_parent_parent_parent_node { - LetSource::WhileLet - } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If { .. }, .. }) = - parent_parent_node - { - LetSource::IfLet - } else { - LetSource::GenericLet + return LetSource::WhileLet; + } + + if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(..), .. }) = parent_parent_node { + return LetSource::IfLet; } + + LetSource::GenericLet +} + +// Since this function is called within a let context, it is reasonable to assume that any parent +// `&&` infers a let chain +fn is_let_chain(tcx: TyCtxt<'_>, pat_id: HirId) -> bool { + let hir = tcx.hir(); + let parent = hir.get_parent_node(pat_id); + let parent_parent = hir.get_parent_node(parent); + matches!( + hir.get(parent_parent), + hir::Node::Expr( + hir::Expr { + kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, ..), + .. + }, + .. + ) + ) } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 4cca71424492c..7f15aacc532b3 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -3,6 +3,7 @@ // from live codes are live, and everything else is dead. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -15,6 +16,7 @@ use rustc_middle::middle::privacy; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::Span; use std::mem; // Any local node that may call something in its body block should be @@ -47,6 +49,10 @@ struct MarkSymbolVisitor<'tcx> { ignore_variant_stack: Vec, // maps from tuple struct constructors to tuple struct items struct_constructors: FxHashMap, + // maps from ADTs to ignored derived traits (e.g. Debug and Clone) + // and the span of their respective impl (i.e., part of the derive + // macro) + ignored_derived_traits: FxHashMap>, } impl<'tcx> MarkSymbolVisitor<'tcx> { @@ -242,7 +248,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { /// Automatically generated items marked with `rustc_trivial_field_reads` /// will be ignored for the purposes of dead code analysis (see PR #85200 /// for discussion). - fn should_ignore_item(&self, def_id: DefId) -> bool { + fn should_ignore_item(&mut self, def_id: DefId) -> bool { if let Some(impl_of) = self.tcx.impl_of_method(def_id) { if !self.tcx.has_attr(impl_of, sym::automatically_derived) { return false; @@ -250,6 +256,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) { if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) { + let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap(); + if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() { + let impl_span = self.tcx.def_span(impl_of); + if let Some(v) = self.ignored_derived_traits.get_mut(&adt_def.did) { + v.push((impl_span, trait_of)); + } else { + self.ignored_derived_traits + .insert(adt_def.did, vec![(impl_span, trait_of)]); + } + } return true; } } @@ -571,7 +587,7 @@ fn create_and_seed_worklist<'tcx>( fn find_live<'tcx>( tcx: TyCtxt<'tcx>, access_levels: &privacy::AccessLevels, -) -> FxHashSet { +) -> (FxHashSet, FxHashMap>) { let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels); let mut symbol_visitor = MarkSymbolVisitor { worklist, @@ -584,14 +600,16 @@ fn find_live<'tcx>( pub_visibility: false, ignore_variant_stack: vec![], struct_constructors, + ignored_derived_traits: FxHashMap::default(), }; symbol_visitor.mark_live_symbols(); - symbol_visitor.live_symbols + (symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits) } struct DeadVisitor<'tcx> { tcx: TyCtxt<'tcx>, live_symbols: FxHashSet, + ignored_derived_traits: FxHashMap>, } impl<'tcx> DeadVisitor<'tcx> { @@ -660,7 +678,37 @@ impl<'tcx> DeadVisitor<'tcx> { self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| { let def_id = self.tcx.hir().local_def_id(id); let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id()); - lint.build(&format!("{} is never {}: `{}`", descr, participle, name)).emit() + let mut err = lint.build(&format!("{} is never {}: `{}`", descr, participle, name)); + let hir = self.tcx.hir(); + if let Some(encl_scope) = hir.get_enclosing_scope(id) { + if let Some(encl_def_id) = hir.opt_local_def_id(encl_scope) { + if let Some(ign_traits) = + self.ignored_derived_traits.get(&encl_def_id.to_def_id()) + { + let traits_str = ign_traits + .iter() + .map(|(_, t)| format!("`{}`", self.tcx.item_name(*t))) + .collect::>() + .join(" and "); + let plural_s = pluralize!(ign_traits.len()); + let article = if ign_traits.len() > 1 { "" } else { "a " }; + let is_are = if ign_traits.len() > 1 { "these are" } else { "this is" }; + let msg = format!( + "`{}` has {}derived impl{} for the trait{} {}, but {} \ + intentionally ignored during dead code analysis", + self.tcx.item_name(encl_def_id.to_def_id()), + article, + plural_s, + plural_s, + traits_str, + is_are + ); + let multispan = ign_traits.iter().map(|(s, _)| *s).collect::>(); + err.span_note(multispan, &msg); + } + } + } + err.emit(); }); } } @@ -790,7 +838,7 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> { pub fn check_crate(tcx: TyCtxt<'_>) { let access_levels = &tcx.privacy_access_levels(()); - let live_symbols = find_live(tcx, access_levels); - let mut visitor = DeadVisitor { tcx, live_symbols }; + let (live_symbols, ignored_derived_traits) = find_live(tcx, access_levels); + let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits }; tcx.hir().walk_toplevel_module(&mut visitor); } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 8853577371ad6..a5c4140e31387 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -375,7 +375,10 @@ impl [T] { /// Sorts the slice with a key extraction function. /// - /// During sorting, the key function is called only once per element. + /// During sorting, the key function is called at most once per element, by using + /// temporary storage to remember the results of key evaluation. + /// The order of calls to the key function is unspecified and may change in future versions + /// of the standard library. /// /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \* log(*n*)) /// worst-case, where the key function is *O*(*m*). diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 8adfb6f4bcf52..611f4ab38ab33 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -551,6 +551,29 @@ impl Option { matches!(*self, Some(_)) } + /// Returns `true` if the option is a [`Some`] wrapping a value matching the predicate. + /// + /// # Examples + /// + /// ``` + /// #![feature(is_some_with)] + /// + /// let x: Option = Some(2); + /// assert_eq!(x.is_some_with(|&x| x > 1), true); + /// + /// let x: Option = Some(0); + /// assert_eq!(x.is_some_with(|&x| x > 1), false); + /// + /// let x: Option = None; + /// assert_eq!(x.is_some_with(|&x| x > 1), false); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "is_some_with", issue = "93050")] + pub fn is_some_with(&self, f: impl FnOnce(&T) -> bool) -> bool { + matches!(self, Some(x) if f(x)) + } + /// Returns `true` if the option is a [`None`] value. /// /// # Examples diff --git a/library/core/src/result.rs b/library/core/src/result.rs index b8f0d84746cce..fbd6d419236ae 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -542,6 +542,29 @@ impl Result { matches!(*self, Ok(_)) } + /// Returns `true` if the result is [`Ok`] wrapping a value matching the predicate. + /// + /// # Examples + /// + /// ``` + /// #![feature(is_some_with)] + /// + /// let x: Result = Ok(2); + /// assert_eq!(x.is_ok_with(|&x| x > 1), true); + /// + /// let x: Result = Ok(0); + /// assert_eq!(x.is_ok_with(|&x| x > 1), false); + /// + /// let x: Result = Err("hey"); + /// assert_eq!(x.is_ok_with(|&x| x > 1), false); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "is_some_with", issue = "93050")] + pub fn is_ok_with(&self, f: impl FnOnce(&T) -> bool) -> bool { + matches!(self, Ok(x) if f(x)) + } + /// Returns `true` if the result is [`Err`]. /// /// # Examples @@ -563,6 +586,30 @@ impl Result { !self.is_ok() } + /// Returns `true` if the result is [`Err`] wrapping a value matching the predicate. + /// + /// # Examples + /// + /// ``` + /// #![feature(is_some_with)] + /// use std::io::{Error, ErrorKind}; + /// + /// let x: Result = Err(Error::new(ErrorKind::NotFound, "!")); + /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), true); + /// + /// let x: Result = Err(Error::new(ErrorKind::PermissionDenied, "!")); + /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false); + /// + /// let x: Result = Ok(123); + /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "is_some_with", issue = "93050")] + pub fn is_err_with(&self, f: impl FnOnce(&E) -> bool) -> bool { + matches!(self, Err(x) if f(x)) + } + ///////////////////////////////////////////////////////////////////////// // Adapter for each variant ///////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 9c1b79d696697..d859bff1a45fa 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -373,38 +373,61 @@ impl CString { /// the position of the nul byte. #[stable(feature = "rust1", since = "1.0.0")] pub fn new>>(t: T) -> Result { - trait SpecIntoVec { - fn into_vec(self) -> Vec; + trait SpecNewImpl { + fn spec_new_impl(self) -> Result; } - impl>> SpecIntoVec for T { - default fn into_vec(self) -> Vec { - self.into() + + impl>> SpecNewImpl for T { + default fn spec_new_impl(self) -> Result { + let bytes: Vec = self.into(); + match memchr::memchr(0, &bytes) { + Some(i) => Err(NulError(i, bytes)), + None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), + } } } - // Specialization for avoiding reallocation. - impl SpecIntoVec for &'_ [u8] { - fn into_vec(self) -> Vec { - let mut v = Vec::with_capacity(self.len() + 1); - v.extend(self); - v + + // Specialization for avoiding reallocation + #[inline(always)] // Without that it is not inlined into specializations + fn spec_new_impl_bytes(bytes: &[u8]) -> Result { + // We cannot have such large slice that we would overflow here + // but using `checked_add` allows LLVM to assume that capacity never overflows + // and generate twice shorter code. + // `saturating_add` doesn't help for some reason. + let capacity = bytes.len().checked_add(1).unwrap(); + + // Allocate before validation to avoid duplication of allocation code. + // We still need to allocate and copy memory even if we get an error. + let mut buffer = Vec::with_capacity(capacity); + buffer.extend(bytes); + + // Check memory of self instead of new buffer. + // This allows better optimizations if lto enabled. + match memchr::memchr(0, bytes) { + Some(i) => Err(NulError(i, buffer)), + None => Ok(unsafe { CString::from_vec_unchecked(buffer) }), } } - impl SpecIntoVec for &'_ str { - fn into_vec(self) -> Vec { - let mut v = Vec::with_capacity(self.len() + 1); - v.extend(self.as_bytes()); - v + + impl SpecNewImpl for &'_ [u8] { + fn spec_new_impl(self) -> Result { + spec_new_impl_bytes(self) } } - Self::_new(SpecIntoVec::into_vec(t)) - } + impl SpecNewImpl for &'_ str { + fn spec_new_impl(self) -> Result { + spec_new_impl_bytes(self.as_bytes()) + } + } - fn _new(bytes: Vec) -> Result { - match memchr::memchr(0, &bytes) { - Some(i) => Err(NulError(i, bytes)), - None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), + impl SpecNewImpl for &'_ mut [u8] { + fn spec_new_impl(self) -> Result { + spec_new_impl_bytes(self) + } } + + t.spec_new_impl() } /// Creates a C-compatible string by consuming a byte vector, diff --git a/src/doc/book b/src/doc/book index d3740fb7aad0e..f17df27fc1469 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c +Subproject commit f17df27fc14696912c48b8b7a7a8fa49e648088d diff --git a/src/doc/nomicon b/src/doc/nomicon index c05c452b36358..66d097d3d80e8 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit c05c452b36358821bf4122f9c418674edd1d713d +Subproject commit 66d097d3d80e8f88c288c6879c7c2b909ecf8ad4 diff --git a/src/doc/reference b/src/doc/reference index f8ba2f12df60e..4dee6eb63d728 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit f8ba2f12df60ee19b96de24ae5b73af3de8a446b +Subproject commit 4dee6eb63d728ffb9e7a2ed443e9ada9275c69d2 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 875464457c410..78dd6a4684cf8 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 875464457c4104686faf667f47848aa7b0f0a744 +Subproject commit 78dd6a4684cf8d6b72275fab6d0429ea40b66338 diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index dbc068ce6b13b..44a9a571fa1f8 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -148,8 +148,6 @@ h1.fqn { } .main-heading { display: flex; - border-bottom: 1px dashed #DDDDDD; - padding-bottom: 6px; margin-bottom: 15px; /* workaround to keep flex from breaking below 700 px width due to the float: right on the nav @@ -785,7 +783,6 @@ nav.sub { nav.sub { flex-grow: 1; - padding-bottom: 10px; margin-bottom: 25px; } .source nav.sub { diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 82a2be67ceb0c..69097b81b9f1c 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -194,9 +194,6 @@ pre, .rustdoc.source .example-wrap { pre.rust .comment { color: #788797; } pre.rust .doccomment { color: #a1ac88; } -nav:not(.sidebar) { - border-bottom-color: #424c57; -} nav.main .current { border-top-color: #5c6773; border-bottom-color: #5c6773; diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 761bf50dd36b1..39165b2fc058f 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -151,9 +151,6 @@ a.result-keyword:focus { background-color: #884719; } pre.rust .comment { color: #8d8d8b; } pre.rust .doccomment { color: #8ca375; } -nav:not(.sidebar) { - border-bottom-color: #4e4e4e; -} nav.main .current { border-top-color: #eee; border-bottom-color: #eee; diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 7cca7d4004b5e..448c9ac603c82 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -148,9 +148,6 @@ a.result-keyword:focus { background-color: #afc6e4; } .content .fnname { color: #AD7C37; } .content span.keyword, .content a.keyword, .block a.current.keyword { color: #3873AD; } -nav:not(.sidebar) { - border-bottom-color: #e0e0e0; -} nav.main .current { border-top-color: #000; border-bottom-color: #000; diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml index 34ff2de3a9b2b..48e0156f1b81b 100644 --- a/src/test/rustdoc-gui/headings.goml +++ b/src/test/rustdoc-gui/headings.goml @@ -15,7 +15,6 @@ goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html assert-css: ("h1.fqn", {"font-size": "24px"}) -assert-css: (".main-heading", {"border-bottom-width": "1px"}) assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"}) assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"}) @@ -55,7 +54,6 @@ assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "15.2p goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html assert-css: ("h1.fqn", {"font-size": "24px"}) -assert-css: (".main-heading", {"border-bottom-width": "1px"}) assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"}) assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"}) @@ -115,7 +113,6 @@ assert-css: (".sidebar .others h3", {"border-bottom-width": "0px"}, ALL) goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html assert-css: ("h1.fqn", {"font-size": "24px"}) -assert-css: (".main-heading", {"border-bottom-width": "1px"}) assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"}) assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"}) @@ -148,7 +145,6 @@ assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": " goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html assert-css: ("h1.fqn", {"font-size": "24px"}) -assert-css: (".main-heading", {"border-bottom-width": "1px"}) assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"}) assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"}) diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml index 67b9164cfec71..4c83fd6c0e31c 100644 --- a/src/test/rustdoc-gui/toggle-docs-mobile.goml +++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml @@ -1,12 +1,12 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html size: (433, 600) assert-attribute: (".top-doc", {"open": ""}) -click: (4, 260) // This is the position of the top doc comment toggle +click: (4, 250) // This is the position of the top doc comment toggle assert-attribute-false: (".top-doc", {"open": ""}) -click: (4, 260) +click: (4, 250) assert-attribute: (".top-doc", {"open": ""}) // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked. -click: (3, 260) +click: (3, 250) assert-attribute: (".top-doc", {"open": ""}) // Assert the position of the toggle on the top doc block. @@ -22,10 +22,10 @@ assert-position: ( // Now we do the same but with a little bigger width size: (600, 600) assert-attribute: (".top-doc", {"open": ""}) -click: (4, 260) // New Y position since all search elements are back on one line. +click: (4, 250) // New Y position since all search elements are back on one line. assert-attribute-false: (".top-doc", {"open": ""}) -click: (4, 260) +click: (4, 250) assert-attribute: (".top-doc", {"open": ""}) // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked. -click: (3, 260) +click: (3, 250) assert-attribute: (".top-doc", {"open": ""}) diff --git a/src/test/ui/derive-uninhabited-enum-38885.stderr b/src/test/ui/derive-uninhabited-enum-38885.stderr index 72607629d3c10..2a44e56a3302c 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.stderr +++ b/src/test/ui/derive-uninhabited-enum-38885.stderr @@ -5,6 +5,12 @@ LL | Void(Void), | ^^^^^^^^^^ | = note: `-W dead-code` implied by `-W unused` +note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis + --> $DIR/derive-uninhabited-enum-38885.rs:10:10 + | +LL | #[derive(Debug)] + | ^^^^^ + = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) warning: 1 warning emitted diff --git a/src/test/ui/derives/clone-debug-dead-code.stderr b/src/test/ui/derives/clone-debug-dead-code.stderr index 226007f3647b1..67bb574315a72 100644 --- a/src/test/ui/derives/clone-debug-dead-code.stderr +++ b/src/test/ui/derives/clone-debug-dead-code.stderr @@ -15,18 +15,39 @@ error: field is never read: `f` | LL | struct B { f: () } | ^^^^^ + | +note: `B` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis + --> $DIR/clone-debug-dead-code.rs:9:10 + | +LL | #[derive(Clone)] + | ^^^^^ + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) error: field is never read: `f` --> $DIR/clone-debug-dead-code.rs:14:12 | LL | struct C { f: () } | ^^^^^ + | +note: `C` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis + --> $DIR/clone-debug-dead-code.rs:13:10 + | +LL | #[derive(Debug)] + | ^^^^^ + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) error: field is never read: `f` --> $DIR/clone-debug-dead-code.rs:18:12 | LL | struct D { f: () } | ^^^^^ + | +note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis + --> $DIR/clone-debug-dead-code.rs:17:10 + | +LL | #[derive(Debug,Clone)] + | ^^^^^ ^^^^^ + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) error: field is never read: `f` --> $DIR/clone-debug-dead-code.rs:21:12 diff --git a/src/test/ui/expr/if/attrs/let-chains-attr.rs b/src/test/ui/expr/if/attrs/let-chains-attr.rs index 5237a9ff3961a..2cd8731141af7 100644 --- a/src/test/ui/expr/if/attrs/let-chains-attr.rs +++ b/src/test/ui/expr/if/attrs/let-chains-attr.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete +#![feature(let_chains)] #[cfg(FALSE)] fn foo() { diff --git a/src/test/ui/expr/if/attrs/let-chains-attr.stderr b/src/test/ui/expr/if/attrs/let-chains-attr.stderr deleted file mode 100644 index 8b9874715342c..0000000000000 --- a/src/test/ui/expr/if/attrs/let-chains-attr.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/let-chains-attr.rs:3:12 - | -LL | #![feature(let_chains)] - | ^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #53667 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/lint/dead-code/unused-variant.stderr b/src/test/ui/lint/dead-code/unused-variant.stderr index a547f5af4b082..3b5683a7748fa 100644 --- a/src/test/ui/lint/dead-code/unused-variant.stderr +++ b/src/test/ui/lint/dead-code/unused-variant.stderr @@ -9,6 +9,12 @@ note: the lint level is defined here | LL | #![deny(dead_code)] | ^^^^^^^^^ +note: `Enum` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis + --> $DIR/unused-variant.rs:3:10 + | +LL | #[derive(Clone)] + | ^^^^^ + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/mir/mir_let_chains_drop_order.rs b/src/test/ui/mir/mir_let_chains_drop_order.rs new file mode 100644 index 0000000000000..01f943c87dd7f --- /dev/null +++ b/src/test/ui/mir/mir_let_chains_drop_order.rs @@ -0,0 +1,93 @@ +// run-pass +// needs-unwind +// ignore-wasm32-bare compiled with panic=abort by default + +// See `mir_drop_order.rs` for more information + +#![feature(let_chains)] + +use std::cell::RefCell; +use std::panic; + +pub struct DropLogger<'a, T> { + extra: T, + id: usize, + log: &'a panic::AssertUnwindSafe>> +} + +impl<'a, T> Drop for DropLogger<'a, T> { + fn drop(&mut self) { + self.log.0.borrow_mut().push(self.id); + } +} + +struct InjectedFailure; + +#[allow(unreachable_code)] +fn main() { + let log = panic::AssertUnwindSafe(RefCell::new(vec![])); + let d = |id, extra| DropLogger { extra, id: id, log: &log }; + let get = || -> Vec<_> { + let mut m = log.0.borrow_mut(); + let n = m.drain(..); + n.collect() + }; + + { + let _x = ( + d( + 0, + d( + 1, + if let Some(_) = d(2, Some(true)).extra && let DropLogger { .. } = d(3, None) { + None + } else { + Some(true) + } + ).extra + ), + d(4, None), + &d(5, None), + d(6, None), + if let DropLogger { .. } = d(7, None) && let DropLogger { .. } = d(8, None) { + d(9, None) + } + else { + // 10 is not constructed + d(10, None) + } + ); + assert_eq!(get(), vec![3, 8, 7, 1, 2]); + } + assert_eq!(get(), vec![0, 4, 6, 9, 5]); + + let _ = std::panic::catch_unwind(|| { + ( + d( + 11, + d( + 12, + if let Some(_) = d(13, Some(true)).extra + && let DropLogger { .. } = d(14, None) + { + None + } else { + Some(true) + } + ).extra + ), + d(15, None), + &d(16, None), + d(17, None), + if let DropLogger { .. } = d(18, None) && let DropLogger { .. } = d(19, None) { + d(20, None) + } + else { + // 10 is not constructed + d(21, None) + }, + panic::panic_any(InjectedFailure) + ); + }); + assert_eq!(get(), vec![14, 19, 20, 17, 15, 11, 18, 16, 12, 13]); +} diff --git a/src/test/ui/pattern/issue-82290.rs b/src/test/ui/pattern/issue-82290.rs deleted file mode 100644 index d8da0ac8aa6c5..0000000000000 --- a/src/test/ui/pattern/issue-82290.rs +++ /dev/null @@ -1,9 +0,0 @@ -// check-pass - -#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete - -fn main() { - if true && let x = 1 { //~ WARN irrefutable `let` pattern - let _ = x; - } -} diff --git a/src/test/ui/pattern/issue-82290.stderr b/src/test/ui/pattern/issue-82290.stderr deleted file mode 100644 index 0a3cf2c794f47..0000000000000 --- a/src/test/ui/pattern/issue-82290.stderr +++ /dev/null @@ -1,21 +0,0 @@ -warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-82290.rs:3:12 - | -LL | #![feature(let_chains)] - | ^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #53667 for more information - -warning: irrefutable `let` pattern - --> $DIR/issue-82290.rs:6:16 - | -LL | if true && let x = 1 { - | ^^^^^^^^^ - | - = note: `#[warn(irrefutable_let_patterns)]` on by default - = note: this pattern will always match, so the `let` is useless - = help: consider removing `let` - -warning: 2 warnings emitted - diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs index 2a2c0be52630b..34d2d84da934f 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs @@ -8,36 +8,36 @@ fn _if_let_guard() { //~^ ERROR `if let` guards are experimental () if (let 0 = 1) => {} - //~^ ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable () if (((let 0 = 1))) => {} - //~^ ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable () if true && let 0 = 1 => {} - //~^ ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable () if let 0 = 1 && true => {} - //~^ ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable () if (let 0 = 1) && true => {} - //~^ ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable () if true && (let 0 = 1) => {} - //~^ ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable () if (let 0 = 1) && (let 0 = 1) => {} - //~^ ERROR `let` expressions in this position are experimental - //~| ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} - //~^ ERROR `let` expressions in this position are experimental - //~| ERROR `let` expressions in this position are experimental - //~| ERROR `let` expressions in this position are experimental - //~| ERROR `let` expressions in this position are experimental - //~| ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable + //~| ERROR `let` expressions in this position are unstable () if let Range { start: _, end: _ } = (true..true) && false => {} - //~^ ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable _ => {} } } @@ -52,9 +52,9 @@ fn _macros() { } } use_expr!((let 0 = 1 && 0 == 0)); - //~^ ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable use_expr!((let 0 = 1)); - //~^ ERROR `let` expressions in this position are experimental + //~^ ERROR `let` expressions in this position are unstable match () { #[cfg(FALSE)] () if let 0 = 1 => {} diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr index bedcdcb019ba9..0cda6ba9a9927 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -27,7 +27,7 @@ LL | () if let 0 = 1 => {} = help: add `#![feature(if_let_guard)]` to the crate attributes to enable = help: you can write `if matches!(, )` instead of `if let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:10:16 | LL | () if (let 0 = 1) => {} @@ -35,9 +35,8 @@ LL | () if (let 0 = 1) => {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:13:18 | LL | () if (((let 0 = 1))) => {} @@ -45,9 +44,8 @@ LL | () if (((let 0 = 1))) => {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:16:23 | LL | () if true && let 0 = 1 => {} @@ -55,9 +53,8 @@ LL | () if true && let 0 = 1 => {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:19:15 | LL | () if let 0 = 1 && true => {} @@ -65,9 +62,8 @@ LL | () if let 0 = 1 && true => {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:22:16 | LL | () if (let 0 = 1) && true => {} @@ -75,9 +71,8 @@ LL | () if (let 0 = 1) && true => {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:25:24 | LL | () if true && (let 0 = 1) => {} @@ -85,9 +80,8 @@ LL | () if true && (let 0 = 1) => {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:28:16 | LL | () if (let 0 = 1) && (let 0 = 1) => {} @@ -95,9 +89,8 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:28:31 | LL | () if (let 0 = 1) && (let 0 = 1) => {} @@ -105,9 +98,8 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:32:15 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} @@ -115,9 +107,8 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:32:28 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} @@ -125,9 +116,8 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:32:42 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} @@ -135,9 +125,8 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:32:55 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} @@ -145,9 +134,8 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:32:68 | LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} @@ -155,9 +143,8 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:39:15 | LL | () if let Range { start: _, end: _ } = (true..true) && false => {} @@ -165,9 +152,8 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:54:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); @@ -175,9 +161,8 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:56:16 | LL | use_expr!((let 0 = 1)); @@ -185,7 +170,6 @@ LL | use_expr!((let 0 = 1)); | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` error: aborting due to 19 previous errors diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs b/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs new file mode 100644 index 0000000000000..708bcdd0aefe3 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(let_chains)] + +fn main() { + let first = Some(1); + let second = Some(2); + let mut n = 0; + if let x = first && let y = second && 1 == 1 { + assert_eq!(x, first); + assert_eq!(y, second); + n = 1; + } + assert_eq!(n, 1); +} diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs index 710fdd57ed7b3..69bc189dd3579 100644 --- a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs +++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // compile-flags: -Z unpretty=expanded fn main() { diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout index 6052ea95d0f85..e737ef26e9b38 100644 --- a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout +++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout @@ -4,7 +4,7 @@ use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // compile-flags: -Z unpretty=expanded fn main() { if let 0 = 1 {} } diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs new file mode 100644 index 0000000000000..a7e108d72d1ff --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs @@ -0,0 +1,20 @@ +fn and_chain() { + let z; + if true && { z = 3; true} && z == 3 {} + //~^ ERROR use of possibly-uninitialized +} + +fn and_chain_2() { + let z; + true && { z = 3; true} && z == 3; + //~^ ERROR use of possibly-uninitialized +} + +fn or_chain() { + let z; + if false || { z = 3; false} || z == 3 {} + //~^ ERROR use of possibly-uninitialized +} + +fn main() { +} diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr new file mode 100644 index 0000000000000..3c47040cc8c24 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr @@ -0,0 +1,21 @@ +error[E0381]: use of possibly-uninitialized variable: `z` + --> $DIR/chains-without-let.rs:3:34 + | +LL | if true && { z = 3; true} && z == 3 {} + | ^ use of possibly-uninitialized `z` + +error[E0381]: use of possibly-uninitialized variable: `z` + --> $DIR/chains-without-let.rs:9:31 + | +LL | true && { z = 3; true} && z == 3; + | ^ use of possibly-uninitialized `z` + +error[E0381]: use of possibly-uninitialized variable: `z` + --> $DIR/chains-without-let.rs:15:36 + | +LL | if false || { z = 3; false} || z == 3 {} + | ^ use of possibly-uninitialized `z` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs index b0b3464c61017..5b2693d07a790 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs @@ -18,7 +18,6 @@ // To that end, we check some positions which is not part of the language above. #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. -//~^ WARN the feature `let_chains` is incomplete #![allow(irrefutable_let_patterns)] diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 1433a16d7274a..4c830554d435c 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -1,5 +1,5 @@ error: expressions must be enclosed in braces to be used as const generic arguments - --> $DIR/disallowed-positions.rs:233:9 + --> $DIR/disallowed-positions.rs:232:9 | LL | true && let 1 = 1 | ^^^^^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | { true && let 1 = 1 } | + + error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:30:9 + --> $DIR/disallowed-positions.rs:29:9 | LL | if &let 0 = 0 {} | ^^^^^^^^^ @@ -19,7 +19,7 @@ LL | if &let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:33:9 + --> $DIR/disallowed-positions.rs:32:9 | LL | if !let 0 = 0 {} | ^^^^^^^^^ @@ -28,7 +28,7 @@ LL | if !let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:34:9 + --> $DIR/disallowed-positions.rs:33:9 | LL | if *let 0 = 0 {} | ^^^^^^^^^ @@ -37,7 +37,7 @@ LL | if *let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:36:9 + --> $DIR/disallowed-positions.rs:35:9 | LL | if -let 0 = 0 {} | ^^^^^^^^^ @@ -46,7 +46,7 @@ LL | if -let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:44:9 + --> $DIR/disallowed-positions.rs:43:9 | LL | if (let 0 = 0)? {} | ^^^^^^^^^ @@ -55,7 +55,7 @@ LL | if (let 0 = 0)? {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:48:16 + --> $DIR/disallowed-positions.rs:47:16 | LL | if true || let 0 = 0 {} | ^^^^^^^^^ @@ -64,7 +64,7 @@ LL | if true || let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:49:17 + --> $DIR/disallowed-positions.rs:48:17 | LL | if (true || let 0 = 0) {} | ^^^^^^^^^ @@ -73,7 +73,7 @@ LL | if (true || let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:50:25 + --> $DIR/disallowed-positions.rs:49:25 | LL | if true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -82,7 +82,7 @@ LL | if true && (true || let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:51:25 + --> $DIR/disallowed-positions.rs:50:25 | LL | if true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -91,7 +91,7 @@ LL | if true || (true && let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:54:12 + --> $DIR/disallowed-positions.rs:53:12 | LL | if x = let 0 = 0 {} | ^^^^^^^^^ @@ -100,7 +100,7 @@ LL | if x = let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:57:15 + --> $DIR/disallowed-positions.rs:56:15 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^ @@ -109,7 +109,7 @@ LL | if true..(let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:59:11 + --> $DIR/disallowed-positions.rs:58:11 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^ @@ -118,7 +118,7 @@ LL | if ..(let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:61:9 + --> $DIR/disallowed-positions.rs:60:9 | LL | if (let 0 = 0).. {} | ^^^^^^^^^ @@ -127,7 +127,7 @@ LL | if (let 0 = 0).. {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:65:8 + --> $DIR/disallowed-positions.rs:64:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:69:8 + --> $DIR/disallowed-positions.rs:68:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:76:8 + --> $DIR/disallowed-positions.rs:75:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | if let Range { start: F, end } = F..|| true {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:84:8 + --> $DIR/disallowed-positions.rs:83:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ LL | if let Range { start: true, end } = t..&&false {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:90:19 + --> $DIR/disallowed-positions.rs:89:19 | LL | if let true = let true = true {} | ^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | if let true = let true = true {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:94:12 + --> $DIR/disallowed-positions.rs:93:12 | LL | while &let 0 = 0 {} | ^^^^^^^^^ @@ -181,7 +181,7 @@ LL | while &let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:97:12 + --> $DIR/disallowed-positions.rs:96:12 | LL | while !let 0 = 0 {} | ^^^^^^^^^ @@ -190,7 +190,7 @@ LL | while !let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:98:12 + --> $DIR/disallowed-positions.rs:97:12 | LL | while *let 0 = 0 {} | ^^^^^^^^^ @@ -199,7 +199,7 @@ LL | while *let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:100:12 + --> $DIR/disallowed-positions.rs:99:12 | LL | while -let 0 = 0 {} | ^^^^^^^^^ @@ -208,7 +208,7 @@ LL | while -let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:108:12 + --> $DIR/disallowed-positions.rs:107:12 | LL | while (let 0 = 0)? {} | ^^^^^^^^^ @@ -217,7 +217,7 @@ LL | while (let 0 = 0)? {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:112:19 + --> $DIR/disallowed-positions.rs:111:19 | LL | while true || let 0 = 0 {} | ^^^^^^^^^ @@ -226,7 +226,7 @@ LL | while true || let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:113:20 + --> $DIR/disallowed-positions.rs:112:20 | LL | while (true || let 0 = 0) {} | ^^^^^^^^^ @@ -235,7 +235,7 @@ LL | while (true || let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:114:28 + --> $DIR/disallowed-positions.rs:113:28 | LL | while true && (true || let 0 = 0) {} | ^^^^^^^^^ @@ -244,7 +244,7 @@ LL | while true && (true || let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:115:28 + --> $DIR/disallowed-positions.rs:114:28 | LL | while true || (true && let 0 = 0) {} | ^^^^^^^^^ @@ -253,7 +253,7 @@ LL | while true || (true && let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:118:15 + --> $DIR/disallowed-positions.rs:117:15 | LL | while x = let 0 = 0 {} | ^^^^^^^^^ @@ -262,7 +262,7 @@ LL | while x = let 0 = 0 {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:121:18 + --> $DIR/disallowed-positions.rs:120:18 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^ @@ -271,7 +271,7 @@ LL | while true..(let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:123:14 + --> $DIR/disallowed-positions.rs:122:14 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^ @@ -280,7 +280,7 @@ LL | while ..(let 0 = 0) {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:125:12 + --> $DIR/disallowed-positions.rs:124:12 | LL | while (let 0 = 0).. {} | ^^^^^^^^^ @@ -289,7 +289,7 @@ LL | while (let 0 = 0).. {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:129:11 + --> $DIR/disallowed-positions.rs:128:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -298,7 +298,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:133:11 + --> $DIR/disallowed-positions.rs:132:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -307,7 +307,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:140:11 + --> $DIR/disallowed-positions.rs:139:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -316,7 +316,7 @@ LL | while let Range { start: F, end } = F..|| true {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:148:11 + --> $DIR/disallowed-positions.rs:147:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL | while let Range { start: true, end } = t..&&false {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:154:22 + --> $DIR/disallowed-positions.rs:153:22 | LL | while let true = let true = true {} | ^^^^^^^^^^^^^^^ @@ -334,7 +334,7 @@ LL | while let true = let true = true {} = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:168:6 + --> $DIR/disallowed-positions.rs:167:6 | LL | &let 0 = 0; | ^^^^^^^^^ @@ -343,7 +343,7 @@ LL | &let 0 = 0; = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:170:6 + --> $DIR/disallowed-positions.rs:169:6 | LL | !let 0 = 0; | ^^^^^^^^^ @@ -352,7 +352,7 @@ LL | !let 0 = 0; = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:171:6 + --> $DIR/disallowed-positions.rs:170:6 | LL | *let 0 = 0; | ^^^^^^^^^ @@ -361,7 +361,7 @@ LL | *let 0 = 0; = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:173:6 + --> $DIR/disallowed-positions.rs:172:6 | LL | -let 0 = 0; | ^^^^^^^^^ @@ -370,7 +370,7 @@ LL | -let 0 = 0; = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:181:6 + --> $DIR/disallowed-positions.rs:180:6 | LL | (let 0 = 0)?; | ^^^^^^^^^ @@ -379,7 +379,7 @@ LL | (let 0 = 0)?; = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:185:13 + --> $DIR/disallowed-positions.rs:184:13 | LL | true || let 0 = 0; | ^^^^^^^^^ @@ -388,7 +388,7 @@ LL | true || let 0 = 0; = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:186:14 + --> $DIR/disallowed-positions.rs:185:14 | LL | (true || let 0 = 0); | ^^^^^^^^^ @@ -397,7 +397,7 @@ LL | (true || let 0 = 0); = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:187:22 + --> $DIR/disallowed-positions.rs:186:22 | LL | true && (true || let 0 = 0); | ^^^^^^^^^ @@ -406,7 +406,7 @@ LL | true && (true || let 0 = 0); = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:190:9 + --> $DIR/disallowed-positions.rs:189:9 | LL | x = let 0 = 0; | ^^^^^^^^^ @@ -415,7 +415,7 @@ LL | x = let 0 = 0; = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:192:12 + --> $DIR/disallowed-positions.rs:191:12 | LL | true..(let 0 = 0); | ^^^^^^^^^ @@ -424,7 +424,7 @@ LL | true..(let 0 = 0); = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:193:8 + --> $DIR/disallowed-positions.rs:192:8 | LL | ..(let 0 = 0); | ^^^^^^^^^ @@ -433,7 +433,7 @@ LL | ..(let 0 = 0); = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:194:6 + --> $DIR/disallowed-positions.rs:193:6 | LL | (let 0 = 0)..; | ^^^^^^^^^ @@ -442,7 +442,7 @@ LL | (let 0 = 0)..; = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:196:6 + --> $DIR/disallowed-positions.rs:195:6 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -451,7 +451,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:200:6 + --> $DIR/disallowed-positions.rs:199:6 | LL | (let true = let true = true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -460,7 +460,7 @@ LL | (let true = let true = true); = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:204:6 + --> $DIR/disallowed-positions.rs:203:6 | LL | &let 0 = 0 | ^^^^^^^^^ @@ -469,7 +469,7 @@ LL | &let 0 = 0 = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:215:17 + --> $DIR/disallowed-positions.rs:214:17 | LL | true && let 1 = 1 | ^^^^^^^^^ @@ -478,7 +478,7 @@ LL | true && let 1 = 1 = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:219:17 + --> $DIR/disallowed-positions.rs:218:17 | LL | true && let 1 = 1 | ^^^^^^^^^ @@ -487,7 +487,7 @@ LL | true && let 1 = 1 = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:223:17 + --> $DIR/disallowed-positions.rs:222:17 | LL | true && let 1 = 1 | ^^^^^^^^^ @@ -496,7 +496,7 @@ LL | true && let 1 = 1 = note: as well as when nested within `&&` and parentheses in those conditions error: `let` expressions are not supported here - --> $DIR/disallowed-positions.rs:233:17 + --> $DIR/disallowed-positions.rs:232:17 | LL | true && let 1 = 1 | ^^^^^^^^^ @@ -504,17 +504,8 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if`- and `while`-expressions = note: as well as when nested within `&&` and parentheses in those conditions -warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/disallowed-positions.rs:20:12 - | -LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. - | ^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #53667 for more information - error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:30:8 + --> $DIR/disallowed-positions.rs:29:8 | LL | if &let 0 = 0 {} | ^^^^^^^^^^ expected `bool`, found `&bool` @@ -526,19 +517,19 @@ LL + if let 0 = 0 {} | error[E0614]: type `bool` cannot be dereferenced - --> $DIR/disallowed-positions.rs:34:8 + --> $DIR/disallowed-positions.rs:33:8 | LL | if *let 0 = 0 {} | ^^^^^^^^^^ error[E0600]: cannot apply unary operator `-` to type `bool` - --> $DIR/disallowed-positions.rs:36:8 + --> $DIR/disallowed-positions.rs:35:8 | LL | if -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:44:8 + --> $DIR/disallowed-positions.rs:43:8 | LL | if (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` @@ -546,7 +537,7 @@ LL | if (let 0 = 0)? {} = help: the trait `Try` is not implemented for `bool` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/disallowed-positions.rs:44:19 + --> $DIR/disallowed-positions.rs:43:19 | LL | / fn nested_within_if_expr() { LL | | if &let 0 = 0 {} @@ -563,7 +554,7 @@ LL | | } = help: the trait `FromResidual<_>` is not implemented for `()` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:54:8 + --> $DIR/disallowed-positions.rs:53:8 | LL | if x = let 0 = 0 {} | ^^^^^^^^^^^^^ expected `bool`, found `()` @@ -574,7 +565,7 @@ LL | if x == let 0 = 0 {} | ~~ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:57:8 + --> $DIR/disallowed-positions.rs:56:8 | LL | if true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -583,7 +574,7 @@ LL | if true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:59:8 + --> $DIR/disallowed-positions.rs:58:8 | LL | if ..(let 0 = 0) {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` @@ -592,7 +583,7 @@ LL | if ..(let 0 = 0) {} found struct `RangeTo` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:61:8 + --> $DIR/disallowed-positions.rs:60:8 | LL | if (let 0 = 0).. {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` @@ -601,7 +592,7 @@ LL | if (let 0 = 0).. {} found struct `RangeFrom` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:65:12 + --> $DIR/disallowed-positions.rs:64:12 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -612,7 +603,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:65:8 + --> $DIR/disallowed-positions.rs:64:8 | LL | if let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -621,7 +612,7 @@ LL | if let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:69:12 + --> $DIR/disallowed-positions.rs:68:12 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -632,7 +623,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:69:8 + --> $DIR/disallowed-positions.rs:68:8 | LL | if let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -641,7 +632,7 @@ LL | if let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:76:12 + --> $DIR/disallowed-positions.rs:75:12 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -652,16 +643,16 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:76:41 + --> $DIR/disallowed-positions.rs:75:41 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^ expected `bool`, found closure | = note: expected type `bool` - found closure `[closure@$DIR/disallowed-positions.rs:76:41: 76:48]` + found closure `[closure@$DIR/disallowed-positions.rs:75:41: 75:48]` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:76:8 + --> $DIR/disallowed-positions.rs:75:8 | LL | if let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -670,7 +661,7 @@ LL | if let Range { start: F, end } = F..|| true {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:84:12 + --> $DIR/disallowed-positions.rs:83:12 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -681,13 +672,13 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:84:44 + --> $DIR/disallowed-positions.rs:83:44 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^ expected `bool`, found `&&bool` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:84:8 + --> $DIR/disallowed-positions.rs:83:8 | LL | if let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -696,7 +687,7 @@ LL | if let Range { start: true, end } = t..&&false {} found struct `std::ops::Range` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:40:20 + --> $DIR/disallowed-positions.rs:39:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -704,7 +695,7 @@ LL | if let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:94:11 + --> $DIR/disallowed-positions.rs:93:11 | LL | while &let 0 = 0 {} | ^^^^^^^^^^ expected `bool`, found `&bool` @@ -716,19 +707,19 @@ LL + while let 0 = 0 {} | error[E0614]: type `bool` cannot be dereferenced - --> $DIR/disallowed-positions.rs:98:11 + --> $DIR/disallowed-positions.rs:97:11 | LL | while *let 0 = 0 {} | ^^^^^^^^^^ error[E0600]: cannot apply unary operator `-` to type `bool` - --> $DIR/disallowed-positions.rs:100:11 + --> $DIR/disallowed-positions.rs:99:11 | LL | while -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:108:11 + --> $DIR/disallowed-positions.rs:107:11 | LL | while (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` @@ -736,7 +727,7 @@ LL | while (let 0 = 0)? {} = help: the trait `Try` is not implemented for `bool` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/disallowed-positions.rs:108:22 + --> $DIR/disallowed-positions.rs:107:22 | LL | / fn nested_within_while_expr() { LL | | while &let 0 = 0 {} @@ -753,7 +744,7 @@ LL | | } = help: the trait `FromResidual<_>` is not implemented for `()` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:118:11 + --> $DIR/disallowed-positions.rs:117:11 | LL | while x = let 0 = 0 {} | ^^^^^^^^^^^^^ expected `bool`, found `()` @@ -764,7 +755,7 @@ LL | while x == let 0 = 0 {} | ~~ error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:121:11 + --> $DIR/disallowed-positions.rs:120:11 | LL | while true..(let 0 = 0) {} | ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -773,7 +764,7 @@ LL | while true..(let 0 = 0) {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:123:11 + --> $DIR/disallowed-positions.rs:122:11 | LL | while ..(let 0 = 0) {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` @@ -782,7 +773,7 @@ LL | while ..(let 0 = 0) {} found struct `RangeTo` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:125:11 + --> $DIR/disallowed-positions.rs:124:11 | LL | while (let 0 = 0).. {} | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` @@ -791,7 +782,7 @@ LL | while (let 0 = 0).. {} found struct `RangeFrom` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:129:15 + --> $DIR/disallowed-positions.rs:128:15 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -802,7 +793,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:129:11 + --> $DIR/disallowed-positions.rs:128:11 | LL | while let Range { start: _, end: _ } = true..true && false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -811,7 +802,7 @@ LL | while let Range { start: _, end: _ } = true..true && false {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:133:15 + --> $DIR/disallowed-positions.rs:132:15 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -822,7 +813,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:133:11 + --> $DIR/disallowed-positions.rs:132:11 | LL | while let Range { start: _, end: _ } = true..true || false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -831,7 +822,7 @@ LL | while let Range { start: _, end: _ } = true..true || false {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:140:15 + --> $DIR/disallowed-positions.rs:139:15 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool` @@ -842,16 +833,16 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:140:44 + --> $DIR/disallowed-positions.rs:139:44 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^ expected `bool`, found closure | = note: expected type `bool` - found closure `[closure@$DIR/disallowed-positions.rs:140:44: 140:51]` + found closure `[closure@$DIR/disallowed-positions.rs:139:44: 139:51]` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:140:11 + --> $DIR/disallowed-positions.rs:139:11 | LL | while let Range { start: F, end } = F..|| true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -860,7 +851,7 @@ LL | while let Range { start: F, end } = F..|| true {} found struct `std::ops::Range` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:148:15 + --> $DIR/disallowed-positions.rs:147:15 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` @@ -871,13 +862,13 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:148:47 + --> $DIR/disallowed-positions.rs:147:47 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^ expected `bool`, found `&&bool` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:148:11 + --> $DIR/disallowed-positions.rs:147:11 | LL | while let Range { start: true, end } = t..&&false {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range` @@ -886,7 +877,7 @@ LL | while let Range { start: true, end } = t..&&false {} found struct `std::ops::Range` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:104:23 + --> $DIR/disallowed-positions.rs:103:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` @@ -894,19 +885,19 @@ LL | while let 0 = 0? {} = help: the trait `Try` is not implemented for `{integer}` error[E0614]: type `bool` cannot be dereferenced - --> $DIR/disallowed-positions.rs:171:5 + --> $DIR/disallowed-positions.rs:170:5 | LL | *let 0 = 0; | ^^^^^^^^^^ error[E0600]: cannot apply unary operator `-` to type `bool` - --> $DIR/disallowed-positions.rs:173:5 + --> $DIR/disallowed-positions.rs:172:5 | LL | -let 0 = 0; | ^^^^^^^^^^ cannot apply unary operator `-` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:181:5 + --> $DIR/disallowed-positions.rs:180:5 | LL | (let 0 = 0)?; | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` @@ -914,7 +905,7 @@ LL | (let 0 = 0)?; = help: the trait `Try` is not implemented for `bool` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/disallowed-positions.rs:181:16 + --> $DIR/disallowed-positions.rs:180:16 | LL | / fn outside_if_and_while_expr() { LL | | &let 0 = 0; @@ -931,7 +922,7 @@ LL | | } = help: the trait `FromResidual<_>` is not implemented for `()` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:196:10 + --> $DIR/disallowed-positions.rs:195:10 | LL | (let Range { start: _, end: _ } = true..true || false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` @@ -942,7 +933,7 @@ LL | (let Range { start: _, end: _ } = true..true || false); found struct `std::ops::Range<_>` error[E0308]: mismatched types - --> $DIR/disallowed-positions.rs:204:5 + --> $DIR/disallowed-positions.rs:203:5 | LL | fn outside_if_and_while_expr() { | - help: try adding a return type: `-> &bool` @@ -951,14 +942,14 @@ LL | &let 0 = 0 | ^^^^^^^^^^ expected `()`, found `&bool` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/disallowed-positions.rs:177:17 + --> $DIR/disallowed-positions.rs:176:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` -error: aborting due to 103 previous errors; 1 warning emitted +error: aborting due to 103 previous errors Some errors have detailed explanations: E0277, E0308, E0600, E0614. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs index 2b4259e9dc150..53fec8316e7e7 100644 --- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs +++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs @@ -12,79 +12,79 @@ fn _if() { if let 0 = 1 {} // Stable! if (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] if (((let 0 = 1))) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] if true && let 0 = 1 {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] if let 0 = 1 && true {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] if (let 0 = 1) && true {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] if true && (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] if (let 0 = 1) && (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] if let Range { start: _, end: _ } = (true..true) && false {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] } fn _while() { while let 0 = 1 {} // Stable! while (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] while (((let 0 = 1))) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] while true && let 0 = 1 {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] while let 0 = 1 && true {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] while (let 0 = 1) && true {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] while true && (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] while (let 0 = 1) && (let 0 = 1) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} - //~^ ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] - //~| ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] + //~| ERROR `let` expressions in this position are unstable [E0658] while let Range { start: _, end: _ } = (true..true) && false {} - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] } fn _macros() { macro_rules! noop_expr { ($e:expr) => {}; } noop_expr!((let 0 = 1)); - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] macro_rules! use_expr { ($e:expr) => { @@ -93,11 +93,11 @@ fn _macros() { } } use_expr!((let 0 = 1 && 0 == 0)); - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] use_expr!((let 0 = 1)); - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] #[cfg(FALSE)] (let 0 = 1); - //~^ ERROR `let` expressions in this position are experimental [E0658] + //~^ ERROR `let` expressions in this position are unstable [E0658] use_expr!(let 0 = 1); //~^ ERROR no rules expected the token `let` // ^--- FIXME(53667): Consider whether `Let` can be added to `ident_can_begin_expr`. diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr index 180eee0cadfe6..458826498fe2d 100644 --- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr @@ -7,7 +7,7 @@ LL | macro_rules! use_expr { LL | use_expr!(let 0 = 1); | ^^^ no rules expected this token in macro call -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:14:9 | LL | if (let 0 = 1) {} @@ -15,9 +15,8 @@ LL | if (let 0 = 1) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:17:11 | LL | if (((let 0 = 1))) {} @@ -25,9 +24,8 @@ LL | if (((let 0 = 1))) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:20:16 | LL | if true && let 0 = 1 {} @@ -35,9 +33,8 @@ LL | if true && let 0 = 1 {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:23:8 | LL | if let 0 = 1 && true {} @@ -45,9 +42,8 @@ LL | if let 0 = 1 && true {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:26:9 | LL | if (let 0 = 1) && true {} @@ -55,9 +51,8 @@ LL | if (let 0 = 1) && true {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:29:17 | LL | if true && (let 0 = 1) {} @@ -65,9 +60,8 @@ LL | if true && (let 0 = 1) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:32:9 | LL | if (let 0 = 1) && (let 0 = 1) {} @@ -75,9 +69,8 @@ LL | if (let 0 = 1) && (let 0 = 1) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:32:24 | LL | if (let 0 = 1) && (let 0 = 1) {} @@ -85,9 +78,8 @@ LL | if (let 0 = 1) && (let 0 = 1) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:36:8 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -95,9 +87,8 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:36:21 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -105,9 +96,8 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:36:35 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -115,9 +105,8 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:36:48 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -125,9 +114,8 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:36:61 | LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -135,9 +123,8 @@ LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:43:8 | LL | if let Range { start: _, end: _ } = (true..true) && false {} @@ -145,9 +132,8 @@ LL | if let Range { start: _, end: _ } = (true..true) && false {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:50:12 | LL | while (let 0 = 1) {} @@ -155,9 +141,8 @@ LL | while (let 0 = 1) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:53:14 | LL | while (((let 0 = 1))) {} @@ -165,9 +150,8 @@ LL | while (((let 0 = 1))) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:56:19 | LL | while true && let 0 = 1 {} @@ -175,9 +159,8 @@ LL | while true && let 0 = 1 {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:59:11 | LL | while let 0 = 1 && true {} @@ -185,9 +168,8 @@ LL | while let 0 = 1 && true {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:62:12 | LL | while (let 0 = 1) && true {} @@ -195,9 +177,8 @@ LL | while (let 0 = 1) && true {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:65:20 | LL | while true && (let 0 = 1) {} @@ -205,9 +186,8 @@ LL | while true && (let 0 = 1) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:68:12 | LL | while (let 0 = 1) && (let 0 = 1) {} @@ -215,9 +195,8 @@ LL | while (let 0 = 1) && (let 0 = 1) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:68:27 | LL | while (let 0 = 1) && (let 0 = 1) {} @@ -225,9 +204,8 @@ LL | while (let 0 = 1) && (let 0 = 1) {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:72:11 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -235,9 +213,8 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:72:24 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -245,9 +222,8 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:72:38 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -255,9 +231,8 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:72:51 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -265,9 +240,8 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:72:64 | LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {} @@ -275,9 +249,8 @@ LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) { | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:79:11 | LL | while let Range { start: _, end: _ } = (true..true) && false {} @@ -285,9 +258,8 @@ LL | while let Range { start: _, end: _ } = (true..true) && false {} | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:99:20 | LL | #[cfg(FALSE)] (let 0 = 1); @@ -295,9 +267,8 @@ LL | #[cfg(FALSE)] (let 0 = 1); | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:86:17 | LL | noop_expr!((let 0 = 1)); @@ -305,9 +276,8 @@ LL | noop_expr!((let 0 = 1)); | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:95:16 | LL | use_expr!((let 0 = 1 && 0 == 0)); @@ -315,9 +285,8 @@ LL | use_expr!((let 0 = 1 && 0 == 0)); | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` -error[E0658]: `let` expressions in this position are experimental +error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:97:16 | LL | use_expr!((let 0 = 1)); @@ -325,7 +294,6 @@ LL | use_expr!((let 0 = 1)); | = note: see issue #53667 for more information = help: add `#![feature(let_chains)]` to the crate attributes to enable - = help: you can write `matches!(, )` instead of `let = ` error: aborting due to 33 previous errors diff --git a/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs new file mode 100644 index 0000000000000..5915cb9df269c --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs @@ -0,0 +1,27 @@ +// check-pass + +#![feature(let_chains)] + +use std::ops::Range; + +fn main() { + let opt = Some(None..Some(1)); + + if let first = &opt && let Some(ref second) = first && let None = second.start { + } + if let Some(ref first) = opt && let second = first && let _third = second { + } + if let Some(ref first) = opt + && let Range { start: local_start, end: _ } = first + && let None = local_start { + } + + while let first = &opt && let Some(ref second) = first && let None = second.start { + } + while let Some(ref first) = opt && let second = first && let _third = second { + } + while let Some(ref first) = opt + && let Range { start: local_start, end: _ } = first + && let None = local_start { + } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs b/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs new file mode 100644 index 0000000000000..3eb8a9ad06020 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs @@ -0,0 +1,16 @@ +// check-pass + +pub enum UnOp { + Not(Vec<()>), +} + +pub fn foo() { + if let Some(x) = None { + match x { + UnOp::Not(_) => {} + } + } +} + +fn main() { +} diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs b/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs new file mode 100644 index 0000000000000..6b7d883565085 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(let_chains)] + +fn main() { + let x = Some(vec!["test"]); + + if let Some(v) = x && v.is_empty() { + println!("x == Some([])"); + } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs b/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs new file mode 100644 index 0000000000000..7c7e31f4db400 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(let_chains)] + +fn main() { + let opt = Some("foo bar"); + + if true && let Some(x) = opt { + println!("{}", x); + } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs b/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs new file mode 100644 index 0000000000000..6b91c455e0e97 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs @@ -0,0 +1,9 @@ +// check-pass + +fn main() { + loop { + // [1][0] should leave top scope + if true && [1][0] == 1 && true { + } + } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs new file mode 100644 index 0000000000000..0856a10520636 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs @@ -0,0 +1,35 @@ +// run-pass + +#![feature(let_chains)] + +fn check_if_let(opt: Option>>, value: i32) -> bool { + if let Some(first) = opt + && let Some(second) = first + && let Some(third) = second + && third == value + { + true + } + else { + false + } +} + +fn check_while_let(opt: Option>>, value: i32) -> bool { + while let Some(first) = opt + && let Some(second) = first + && let Some(third) = second + && third == value + { + return true; + } + false +} + +fn main() { + assert_eq!(check_if_let(Some(Some(Some(1))), 1), true); + assert_eq!(check_if_let(Some(Some(Some(1))), 9), false); + + assert_eq!(check_while_let(Some(Some(Some(1))), 1), true); + assert_eq!(check_while_let(Some(Some(Some(1))), 9), false); +}