From 521b1ee974296b4d2ecce79efaa10347642d1e3e Mon Sep 17 00:00:00 2001 From: pierwill Date: Mon, 25 Oct 2021 15:43:07 -0500 Subject: [PATCH 01/16] Improve terminology around "after typeck" --- compiler/rustc_infer/src/infer/mod.rs | 2 +- compiler/rustc_lint/src/context.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 4 ++-- compiler/rustc_middle/src/ty/normalize_erasing_regions.rs | 4 ++-- compiler/rustc_middle/src/ty/sty.rs | 4 ++-- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_target/src/asm/mod.rs | 2 +- compiler/rustc_trait_selection/src/traits/codegen.rs | 8 +++++--- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- compiler/rustc_trait_selection/src/traits/project.rs | 2 +- .../rustc_trait_selection/src/traits/query/normalize.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 2 +- 13 files changed, 20 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9dae978dcde7d..d6d1dfb71132c 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -200,7 +200,7 @@ pub struct InferCtxtInner<'tcx> { // Opaque types found in explicit return types and their // associated fresh inference variable. Writeback resolves these // variables to get the concrete type, which can be used to - // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. + // 'de-opaque' OpaqueTypeDecl outside of type inference. pub opaque_types: OpaqueTypeMap<'tcx>, /// A map from inference variables created from opaque diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 4c936dec6f2cd..5012a69e92813 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -523,7 +523,7 @@ impl LintStore { } } -/// Context for lint checking after type checking. +/// Context for lint checking outside of type inference. pub struct LateContext<'tcx> { /// Type context we're checking in. pub tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 253ac266bedaa..da3be223690b8 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -864,7 +864,7 @@ pub struct LocalDecl<'tcx> { /// across a suspension point against the type components of the generator /// which type checking knows are live across a suspension point. We need to /// flag drop flags to avoid triggering this check as they are introduced - /// after typeck. + /// outside of type inference. /// /// This should be sound because the drop flags are fully algebraic, and /// therefore don't affect the auto-trait or outlives properties of the diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8240273acad4c..b1cb574e40039 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -211,7 +211,7 @@ pub struct CommonLifetimes<'tcx> { /// `ReStatic` pub re_static: Region<'tcx>, - /// Erased region, used after type-checking + /// Erased region, used outside of type inference. pub re_erased: Region<'tcx>, } @@ -351,7 +351,7 @@ pub struct TypeckResults<'tcx> { field_indices: ItemLocalMap, /// Stores the types for various nodes in the AST. Note that this table - /// is not guaranteed to be populated until after typeck. See + /// is not guaranteed to be populated outside inference. See /// typeck::check::fn_ctxt for details. node_types: ItemLocalMap>, diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 11399506b96e4..ec3029359030f 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -16,8 +16,8 @@ impl<'tcx> TyCtxt<'tcx> { /// Erase the regions in `value` and then fully normalize all the /// types found within. The result will also have regions erased. /// - /// This is appropriate to use only after type-check: it assumes - /// that normalization will succeed, for example. + /// This should only be used outside of type inference. For example, + /// it assumes that normalization will succeed. pub fn normalize_erasing_regions(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 874de3366d792..25d69ff9ea6bf 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1391,11 +1391,11 @@ pub enum RegionKind { /// Static data that has an "infinite" lifetime. Top in the region lattice. ReStatic, - /// A region variable. Should not exist after typeck. + /// A region variable. Should not exist outside of type inference. ReVar(RegionVid), /// A placeholder region -- basically, the higher-ranked version of `ReFree`. - /// Should not exist after typeck. + /// Should not exist outside of type inference. RePlaceholder(ty::PlaceholderRegion), /// Empty lifetime is for data that is never accessed. We tag the diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 543cd0247a53d..067c1c933b2a5 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -985,7 +985,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( tcx.dep_graph.with_ignore(|| { info!("Dumping crate {}", cratename); - // Privacy checking requires and is done after type checking; use a + // Privacy checking must be done outside of type inference; use a // fallback in case the access levels couldn't have been correctly computed. let access_levels = match tcx.sess.compile_status() { Ok(..) => tcx.privacy_access_levels(()), diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 99699c50df584..85422aefbebc0 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -414,7 +414,7 @@ impl InlineAsmRegClass { } /// Returns a suggested register class to use for this type. This is called - /// after type checking via `supported_types` fails to give a better error + /// when `supported_types` fails to give a better error /// message to the user. pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option { match self { diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index f06f0e32f414b..28a1516ee6764 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -18,7 +18,6 @@ use rustc_middle::ty::{self, TyCtxt}; /// that type check should guarantee to us that all nested /// obligations *could be* resolved if we wanted to. /// -/// Assumes that this is run after the entire crate has been successfully type-checked. /// This also expects that `trait_ref` is fully normalized. pub fn codegen_fulfill_obligation<'tcx>( tcx: TyCtxt<'tcx>, @@ -101,7 +100,7 @@ pub fn codegen_fulfill_obligation<'tcx>( /// Finishes processes any obligations that remain in the /// fulfillment context, and then returns the result with all type /// variables removed and regions erased. Because this is intended -/// for use after type-check has completed, if any errors occur, +/// for use outside of type inference, if any errors occur, /// it will panic. It is used during normalization and other cases /// where processing the obligations in `fulfill_cx` may cause /// type inference variables that appear in `result` to be @@ -123,7 +122,10 @@ where if let Err(errors) = fulfill_cx.select_all_or_error(infcx) { infcx.tcx.sess.delay_span_bug( rustc_span::DUMMY_SP, - &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors), + &format!( + "Encountered errors `{:?}` resolving bounds outside of type inference", + errors + ), ); } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 8f247184e8808..e4b4b357e61f3 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -295,7 +295,7 @@ pub fn normalize_param_env_or_error<'tcx>( // // In any case, in practice, typeck constructs all the // parameter environments once for every fn as it goes, - // and errors will get reported then; so after typeck we + // and errors will get reported then; so outside of type inference we // can be sure that no errors should occur. debug!( diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index b8c66931cbe52..603234b6ba95d 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -392,7 +392,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // severe performance implications for large opaque types with // late-bound regions. See `issue-88862` benchmark. ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { - // Only normalize `impl Trait` after type-checking, usually in codegen. + // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 1364cf1c99535..c4053c7a14cfc 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -210,7 +210,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // severe performance implications for large opaque types with // late-bound regions. See `issue-88862` benchmark. ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { - // Only normalize `impl Trait` after type-checking, usually in codegen. + // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index af3706f886e9c..5a240a7dacfc8 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -267,7 +267,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // kind of an "idempotent" action, but I'm not sure where would be // a better place. In practice, we construct environments for // every fn once during type checking, and we'll abort if there - // are any errors at that point, so after type checking you can be + // are any errors at that point, so outside of type inference you can be // sure that this will succeed without errors anyway. if tcx.sess.opts.debugging_opts.chalk { From d671948779fc14c195833f48b64e2c6e1a54a0bb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jan 2022 18:43:55 -0800 Subject: [PATCH 02/16] Allow eliding GATs in expr position --- compiler/rustc_typeck/src/astconv/generics.rs | 2 +- compiler/rustc_typeck/src/astconv/mod.rs | 15 +++++++- .../elided-in-expr-position.rs | 38 +++++++++++++++++++ .../elided-in-expr-position.stderr | 35 +++++++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/generic-associated-types/elided-in-expr-position.rs create mode 100644 src/test/ui/generic-associated-types/elided-in-expr-position.stderr diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 956696546da8e..05ff7f818c75f 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -445,7 +445,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count; let infer_lifetimes = - gen_pos != GenericArgPosition::Type && !gen_args.has_lifetime_params(); + (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params(); if gen_pos != GenericArgPosition::Type && !gen_args.bindings.is_empty() { Self::prohibit_assoc_ty_binding(tcx, gen_args.bindings[0].span); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 17cf366761124..71444d8a8af34 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -482,7 +482,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) -> subst::GenericArg<'tcx> { let tcx = self.astconv.tcx(); match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), + GenericParamDefKind::Lifetime => self + .astconv + .re_infer(Some(param), self.span) + .unwrap_or_else(|| { + debug!(?param, "unelided lifetime in signature"); + + // This indicates an illegal lifetime in a non-assoc-trait position + tcx.sess.delay_span_bug(self.span, "unelided lifetime in signature"); + + // Supply some dummy value. We don't have an + // `re_error`, annoyingly, so use `'static`. + tcx.lifetimes.re_static + }) + .into(), GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.rs b/src/test/ui/generic-associated-types/elided-in-expr-position.rs new file mode 100644 index 0000000000000..482d0d5c00a63 --- /dev/null +++ b/src/test/ui/generic-associated-types/elided-in-expr-position.rs @@ -0,0 +1,38 @@ +#![feature(generic_associated_types)] +#![allow(unused)] + +pub trait Trait { + type Assoc<'a> where Self: 'a; + + fn f(&self) -> Self::Assoc<'_>; + + // Disallow elision in return position, for now + fn g(&self) -> Self::Assoc; + //~^ ERROR missing generics for associated type `Trait::Assoc` +} + +pub struct Struct { + item: f32 +} + +pub struct GenericStruct<'a> { + ref_item: &'a f32 +} + +impl Trait for Struct { + type Assoc<'a> = GenericStruct<'a>; + + fn f(&self) -> Self::Assoc<'_> { + Self::Assoc { + ref_item: &self.item + } + } + + // Disallow elision in return position, for now + fn g(&self) -> Self::Assoc { + //~^ ERROR missing generics for associated type `Trait::Assoc` + todo!() + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.stderr b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr new file mode 100644 index 0000000000000..9263f3d67e3d2 --- /dev/null +++ b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr @@ -0,0 +1,35 @@ +error[E0107]: missing generics for associated type `Trait::Assoc` + --> $DIR/elided-in-expr-position.rs:10:26 + | +LL | fn g(&self) -> Self::Assoc; + | ^^^^^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/elided-in-expr-position.rs:5:10 + | +LL | type Assoc<'a> where Self: 'a; + | ^^^^^ -- +help: add missing lifetime argument + | +LL | fn g(&self) -> Self::Assoc<'_>; + | ~~~~~~~~~ + +error[E0107]: missing generics for associated type `Trait::Assoc` + --> $DIR/elided-in-expr-position.rs:32:26 + | +LL | fn g(&self) -> Self::Assoc { + | ^^^^^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/elided-in-expr-position.rs:5:10 + | +LL | type Assoc<'a> where Self: 'a; + | ^^^^^ -- +help: add missing lifetime argument + | +LL | fn g(&self) -> Self::Assoc<'_> { + | ~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. From 32ab0b88f4248c612cb795d1f02d0030e30f57b5 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Sat, 22 Jan 2022 15:47:02 -0500 Subject: [PATCH 03/16] respect doc(hidden) when suggesting available fields --- compiler/rustc_typeck/src/check/expr.rs | 1 + .../issue-93210-ignore-doc-hidden.rs | 24 +++++++++++++++++++ .../issue-93210-ignore-doc-hidden.stderr | 19 +++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.rs create mode 100644 src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 23cc4b0ffc814..371f12fa6f4b4 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1794,6 +1794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .1; field.vis.is_accessible_from(def_scope, self.tcx) }) + .filter(|field| !self.tcx.is_doc_hidden(field.did)) .map(|field| field.name) .collect() } diff --git a/src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.rs b/src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.rs new file mode 100644 index 0000000000000..0efc7daa3e17b --- /dev/null +++ b/src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.rs @@ -0,0 +1,24 @@ +#[derive(Default)] +pub struct A { + #[doc(hidden)] + pub hello: i32, + pub bye: i32, +} + +#[derive(Default)] +pub struct B { + pub hello: i32, + pub bye: i32, +} + +fn main() { + A::default().hey; + //~^ ERROR no field `hey` on type `A` + //~| NOTE unknown field + //~| NOTE available fields are: `bye` + + B::default().hey; + //~^ ERROR no field `hey` on type `B` + //~| NOTE unknown field + //~| NOTE available fields are: `hello`, `bye` +} diff --git a/src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.stderr b/src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.stderr new file mode 100644 index 0000000000000..784986d3b95fb --- /dev/null +++ b/src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.stderr @@ -0,0 +1,19 @@ +error[E0609]: no field `hey` on type `A` + --> $DIR/issue-93210-ignore-doc-hidden.rs:15:18 + | +LL | A::default().hey; + | ^^^ unknown field + | + = note: available fields are: `bye` + +error[E0609]: no field `hey` on type `B` + --> $DIR/issue-93210-ignore-doc-hidden.rs:20:18 + | +LL | B::default().hey; + | ^^^ unknown field + | + = note: available fields are: `hello`, `bye` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0609`. From b734abcbaeaec78828d00596c008d05d6c03c1b3 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Mon, 24 Jan 2022 13:13:29 +0100 Subject: [PATCH 04/16] Handle unstability as well, including "field typo suggestions" --- compiler/rustc_typeck/src/check/expr.rs | 40 +++++++++++++++++++------ 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 371f12fa6f4b4..2cad8aab29ec9 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -35,6 +35,7 @@ use rustc_hir::{ExprKind, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; +use rustc_middle::middle::stability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts}; @@ -1720,9 +1721,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => { // prevent all specified fields from being suggested let skip_fields = skip_fields.iter().map(|x| x.ident.name); - if let Some(field_name) = - Self::suggest_field_name(variant, field.ident.name, skip_fields.collect()) - { + if let Some(field_name) = self.suggest_field_name( + variant, + field.ident.name, + skip_fields.collect(), + expr_span, + ) { err.span_suggestion( field.ident.span, "a field with a similar name exists", @@ -1743,7 +1747,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("`{}` does not have this field", ty), ); } - let available_field_names = self.available_field_names(variant); + let available_field_names = + self.available_field_names(variant, expr_span); if !available_field_names.is_empty() { err.note(&format!( "available fields are: {}", @@ -1759,19 +1764,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } - // Return an hint about the closest match in field names + // Return a hint about the closest match in field names fn suggest_field_name( + &self, variant: &'tcx ty::VariantDef, field: Symbol, skip: Vec, + // The span where stability will be checked + span: Span, ) -> Option { let names = variant .fields .iter() .filter_map(|field| { // ignore already set fields and private fields from non-local crates + // and unstable fields. if skip.iter().any(|&x| x == field.name) || (!variant.def_id.is_local() && !field.vis.is_public()) + || matches!( + self.tcx.eval_stability(field.did, None, span, None), + stability::EvalResult::Deny { .. } + ) { None } else { @@ -1783,7 +1796,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { find_best_match_for_name(&names, field, None) } - fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec { + fn available_field_names( + &self, + variant: &'tcx ty::VariantDef, + access_span: Span, + ) -> Vec { variant .fields .iter() @@ -1793,6 +1810,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .adjust_ident_and_get_scope(field.ident(self.tcx), variant.def_id, self.body_id) .1; field.vis.is_accessible_from(def_scope, self.tcx) + && !matches!( + self.tcx.eval_stability(field.did, None, access_span, None), + stability::EvalResult::Deny { .. } + ) }) .filter(|field| !self.tcx.is_doc_hidden(field.did)) .map(|field| field.name) @@ -1959,7 +1980,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_first_deref_field(&mut err, expr, base, field); } ty::Adt(def, _) if !def.is_enum() => { - self.suggest_fields_on_recordish(&mut err, def, field); + self.suggest_fields_on_recordish(&mut err, def, field, expr.span); } ty::Param(param_ty) => { self.point_at_param_definition(&mut err, param_ty); @@ -2122,9 +2143,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, def: &'tcx ty::AdtDef, field: Ident, + access_span: Span, ) { if let Some(suggested_field_name) = - Self::suggest_field_name(def.non_enum_variant(), field.name, vec![]) + self.suggest_field_name(def.non_enum_variant(), field.name, vec![], access_span) { err.span_suggestion( field.span, @@ -2135,7 +2157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { err.span_label(field.span, "unknown field"); let struct_variant_def = def.non_enum_variant(); - let field_names = self.available_field_names(struct_variant_def); + let field_names = self.available_field_names(struct_variant_def, access_span); if !field_names.is_empty() { err.note(&format!( "available fields are: {}", From ecd06e1e6ad28daab4e0ed5a8d6014a3ca2affb9 Mon Sep 17 00:00:00 2001 From: threadexception Date: Tue, 18 Jan 2022 17:09:17 +0100 Subject: [PATCH 05/16] Don't suggest inaccessible fields --- compiler/rustc_typeck/src/check/expr.rs | 28 +++++++++++++------- src/test/ui/suggestions/private-field.rs | 19 +++++++++++++ src/test/ui/suggestions/private-field.stderr | 11 ++++++++ 3 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/suggestions/private-field.rs create mode 100644 src/test/ui/suggestions/private-field.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 3e73cc659ec46..af2ac9bb2ee53 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -31,7 +31,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{ExprKind, QPath}; +use rustc_hir::{ExprKind, HirId, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; @@ -1948,7 +1948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}", field, base, expr, expr_t ); - let mut err = self.no_such_field_err(field, expr_t); + let mut err = self.no_such_field_err(field, expr_t, base.hir_id); match *expr_t.peel_refs().kind() { ty::Array(_, len) => { @@ -2186,6 +2186,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, field: Ident, expr_t: &'tcx ty::TyS<'tcx>, + id: HirId, ) -> DiagnosticBuilder<'_> { let span = field.span; debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t); @@ -2203,9 +2204,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // try to add a suggestion in case the field is a nested field of a field of the Adt if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) { for candidate_field in fields.iter() { - if let Some(field_path) = - self.check_for_nested_field(span, field, candidate_field, substs, vec![]) - { + if let Some(field_path) = self.check_for_nested_field( + span, + field, + candidate_field, + substs, + vec![], + self.tcx.parent_module(id).to_def_id(), + ) { let field_path_str = field_path .iter() .map(|id| id.name.to_ident_string()) @@ -2257,6 +2263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_field: &ty::FieldDef, subst: SubstsRef<'tcx>, mut field_path: Vec, + id: DefId, ) -> Option> { debug!( "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}", @@ -2276,10 +2283,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = candidate_field.ty(self.tcx, subst); if let Some((nested_fields, subst)) = self.get_field_candidates(span, &field_ty) { for field in nested_fields.iter() { - let ident = field.ident(self.tcx).normalize_to_macros_2_0(); - if ident == target_field { - return Some(field_path); - } else { + let accessible = field.vis.is_accessible_from(id, self.tcx); + if accessible { + let ident = field.ident(self.tcx).normalize_to_macros_2_0(); + if ident == target_field { + return Some(field_path); + } let field_path = field_path.clone(); if let Some(path) = self.check_for_nested_field( span, @@ -2287,6 +2296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field, subst, field_path, + id, ) { return Some(path); } diff --git a/src/test/ui/suggestions/private-field.rs b/src/test/ui/suggestions/private-field.rs new file mode 100644 index 0000000000000..1cc4d2a4d066e --- /dev/null +++ b/src/test/ui/suggestions/private-field.rs @@ -0,0 +1,19 @@ +// compile-flags: --crate-type lib +pub struct S { + pub val: string::MyString, +} + +pub fn test(s: S) { + dbg!(s.cap) //~ ERROR: no field `cap` on type `S` [E0609] +} + +pub(crate) mod string { + + pub struct MyString { + buf: MyVec, + } + + struct MyVec { + cap: usize, + } +} diff --git a/src/test/ui/suggestions/private-field.stderr b/src/test/ui/suggestions/private-field.stderr new file mode 100644 index 0000000000000..c38c795e07ae8 --- /dev/null +++ b/src/test/ui/suggestions/private-field.stderr @@ -0,0 +1,11 @@ +error[E0609]: no field `cap` on type `S` + --> $DIR/private-field.rs:7:12 + | +LL | dbg!(s.cap) + | ^^^ unknown field + | + = note: available fields are: `val` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0609`. From cd4245d318b04c8b44aed7e682c49b0507086d6c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 27 Jan 2022 00:25:17 +0300 Subject: [PATCH 06/16] Make char::DecodeUtf16::size_hist more precise New implementation takes into account contents of `self.buf` and rounds lower bound up instead of down. --- library/core/src/char/decode.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 5dd8c5ef78941..f3fef85ef1de5 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -120,9 +120,21 @@ impl> Iterator for DecodeUtf16 { #[inline] fn size_hint(&self) -> (usize, Option) { let (low, high) = self.iter.size_hint(); - // we could be entirely valid surrogates (2 elements per - // char), or entirely non-surrogates (1 element per char) - (low / 2, high) + + // `self.buf` will never contain the first part of a surrogate, + // so the presence of `buf == Some(...)` always means +1 + // on lower and upper bound. + let addition_from_buf = self.buf.is_some() as usize; + + // `self.iter` could contain entirely valid surrogates (2 elements per + // char), or entirely non-surrogates (1 element per char). + // + // On odd lower bound, at least one element must stay unpaired + // (with other elements from `self.iter`), so we round up. + let low = low.div_ceil(2) + addition_from_buf; + let high = high.and_then(|h| h.checked_add(addition_from_buf)); + + (low, high) } } From 9c8cd1ff376568ffe41ee94f2c99a0d3d83262d5 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 27 Jan 2022 00:50:34 +0300 Subject: [PATCH 07/16] Add a test for `char::DecodeUtf16::size_hint` --- library/core/tests/char.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs index 2b857a6591929..d776a08323c03 100644 --- a/library/core/tests/char.rs +++ b/library/core/tests/char.rs @@ -308,6 +308,31 @@ fn test_decode_utf16() { check(&[0xD800, 0], &[Err(0xD800), Ok('\0')]); } +#[test] +fn test_decode_utf16_size_hint() { + fn check(s: &[u16]) { + let mut iter = char::decode_utf16(s.iter().cloned()); + + loop { + let count = iter.clone().count(); + let (lower, upper) = iter.size_hint(); + + assert!( + lower <= count && count <= upper.unwrap(), + "lower = {lower}, upper = {upper:?}" + ); + + if let None = iter.next() { + break; + } + } + } + + check(&[0xD800, 0x41, 0x42]); + check(&[0xD800, 0]); + check(&[0xD834, 0x006d]); +} + #[test] fn ed_iterator_specializations() { // Check counting From 2fb617ca0f1edd42116ebe8e8175b4abb2042a9b Mon Sep 17 00:00:00 2001 From: George Bateman Date: Thu, 27 Jan 2022 22:13:01 +0000 Subject: [PATCH 08/16] Clarify documentation on char::MAX --- library/core/src/char/methods.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 7250dca2adfe4..62ef1ca788549 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -9,11 +9,11 @@ use super::*; #[lang = "char"] impl char { - /// The highest valid code point a `char` can have. + /// The highest valid code point a `char` can have, 0x10FFFF. /// - /// A `char` is a [Unicode Scalar Value], which means that it is a [Code - /// Point], but only ones within a certain range. `MAX` is the highest valid - /// code point that's a valid [Unicode Scalar Value]. + /// A [Code Point] is any value between zero and `char::MAX`, inclusive. A + /// `char` is a [Unicode Scalar Value], which is a Code Point that is not + /// in the range `0xD800..=0xDFFF`. /// /// [Unicode Scalar Value]: https://www.unicode.org/glossary/#unicode_scalar_value /// [Code Point]: https://www.unicode.org/glossary/#code_point From 2c97d1012e52c9a7ac217a15cce71473cc070e26 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 28 Jan 2022 12:20:58 +0300 Subject: [PATCH 09/16] Fix wrong assumption in `DecodeUtf16::size_hint` `self.buf` can contain a surrogate, but only a leading one. --- library/core/src/char/decode.rs | 13 +++++++++---- library/core/tests/char.rs | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index f3fef85ef1de5..81d49ffe06e6d 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -121,10 +121,15 @@ impl> Iterator for DecodeUtf16 { fn size_hint(&self) -> (usize, Option) { let (low, high) = self.iter.size_hint(); - // `self.buf` will never contain the first part of a surrogate, - // so the presence of `buf == Some(...)` always means +1 - // on lower and upper bound. - let addition_from_buf = self.buf.is_some() as usize; + // If + // - `self.buf` contains a non surrogate (`u < 0xD800 || 0xDFFF < u`), or + // - `high == Some(0)` (and `self.buf` contains a leading surrogate since + // it can never contain a trailing surrogate) + // + // then buf contains an additional character or error that doesn't + // need a pair from `self.iter`, so it's +1 additional element. + let addition_from_buf = + self.buf.map_or(false, |u| u < 0xD800 || 0xDFFF < u || high == Some(0)) as usize; // `self.iter` could contain entirely valid surrogates (2 elements per // char), or entirely non-surrogates (1 element per char). diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs index d776a08323c03..347ac04feb31c 100644 --- a/library/core/tests/char.rs +++ b/library/core/tests/char.rs @@ -319,7 +319,7 @@ fn test_decode_utf16_size_hint() { assert!( lower <= count && count <= upper.unwrap(), - "lower = {lower}, upper = {upper:?}" + "lower = {lower}, count = {count}, upper = {upper:?}" ); if let None = iter.next() { @@ -328,6 +328,7 @@ fn test_decode_utf16_size_hint() { } } + check(&[0xD800, 0xD800, 0xDC00]); check(&[0xD800, 0x41, 0x42]); check(&[0xD800, 0]); check(&[0xD834, 0x006d]); From f8a013f858c2f24a881c27110444fcc7b6c0a5e0 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 7 Jan 2022 14:50:43 -0800 Subject: [PATCH 10/16] Fix some CSS warnings and errors from VS Code There's no such CSS rule as `box-shadow-color`, so I instead copied the whole `box-shadow` property to each rule to make it actually apply. --- src/librustdoc/html/static/css/rustdoc.css | 1 - src/librustdoc/html/static/css/themes/ayu.css | 4 ++-- src/librustdoc/html/static/css/themes/dark.css | 4 ++-- src/librustdoc/html/static/css/themes/light.css | 6 ++++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4c79218f62a4d..b4bd13778bcf8 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1502,7 +1502,6 @@ kbd { vertical-align: middle; border: solid 1px; border-radius: 3px; - box-shadow: inset 0 -1px 0; cursor: default; } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 5d60aca6f27cd..07cb8f7ac1cbd 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -531,7 +531,7 @@ kbd { background-color: #314559; border-color: #5c6773; border-bottom-color: #5c6773; - box-shadow-color: #c6cbd1; + box-shadow: inset 0 -1px 0 #5c6773; } #theme-picker, #settings-menu, #help-button { @@ -630,5 +630,5 @@ input:checked + .slider { background: #616161; } .toggle-line:hover .toggle-line-inner { - background: ##898989; + background: #898989; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 96588af54e8fb..ae194279090ea 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -407,7 +407,7 @@ kbd { background-color: #fafbfc; border-color: #d1d5da; border-bottom-color: #c6cbd1; - box-shadow-color: #c6cbd1; + box-shadow: inset 0 -1px 0 #c6cbd1; } #theme-picker, #settings-menu, #help-button { @@ -496,5 +496,5 @@ div.files > .selected { background: #616161; } .toggle-line:hover .toggle-line-inner { - background: ##898989; + background: #898989; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index edb346c23b48c..2bc5ebbb2ecd7 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -44,7 +44,9 @@ pre, .rustdoc.source .example-wrap { } .rust-logo { - /* No need for a border in here! */ + /* This rule exists to force other themes to explicitly style the logo. + * Rustdoc has a custom linter for this purpose. + */ } /* Improve the scrollbar display on webkit-based browsers */ @@ -391,7 +393,7 @@ kbd { background-color: #fafbfc; border-color: #d1d5da; border-bottom-color: #c6cbd1; - box-shadow-color: #c6cbd1; + box-shadow: inset 0 -1px 0 #c6cbd1; } #theme-picker, #settings-menu, #help-button { From 17cd2cd5927cf1075efbd0f4a859182eb102b920 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 30 Jan 2022 15:32:21 +0300 Subject: [PATCH 11/16] Fix an edge case in `chat::DecodeUtf16::size_hint` There are cases, when data in the buf might or might not be an error. --- library/core/src/char/decode.rs | 30 +++++++++++++++++++----------- library/core/tests/char.rs | 1 + 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 81d49ffe06e6d..8b9f979b573f7 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -121,23 +121,31 @@ impl> Iterator for DecodeUtf16 { fn size_hint(&self) -> (usize, Option) { let (low, high) = self.iter.size_hint(); - // If - // - `self.buf` contains a non surrogate (`u < 0xD800 || 0xDFFF < u`), or - // - `high == Some(0)` (and `self.buf` contains a leading surrogate since - // it can never contain a trailing surrogate) - // - // then buf contains an additional character or error that doesn't - // need a pair from `self.iter`, so it's +1 additional element. - let addition_from_buf = - self.buf.map_or(false, |u| u < 0xD800 || 0xDFFF < u || high == Some(0)) as usize; + let (low_buf, high_buf) = match self.buf { + // buf is empty, no additional elements from it. + None => (0, 0), + // `u` is a non surrogate, so it's always an additional character. + Some(u) if u < 0xD800 || 0xDFFF < u => (1, 1), + // `u` is a leading surrogate (it can never be a trailing surrogate and + // it's a surrogate due to the previous branch) and `self.iter` is empty. + // + // `u` can't be paired, since the `self.iter` is empty, + // so it will always become an additional element (error). + Some(_u) if high == Some(0) => (1, 1), + // `u` is a leading surrogate and `iter` may be non-empty. + // + // `u` can either pair with a trailing surrogate, in which case no additional elements + // are produced, or it can become an error, in which case it's an additional character (error). + Some(_u) => (0, 1), + }; // `self.iter` could contain entirely valid surrogates (2 elements per // char), or entirely non-surrogates (1 element per char). // // On odd lower bound, at least one element must stay unpaired // (with other elements from `self.iter`), so we round up. - let low = low.div_ceil(2) + addition_from_buf; - let high = high.and_then(|h| h.checked_add(addition_from_buf)); + let low = low.div_ceil(2) + low_buf; + let high = high.and_then(|h| h.checked_add(high_buf)); (low, high) } diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs index 347ac04feb31c..4c899b6eb43d0 100644 --- a/library/core/tests/char.rs +++ b/library/core/tests/char.rs @@ -329,6 +329,7 @@ fn test_decode_utf16_size_hint() { } check(&[0xD800, 0xD800, 0xDC00]); + check(&[0xD800, 0xD800, 0x0]); check(&[0xD800, 0x41, 0x42]); check(&[0xD800, 0]); check(&[0xD834, 0x006d]); From 9aaf52b66a920f286bf235e6d5ba8c72099b1273 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Sun, 30 Jan 2022 19:41:52 +0000 Subject: [PATCH 12/16] (#93392) Update char::MAX docs and core::char::MAX --- library/core/src/char/methods.rs | 17 +++++++++++------ library/core/src/char/mod.rs | 17 +++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 62ef1ca788549..c4c0a5a6c78ad 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -9,14 +9,19 @@ use super::*; #[lang = "char"] impl char { - /// The highest valid code point a `char` can have, 0x10FFFF. + /// The highest valid code point a `char` can have, `'\u{10FFFF}'`. /// - /// A [Code Point] is any value between zero and `char::MAX`, inclusive. A - /// `char` is a [Unicode Scalar Value], which is a Code Point that is not - /// in the range `0xD800..=0xDFFF`. + /// # Examples + /// + /// ``` + /// # fn something_which_returns_char() -> char { 'a' } + /// let c: char = something_which_returns_char(); + /// assert!(c <= char::MAX); /// - /// [Unicode Scalar Value]: https://www.unicode.org/glossary/#unicode_scalar_value - /// [Code Point]: https://www.unicode.org/glossary/#code_point + /// let value_at_max = char::MAX as u32; + /// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}')); + /// assert_eq!(char::from_u32(value_at_max + 1), None); + /// ``` #[stable(feature = "assoc_char_consts", since = "1.52.0")] pub const MAX: char = '\u{10ffff}'; diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index f65f84e93aebe..9364ac4f3ec1f 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -89,14 +89,19 @@ const MAX_THREE_B: u32 = 0x10000; Cn Unassigned a reserved unassigned code point or a noncharacter */ -/// The highest valid code point a `char` can have. +/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. /// -/// A [`char`] is a [Unicode Scalar Value], which means that it is a [Code -/// Point], but only ones within a certain range. `MAX` is the highest valid -/// code point that's a valid [Unicode Scalar Value]. +/// # Examples /// -/// [Unicode Scalar Value]: https://www.unicode.org/glossary/#unicode_scalar_value -/// [Code Point]: https://www.unicode.org/glossary/#code_point +/// ``` +/// # fn something_which_returns_char() -> char { 'a' } +/// let c: char = something_which_returns_char(); +/// assert!(c <= char::MAX); +/// +/// let value_at_max = char::MAX as u32; +/// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}')); +/// assert_eq!(char::from_u32(value_at_max + 1), None); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MAX: char = char::MAX; From cb93e9c0ec6058df03e163fd7b3e652f7f22041d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 21 Jan 2022 01:34:19 -0800 Subject: [PATCH 13/16] Compute indent never relative to current column Previously the pretty printer would compute indentation always relative to whatever column a block begins at, like this: fn demo(arg1: usize, arg2: usize); This is never the thing to do in the dominant contemporary Rust style. Rustfmt's default and the style used by the vast majority of Rust codebases is block indentation: fn demo( arg1: usize, arg2: usize, ); where every indentation level is a multiple of 4 spaces and each level is indented relative to the indentation of the previous line, not the position that the block starts in. --- compiler/rustc_ast_pretty/src/pp.rs | 39 ++++++++++--------- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index d41cebc98df3c..78b519651644a 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -178,7 +178,7 @@ impl Token { #[derive(Copy, Clone)] enum PrintFrame { Fits, - Broken { offset: isize, breaks: Breaks }, + Broken { indent: usize, breaks: Breaks }, } const SIZE_INFINITY: isize = 0xffff; @@ -204,6 +204,8 @@ pub struct Printer { scan_stack: VecDeque, /// Stack of blocks-in-progress being flushed by print print_stack: Vec, + /// Level of indentation of current line + indent: usize, /// Buffered indentation to avoid writing trailing whitespace pending_indentation: isize, /// The token most recently popped from the left boundary of the @@ -229,6 +231,7 @@ impl Printer { right_total: 0, scan_stack: VecDeque::new(), print_stack: Vec::new(), + indent: 0, pending_indentation: 0, last_printed: None, } @@ -368,38 +371,38 @@ impl Printer { *self .print_stack .last() - .unwrap_or(&PrintFrame::Broken { offset: 0, breaks: Breaks::Inconsistent }) + .unwrap_or(&PrintFrame::Broken { indent: 0, breaks: Breaks::Inconsistent }) } fn print_begin(&mut self, token: BeginToken, size: isize) { if size > self.space { - let col = self.margin - self.space + token.offset; - self.print_stack.push(PrintFrame::Broken { offset: col, breaks: token.breaks }); + self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks }); + self.indent = (self.indent as isize + token.offset) as usize; } else { self.print_stack.push(PrintFrame::Fits); } } fn print_end(&mut self) { - self.print_stack.pop().unwrap(); + if let PrintFrame::Broken { indent, .. } = self.print_stack.pop().unwrap() { + self.indent = indent; + } } fn print_break(&mut self, token: BreakToken, size: isize) { - let break_offset = - match self.get_top() { - PrintFrame::Fits => None, - PrintFrame::Broken { offset, breaks: Breaks::Consistent } => Some(offset), - PrintFrame::Broken { offset, breaks: Breaks::Inconsistent } => { - if size > self.space { Some(offset) } else { None } - } - }; - if let Some(offset) = break_offset { - self.out.push('\n'); - self.pending_indentation = offset + token.offset; - self.space = self.margin - (offset + token.offset); - } else { + let fits = match self.get_top() { + PrintFrame::Fits => true, + PrintFrame::Broken { breaks: Breaks::Consistent, .. } => false, + PrintFrame::Broken { breaks: Breaks::Inconsistent, .. } => size <= self.space, + }; + if fits { self.pending_indentation += token.blank_space; self.space -= token.blank_space; + } else { + self.out.push('\n'); + let indent = self.indent as isize + token.offset; + self.pending_indentation = indent; + self.space = self.margin - indent; } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 96dbd3dca156e..dff85f52b15c8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -655,7 +655,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere // Outer-box is consistent. self.cbox(INDENT_UNIT); // Head-box is inconsistent. - self.ibox(w.len() + 1); + self.ibox(0); // Keyword that starts the head. if !w.is_empty() { self.word_nbsp(w); From 8ac05b97660ec3bd5e8f0d3b7edb246b6cea9c32 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 20 Jan 2022 21:22:40 -0800 Subject: [PATCH 14/16] Fix some double indents on exprs containing blocks The `print_expr` method already places an `ibox(INDENT_UNIT)` around every expr that gets printed. Some exprs were then using `self.head` inside of that, which does its own `cbox(INDENT_UNIT)`, resulting in two levels of indentation: while true { stuff; } This commit fixes those cases to produce the expected single level of indentation within every expression containing a block. while true { stuff; } --- .../rustc_ast_pretty/src/pprust/state/expr.rs | 24 ++++++++++++------- .../rustc_ast_pretty/src/pprust/state/item.rs | 4 ++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 956200d60f507..6a5bba30b8bca 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -320,7 +320,9 @@ impl<'a> State<'a> { self.print_ident(label.ident); self.word_space(":"); } - self.head("while"); + self.cbox(0); + self.ibox(0); + self.word_nbsp("while"); self.print_expr_as_cond(test); self.space(); self.print_block_with_attrs(blk, attrs); @@ -330,7 +332,9 @@ impl<'a> State<'a> { self.print_ident(label.ident); self.word_space(":"); } - self.head("for"); + self.cbox(0); + self.ibox(0); + self.word_nbsp("for"); self.print_pat(pat); self.space(); self.word_space("in"); @@ -343,12 +347,14 @@ impl<'a> State<'a> { self.print_ident(label.ident); self.word_space(":"); } - self.head("loop"); + self.cbox(0); + self.ibox(0); + self.word_nbsp("loop"); self.print_block_with_attrs(blk, attrs); } ast::ExprKind::Match(ref expr, ref arms) => { - self.cbox(INDENT_UNIT); - self.ibox(INDENT_UNIT); + self.cbox(0); + self.ibox(0); self.word_nbsp("match"); self.print_expr_as_cond(expr); self.space(); @@ -388,7 +394,7 @@ impl<'a> State<'a> { self.word_space(":"); } // containing cbox, will be closed by print-block at } - self.cbox(INDENT_UNIT); + self.cbox(0); // head-box, will be closed by print-block after { self.ibox(0); self.print_block_with_attrs(blk, attrs); @@ -397,7 +403,7 @@ impl<'a> State<'a> { 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.cbox(0); self.ibox(0); self.print_block_with_attrs(blk, attrs); } @@ -500,7 +506,9 @@ impl<'a> State<'a> { self.word("?") } ast::ExprKind::TryBlock(ref blk) => { - self.head("try"); + self.cbox(0); + self.ibox(0); + self.word_nbsp("try"); self.print_block_with_attrs(blk, attrs) } ast::ExprKind::Err => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index e575d6aa7e2fc..dac84ae9d5fc8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,5 +1,5 @@ use crate::pp::Breaks::Inconsistent; -use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; +use crate::pprust::state::{AnnNode, PrintState, State}; use rustc_ast as ast; use rustc_ast::GenericBound; @@ -377,7 +377,7 @@ impl<'a> State<'a> { self.space_if_not_bol(); self.maybe_print_comment(v.span.lo()); self.print_outer_attributes(&v.attrs); - self.ibox(INDENT_UNIT); + self.ibox(0); self.print_variant(v); self.word(","); self.end(); From 402f322940caddcf80ee5fb8a5006be50d26ad15 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 21 Jan 2022 01:34:06 -0800 Subject: [PATCH 15/16] Bless all pretty printer tests and ui tests --- src/test/pretty/ast-stmt-expr-attr.rs | 74 +++++++++---------- .../block-comment-trailing-whitespace2.rs | 6 +- src/test/pretty/block-comment-wchar.pp | 8 +- src/test/pretty/delimited-token-groups.rs | 20 ++--- src/test/pretty/issue-4264.pp | 70 +++++++----------- .../issue-68710-field-attr-proc-mac-lost.rs | 8 +- src/test/pretty/macro_rules.rs | 4 +- src/test/pretty/match-naked-expr-medium.rs | 8 +- src/test/pretty/stmt_expr_attributes.rs | 66 ++++++++--------- src/test/pretty/vec-comments.pp | 32 ++++---- .../ui/attributes/key-value-expansion.stderr | 10 +-- .../defaults/pretty-printing-ast.stdout | 2 +- src/test/ui/match/issue-82392.stdout | 18 ++--- src/test/ui/proc-macro/cfg-eval-inner.stdout | 8 +- .../proc-macro/issue-75930-derive-cfg.stdout | 50 ++++++------- .../proc-macro/macro-rules-derive-cfg.stdout | 8 +- src/test/ui/proc-macro/quote-debug.stdout | 44 ++++++----- .../auxiliary/param-attrs.rs | 4 +- .../type-alias-impl-trait/issue-60662.stdout | 4 +- 19 files changed, 210 insertions(+), 234 deletions(-) diff --git a/src/test/pretty/ast-stmt-expr-attr.rs b/src/test/pretty/ast-stmt-expr-attr.rs index e32f5ca24ea0f..2404b32194289 100644 --- a/src/test/pretty/ast-stmt-expr-attr.rs +++ b/src/test/pretty/ast-stmt-expr-attr.rs @@ -28,67 +28,67 @@ fn syntax() { let _ = #[attr] (x as Y); let _ = #[attr] while true { - #![attr] - }; + #![attr] + }; let _ = #[attr] while let Some(false) = true { - #![attr] - }; + #![attr] + }; let _ = #[attr] for x in y { - #![attr] - }; + #![attr] + }; let _ = #[attr] loop { - #![attr] - }; + #![attr] + }; let _ = #[attr] match true { - #![attr] - #[attr] - _ => false, - }; + #![attr] + #[attr] + _ => false, + }; let _ = #[attr] || #[attr] foo; let _ = #[attr] move || #[attr] foo; let _ = #[attr] || - #[attr] { - #![attr] - foo - }; + #[attr] { + #![attr] + foo + }; let _ = #[attr] move || - #[attr] { - #![attr] - foo - }; + #[attr] { + #![attr] + foo + }; let _ = #[attr] || - { - #![attr] - foo - }; + { + #![attr] + foo + }; let _ = #[attr] move || - { - #![attr] - foo - }; + { + #![attr] + foo + }; let _ = #[attr] { - #![attr] - }; + #![attr] + }; let _ = #[attr] { - #![attr] - let _ = (); - }; + #![attr] + let _ = (); + }; let _ = #[attr] { - #![attr] - let _ = (); - foo - }; + #![attr] + let _ = (); + foo + }; let _ = #[attr] x = y; let _ = #[attr] (x = y); let _ = #[attr] x += y; diff --git a/src/test/pretty/block-comment-trailing-whitespace2.rs b/src/test/pretty/block-comment-trailing-whitespace2.rs index e53d51e34cefa..9e949726751e7 100644 --- a/src/test/pretty/block-comment-trailing-whitespace2.rs +++ b/src/test/pretty/block-comment-trailing-whitespace2.rs @@ -2,7 +2,7 @@ // pp-exact fn f() {} /* - The next line should not be indented. +The next line should not be indented. - That one. It shouldn't have been indented. - */ +That one. It shouldn't have been indented. +*/ diff --git a/src/test/pretty/block-comment-wchar.pp b/src/test/pretty/block-comment-wchar.pp index 385afa4f33ec1..8c8580b07c218 100644 --- a/src/test/pretty/block-comment-wchar.pp +++ b/src/test/pretty/block-comment-wchar.pp @@ -93,9 +93,9 @@ // Taken from https://www.unicode.org/Public/UNIDATA/PropList.txt let chars = ['\x0A', '\x0B', '\x0C', '\x0D', '\x20', '\u{85}', '\u{A0}', - '\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}', - '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}', - '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}', - '\u{205F}', '\u{3000}']; + '\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}', + '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}', + '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}', + '\u{205F}', '\u{3000}']; for c in &chars { let ws = c.is_whitespace(); println!("{} {}", c, ws); } } diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs index 1137d80456489..c7c9277faf69e 100644 --- a/src/test/pretty/delimited-token-groups.rs +++ b/src/test/pretty/delimited-token-groups.rs @@ -17,9 +17,9 @@ mac! { mac! { a(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa) a + aaaaaaaa aaaaaaaa) a [aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa] a + aaaaaaaa aaaaaaaa] a { aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa @@ -27,22 +27,22 @@ mac! { } mac!(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa); +aaaaaaaa aaaaaaaa); mac![aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa]; +aaaaaaaa aaaaaaaa]; mac! { aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa } #[rustc_dummy(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa aaaaaaaa)] +aaaaaaaa aaaaaaaa aaaaaaaa)] #[rustc_dummy[aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa aaaaaaaa]] +aaaaaaaa aaaaaaaa aaaaaaaa]] #[rustc_dummy { - aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa - }] + aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa + aaaaaaaa aaaaaaaa +}] #[rustc_dummy = - "aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa"] +"aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa"] fn main() {} diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 93967e720c1b0..3830c3aa6c9f1 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -11,15 +11,15 @@ pub fn foo(_: [i32; (3 as usize)]) ({ } as ()) pub fn bar() ({ - const FOO: usize = ((5 as usize) - (4 as usize) as usize); - let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); + const FOO: usize = ((5 as usize) - (4 as usize) as usize); + let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); - let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); + let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); - let _ = - (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) - as &[i32; 3]) as *const _ as *const [i32; 3]) as - *const [i32; (3 as usize)] as *const [i32; 3]); + let _ = + (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as + &[i32; 3]) as *const _ as *const [i32; 3]) as + *const [i32; (3 as usize)] as *const [i32; 3]); @@ -29,29 +29,19 @@ - ({ - let res = - ((::alloc::fmt::format as - for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 - as - fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" - as - &str)] - as - [&str; 1]) - as - &[&str; 1]), - (&([] - as - [ArgumentV1; 0]) - as - &[ArgumentV1; 0])) - as - Arguments)) - as String); - (res as String) - } as String); - } as ()) + ({ + let res = + ((::alloc::fmt::format as + for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 + as + fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" + as &str)] as [&str; 1]) as + &[&str; 1]), + (&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) as + Arguments)) as String); + (res as String) + } as String); + } as ()) pub type Foo = [i32; (3 as usize)]; pub struct Bar { pub x: [i32; (3 as usize)], @@ -60,19 +50,9 @@ pub enum Baz { BazVariant([i32; (5 as usize)]), } pub fn id(x: T) -> T ({ (x as T) } as T) pub fn use_id() ({ - let _ = - ((id::<[i32; (3 as usize)]> as - fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 - as - i32), - (2 - as - i32), - (3 - as - i32)] - as - [i32; 3])) - as [i32; 3]); - } as ()) + let _ = + ((id::<[i32; (3 as usize)]> as + fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32), + (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]); + } as ()) fn main() ({ } as ()) diff --git a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs index ed7879001d559..87f525a6178e6 100644 --- a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs +++ b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs @@ -9,8 +9,8 @@ struct C { #[allow()] const C: C = C{ - #[cfg(debug_assertions)] - field: 0, + #[cfg(debug_assertions)] + field: 0, - #[cfg(not(debug_assertions))] - field: 1,}; + #[cfg(not(debug_assertions))] + field: 1,}; diff --git a/src/test/pretty/macro_rules.rs b/src/test/pretty/macro_rules.rs index fb66e4a775842..01adb14133b35 100644 --- a/src/test/pretty/macro_rules.rs +++ b/src/test/pretty/macro_rules.rs @@ -12,8 +12,8 @@ macro_rules! matcher_brackets { macro_rules! all_fragments { ($b : block, $e : expr, $i : ident, $it : item, $l : lifetime, $lit : - literal, $m : meta, $p : pat, $pth : path, $s : stmt, $tt : tt, $ty : ty, - $vis : vis) => {} ; + literal, $m : meta, $p : pat, $pth : path, $s : stmt, $tt : tt, $ty : ty, + $vis : vis) => {} ; } fn main() {} diff --git a/src/test/pretty/match-naked-expr-medium.rs b/src/test/pretty/match-naked-expr-medium.rs index a124fdff3900d..836af99002d65 100644 --- a/src/test/pretty/match-naked-expr-medium.rs +++ b/src/test/pretty/match-naked-expr-medium.rs @@ -5,10 +5,10 @@ fn main() { let _y = match x { Some(_) => - ["some(_)".to_string(), "not".to_string(), "SO".to_string(), - "long".to_string(), "string".to_string()], + ["some(_)".to_string(), "not".to_string(), "SO".to_string(), + "long".to_string(), "string".to_string()], None => - ["none".to_string(), "a".to_string(), "a".to_string(), - "a".to_string(), "a".to_string()], + ["none".to_string(), "a".to_string(), "a".to_string(), + "a".to_string(), "a".to_string()], }; } diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index 01533cd8107b0..96bde96200af9 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -48,9 +48,9 @@ fn _4() { let _ = #[rustc_dummy] match () { - #![rustc_dummy] - () => (), - }; + #![rustc_dummy] + () => (), + }; } fn _5() { @@ -156,56 +156,56 @@ fn _11() { let _ = #[rustc_dummy] 0 as usize; let _ = #[rustc_dummy] while false { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] while let None = Some(()) { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] for _ in 0..0 { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] loop { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] match false { - #![rustc_dummy] - _ => (), - }; + #![rustc_dummy] + _ => (), + }; let _ = #[rustc_dummy] || #[rustc_dummy] (); let _ = #[rustc_dummy] move || #[rustc_dummy] (); let _ = #[rustc_dummy] || - { - #![rustc_dummy] - #[rustc_dummy] - () - }; + { + #![rustc_dummy] + #[rustc_dummy] + () + }; let _ = #[rustc_dummy] move || - { - #![rustc_dummy] - #[rustc_dummy] - () - }; + { + #![rustc_dummy] + #[rustc_dummy] + () + }; let _ = #[rustc_dummy] { - #![rustc_dummy] - }; + #![rustc_dummy] + }; let _ = #[rustc_dummy] { - #![rustc_dummy] - let _ = (); - }; + #![rustc_dummy] + let _ = (); + }; let _ = #[rustc_dummy] { - #![rustc_dummy] - let _ = (); - () - }; + #![rustc_dummy] + let _ = (); + () + }; let mut x = 0; let _ = #[rustc_dummy] x = 15; let _ = #[rustc_dummy] x += 15; diff --git a/src/test/pretty/vec-comments.pp b/src/test/pretty/vec-comments.pp index a150cf0b8ea8a..f2f807c59de99 100644 --- a/src/test/pretty/vec-comments.pp +++ b/src/test/pretty/vec-comments.pp @@ -4,26 +4,26 @@ fn main() { let _v1 = [ - // Comment - 0, - // Comment - 1, - // Comment - 2]; + // Comment + 0, + // Comment + 1, + // Comment + 2]; let _v2 = [0, // Comment - 1, // Comment - 2]; // Comment + 1, // Comment + 2]; // Comment let _v3 = [ - /* Comment */ - 0, - /* Comment */ - 1, - /* Comment */ - 2]; + /* Comment */ + 0, + /* Comment */ + 1, + /* Comment */ + 2]; let _v4 = [0, /* Comment */ - 1, /* Comment */ - 2]; /* Comment */ + 1, /* Comment */ + 2]; /* Comment */ } diff --git a/src/test/ui/attributes/key-value-expansion.stderr b/src/test/ui/attributes/key-value-expansion.stderr index 464e1e1cda779..1b7cb76b55366 100644 --- a/src/test/ui/attributes/key-value-expansion.stderr +++ b/src/test/ui/attributes/key-value-expansion.stderr @@ -16,11 +16,11 @@ LL | bug!(); = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info) error: unexpected token: `{ - let res = - ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], - &[::core::fmt::ArgumentV1::new_display(&"u8")])); - res - }.as_str()` + let res = + ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], + &[::core::fmt::ArgumentV1::new_display(&"u8")])); + res + }.as_str()` --> $DIR/key-value-expansion.rs:48:23 | LL | doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()} diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout index 99fe9d2e4b3c3..121138605f1a2 100644 --- a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout +++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout @@ -15,4 +15,4 @@ trait Foo {} fn foo() {} struct Range; + FROM>; diff --git a/src/test/ui/match/issue-82392.stdout b/src/test/ui/match/issue-82392.stdout index 4f46e32dc3070..2054d43c40957 100644 --- a/src/test/ui/match/issue-82392.stdout +++ b/src/test/ui/match/issue-82392.stdout @@ -7,13 +7,11 @@ extern crate std; // check-pass pub fn main() ({ - (if (true as bool) - ({ } as - ()) else if (let Some(a) = - ((Some as - fn(i32) -> Option {Option::::Some})((3 - as - i32)) - as Option) as bool) - ({ } as ()) as ()) - } as ()) + (if (true as bool) + ({ } as + ()) else if (let Some(a) = + ((Some as + fn(i32) -> Option {Option::::Some})((3 + as i32)) as Option) as bool) ({ } as ()) + as ()) + } as ()) diff --git a/src/test/ui/proc-macro/cfg-eval-inner.stdout b/src/test/ui/proc-macro/cfg-eval-inner.stdout index debbad57a8699..9d25def587cd6 100644 --- a/src/test/ui/proc-macro/cfg-eval-inner.stdout +++ b/src/test/ui/proc-macro/cfg-eval-inner.stdout @@ -1,9 +1,9 @@ PRINT-ATTR INPUT (DISPLAY): impl Foo < [u8 ; - { - #! [rustc_dummy(cursed_inner)] #! [allow(unused)] struct Inner - { field : [u8 ; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0 - }] > { #! [rustc_dummy(evaluated_attr)] fn bar() {} } +{ + #! [rustc_dummy(cursed_inner)] #! [allow(unused)] struct Inner + { field : [u8 ; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0 +}] > { #! [rustc_dummy(evaluated_attr)] fn bar() {} } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "impl", diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout index fdd178a52292f..c81fa201cbcf5 100644 --- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -4,23 +4,23 @@ struct Foo < #[cfg(FALSE)] A, B > #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : bool, third : [u8 ; - { - #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ; - #[cfg(FALSE)] let a = 25 ; match true - { - #[cfg(FALSE)] true => {}, - #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {} - } ; #[print_helper(should_be_removed)] fn removed_fn() - { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn - kept_fn() { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum - { - Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] String, u8) - } struct - TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, - #[cfg(FALSE)] bool, u8) ; fn plain_removed_fn() - { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0 - }], #[print_helper(d)] fourth : B + { + #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ; + #[cfg(FALSE)] let a = 25 ; match true + { + #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))] + false => {}, _ => {} + } ; #[print_helper(should_be_removed)] fn removed_fn() + { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() + { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum + { + Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] String, u8) + } struct + TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] bool, u8) ; fn plain_removed_fn() + { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0 + }], #[print_helper(d)] fourth : B } PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { @@ -1276,14 +1276,14 @@ PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_hel { second : bool, third : [u8 ; - { - #[cfg(not(FALSE))] struct Inner ; match true - { #[allow(warnings)] false => {}, _ => {} } ; #[print_helper(c)] - #[cfg(not(FALSE))] fn kept_fn() - { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum - { Foo(#[cfg(not(FALSE))] i32, u8) } struct - TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0 - }], #[print_helper(d)] fourth : B + { + #[cfg(not(FALSE))] struct Inner ; match true + { #[allow(warnings)] false => {}, _ => {} } ; #[print_helper(c)] + #[cfg(not(FALSE))] fn kept_fn() + { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum + { Foo(#[cfg(not(FALSE))] i32, u8) } struct + TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0 + }], #[print_helper(d)] fourth : B } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { diff --git a/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout b/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout index 6e2b6a2e5bdf6..74641058ef3d2 100644 --- a/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout +++ b/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout @@ -2,10 +2,10 @@ PRINT-DERIVE INPUT (DISPLAY): struct Foo { val : [bool ; - { - let a = #[rustc_dummy(first)] #[rustc_dummy(second)] - { #! [allow(unused)] 30 } ; 0 - }] + { + let a = #[rustc_dummy(first)] #[rustc_dummy(second)] + { #! [allow(unused)] 30 } ; 0 + }] } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { diff --git a/src/test/ui/proc-macro/quote-debug.stdout b/src/test/ui/proc-macro/quote-debug.stdout index 4bdc04b9ac430..79651f01b9534 100644 --- a/src/test/ui/proc-macro/quote-debug.stdout +++ b/src/test/ui/proc-macro/quote-debug.stdout @@ -19,29 +19,27 @@ extern crate proc_macro; fn main() { [crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("let", - crate::Span::recover_proc_macro_span(0)))), - crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello", - crate::Span::recover_proc_macro_span(1)))), - crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3d}', - crate::Spacing::Alone))), - crate::TokenStream::from(crate::TokenTree::Literal({ - let mut iter = - "\"world\"".parse::().unwrap().into_iter(); - if let (Some(crate::TokenTree::Literal(mut lit)), - None) = - (iter.next(), - iter.next()) - { - lit.set_span(crate::Span::recover_proc_macro_span(2)); - lit - } else { - { - ::core::panicking::panic("internal error: entered unreachable code") - } - } - })), - crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}', - crate::Spacing::Alone)))].iter().cloned().collect::() + crate::Span::recover_proc_macro_span(0)))), + crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello", + crate::Span::recover_proc_macro_span(1)))), + crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3d}', + crate::Spacing::Alone))), + crate::TokenStream::from(crate::TokenTree::Literal({ + let mut iter = + "\"world\"".parse::().unwrap().into_iter(); + if let (Some(crate::TokenTree::Literal(mut lit)), + None) = + (iter.next(), iter.next()) { + lit.set_span(crate::Span::recover_proc_macro_span(2)); + lit + } else { + { + ::core::panicking::panic("internal error: entered unreachable code") + } + } + })), + crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}', + crate::Spacing::Alone)))].iter().cloned().collect::() } const _: () = { diff --git a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs index 8800d3e66f9e4..82c4120b4c789 100644 --- a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs +++ b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs @@ -37,7 +37,7 @@ checker!(rename_params, r#"impl Foo fn hello(#[angery(true)] a : i32, #[a2] b : i32, #[what = "how"] c : u32) {} fn hello2(#[a1] #[a2] a : i32, #[what = "how"] b : i32, #[angery(true)] c : - u32) {} fn + u32) {} fn hello_self(#[a1] #[a2] & self, #[a1] #[a2] a : i32, #[what = "how"] b : - i32, #[angery(true)] c : u32) {} + i32, #[angery(true)] c : u32) {} }"#); diff --git a/src/test/ui/type-alias-impl-trait/issue-60662.stdout b/src/test/ui/type-alias-impl-trait/issue-60662.stdout index 14a49f20e6b22..a46047d91743d 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60662.stdout +++ b/src/test/ui/type-alias-impl-trait/issue-60662.stdout @@ -10,5 +10,5 @@ extern crate std; trait Animal { } fn main() { - pub type ServeFut = /*impl Trait*/; - } + pub type ServeFut = /*impl Trait*/; + } From 125c729e05e563b1e20b52c1b7203e3ac4feab7c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 21 Jan 2022 01:26:00 -0800 Subject: [PATCH 16/16] Restore a visual alignment mode for block comments --- compiler/rustc_ast_pretty/src/pp.rs | 32 +++++++++++++++++-- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- .../block-comment-trailing-whitespace2.rs | 6 ++-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 78b519651644a..e1f43cb20dc38 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -146,6 +146,22 @@ pub enum Breaks { Inconsistent, } +#[derive(Clone, Copy)] +enum IndentStyle { + /// Vertically aligned under whatever column this block begins at. + /// + /// fn demo(arg1: usize, + /// arg2: usize); + Visual, + /// Indented relative to the indentation level of the previous line. + /// + /// fn demo( + /// arg1: usize, + /// arg2: usize, + /// ); + Block { offset: isize }, +} + #[derive(Clone, Copy)] pub struct BreakToken { offset: isize, @@ -154,7 +170,7 @@ pub struct BreakToken { #[derive(Clone, Copy)] pub struct BeginToken { - offset: isize, + indent: IndentStyle, breaks: Breaks, } @@ -377,7 +393,10 @@ impl Printer { fn print_begin(&mut self, token: BeginToken, size: isize) { if size > self.space { self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks }); - self.indent = (self.indent as isize + token.offset) as usize; + self.indent = match token.indent { + IndentStyle::Block { offset } => (self.indent as isize + offset) as usize, + IndentStyle::Visual => (self.margin - self.space) as usize, + }; } else { self.print_stack.push(PrintFrame::Fits); } @@ -425,7 +444,10 @@ impl Printer { /// "raw box" pub fn rbox(&mut self, indent: usize, breaks: Breaks) { - self.scan_begin(BeginToken { offset: indent as isize, breaks }) + self.scan_begin(BeginToken { + indent: IndentStyle::Block { offset: indent as isize }, + breaks, + }) } /// Inconsistent breaking box @@ -438,6 +460,10 @@ impl Printer { self.rbox(indent, Breaks::Consistent) } + pub fn visual_align(&mut self) { + self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent }); + } + pub fn break_offset(&mut self, n: usize, off: isize) { self.scan_break(BreakToken { offset: off, blank_space: n as isize }) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index dff85f52b15c8..b575dc2196133 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -315,7 +315,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.word(cmnt.lines[0].clone()); self.hardbreak() } else { - self.ibox(0); + self.visual_align(); for line in &cmnt.lines { if !line.is_empty() { self.word(line.clone()); diff --git a/src/test/pretty/block-comment-trailing-whitespace2.rs b/src/test/pretty/block-comment-trailing-whitespace2.rs index 9e949726751e7..e53d51e34cefa 100644 --- a/src/test/pretty/block-comment-trailing-whitespace2.rs +++ b/src/test/pretty/block-comment-trailing-whitespace2.rs @@ -2,7 +2,7 @@ // pp-exact fn f() {} /* -The next line should not be indented. + The next line should not be indented. -That one. It shouldn't have been indented. -*/ + That one. It shouldn't have been indented. + */